Pololu Mini SSC under Linux not moving servo

I have a single servo that I am using to move a foamcore arrow like the dial of a meter, to point to various points around it. The servo is connected to a Micro Serial Servo Controller (the manual for it is here: https://www.pololu.com/file/0J37/ssc03a_guide.pdf).

In order to avoid power problems, the servo controller is powered with a 9V 700mA power brick, the servo power is provided by a 5.5V 500mA power brick with a 1000uF capacitor across it, and the Vcc=Vss jumper is removed. That way, if the servo consumes a lot of power, it will not cause the Micro SSC to reset.

The serial connection is from the RS-232 input on the MicroSSC to a straight-through DB9 cable to the serial port on the back of my computer. I had been using a USB-Serial converter, but removed it to see if it was the source of the problem.

My code is at the end of this message. If I set the #define statement so that it is not in MiniSSC II mode, remove the mode jumper so that the board is in Pololu mode, and apply power to the board, the yellow LED comes on and the servo moves. Each time I plug the servo controller in, if the servo is clockwise of a specific position, the servo moves to the specific position. If the servo is counterclockwise of that position, it moves to that position when the program starts.

When I start the program, the yellow LED goes out, and the green LED flickers three times, each 3 seconds apart, as I would expect. However, the servo does not move. When the program ends, all the LEDs are off and the servo is receiving a position signal (it resists turning).

If I re-run the program, the green LED blinks again, as above, when the serial data is sent.

If I add the MiniSSC II mode jumper, the servo does not move when power is applied to the board. The yellow LED comes on. When I run the program, the yellow LED goes out and the green one blinks three times, at three second intervals as before. However, the servo does not move. It also does not resist being turned by hand, so it isn’t getting any positioning signal.

I have tried:

  • Using just the serial cable, using just the USB-serial converter, and using both. The symptoms remain the same.

  • Switching which Micro SSC I use (I have two).

  • Switching which servos I use

  • Switching which port the servos are connected to

  • Changing to the termio configuration from this project: pololu.com/docs/0J4?view_all=1#4

  • Switching between Pololu mode and MiniSSC II mode.

  • Reconfiguring the servo numbers as per page 8 of the instruction manual. The yellow and red LEDs do not light, as the manual says they should, and the green LED blinks once, rather than twice.

  • Using a benchtop supply for the servo.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#define MINISSC

#ifdef MINISSC
#define BAUDRATE B9600
#else
#define BAUDRATE B38400
#endif

#define DEVICE "/dev/ttyS0"

int main(char** argv, int argc) {
	int fd, c, res;
	struct termios oldtio, newtio;
	unsigned char cmd[16];

	fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY); // avoid controll chars

	if (fd < 0) {
		perror(DEVICE);
		exit(-1);
	}

	tcgetattr(fd, &oldtio); // save current port settings
	bzero(&newtio, sizeof(newtio)); // clear struct for new port settings */
	// these settings come from the pololu site
	newtio.c_iflag = 0;
	newtio.c_lflag = 0;
	newtio.c_oflag = 0;
	newtio.c_cflag = BAUDRATE | CS8 | CLOCAL;
	newtio.c_cc[VTIME] = 0;
	newtio.c_cc[VMIN] = 1;

	// flush and apply settings
	tcflush(fd, TCIFLUSH);
	tcsetattr(fd, TCSANOW, &newtio);

#ifdef MINISSC
	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x00; // 0th servo
	cmd[2] = 0x80; // middle position

	res = write(fd, cmd, 3);
	if (res != 3)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x00; // 0th servo
	cmd[2] = 0x00; // Left position

	res = write(fd, cmd, 3);
	if (res != 3)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x00; // 0th servo
	cmd[2] = 0xFF; // Right position

	res = write(fd, cmd, 3);
	if (res != 3)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);
