Interfacing to Pololu Micro Serial Servo

I’ve been building a robot arm out of servos, using the micro serial servo board to keep the servos active and positioned between position changes; this frees up the arduino for logic, etc.
I had to hunt around to get the information I needed to send commands to the board in it’s native mode (it also has a SSCII mode). But I eventually wrote working functions that correspond to each of it’s commands. A more capable programmer would have made a library, but at least I can share the functions, along with the necessary SoftwareSerial code to permit sending commands to the board from pins other than the hardware serial ones (I like to keep the hardware serial free for debugging - for example, sending servo positions to the serial monitor while adjusting them on the fly with a pot):

// Pololu micro serial servo controller modes
// Software Serial from Arduino example by Tom Igoe
// put() (now position_absolute) & set_speed() functions found on pololu forums & modified
// mike crist 2009-01-03

#include <SoftwareSerial.h>

#define rxPin 2
#define txPin 3

// set up a new serial port
SoftwareSerial softSerial =  SoftwareSerial(rxPin, txPin);

void setup()
{
  pinMode(rxPin, INPUT);
  digitalWrite(txPin, HIGH); // keeps pololu board from getting spurious signal
  pinMode(txPin, OUTPUT);
  
  // set the data rate for the hardware serial port
  Serial.begin(9600);
  // set the data rate for the SoftwareSerial port
  softSerial.begin(9600);
  
  // set initial servo speeds
  set_speed(0, 10);
  set_speed(1, 10);
  set_speed(2, 10);
  set_speed(3, 10);
  
  //set and move servos to neutral positions using command 5
  set_neutral(0, 3000);
  set_neutral(1, 3000);
  set_neutral(2, 3000);
  set_neutral(3, 3000);
  
  //initialize servos using command 0
  set_servo_parameters(0, 15);
  set_servo_parameters(1, 15);
  set_servo_parameters(2, 15);
  set_servo_parameters(3, 15);
  set_servo_parameters(4, 15);
}

void loop()
{
  
}

void set_servo_parameters(byte servo, byte rangeVal)
{
   //this function uses pololu mode command 0 to set servo parameters
   //servo is the servo number (typically 0-7)
   //rangeVal of 15 gives 180 deg in 8-bit, 90 deg in 7 bit
   
   byte temp;
   byte parameters;
   
   temp = 1 << 6;                     //set first two bits of parameters (on = 1, forward = 0)
   temp = temp + (rangeVal & 0x1f);   //put first five bits of rangeVal into temp
   parameters = temp & 0x7f;          //take only bottom 7 bits
      
   //Send a Pololu Protocol command
   softSerial.print(0x80,BYTE);       //start byte
   softSerial.print(0x01,BYTE);       //device id
   softSerial.print(0x00,BYTE);       //command number
   softSerial.print(servo,BYTE);      //servo number
   softSerial.print(parameters,BYTE); //parameters
}

void set_speed(byte servo, byte speedVal)
{
   //this function uses pololu mode command 1 to set speed
   //servo is the servo number (typically 0-7)
   //speedVal is servo speed (1=slowest, 127=fastest, 0=full)
   //set speedVal to zero to turn off speed limiting
   
   speedVal = speedVal & 0x7f; //take only lower 7 bits of the speed
   
   //Send a Pololu Protocol command
   softSerial.print(0x80,BYTE);     //start byte
   softSerial.print(0x01,BYTE);     //device id
   softSerial.print(0x01,BYTE);     //command number
   softSerial.print(servo,BYTE);    //servo number
   softSerial.print(speedVal,BYTE); //speed
}

void position_7bit(byte servo, byte posValue)
{
  //this function uses pololu mode command 2 to set position  
  //servo is the servo number (typically 0-7)
  //posValue * range (set with command 0) adjusted by neutral (set with command 5)
  //determines servo position

   byte pos = posValue & 0x7f;     //get lower 7 bits of position

   //Send a Pololu Protocol command
   softSerial.print(0x80,BYTE);     //start byte
   softSerial.print(0x01,BYTE);     //device id
   softSerial.print(0x02,BYTE);     //command number
   softSerial.print(servo,BYTE);    //servo number
   softSerial.print(pos, BYTE);     //position
}

