How to use serial .write to send specific 3 byte command over serial


This is my setup to control a robotic arm comprised of 9 servos. I need to send a 3 byte command to a servo controller over a serial connection. They must be sent as individual byte values, not as text representations of numbers. This is what the manual states:

For example, to run servo 3 at a speed of 4 units per frame to position 100, your instruction would be as follows. [255, (128+3), 100]

The code I have been playing with and failing is this:

#include <SoftwareSerial.h>

const byte rxPin = 10;
const byte txPin = 9;

byte sync = 255;
byte pos = 127;
byte servo = 0;

// Set up a new SoftwareSerial object
SoftwareSerial mySerial (rxPin, txPin);

void setup() {
  // put your setup code here, to run once:
mySerial .begin(9600); // set up Serial library at 9600 bps
}

void loop() {
 // put your main code here, to run repeatedly:
mySerial .write(sync);
mySerial .write(servo);
mySerial .write(pos);
delay(10000);
pos = 184;
mySerial .write(sync);
mySerial .write(servo);
mySerial .write(pos);

pos = 127;
delay(10000);
}

Ultimately I want to be able to create movements that would consist of numerous commands strung together to create a full function such as picking something up, etc. But I cant seem to figure out how to get the command to the servo controller to even begin. Currently my code does not move the servos at all and I never see the LED flash on the servo controller indicating it has received a command. Using the same code on the hardware serial and printing it I get:

�255
0
127
�255
0
127�255
0
127
�255
0
127

so it seems to be sending the numbers but I guess not correctly?

Note the order of the bytes in the example

Compare that with the order of the bytes sent by your code

Note too how the servo number is represented, ie 128 + servo number

Once you have the servo working as in your sketch there is a better method to send 3 bytes with a single command. Note that I used the example values

byte command[] = {255, 128+3, 100};
mySerial.write(command, sizeof(command));
1 Like

How did you wire the Serial line?


this will work

Working with arrays as indicated by @UKHeliBob is possible too and help you pack everything together.

You could also work with a structure if you need nice names for each byte of a command

struct __attribute__((packed, aligned(1))) Command {
  byte sync;
  byte servo;
  byte pos;
};

Command runServo1Command = {255, 1, 127};

size_t execute(const Command& command) {
  return Serial.write(reinterpret_cast<const uint8_t*>(&command), sizeof command);
}

void setup() {
  Serial.begin(115200);
  execute(runServo1Command);
  runServo1Command.pos = 184;
  execute(runServo1Command);
}

void loop() {}

Also, if the sync byte is always 255 then it does not need to be part of the structure or array, it can just be inserted in the execute function

struct __attribute__((packed, aligned(1))) Command {
  byte servo;
  byte pos;
};

Command runServo1Command = {1, 127};

bool execute(const Command& command) {
  size_t cptr = Serial.write(0xFF);
  cptr +=  Serial.write(reinterpret_cast<const uint8_t*>(&command), sizeof command );
  return cptr == 3; // will return true if the 3 bytes have been sent (YMMV)
}

void setup() {
  Serial.begin(115200);
  execute(runServo1Command);
  runServo1Command.pos = 184;
  execute(runServo1Command);
}

void loop() {}

(of course use your mySerial instead of Serial)

I tried this code, and the other coding examples presented by others, but got no response from the servo controller. It should have its LED light go off after receiving its first command then blink on any further commands. This puzzled me so much that I reinstalled the old mini-ABB board using a BS2 chip to make sure the servo controller still worked. It did. The ABB board has 3 buttons and they are currently programmed to pickup a ping pong ball, insert it in a holder, which then throws it. This was programmed with Basic Stamp, but not by me obviously. The basic stamp 2 program example to send a command looks like this:

serout 8,n96n, [sync, svo + speed, pos1]

It seems like my softwareserial port isn't working? How can I test to see if anything is actually being transmitted? I know I can serial.println on the hardware serial port. Is there a way to forward that output to the hardware serial port so I can see what is being sent, if anything?

This is all good stuff that I hope to incorporate, but I've tried the various code given to me and cant get any response from the servo controller. I put back my old mini-ABB board and confirmed that the servo controller board is still working. I'm wondering if my software serial is even transmitting anything. I can see the numbers being transmitted on the hardware serial when testing, but I'm not sure how to confirm if the softwareserial port is even sending anything. Is there a way to echo the transmitted variables on a software serial?

