Talking to the SSC-32

Working in C#, I’m trying to ‘Query Movement Status’ using the

Q

command of the form;

        serialPort1.Write("Q" + CR);

CR is defined by Char CR = Convert.ToChar(13);

And it works well on other commands but when I send the ‘Q’ command, the system hangs.

Any advice?

Do you have a delay in your program to allow the ssc-32 to receive and process the info, and then send it back?

I’m not a programming guru, but first off, which firmware is installed on the SSC-32. Some early versions did not have a very long delay when quering the SSC-32 before the reply was sent. However it didn’t really effect the PC connections as they are pretty fast.

I tried a delay but it didn’t seem to matter. The system still hung. Sounds like a may be missing something fundamental.

Does is work when you send it a “Q” in hyperterminal?

Bill I asked you what version of firmware are you using. Send the command ver and it will reply with the version number. And the delay I was refering to is the delay before the SSC-32 replys to a query, not a delay your program puts in. In fact adding a delay in your program would gurantee the response would be missed. I hope some of the programming guru’s can help you with this.

I am not a C# expert, but…

First, I am assuming you have the ssc-32 hooked up to a PC and you know the serial communications are working properly. i.e. you can communicate with it with LynxTerm or Hyperterm.

It might help to see a bigger piece of your code here. For example, right after you do the serialPort1.Write, do you try to do a read? Do you have this code in some type of exception handling block (Try Catch…)?

What do you mean when you say the system hangs? Which side hangs? If it is the PC side, I assume you are saying your PC program hangs, not the entire system?

Can you run your C# code under a debugger? If so what happens when you try to step over the line that deoes the SerialPort.Write? If you have this code in a Try/Catch block is the catch triggered? If have not tried the try/catch, you might try and maybe put a beep in it or the like…

I know that when I did VB code I needed the catch for things like this as sometimes events would happen, and if you do not provide code to handle an exception, the system code would catch the timeouts or other exceptions and kill/hang the program?

Good Luck

download the ssc terminal program and connect with that

the send Q and press return

it should reply with a fullstop if I remember rightly.

then type VER and press return…

if you get the version back then the SSC is not locked up and its something to do with your reply handling…

The following works fine on mine

Public WithEvents SSC_IO As SerialPort

Private Sub SSC_IO_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SSC_IO.DataReceived
        Dim pos As Integer
        inbuffer += SSC_IO.ReadExisting
        While InStr(inbuffer, vbCr) > 0
              pos = InStr(inbuffer, vbCr)
              If pos > 0 Then
                  'do whatever you need to do at this point
                  inbuffer = Right(inbuffer, Len(inbuffer) - pos)
              End If
        End While
End Sub

I know this is VB.NET but they are very similar

You also need to set the port correctly at load or in an init

    Public Function OpenCommPort(ByVal Port As String, ByVal Baudrate As Integer) As Boolean
        Try
            SSC_IO = New SerialPort

            With SSC_IO
                .PortName = Port      'Port name validity must be handled by calling application
                .BaudRate = Baudrate
                .DataBits = 8
                .Parity = IO.Ports.Parity.None
                .DiscardNull = False
                .Handshake = IO.Ports.Handshake.None
                .ReceivedBytesThreshold = 1
                .Encoding = System.Text.Encoding.GetEncoding(28591)
                .Open()
                Me.mvar_IsOpen = True
                Return True
            End With

        Catch ex As Exception
            mvar_IsOpen = False
            Return False
        End Try

    End Function

Thanks for the suggestion to use Terminal. It indicated that the SSC-32 is working and it does reply to the command. So far, so good. After some trial and error it appears that the ReadChar command works while the ReadLine command does not. I believe the ReadLine command expects some kind of End-of-String character where the ReadChar just grabs one character.

Now I’m struggling to ‘Wait’ for the “.” character to tell me the move has completed. Do I have to ping the SSC-32 repeatedly with “Q” and follow each “Q” with a ReadChar until I get the “.”?

I also loaded the latest FirmWare but I don’t know if that fixed anything. I was running 1.03 Beta. I’ve had the board for a while.

Anyhow, can someone post an example, similar to what PaulP posted that would work in C#?

Thanks again for all the help - Onward!

This last update changed the following properties for the queries.

Same as version 1.03X. Pulse Offset bug fixed. Added a 600uS transmit delay and a 70uS pacing for the query commands. This will allow communication with slower processors, such as the BS2.

These were added for slower processors. The PC should be able to talk fast enough to catch the responses without the delays.

Yes, you send the Q command and then you have to read a character to receive the response, which will either be a “.” (move not complete) or a “+” (move complete). This is what I do in my Python code for the SSC-32 and should be equivalent to what needs to be done in any programming language.

You should be running the 1.06 firmware.

Here is the Python code I use with the SSC-32:

[code]#!/usr/bin/python

Import the Serial module

import serial;

EOL = “\r”;
command = “”;

Set the SSC-32 port - “COM1:” for Windows, “/dev/ttyS0” for Linux

SSC32_Port = “/dev/ttyS0”;

LeftMChan = 0;
LeftMStop = 1520;

RightMChan = 1;
RightMStop = 1525;

PanChan = 2;
PanHome = 1530;
PanREnd = 2150;
PanLEnd = 900;

TiltChan = 3;
TiltHome = 1430;
TiltUEnd = 500;
TiltDEnd = 1550;

Reads single characters until a CR is read

def Response (port):
ich = “”;
resp = “”;

