Pololu Micro Serial Servo + Low-Voltage Motor Controller

I am using Pololu Micro Serial Servo Controller and a Pololu Low-Voltage Dual Serial Motor Controller with a Arduino Diecimilla board. I have used Pin 1 (TX) to connect to Pin 4 on the Motor controller. How should the “logic-level serial input” on the Servo Controller be connected to the Arduino? I have included my code to clarify my project.
I understand from the guide that: “This motor controller interface protocol is compatiable with other Pololu serial devices such as our servo controllers.” but need help on how to use both controllers.

/*
Sample code for RobotShop Rover v1.0
www.RobotShop.com
This code uses subroutines to explore all aspects of the RobotShop Rover, including the
motors, motor controller, IR Sensor and Pan/Tilt. The Rover will proceed in a straight
line and once it encounters an obstacle will stop, flash the LED, move the pan and tilt to a
new location, reverse, rotate ~90 degrees, re-center the pan and tilt and proceed until the
next obstacle. We encourage you to experiment with and improve the code.
Note 1: The kit does not include a servo controller; however, the pan and tilt can be
controlled directly from the Arduino. A servo needs to be refreshed at least once every
500ms, though when working directly off the Arduino, it is difficult to refresh the servo
especially if the delay() function is used. The system works best when using 1.2V
rechargeable batteries (instead of 1.5V alkaline) as the servos retain their last position due
to friction. For proper control of the pan and tilt, consider the RB-Pol-18 “Pololu Micro
Serial 8 Servo Controller”.
Note 2: The motor controller manual specifies that the controller should be OFF when
uploading code to the microcontroller. Use one of the included ON/OFF switches to
ensure the controller is OFF when uploading code (or physically disconnect the Tx/Rx
wires to the controller). You only need to do this when uploading new code.
Note 3: As with any electro-mechanical system, the ideal choice is to use high capacity
rechargeable batteries. The rover should last for roughly 30minutes depending on many
factors (terrain, incline, speed of motors). The 9V battery ONLY powers the Arduino
microcontroller. If the system is behaving erratically, check the battery power; a
minimum of 9V is required by the Arduino.
Note 4: Triple check that all wires are properly connected before loading the code. Test
each system individually by commenting the code using two backslashes.
*/
#define MIN_POS 500 // the minuimum pulse width for your servos
#define MAX_POS 5500 // maximum pulse width for your servos
// set servo speed, goes from 1 to 127
int servoSpeed = 120; // 1 = fastest  127 = slowest
//int servopulse1 = 1250; //test servo tilt position (0 to 180)
//int servopulse2 = 1550; //test servo pan position (0 to 180)
//int servopin1 = 9; //analog pin 1=15
//int servopin2 = 10; //analog pin 3=17
int motor_reset = 2; //digital pin 2 assigned to motor reset
int irpin = 3;
int distance = 0;
int period;
int timeUp = 680; // 1000000/(2 * frequency)
//int ledpin = 13;
int speakerOut = 9;
struct t_mtab { char c, pat; } ;

struct t_mtab morsetab[] = {
  	{'.', 106},
	{',', 115},
	{'?', 76},
	{'/', 41},
	{'A', 6},
	{'B', 17},
	{'C', 21},
	{'D', 9},
	{'E', 2},
	{'F', 20},
	{'G', 11},
	{'H', 16},
	{'I', 4},
	{'J', 30},
	{'K', 13},
	{'L', 18},
	{'M', 7},
	{'N', 5},
	{'O', 15},
	{'P', 22},
	{'Q', 27},
	{'R', 10},
	{'S', 8},
	{'T', 3},
	{'U', 12},
	{'V', 24},
	{'W', 14},
	{'X', 25},
	{'Y', 29},
	{'Z', 19},
	{'1', 62},
	{'2', 60},
	{'3', 56},
	{'4', 48},
	{'5', 32},
	{'6', 33},
	{'7', 35},
	{'8', 39},
	{'9', 47},
	{'0', 63}
} ;

#define N_MORSE  (sizeof(morsetab)/sizeof(morsetab[0]))

#define SPEED  (5)
#define DOTLEN  (1200/SPEED)
#define DASHLEN  (3*(1200/SPEED))

