PDA

View Full Version : baby steps with the pololu servo controller



csdude
01-17-2010, 05:50 PM
Hello all,

So I finally had time to start playing with the pololu servo controller.

I hooked it up to a Linux box (both on a serial port, and a serial port via USB), but I don't get much response. (none actually)

I see the orange light go out when I send something (and come back on) when connected via a USB emulated serial port (so it is getting something).

what is the command set? (Is there a "hello, is there anybody out there?" command? that prints a version number or so?

any examples? (preferably in C?)

MikeG
01-17-2010, 06:08 PM
The command set is in the pololu servo controller manual
http://www.pololu.com/file/0J38/ssc04a_guide.pdf

csdude
01-17-2010, 06:20 PM
The command set is in the pololu servo controller manual
http://www.pololu.com/file/0J38/ssc04a_guide.pdf

Right, I have the manual, but wondering if there was more.

So I am doing this:

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; // set to 3000, high = 0x0B
cmd[5] = 0xB8; // low = 0xB8
cmd[6] = 0x00;

cmd being an unsigned char cmd[16];

That should put the 1st servo in 'neutral' correct?

lnxfergy
01-17-2010, 07:34 PM
Just checking, you've got the jumpers correct, right?

-Fergs

Formori
01-17-2010, 07:43 PM
I'm not sure what the command structure for the Pololu mode is, so I'm not sure what the problem is there. But if you want to troubleshoot any connetion problems first, change the jumper to the Mini-SCII mode (I'm assuming you have an 8-channel version controller?) and enter the basic control mode, which for centered is;

1st = 0x00 (initialize)
2nd = 0x00 (device #) (device is 1st, therefore named zero)
3rd = 0x80 (position)

If you try this (if this is completely correct, check your manual, I'm not sure since I haven't used mine in a while :D), and your still not getting anything out, then it's your connection, so maybe try another serial source? Different baud rate?

If this works then it's just the Pololu mode code not receiving properly, if it receives properly it should flash the green light during transmission.

Hope this helps, but it would be really useful to find out which controller your trying to send the commands to? :confused:

csdude
01-17-2010, 08:22 PM
Just checking, you've got the jumpers correct, right?

-Fergs

Yes I have the jumpers correct. I hooked it up to a windows 7 box. I can "center" the servo, but not make it move anywhere else.

On Linux I am still trying to figure if it isn't the port settings BUT I do see the orange light go on and off (off when I access the port)

csdude
01-17-2010, 08:23 PM
I'm not sure what the command structure for the Pololu mode is, so I'm not sure what the problem is there. But if you want to troubleshoot any connetion problems first, change the jumper to the Mini-SCII mode (I'm assuming you have an 8-channel version controller?) and enter the basic control mode, which for centered is;

1st = 0x00 (initialize)
2nd = 0x00 (device #) (device is 1st, therefore named zero)
3rd = 0x80 (position)

If you try this (if this is completely correct, check your manual, I'm not sure since I haven't used mine in a while :D), and your still not getting anything out, then it's your connection, so maybe try another serial source? Different baud rate?

If this works then it's just the Pololu mode code not receiving properly, if it receives properly it should flash the green light during transmission.

Hope this helps, but it would be really useful to find out which controller your trying to send the commands to? :confused:


I will try that, thanks. I do have the pololu 8 port servo controller. I'll try to set it in that other mode. and see what happens.

thanks!

MikeG
01-17-2010, 08:35 PM
I guess your USB to serial adapter is working since it works in Windows? Your using the Pololu Mode? The suggestion above was to use SSCII mode. Have you tried that? (Edit: late on the post)

According to the manual the protocol is 8N1. Did you setup the serial port correctly? It's hard to help because you have not give much information. We are all just guessing. How about posting all your code.

csdude
01-17-2010, 09:36 PM
here's the code:
(I am still working on getting things in the other mode) (and I switched the DTR/RTS jumper to CTS



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

#define BAUDRATE B38400
#define DEVICE "/dev/ttyUSB0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */

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

fd = open(DEVICE, O_RDWR | O_NOCTTY ); // 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);

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; // set to 3000, high = 0x0B
cmd[5] = 0xb8; // low = 0xB8
cmd[6] = 0x00;

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

sleep(3);

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

jes1510
01-17-2010, 09:36 PM
Code for an Arduino to talk to a Pololu serial controller via a software serial port:





void servoAbsolute(int servo, int angle)
{//servo is the servo number (typically 0-7)
//angle is the absoltue position from 500 to 5500
digitalWrite(greenLED, HIGH);

unsigned char buff[6];

unsigned int temp;
unsigned char pos_hi,pos_low;

temp=angle&0x1f80;
pos_hi=temp>>7;
pos_low=angle & 0x7f;

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x04;//command number
buff[3]=servo;//servo number
buff[4]=pos_hi;//data1
buff[5]=pos_low;//data2

for(int i=0;i<6;i++){
mySerial.print(buff[i],BYTE);
//Serial.println((buff[i] + '0'), BYTE);
}
digitalWrite(greenLED, LOW);
}

void servoSpeed(int servo, int value) {
unsigned char buff[5];

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x01;//command number
buff[3]=servo;//servo number
buff[4]=value;//Servo Speed
for(int i=0;i<5;i++){
mySerial.print(buff[i],BYTE);
// Serial.print(buff[i], BYTE);
}
}



void servoSet8Bit(int servo, int angle)
{//servo is the servo number (typically 0-7)
//angle is the absoltue position from 500 to 5500

unsigned char buff[6];

unsigned int temp;
unsigned char pos_hi,pos_low;

temp=angle&0x1f80;
pos_hi=temp>>7;
pos_low=angle & 0x7f;

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x03;//command number
buff[3]=servo;//servo number
buff[4]=pos_hi;//data1
buff[5]=pos_low;//data2

for(int i=0;i<6;i++){
mySerial.print(buff[i],BYTE);

}
}


void setServoParam(int servo, int data) {
unsigned char buff[5];
buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x03;//command number
buff[3]=servo;//servo number
buff[4]=data;


for(int i=0;i<5;i++){
mySerial.print(buff[i],BYTE);
//Serial.println((buff[i] + '0'), BYTE);

}
}

Edit: i don't know if that is useful to you but I have been meaning to post it for a while.

csdude
01-17-2010, 10:00 PM
Code for an Arduino to talk to a Pololu serial controller via a software serial port:





void servoAbsolute(int servo, int angle)
{//servo is the servo number (typically 0-7)
//angle is the absoltue position from 500 to 5500
digitalWrite(greenLED, HIGH);

unsigned char buff[6];

unsigned int temp;
unsigned char pos_hi,pos_low;

temp=angle&0x1f80;
pos_hi=temp>>7;
pos_low=angle & 0x7f;

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x04;//command number
buff[3]=servo;//servo number
buff[4]=pos_hi;//data1
buff[5]=pos_low;//data2

for(int i=0;i<6;i++){
mySerial.print(buff[i],BYTE);
//Serial.println((buff[i] + '0'), BYTE);
}
digitalWrite(greenLED, LOW);
}

void servoSpeed(int servo, int value) {
unsigned char buff[5];

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x01;//command number
buff[3]=servo;//servo number
buff[4]=value;//Servo Speed
for(int i=0;i<5;i++){
mySerial.print(buff[i],BYTE);
// Serial.print(buff[i], BYTE);
}
}



void servoSet8Bit(int servo, int angle)
{//servo is the servo number (typically 0-7)
//angle is the absoltue position from 500 to 5500

unsigned char buff[6];

unsigned int temp;
unsigned char pos_hi,pos_low;

temp=angle&0x1f80;
pos_hi=temp>>7;
pos_low=angle & 0x7f;

buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x03;//command number
buff[3]=servo;//servo number
buff[4]=pos_hi;//data1
buff[5]=pos_low;//data2

for(int i=0;i<6;i++){
mySerial.print(buff[i],BYTE);

}
}


void setServoParam(int servo, int data) {
unsigned char buff[5];
buff[0]=0x80;//start byte
buff[1]=0x01;//device id
buff[2]=0x03;//command number
buff[3]=servo;//servo number
buff[4]=data;


for(int i=0;i<5;i++){
mySerial.print(buff[i],BYTE);
//Serial.println((buff[i] + '0'), BYTE);

}
}

Edit: i don't know if that is useful to you but I have been meaning to post it for a while.


Hi Jes,

That is kinda what I am doing.

btw, I found out a few mins ago that the board ships in Mini SSC II mode. In pololu mode I can move the servo around on the windows box (I used the pololu test program).
I am sending the exact same thing to the serial port on the linux box.

It must be a port setting I am not having right

csdude
01-17-2010, 10:09 PM
I guess your USB to serial adapter is working since it works in Windows? Your using the Pololu Mode? The suggestion above was to use SSCII mode. Have you tried that? (Edit: late on the post)

According to the manual the protocol is 8N1. Did you setup the serial port correctly? It's hard to help because you have not give much information. We are all just guessing. How about posting all your code.

I noticed the board comes in MINI mode. yes I have the port set to 8N1 (8 bit, no parity 1 stop bit)

Adrenalynn
01-17-2010, 11:23 PM
I was just commenting your serial code and noticed you're not opening with the O_NDELAY flag...

If you don't have DCD connected and supported, that's going to be a pretty negative thing.

The O_NDELAY flag tells UNIX that this program doesn't care about the state of the DCD line. It's great if you've got a terminal with all the lines supported (it tells us if the other side is up or not), and a requirement if you have a modem, but who knows whether the board even brings-up DCD? And if your cable has a DCD wire - If you don't specify the flag, then your process gets put to sleep until the DCD line is brought to the space voltage.

I stopped reading your uncommented serial code there. :) If that doesn't work, I'll go comment the rest of it. The other thing _I'd_ do is hook up a cross over cable from one serial port to another, or over to the Windows box and then run RealTerm (free) on the Windows machine and set it up to listen to what Linux is sending. Sometimes you get kernel messages out on the first terminal, and that can really ruin your day.

>> I hooked it up to a Linux box (both on a serial port

>> [from code]
#define DEVICE "/dev/ttyUSB0"

I hope you didn't do that then, right? ;)

csdude
01-18-2010, 12:50 AM
I was just commenting your serial code and noticed you're not opening with the O_NDELAY flag...

If you don't have DCD connected and supported, that's going to be a pretty negative thing.

The O_NDELAY flag tells UNIX that this program doesn't care about the state of the DCD line. It's great if you've got a terminal with all the lines supported (it tells us if the other side is up or not), and a requirement if you have a modem, but who knows whether the board even brings-up DCD? And if your cable has a DCD wire - If you don't specify the flag, then your process gets put to sleep until the DCD line is brought to the space voltage.

I stopped reading your uncommented serial code there. :) If that doesn't work, I'll go comment the rest of it. The other thing _I'd_ do is hook up a cross over cable from one serial port to another, or over to the Windows box and then run RealTerm (free) on the Windows machine and set it up to listen to what Linux is sending. Sometimes you get kernel messages out on the first terminal, and that can really ruin your day.

>> I hooked it up to a Linux box (both on a serial port

>> [from code]
#define DEVICE "/dev/ttyUSB0"

I hope you didn't do that then, right? ;)

Hey Lynn,

I realized the ndelay just a few mins ago... I changed that, BUT still no cigar
(I have to build another x-over cable, *lol* I cleaned out the garage this summer and found one and was thinking "when would I ever use that again?"

csdude
01-18-2010, 01:48 AM
alright,

I have some servo's moving... with just some wild guesses as parameters.

However I it only works if I take the DTR/RTS reset jumper off. (that probably means my port is keeping and DTR and RTS high and constantly resets the port? If I take the jumper off it works, but of course that way I can't reset the board.

Another thing I have to figure out is what exactly goes into byte 5 and 6 of the "pololu" command x04
(and the the other 5 commands for that matter)

thanks all for helping me so far!

Ron

jes1510
01-18-2010, 08:24 AM
If you are talking about the absolute position command then that is the first one in the code that I posted ("servoAbsolute"). Byte 5 is the high byte of the servo positiopn. Byte 6 is the low byte.

csdude
01-18-2010, 09:22 AM
If you are talking about the absolute position command then that is the first one in the code that I posted ("servoAbsolute"). Byte 5 is the high byte of the servo positiopn. Byte 6 is the low byte.

Right, the absolute position; let's see if I have it right.

So neutral/center is at 1500 μs and that is 3000 in 'pololu steps'. According to the specs the resolution is 0.5 μs per 0.05 degrees. So 180 degrees would be 1800μs or in pololu steps 3600

So if I go from 90 degrees left to center to 90 degrees right:

600 μs - 1500 μs - 2400 μs or
1200 - 3000 - 4800 in 'pololu steps'
0x4b0 - 0xbb8 - 0x12c0 (same thing but hex)

So if I do something like:

for (i = x4b0; i <= 0x12c0; i++)
port-write("0x80 0x01 0x04 0x00 MSB(i) LSB(i)") // not actual code

than the servo would go from 90 degrees left to 90 degrees right, correct?

edit: Of course I could just move it to the left, than center and than right, but that way you can do a 'sweep'

or do something like:
for (i = x4b0; i <= 0x12c0; i+=10)
port-write("0x80 0x01 0x04 0x00 MSB(i) LSB(i)") // not actual code

to make 5 degree steps

csdude
01-18-2010, 05:15 PM
hello again,

there is no way to test to see if the servo is done with executing a command you sent to the servo board, is there? (I see an echo of the command sent, but that is what it is, an echo.. it is not sent after the servo itself was done)

MikeG
01-18-2010, 06:28 PM
General hobby RC servos do not provide position feedback. If you know the angular velocity you should be able to make a good guess. A quick Google search will turn up a lot of info if you want to try reading the voltage across the internal POT.

This is one of the main reasons I (as well as others around here) use Dynamixels.

jes1510
01-18-2010, 06:40 PM
Look in the tutorials section for a tutorial I wrote on how to modify a hobby servo as MikeG mentioned.

As for the pololu controller, there is no way to get feedback when the controller has finished a move. The best you can do is a time based guess.

csdude
01-18-2010, 09:15 PM
General hobby RC servos do not provide position feedback. If you know the angular velocity you should be able to make a good guess. A quick Google search will turn up a lot of info if you want to try reading the voltage across the internal POT.

This is one of the main reasons I (as well as others around here) use Dynamixels.

Ah, gotcha, thanks.

I wrote something to guess the angular speed of an older servo. (I have an older one to mess with, so I don't break it on the first few tries.)
Anyway, it is an airtronics 94102, rated at 0.22/60deg. What does that mean? that it takes that servo 0.22 secs to travel 60deg? (the one I am toying with for sure doesn't do that)

csdude
01-18-2010, 09:17 PM
Look in the tutorials section for a tutorial I wrote on how to modify a hobby servo as MikeG mentioned.

As for the pololu controller, there is no way to get feedback when the controller has finished a move. The best you can do is a time based guess.

I kind of figured that there is no way to get feedback out of that one.

I'll check and see if I can find it

csdude
01-18-2010, 09:28 PM
Look in the tutorials section for a tutorial I wrote on how to modify a hobby servo as MikeG mentioned.

As for the pololu controller, there is no way to get feedback when the controller has finished a move. The best you can do is a time based guess.


Hey that's a pretty good and clear tutorial, I might give that a shot sometime.

MikeG
01-18-2010, 09:58 PM
Anyway, it is an airtronics 94102, rated at 0.22/60deg. What does that mean? that it takes that servo 0.22 secs to travel 60deg?

Rigth, 0.22 secs to travel 60deg under no load.

csdude
01-19-2010, 12:01 PM
Rigth, 0.22 secs to travel 60deg under no load.

Ok, is it that you can't reach that speed using command 0x04, but only with the combination of the first 2 (or first and third?)

Also, is command 0x05 mean to set the servo to neutral and switch it off? (when I try that one a servo is still 'powered' and holding it's position)

MikeG
01-19-2010, 01:42 PM
csdude, I have no idea and I don't own a Pololu servo controller. I bet the manufacturer knows though.