void position_8bit(byte servo, byte posValue)
{
  //this function uses pololu mode command 3 to set position  
  //servo is the servo number (typically 0-7)
  //posValue * range (set with command 0) adjusted by neutral (set with command 5)
  //determines servo position

   byte temp;
   byte pos_hi,pos_low;
   
   temp = posValue & 0x80;      //get bit 8 of position
   pos_hi = temp >> 7;            //shift bit 8 by 7
   pos_low = posValue & 0x7f;     //get lower 7 bits of position

   //Send a Pololu Protocol command
   softSerial.print(0x80,BYTE);     //start byte
   softSerial.print(0x01,BYTE);     //device id
   softSerial.print(0x03,BYTE);     //command number
   softSerial.print(servo,BYTE);    //servo number
   softSerial.print(pos_hi, BYTE);  //bits 8 thru 13
   softSerial.print(pos_low, BYTE); //bottom 7 bits
}

void position_absolute(byte servo, int angle)
{
  //this function uses pololu mode command 4 to set absolute position  
  //servo is the servo number (typically 0-7)
  //angle is the absolute position from 500 to 5500

   unsigned int temp;
   byte pos_hi,pos_low;
   
   temp = angle & 0x1f80;  //get bits 8 thru 13 of position
   pos_hi = temp >> 7;     //shift bits 8 thru 13 by 7
   pos_low = angle & 0x7f; //get lower 7 bits of position

   //Send a Pololu Protocol command
   softSerial.print(0x80, BYTE);    //start byte
   softSerial.print(0x01, BYTE);    //device id
   softSerial.print(0x04, BYTE);    //command number
   softSerial.print(servo, BYTE);   //servo number
   softSerial.print(pos_hi, BYTE);  //bits 8 thru 13
   softSerial.print(pos_low, BYTE); //bottom 7 bits
}

void set_neutral(byte servo, int angle)
{
  //this function uses pololu mode command 5 to set neutral position  
  //servo is the servo number (typically 0-7)
  //angle is the absolute position from 500 to 5500

   unsigned int temp;
   byte pos_hi,pos_low;
   
   temp = angle & 0x1f80;  //get bits 8 thru 13 of position
   pos_hi = temp >> 7;     //shift bits 8 thru 13 by 7
   pos_low = angle & 0x7f; //get lower 7 bits of position

   //Send a Pololu Protocol command
   softSerial.print(0x80, BYTE);    //start byte
   softSerial.print(0x01, BYTE);    //device id
   softSerial.print(0x05, BYTE);    //command number
   softSerial.print(servo, BYTE);   //servo number
   softSerial.print(pos_hi, BYTE);  //bits 8 thru 13
   softSerial.print(pos_low, BYTE); //bottom 7 bits
}

would be nice to see how are you connecting the servo controller to the arduino!

? using the micro serial servo board to keep the servos active and positioned between position changes; this frees up the arduino for logic, etc.

This is an old thread, the servo library in the current Arduino release handles servo refresh for up to 12 servos without requiring any attention from the sketch logic. If you use the arduino library then almost all the code in shown in post 1 disappears. There is an advantage to the external board in that it only requires two arduino pins whereas the native Arduino version uses one digital pin per servo. But if that is not an issue then consider using the Arduino’s Servo capability.

This is what I have achieved with the Arduino MegaServo library, it works good but I want it move smoother and to have more control on the servos movement and speed.

http://www.youtube.com/watch?v=_z8Lkqe0S-4

I'm having difficulties making the robot movements smoother and for that I purchased the servo controller. Fow now I just need to know how to connect both the devices.

Very impressive installation!
You can get smoother movements with the MegaServo library if you drive it with microsecond values instead of degrees.
Here is a test sketch that provides an example.

#include <Servo.h>  // change this to MegaServo.h if using that version of the library

// test sketch for (Mega)Servo library
// this will sweep all servos back and forth once, then position according to voltage on potPin


#define FIRST_SERVO_PIN  2  
#define NBR_SERVOS       12 // set this to your number of servos

