Programming ssc-32 using C# - serial port communication

I’m using C# to program my ssc-32 from my PC. I can write commands to it, but I can’t completely figure out how to get feedback from it.

I’m trying to use the query movement status ("Q ") and query pulse width commands ("QP ") that it talks about in the ssc-32 manual.

Here’s one of the methods I’ve tried so far:

try { serialPort.Write("Q \r"); string output = serialPort.ReadExisting(); Console.WriteLine("Output:" + output); } catch (TimeoutException) { }

It worked mostly with “Q \r”, but didn’t output anything using the “QP \r” command. Does the need to be something different?

Let me know if anyone knows how to do this,

Thanks!

You might need to place a delay between the sending a command and trying to read a response from the chip. The chip needs a little bit of time to do its thing and reply.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static SerialPort _serialPort;

        static void Main(string] args)
        {
            try
            {
                _serialPort = new SerialPort();
                _serialPort.PortName = "COM3";
                _serialPort.Open();
                _serialPort.Write("#27 P1600 S750\r");
                string output;
                output = "";
                //Example: "Q <cr>"
                //This will return a "." if the previous move is complete, or a "+" if it is still in progress.
                while (!(output == ".")) //loop until you get back a period
                {
                    _serialPort.Write("Q  \r");
                    output = _serialPort.ReadExisting();
                    Console.WriteLine(output);
                    Thread.Sleep(10);
                }
                _serialPort.Close();
            }
            catch (TimeoutException) { } 
        }
    }
}

excellent! Adding the delay makes the “Q \r” command work.

I still can’t get the "QP " command to work though. I think I’m formatting it incorrectly for C#.

Should it be “QP \r” or does the have to be something different?

The byte you receive might not be a printable character. Try sending the servo position 1100 and then see if you get an ascii “n” position reply when queried.

It doesn’t get an ascii “n” position when queried. I just checked and the manual says it will return a binary value. Do I have to convert this to a string in order for it to print? ReadExisting() only returns a string I believe, so will it not read the position that’s returned?

What would be returned is 110 decimal, 6E hex, and 1101110 binary. Save the returned value as a sting value and it should print as an n. You can try this using lynxterm.

We had similar problems initial problems in Tcl. This code worked for us. Had problems reading the response from the SSC32 when querying prior to using this. This event-based program in Tcl worked. If you are using RIOS to program the robot (very easy to do) but need the ASCII strings to send down the line without RIOS, export your sequence to Basicstamp. The code there contains the pulsewidths. You dont need to work out the calibrations from XYZ that are internal to RIOS that way.

You don’t really need to use the querying to control the robot: if you use a BS2 controller (we did not), it just waits for a time longer than you tell the motion to complete in. But if you want to query this worked.

We used Tcl to strip out the relevant ascii strings from the BS2 code and write them to the input files that this program reads; i.e. the ASCII input file looks like many many lines of the form
#0 P699 #1 P893 #2 P1543 #3 P1011 #4 P1899 T1500
automatically stripped out of the bs2 code.

This version works to debug any problems you may have. All I can say is that it worked on my PC. Eventually we used the ASCII strings in the sequences and transferred them to a VMS system [yes still some around] to control the arm (with no querying, just waiting between each instruction).

Minor adaption from a program written to communicate with a modem on at website (stripped html to avoid problems with this site) wiki.tcl.tk/447

Uses event-driven programming to read the reponse from

the SSC-32 board when polling the board for the state by repeatedly

sending “Q” for query and waiting for a period to indicate motion completed

before sending next string in sequence

Original comments below

#=========================================================

simple serial port example to send AT to modem and

wait for OK response in a fixed amount of time. At the

bottom is a simple loop to do this 20x to check serial

handler reliability…

Works well on Tcl 8.0 and up on Unix (Solaris/NT), poorly on

the tclsh included with Tcl 8.1.1 on NT, but pretty well on

the wish included with same.

NOTE may need to set comPort appropriately for your

platform. Must have a modem configured to respond

with “OK” to “AT” commands.

=============================================================

Only major changes are to the MAIN body

switch $tcl_platform(os) {
{Linux} {set comPort /dev/modem}
{SunOS} {set comPort /dev/cua/a}
{Windows NT} {set comPort COM1:}
default {error “Must configure comPort”}
}
set waitSecs 2
set nTries 2000

A cheap version of expect.

Set up a event-driven I/O reader on the channel, output the

string, and wait some number of seconds for the result.

@param fh

a channel opened in non-blocking mode for I/O

with buffering turned off.

@param outstr

a string to send to the output channel – note: end-