void
dash()
{
  digitalWrite(speakerOut, LOW);     
  period = DASHLEN; 
  while (period > 0) 
  {
      digitalWrite(speakerOut, HIGH);
      delayMicroseconds(timeUp);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(timeUp);
      --period;
  }
  digitalWrite(speakerOut, LOW);
  delay(DOTLEN);

  //digitalWrite(LEDpin, HIGH) ;
  //delay(DASHLEN);
  //digitalWrite(LEDpin, LOW) ;
  //delay(DOTLEN) ;
}

void
dit()
{
  digitalWrite(speakerOut, LOW);     
  period = DOTLEN; 
  while (period > 0) 
  {
      digitalWrite(speakerOut, HIGH);
      delayMicroseconds(timeUp);
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(timeUp);
      --period;
  }
  digitalWrite(speakerOut, LOW);
  delay(DOTLEN);

  //digitalWrite(LEDpin, HIGH) ;
  //delay(DOTLEN);
  //digitalWrite(LEDpin, LOW) ;
  //delay(DOTLEN);
}

void
send(char c)
{
  int i ;
  if (c == ' ') {
    Serial.print(c) ;
    delay(7*DOTLEN) ;
    return ;
  }
  for (i=0; i<N_MORSE; i++) {
    if (morsetab[i].c == c) {
      unsigned char p = morsetab[i].pat ;
      Serial.print(morsetab[i].c) ;

      while (p != 1) {
          if (p & 1)
            dash() ;
          else
            dit() ;
          p = p / 2 ;
      }
      delay(2*DOTLEN) ;
      return ;
    }
  }
  /* if we drop off the end, then we send a space */
  Serial.print("?") ;
}

void
sendmsg(char *str)
{
  while (*str)
    send(*str++) ;
  Serial.println("");
}