#define MIN_POS          800 // the minuimum pulse width for your servos
#define MAX_POS         2200  // maximum pulse width for your servos


Servo Servos[NBR_SERVOS] ; // max servos is 32 for mega, 8 for other boards
//MegaServo Servos[NBR_SERVOS] ; // max servos is 32 for mega, 8 for other boards  // use this version if using MegaServo

int pos = 0;      // variable to store the servo position 
int potPin = 0;   // connect a pot to this pin.

void setup()
{
  for( int i =0; i < NBR_SERVOS; i++)
    Servos[i].attach( FIRST_SERVO_PIN + i);

  sweep(MIN_POS,MAX_POS,1); // sweep once stepping one microscond.    
}

void sweep(int min, int max, int step)
{
  for(pos = min; pos < max; pos += step)  // goes from 0 degrees to 180 degrees    
  {                                  // in steps of 1 degree 
    for( int i =0; i < NBR_SERVOS; i++){ 
      Servos[i].write( pos);     // tell servo to go to position  
    }
    delay(20);                  // waits 15ms for the servo to move 
  } 
  for(pos = max; pos>=min; pos-=step)     // goes from 180 degrees to 0 degrees 
  {                                
    for( int i =0; i < NBR_SERVOS; i++){ 
      Servos[i].write( pos);     // tell servo to go to position  
    }
    delay(20);                  // waits 20ms for the servo to move 
  }   
}

void loop()
{ 
  pos = analogRead(potPin);   // read a value from 0 to 1023
  for( int i =0; i < NBR_SERVOS; i++) 
    Servos[i].write( map(pos, 0,1023, MIN_POS,MAX_POS));   
  delay(15);   
}

I have not used the micro serial servo board but if you do want to use it I suggest you use the newSoftSerial library instead of softwareSerial : Direct Port I/O in NewSoftSerial 9 | Arduiniana

Thanks mem! :) I will take a closer look at your code!!

I look forward to hearing how you get on.

I’ve been working on this for a while and finally I have the courage to post the results.

I’m also testing the pololu micro serial servo controller in the hope I could achieve better results. One good thing the pololu controller has, is the ability to set the speed of the movement, I guess it is a good plus to have this extra control. And using this feature together with the filter you get really cool and smooth movements, check the end of the video.

The point I don’t like in this experience is that the robot shakes a lot, but that is due to the weak support. I will have to arrange a solution to void so much shakiness.

The low pass filter below is what makes the desaceleration while the value reaches the destination point. I’ve posted the full code below the video.

filter: 0.05;
destinationValue = 1000;
destinationValueFiltered = destinationValueFiltered * (1.0-filter) + destinationValue * filter;

Code to move one servo directly connected to the Arduino:

// easing servo movements with low pass filter
// the servo signal must be connected directly to the arduino pin 2 

// Time interval, this executes one piece of code from time to time
// Download Metro lybrary and instructions:
// http://www.arduino.cc/playground/Code/Metro
#include <Metro.h>
int duration = 3500; // duration of the interval in miliseconds
Metro intervaller = Metro (duration);

// MegaServo library
// download and instructions: 
// http://www.arduino.cc/playground/Code/MegaServo
#include <MegaServo.h>
MegaServo servos;

// servos minimum and maximum position
#define MIN_POS 800 // the minuimum pulse width for your servos
#define MAX_POS 2200 // maximum pulse width for your servos

// servo pin
#define s0_pin 2

// variables to hold new destination positions
int d0; // destination0
int d0_sh; // destination0 to be smoothed

// the filter to be aplied
// this value will be multiplied by "d0" and added to "d0_sh"
float filtro = 0.05; // 0.01 to 1.0

// setup runs once, when the sketch starts
void setup() {
  // initialize serial comunication
  Serial.begin(9600);
  
  // set servo pin
  servos.attach(s0_pin);
}