The serial is wired with the serial TX on the arduino, pin9, going to the serial-in port on the servo controller board, and then a ground from the servo controller board going to GND on the arduino. Its pretty much just like how the mini-ABB board is wired .

if there is such a thing, what's the type of sync, svo, speed and pos1 ? are you sure they are sent on one byte ?

That is from the manuals section on programming for the SSC-12 or mini SSC III which is what the servo controller is called. This is old stuff, but still just uses the simple mini SSC-II protocol. They are sent as 3 individual bytes like:

  >  BYTE 1         BYTE 2        BYTE 3

[sync marker (255)] [servo # (0-11) [position (1-254)]

Ok

I was wondering if some variables would fit on 2 bytes

What baud rate does the serial interface on the servo controller run at ?

The manual says it is fixed at 9600 baud.

TLDR: Try changing:

to

SoftwareSerial mySerial (rxPin, txPin, true);

so... First, let me say that despite the various suggestions on how to do it better, the code that you have in the original post SHOULD WORK FINE. I do not see anything wrong with the code, or with your translation of what you say you're trying to do to what you've actually done. Serial.write() is the function you want for writing raw bytes.

If this is the Servo Controller you are using: https://www.seetron.com/docs/ssc2mnl.pdf then there are a couple of worrying aspects:
It mentioned a bitrate jumper, which if omitted will cause the board to operate at 2400bps rather than 9600bps. I'll assume that this is present, since it works with your stamp...
More seriously, the manual implies that the board is designed to connect directly to the DB9 serial port of a PC. This would mean "rs232 levels", which are INVERTED compared to the signals put out on Arduino's "TTL level" pins. (They're a different voltage, too, but that shouldn't matter in this case.) A quick glance at a BASIC stamp manual implies that it also will typically output "rs232-like" signals, rather than "ttl-like.

If (2) is your problem, you'll be happy to know that there's an option in the softwareSerial library to output inverted signals.

SoftwareSerial(rxPin, txPin, inverse_logic);

// used like:

SoftwareSerial mySerial(9, 10, true);

Give it a try...

1 Like

Look in your documentation and see what the "n96n" means in words. You may be making assumptions that are wrong.

Ahh. It may be a symbol defined deep in the Stamp IDE, but the SEROUT documentation does rather imply that "baud codes" starting with N are "inverted."

In the Basic Stamp 2 program n96n is a variable name with a value of $4054 which sets a baudmode of 9600, if I understand it correctly. I actually was searching to find what it stood for and then went back and realized it was just a variable name they used to set the 9600 baud rate on. This is a Basic Stamp II program that the manual uses to demonstrate sending commands to the servo controller:

TLDR: IT WORKED!

First, this servo controller is the mini SCC III or SCC-12 which was made by seetron for Lynxmotion specifically for use in one of their hexapod models. It doesn't have the jumpers to change baudrate. It is hard coded at 9600. It does have a serial in pin and also an RJ11 connection for serial. I'm using the serial in pin.

Second, I had wondered if the serial connection was actually being established and just started looking at the whole inverted thing based on some info I found elsewhere, but didn't know enough about anything to actually try to implement it. Having said that.....it worked! I'm not sure why the manual didn't mention anything about needing to be inverted but it also could just be my inexperience. Thanks again!

I'd like to thank everybody that had input here. All the code was good info that I just needed a working serial connection to try and play with. LOL.

Could this code be somehow used to take a long string of these 3 byte commands and send them all so as to make a function out of the entirety which could then be set to execute using a button? Or would I need something different?

Maybe? At some point you may run into problems with how many commands the SSC can accept an process without "pauses." The Arduino can write the data very fast; probably significantly faster than any loop on a Basic Stamp.

Glad you got it working!

From a technical perspective, if you had a 100 bytes array filled with instructions then the same line of code would work

byte command[100] ;
… // code to fill in the array
mySerial.write(command, sizeof command); // send the 100 bytes

You need to double check what are the capabilities on the other side to buffer this data though, the arduino won’t pause and at 9600 bauds the 100 bytes will be out in roughly 100ms