while (ich <> ‘\r’):
ich = port.read(1);

  if (ich <> '\r'):
     resp = resp + ich;

return resp;

Converts a servo position in degrees to uS for the SSC-32

def To_Degrees (uS):
result = 0;

result = (uS - 1500) / 10;

return result;

Converts an SSC-32 servo position in uS to degrees

def To_uS (degrees):
result = 0;

result = (degrees * 10) + 1500;

return result;

Wait for a servo move to be completed

def Wait_for_Servos (port):

ich = “”;

while (ich <> “.”):
Send_Command (port, “Q”, True);

  ich = port.read(1);

return;

Send EOL to the SSC-32 to start a command executing

def Send_EOL (port):

result = port.write(EOL);

return result;

Send a command to the SSC-32 with or without an EOL

def Send_Command (port, cmd, sendeol):

result = port.write (cmd);

if (sendeol):
Send_EOL (port);

return result;

Open the port at 115200 Bps - defaults to 8N1

ssc32 = serial.Serial(SSC32_Port, 115200);

Motors All Stop - Left = Ch0, Right = Ch1

command = “#” + str(LeftMChan) + " P" + str(LeftMStop) + " #" + str(RightMChan) + " P" + str(RightMStop);
Send_Command (ssc32, command, True);

Wait_for_Servos (ssc32);

Home the PING Pan/Tilt Base

command = “#” + str(PanChan) + " P" + str(PanHome) + " #" + str(TiltChan) + " P" + str(TiltHome);
Send_Command (ssc32, command, True);

Wait_for_Servos (ssc32);

Send the version command

command = “ver”;
Send_Command (ssc32, command, False);
Send_EOL (ssc32);

Read the response

inp = Response(ssc32);

Show what we got back

print inp;

command = “#” + str(PanChan) + “P1900” + “#” + str(TiltChan) + “P750 T5000”
Send_Command (ssc32, command, True);

Wait_for_Servos (ssc32);

Close the port

ssc32.close();

Test the conversion functions

print "600 uS = “, To_Degrees(600), " degrees.”;
print "2400 uS = “, To_Degrees(2400), " degrees.”;
print "1500 uS = “, To_Degrees (1500), " degrees.”;

print "-90 degrees = “, To_uS(-90), " uS.”;
print "90 degrees = “, To_uS(90), " uS.”;
print "0 degrees = “, To_uS(0), " uS.”;[/code]
Please note that Python is indent sensitive - that’s how it knows where code blocks begin and end.

8-Dale

The speed of a reasonably modern P.C. more often than not has the opposite effect.

It is common practice to implement a ‘WAIT LOOP’ whereby after a message has been sent, the program will wait in the loop until the response has been seen. It is also important to make sure a TIMEOUT value is used otherwise the application can wait for ever for a failed message…

e.g.

WHILE RESPONSE <> “.” AND RESPONSE <>"+" AND TIMEOUT=FALSE


WEND

TIMEOUT is a boolean flag that becomes TRUE after a timer triggers. The delay can be adjusted to suit the command response expected.

Most languages can implement this somehow.

It is exactly what my code does and works extremely well.

I’m not sure what you are saying. From my understanding of earlier versios of the SSC-32 firmware, if a BS2 asked the SSC-32 for a query, the reply was already sent to the stamp before it is was looking for the reply. So the fix was to add a delay before the reply was sent. I was told that the PC didn’t have this problem.

On the BS2 the reply would be lost because the SSC replied quicker than the the BS2 could get ready to receive…

On a PC it is running a FIFO buffer on the UART.

If you send a command to the SSC and then check to see the response it is often the case that the PC hasnt yet received the response and therefore the buffer will appear empty…

A P.C. UART by default is set to wait for 16 characters to arrive in the FIFO before handling it over to the event handler. If there arent 16 then it will eventually time out before handing them over. This delay can make it appear that the SSC took longer than it actually did to respond.

I always turn OFF the FIFO functions on the P.C. comms ports and in code I always set receive threshold to 1 to make sure that every character is handed over as it arrives and is not held in buffers anywhere.

Setting the receive threshold to 1 (or whatever you smallest message size is) makes sense but I don’t see why you would turn off the FIFO entirely. The whole point in having the FIFO is to buffer characters so you don’t loose any while waiting for the processor/OS to get around to servicing the interrupt that happened when the first character was received.

The FIFO is redundant on modern PC’s. The data is read into a buffer by Windows /Linux and held until the events are read by what ever programming language you are using.

The only time you would loose characters is if your OS load got higher than 90%.

Its a legacy concept from older, slower '486 and '586 based machines when processing was too slow for Windows / Linux to run efficiently.

I finally got things working.
The WAIT function was a good suggestion - thanks,

    private void waitfor()
    {
        Int32 position = 43;

        while (position < 44)
        {
            serialPort1.Write("Q" + CR);
            position = Convert.ToInt32(serialPort1.ReadChar());

        }

    }

I’m currently working on a similar thing but on a larger scale…

Rather than tell a leg what position to assume, I want to just say walk, stop, move sideways etc and let it work out what to do.

The problem I’m having is trying to interleave movement commands with position queries and adc responses and knowing which was which. I can see how I need to achieve it and its almost there but getting the code just right is doing my head bigtime.

I have a group of wait states that I’ve set up and when a response comes in, dependent upon which state is set it will decode the response differently. It needs a bit of tuning but so far its going well.