// main program loop, executes forever after setup()
void loop() {
  
  // check the time interval, if it reaches limit "duration" goes back to one 
  // and runs the code
  if (intervaller.check() == 1) {
    
    // calculate a new random position between max and min values
    d0 = random(MIN_POS, MAX_POS); 
    
    // resets interval with a new random duration
    intervaller.interval(random(500,2000));
   }
  
  // smooth the destination value
  d0_sh = d0_sh * (1.0-filtro) + d0 * filtro;
  
  // assign new position to the servo
  servos.write(d0_sh);
  
  // delay to make the servo move
  delay(25);
}

And this is the code to use with the pololu micro serial servo controller:

// easing servo movements with a low pass filter and Pololu Micro Serial Servo Controller

// Time interval, this executes one piece of code from time to time
// Download Metro lybrary and instructions:
// http://www.arduino.cc/playground/Code/Metro
#include <Metro.h>
int duration = 3500; // duration of the interval in miliseconds
Metro intervaller = Metro (duration);

// servos minimum and maximum position
#define MIN_POS 500 // the minuimum pulse width for your servos
#define MAX_POS 5500 // maximum pulse width for your servos

// variables to hold new destination positions
int d0; // destination0
int d0_sh; // destination0 to be smoothed

// the filter to be aplied
// this value will be multiplied by "d0" and added to "d0_sh"
float filtro = 0.05;   // 0.01 to 1.0

// set servo speed, goes from 1 to 127
int servoSpeed = 120;

// setup runs once, when the sketch starts
void setup() {
  // initialize serial comunication
  Serial.begin(9600);
  
  // set servo pin and speed
  servoSetSpeed(0, servoSpeed);
}

// main program loop, executes forever after setup()
void loop() {
  
  // check the time interval, if it reaches limit "duration" goes back to one 
  // and runs the code
  if (intervaller.check() == 1) {
    
    // calculate a new random position between max and min values
    d0 = random(MIN_POS, MAX_POS);
    
    // resets interval with a new random duration
    intervaller.interval(random(500,3000));
  }
  
  // smooth the destination value
  d0_sh = d0_sh * (1.0-filtro) + d0 * filtro;
  
  // assign new position to the servo
  put(0,d0_sh);
  
  // delay to make the servo move
  delay(25);
}


// functions from this forum topic:
// http://forum.pololu.com/viewtopic.php?f=16&t=745&start=60&st=0&sk=t&sd=a

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

  unsigned char buff[6];

  unsigned int temp;
  unsigned char pos_hi,pos_low;

  //Convert the angle data into two 7-bit bytes
  temp=angle&0x1f80;
  pos_hi=temp>>7;
  pos_low=angle & 0x7f;

  //Construct a Pololu Protocol command sentence
  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

  //Send the command to the servo controller
  for(int i=0;i<6;i++){
    Serial.print(buff[i],BYTE);
  }

}

void servoSetSpeed(int servo, int speed){
  //servo is the servo number (typically 0-7)
  //speed is servo speed (1=fastest, 127=slowest)
  //set speed to zero to turn off speed limiting

  unsigned char buff[5];
  unsigned char speedcmd;

  speedcmd=speed&0x7f;//take only lower 7 bits of speed

  buff[0]=0x80;//start byte
  buff[1]=0x01;//device id
  buff[2]=0x01;//command number
  buff[3]=servo;//servo number
  buff[4]=speed;//data1

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

Here you can find an short article (with images, video and Wiring/Arduino code) to connect Arduino Duemilanove to 6 servo motors using a Pololu Servo controller and managing them with an analog joystick.

Hope it's useful :)

Arduino and Pololu Micro Serial 8 Servo Controller http://www.fabiobiondi.com/blog/2009/12/arduino-and-pololu-micro-serial-8-servo-controller/

So what's problem? My Arduino Duemilanove boards has only 6 analog ports but I need to connect a lot of stuff!!!! What can I do now if I would like to connect 3 analog joysticks (they use 2 pots to manage 2 axis, so 6 analog ports are required) and other 6-8 servo motors?

There is a major misconception in that article.

The six Arduino analog ports are for analog inputs, servo output can be on any port (analog or digital).

A Duemilinove can drive up to twelve servos using digital pins 2 – 13 without the need for an external board.

See the Arduino servo reference page for more information: http://www.arduino.cc/en/Reference/Servo