Servo Control

 

Servo Operation:

          Hobby RC servo motors turn to some angle, based on a PWM control signal.  The servo PWM signal consists of a 50Hz (20ms period) pulse train, in which the pulses may vary from 1ms - 2ms in width (I find 0.5-2.5ms is needed for full range of motion).

          A pulse of 1.5ms is “center” value.  Deviation from 1.5ms pulse width turns the servo as follows (but take these angles with a grain of salt):

(from http://www.seattlerobotics.org/guide/servos.html )

 

          Different manufacturers’ servos behave slightly differently.  For example, most servos claim to have a 90° range of motion.  These servos will respond as follows:

                   1ms pulse              -45°

                   1.5ms pulse           0°

                   2ms pulse              +45° 

The above pulselengths (1-2ms) are typical of the output from hobby RC radio receivers.  However, most motors that claim to be 90° will happily turn through 180° if you supply them with appropriately shorter and longer pulses.  I’ve achieved 180° control of Futaba servos using pulse lengths varying from 0.5ms(-90°) to 2.5ms(+90°).  It seems that outside of the –45°-45° range, there is some loss of linearity.

          The hardstops for the Futaba servos actually permit more than 180° of motion.  You can get an extra 20° range of motion on both ends (from -110° to +110°) by using pulses between nearly zero length and 3ms.

Be careful of that “nearly zero” pulse length.  Some servos have a failsafe feature that powers down the motor if the servo stops receiving pulses.  Other motors interpret “no pulse” as “zero length pulse”.  When the control signal is switched off, these motors will turn as far counterclockwise as they possibly can, until they collide with and press against their internal hardstop.  High torque servos can self destruct this way.  Even if the servo isn’t strong enough to damage itself, the DC motor inside will draw a very large current while it is stalled out.

          I worked around this “feature” of hobby servos by limiting my pulses to a minimum length.  I found that a minimum pulse of 50μs was enough to save a Futaba servo from itself.  Similarly, there will be a maximum pulselength, beyond which the servo collides with its other hard stop.


The seattlerobotics.org page on modifying a servo for speed (instead of position) control

has a good description of the innards of a hobby servo.  The block diagram, below, illustrates how the major functional components inside a servo interact.

The DC motor inside the servo is controlled by the H-bridge at top, right.  When a control pulse comes in to the “Input” node at left, it triggers the Linear Pulse Generator, which outputs a pulse of length determined by the analog voltage of the “Feedback Signal.”  The Feedback Signal is not just the voltage from the position-feedback potentiometer, it is also affected by “back EMF,” the voltage output by the spinning DC motor.  The back EMF is a measure of velocity and is used to damp the servo's motion by preventing it from going too fast and overshooting its target position.  The difference between the control pulse and the LPG pulse is used to generate a PWM signal for the DC motor.

The speed control modification firstly eliminates position-dependence by replacing the potentiometer with a pair of fixed 220K resistors. Secondly, it drastically reduces the resistance on the speed side of the feedback resistor network. After modification the back EMF, not position, primarily determines the voltage at the LPG input. There is also a plastic tab that must be filed away to permit continuous rotation.

(from http://www.seattlerobotics.org/encoder/200009/S3003C.html )


Mark’s Multiple Servo Controller:

          Mark Smorul has written a program for the PIC16F628 to control up to 9 servo motors, via a serial port with hardware (CTS/RTS) handshaking.  The servo controller’s serial port has a CTS (Clear to Send) output that goes high when the chip is ready to receive new serial data.  Sending data to the chip when it is not ready (ie. when CTS is low) will hang the chip.

          This can be avoided by placing a serial buffer (another of Mark’s creations) between your program and the servo controller chip.  The buffer chips will accept up to 64 bytes of data, as fast as you can send it over a single Tx wire.  The buffer chips monitor the servo controller’s CTS signal and send the buffered data to the servo controller when it’s ready.

          Serial instructions to the servo controller should be sent in 3-byte packets like this:

255, address, data

          “255” is a synch byte that lets the chip know a new instruction is about to come in.  “Address” is the address of the motor to be adjusted.  “Address” is a binary number from 0-8 inclusive.  “Address” is NOT an ASCII character, but a binary number.  Lastly, “data” is the position to turn the servo at “address” to.  “Data” may have any value between 0 and 250, inclusive.  The values 251-255 are reserved for internal use by the servo controller chip.  This means that “center” value is 125.

 

Interfacing to Mark’s Servo Controller:

          A simple interface to Mark’s servo controller has been provided in Sam Scheinman’s servocontroller_interface.c.  This file contains a #use rs-232 directive for communicating with the servo controller.  As such, it must be #included AFTER your “#use delay” directive.

          The interface gives you the SC_SetServo function to control your motors:

short SC_SetServo(int address, int data, short buffer_status).  The function accepts an integer from 0-8 (inclusive) for the address, 0-250 (inclusive) for data, and the #defined symbols BUFFERED and NOT_BUFFERED for buffer_status, which tells the program whether or not there is a serial buffer between it and the servo controller.  If the buffer is in place, SC_SetServo doesn’t have to monitor CTS itself as this is done by the buffer.


/*

   This program makes use of servocontroller_interface.c functions to talk to Mark Smorul's

   servo controller chips.  It will set the positions of all 9 servos controlled by the chip, based

   on the position of a potentiometer connected to Pin_A0.

*/

 

#include <16F877.h>

#fuses HS,NOWDT,NOBROWNOUT,NOLVP

#use delay(clock = 20000000)

 

#include "servocontroller_interface.c"

 

#use fast_io(A)

#use fast_io(B)

#use fast_io(C)

 

void main(){

   int analog=128, i=0;

  

   setup_port_a( RA0_ANALOG );

   setup_adc( ADC_CLOCK_INTERNAL );

   set_adc_channel( 0 );

 

   set_tris_a(0b00010001);  //PorA inputs on pin0, analog, nad A4, serial Rx.

   set_tris_b(0);

   set_tris_c(0);

  

   while(true){

      analog = read_adc();

      if(analog > 250) analog = 250;   //full sweep for the servo chips is 0-250, NOT 255.

      for(i=0;i<9;i++){     

         SC_SetServo(i, analog, NOT_BUFFERED);

      }

   }

}