of-line characters must be included in this string,

if desired.

@param regexp

regular expression to match in the incoming data.

@param seconds

number of seconds to wait for above match

@throws error

if eof is detected on the channel while waiting

@returns int

1 if a match is found, 0 otherwise.

proc send_expect {fh outstr regexp seconds} {
global send_exp

 # make sure global vars are initialized properly
 set send_exp($fh.matched)        0
 if {![info exists send_exp($fh.buffer)]} {
     set send_exp($fh.buffer) {}
 }

 # set up our Read handler before outputting the string.
 if {![info exists send_exp($fh.setReader)]} {
     fileevent $fh readable [list private_send_exp_reader \
             $fh $regexp]
     set send_exp($fh.setReader) 1
 }

 # output the string to send
 puts -nonewline $fh $outstr
 flush $fh

 # set up a timer so that we wait a limited amt of seconds
 set afterId [after [expr {$seconds*1000}] \
         [list set send_exp($fh.matched) 0]]
 vwait send_exp($fh.matched)
 set matched $send_exp($fh.matched)
 unset send_exp($fh.matched)
 catch [list after cancel $afterId]

 # If we got an eof, then throw an error
 if {$matched < 0} {
     error "Channel EOF while waiting for data"
     return 0
 }
 return $matched

}

PRIVATE channel read event handler for send_expect. Should

not be called by user.

proc private_send_exp_reader {fh regexp} {
global send_exp

 if {[eof $fh]} {
     close $fh
     set send_exp($fh.matched) -1
     return
 }
 append send_exp($fh.buffer) [read $fh]
 if {[regexp $regexp $send_exp($fh.buffer)]} {
puts stdout "buffer content $send_exp($fh.buffer)"
     set send_exp($fh.matched) 1
 }

}

Return the current contents of the send_expect buffer

@param fh

channel identifier that was used with send_expect

@returns string

the current contents of the buffer for the channel

proc send_exp_getbuf {fh} {
global send_exp
return $send_exp($fh.buffer)
}

Reset the send_expect buffer, returning its contents

@param fh

channel identifier that was used with send_expect

@returns string

the current contents of the buffer for the channel

proc send_exp_resetbuf {fh} {
global send_exp

 set buf $send_exp($fh.buffer)
 set send_exp($fh.buffer) {}
 return $buf

}

Close out a send_expect session, closing I/O event handler

@param fh

channel identifier that was used with send_expect

@returns

the channel identifier passed as the fh parameter

proc send_exp_end {fh} {
global send_exp

 fileevent $fh readable {}
 foreach v [array names send_exp $fh.*] {
     catch [list unset send_exp($v)]
 }
 return $fh

}

MAIN

Ugly but it works on a PC

Reads files with sequences of strings to be sent to the SSC32 of the form

Polls the SSC32 continuously until it receives a period and then sends the next

string in the sequences

fh is the RS232 channel (COM1) and is configured. Note necessary to match board speed

with jumpers on the SSC32 board with the open fconfigure stmt or it won’t work.

filechn is the channel to your file containing the ASCII strings to send to the SSC32

set fh [open $comPort RDWR]
fconfigure $fh -blocking 0 -buffering none
-mode 115200,n,8,1 -translation binary -eofchar {}

set period “.”

Loops until it reads EOF on the sequences defined in your input file

while {1} {

puts -nonewline stdout "Which file do you want to run: "
flush stdout
gets stdin filename
set filechn [open $filename r]

while {![eof $filechn] } {
gets $filechn pulsestring
puts $fh $pulsestring
puts $fh “\r”
#send a CR
puts stdout $pulsestring

#Original function comment below
#============================================================

Loop nTries times, sending AT to modem and expecting OK.

#============================================================

modified to send Q and print out what is received in the buffer

once it arrives. Once a period is received the next instruction

is read from the file and the process repeated until all drives completed.

set nMatches 0
for {set i 0} {$i < $nTries} {incr i} {
if {[send_expect $fh “Q\r” “.” $waitSecs]} {
incr nMatches
regsub -all “\r” [send_exp_getbuf $fh] {\r} buf
regsub -all “\n” $buf {\n} buf

puts “GOT MATCH: <$buf>”

if {
       $buf == $period
    } then {
    puts "Got ."
break
}
 } else {
     puts "NO MATCH IN $waitSecs SECONDS"
 }
 send_exp_resetbuf $fh

};
};#while EOF closure
send_exp_end $fh
close $filechn
puts “Matched $nMatches/$nTries
([expr 100.0*$nMatches/$nTries]%)”
};#infinite while