#else
	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x00; // first servo
	cmd[4] = 0x02; // First position, 600
	cmd[5] = 0x58; //
	cmd[6] = 0x00;

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x00; // first servo
	cmd[4] = 0x0b; // Middle position, 3000
	cmd[5] = 0xb8;
	cmd[6] = 0x00;

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x00; // first servo
	cmd[4] = 0x13; // End position, 5000
	cmd[5] = 0x88;
	cmd[6] = 0x00;

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);
#endif

	/* restore the old port settings */
	tcsetattr(fd, TCSANOW, &oldtio);
}

That code is based on code from https://forum.pololu.com/t/micro-serial-servo-controller-on-linux-problem/3103/1, where the problem was the power supply. I’ve tried adding the lines from https://forum.pololu.com/t/lower-7bits-0x0a/2922/1, but the behavior persists.

I switched to 180 degree ranges rather than 90 degree ranges in MiniSSC II mode, and that seems to have it working, at least well enough for my purposes.

My setup is this:
One Futaba S3003 on port 1 of the MicroSSC.
5.6VDC supplied to the servo power connection from a benchtop power supply
9VDC @ 600mA supplied to the servo controller power connection from a wall wart.
The code at the end of this post.

Anything else, I make no guarantees about.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

#define MINISSC

#ifdef MINISSC
#define BAUDRATE B2400
#else
#define BAUDRATE B19200
#endif

#define DEVICE "/dev/ttyS0"

int main(char** argv, int argc) {
	int fd, c, res;
	struct termios oldtio, newtio;
	unsigned char cmd[16];

	fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY); // avoid control chars

	if (fd < 0) {
		perror(DEVICE);
		exit(-1);
	}

	tcgetattr(fd, &oldtio); // save current port settings
	bzero(&newtio, sizeof(newtio)); // clear struct for new port settings */
	// these settings come from the pololu site
	/* go to 9600 baud */
	cfsetispeed(&newtio, BAUDRATE);
	cfsetospeed(&newtio, BAUDRATE);

	newtio.c_cflag |= (CLOCAL | CREAD); /* enable */

	newtio.c_cflag &= ~PARENB; /* 8N1 */
	newtio.c_cflag &= ~CSTOPB;
	newtio.c_cflag &= ~CSIZE;
	newtio.c_cflag |= CS8;

	// flush and apply settings
	tcflush(fd, TCIFLUSH);
	tcsetattr(fd, TCSANOW, &newtio);

#ifdef MINISSC
	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x09; // 0th servo
	cmd[2] = 0x05; // Left position

	res = write(fd, cmd, 3);
	if (res != 3)
	printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x09; // 0th servo
	cmd[2] = 0x80; // Left position

	res = write(fd, cmd, 3);
	if (res != 3)
	printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0xFF; // MiniSSC sync
	cmd[1] = 0x09; // 0th servo
	cmd[2] = 0xC0; // Right position

	res = write(fd, cmd, 3);
	if (res != 3)
	printf("Error writing to %s\n", DEVICE);

	sleep(3);
#else

	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x01; // first servo
	cmd[4] = 0x02; // First position, 600
	cmd[5] = 0x58; //

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x01; // first servo
	cmd[4] = 0x0b; // Middle position, 3000
	cmd[5] = 0xb8;

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

	cmd[0] = 0x80; // synchronization value (always 0x80 for pololu)
	cmd[1] = 0x01; // device type always 0x01
	cmd[2] = 0x04; // set position
	cmd[3] = 0x01; // first servo
	cmd[4] = 0x13; // End position, 5000
	cmd[5] = 0x88;

	res = write(fd, cmd, 6);
	if (res != 6)
		printf("Error writing to %s\n", DEVICE);

	sleep(3);

#endif

	/* restore the old port settings */
	tcsetattr(fd, TCSANOW, &oldtio);
}

Hello.

If you have anything working at all (e.g. MiniSSC II mode with 180-degree range), all of your hardware and connections are probably fine, and you probably have some mistake in the bytes you are sending in the other cases. I didn’t look at your code much, but as an example, in your first post, you used 0x00 for the second byte and the comment says “0th servo” even though you are using channel 1. In general, sending commands to the wrong servo will result in behavior like you are describing, where the servo controller lights are blinking normally but the servo doesn’t do anything.

- Jan