void setup()
{
pinMode(motor_reset, OUTPUT);
pinMode(speakerOut, OUTPUT);
//pinMode(servopin1, OUTPUT);
//pinMode(servopin2, OUTPUT);
Serial.begin(9600);
digitalWrite(motor_reset, LOW);
delay(50);
digitalWrite(motor_reset, HIGH);
delay(50);
// reset motor controller
// set servo pin and speed
if (servoSpeed >= 1 && servoSpeed <= 127)
{
servoSetSpeed(0, servoSpeed);
servoSetSpeed(1, servoSpeed);
}
}
void loop()
{
//servoposition();
//delay(20);
//digitalWrite(servopin1, LOW);
//digitalWrite(servopin2, LOW);
put(0, 3000);
delay(25);
put(1, 3000);
delay(25);
motorforward();
irdetection();
}
/*subroutine servoposition
void servoposition()
{
for(int i=1; i<=20; i++) // Ensures the servos reach their final position
{
digitalWrite(servopin1, HIGH); // Turn the L motor on
delayMicroseconds(servopulse1); // Length of the pulse sets the motor position
digitalWrite(servopin1, LOW); // Turn the L motor off
delay(20);
digitalWrite(servopin2, HIGH); // Turn the L motor on
delayMicroseconds(servopulse2); // Length of the pulse sets the motor position
digitalWrite(servopin2, LOW); // Turn the L motor off
delay(20);
}
}
*/
void irdetection()
{
distance=analogRead(irpin); // Interface with the Sharp IR Sensor
if (distance<=575&&distance>=425) // Detecting objects within roughly 10cm
{
motorstop(); // stop the rover
//ledwarning(); // light up the LED for 1 second
sendmsg("ZL1XXX QRZ") ;
delay(3000);
//servopulse1=1250; // move the pan/tilt
//servopulse2=2000;
//servoposition(); // refresh the servos
put(0, 1250);
delay(25);
//put(1, 2000);
delay(500);
motorreverse(); // reverse the motors for 1 second
delay(1000);
motorstop(); // stop the motors
delay(1000); // wait 1 second
rotateccw(); // rotate for 2 seconds
delay(2000);
motorstop(); // stop the motors
delay(1000);
//servopulse1=550; // move the servos
//servopulse2=1500;
//servoposition();
put(0, 550);
delay(25);
put(1, 1500);
delay(1000);
}
}
//void ledwarning()
//{
//digitalWrite(ledpin, HIGH); // sets the LED on
//delay(1000);
//digitalWrite(ledpin, LOW); // sets the LED off
//}
//subroutine motor forward
void motorforward()
{
//left motor
unsigned char buff1[6];
buff1[0]=0x80; //start byte - do not change
buff1[1]=0x00; //Device type byte
buff1[2]=0x01; //Motor number and direction byte; motor one =00,01
buff1[3]=0x45; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff1[i], BYTE);}
//right motor
unsigned char buff2[6];
buff2[0]=0x80; //start byte - do not change
buff2[1]=0x00; //Device type byte
buff2[2]=0x03; //Motor number and direction byte; motor two=02,03
buff2[3]=0x45; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff2[i], BYTE);}
}
//subroutine reverse at half speedd
void motorreverse()
{
//left motor
unsigned char buff3[6];
buff3[0]=0x80; //start byte - do not change
buff3[1]=0x00; //Device type byte
buff3[2]=0x00; //Motor number and direction byte; motor one =00,01
buff3[3]=0x35; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff3[i], BYTE);}
//right motor
unsigned char buff4[6];
buff4[0]=0x80; //start byte - do not change
buff4[1]=0x00; //Device type byte
buff4[2]=0x02; //Motor number and direction byte; motor two=02,03
buff4[3]=0x35; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff4[i], BYTE);}
}
//Motor all stop
void motorstop()
{
//left motor
unsigned char buff3[6];
buff3[0]=0x80; //start byte - do not change
buff3[1]=0x00; //Device type byte
buff3[2]=0x00; //Motor number and direction byte; motor one =00,01
buff3[3]=0x00; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff3[i], BYTE);}
//right motor
unsigned char buff4[6];
buff4[0]=0x80; //start byte - do not change
buff4[1]=0x00; //Device type byte
buff4[2]=0x02; //Motor number and direction byte; motor two=02,03
buff4[3]=0x00; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff4[i], BYTE);}
}
void rotateccw()
{
//left motor
unsigned char buff1[6];
buff1[0]=0x80; //start byte - do not change
buff1[1]=0x00; //Device type byte
buff1[2]=0x01; //Motor number and direction byte; motor one =00,01
buff1[3]=0x40; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff1[i], BYTE);}
//right motor
unsigned char buff2[6];
buff2[0]=0x80; //start byte - do not change
buff2[1]=0x00; //Device type byte
buff2[2]=0x02; //Motor number and direction byte; motor two=02,03
buff2[3]=0x40; //Motor speed "0 to 128" (ex 100 is 64 in hex)
for(int i=0; i<4; i++) {Serial.print(buff2[i], BYTE);}
}

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: always 0x80
  buff[1]=0x01; //device id: always 0x01 for an pololu 8 servo controller
  buff[2]=0x04; //command number: 0x04 to set absolute values
  buff[3]=servo; //servo number: 0 to 7
  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);
  }
}

Hello.

You can connect the same serial line going to the motor controller to the servo controller. If you already have the motor controller working, you might similarly work on the servo controller independently first, too, before connecting both at the same time.

- Jan

Thank you. Problem fixed.


If I plugin an Arduino XBee Shield into the Duemilanove how do I handle the two controller wires presently plugged into TX (pin 1) on the Duemilanove? Your help would be much appreciated. Kevin

I don’t understand what you’re asking for or what you’re trying to do. I don’t have specific suggestions if your question is about physically connecting things since I don’t know how the XBee shield fits in with the Arduino. If you’re asking about how to handle it in electrical or programming sense, you’ll have to look at the protocols to see if they can work together; if not, you’ll have to use different lines for the XBee and our serial devices.

- Jan

I have been relying on a software reset of my Low-voltage Dual Serial Motor Controller. If I touch the reset (pin 5) to earth the controller functions 100% but a software reset has no effect. Using Arduino

  int motor_reset = 6; //digital pin 6 assigned to motor reset
void setup()
{
  pinMode(motor_reset, OUTPUT);
//.....
  // reset motor controller
  digitalWrite(motor_reset, LOW);
  delay(500);
  digitalWrite(motor_reset, HIGH);
  delay(50);
}

Should this work ok?
Kevin

It should work. Can you look at what the reset line is doing with an oscilloscope or meter? If you have neither, you could use an LED to watch the line going low and high.

- Jan