BASIC Stamp, Microchip PIC, 8051, and Remote Control Projects

** How To **
Roll-Your-Own
Addressable Serial Servo Controllers

This article will show you how to use the tiny 8-pin PIC12C671 to create your own serial servo controller chips.

A dedicated servo motor control IC has several obvious advantages, and is considerably less expensive than purchasing a large motor control board.  This is especially true if you only need a single servo controller.  Why buy a board with 8 or more motor capacity if you only need to control a single servo..?

For the rest of this article, I'll just refer to them as servo-pods.  This seemed like an appropriate name at the time, and has no other real meaning.  Servo-pods have several advantages.  Here's just a few.

bullet

Each PIC is totally dedicated to the specific function of controlling a single servo motor.

bullet

Individual servo-pods can be placed anywhere -- even attached to the servo motor itself.

bullet

Multiple servo-pods can have the same address allowing control of several motors at "exactly" the same time with a single data transmission.

bullet

There are no wasted servo controller output ports.

bullet

Hundreds of servo motors can be controlled on a single serial data-bus.

I could blab all-day-long about how handy these little doo-dads are, but that would make for a pretty boring article.  You'll see soon enough just how cool these things really are once you start using them anyhow, so let's just dive right on in to the good stuff...!

The code for the servo-pod is very simple, and modifications to suit your specific needs shouldn't be much of a problem.  My motto is to keep it simple if at all possible, and always leave plenty of room for expansion.  This project does exactly that....

The Code:


include "modedefs.bas"

define	osccal_1k 1    	'Set osccal for OTP chips

pos	var byte 	'Servo position
servo1	var gpio.5      'Servo control output-pin
serpin	var gpio.4	'Serial control input-pin
ID	var byte 	'ID number storage variable
ID	=   5		'Assign unique ID to servo-pod
adcon1	=   7    	'All pins digital I/O, not AD
trisio	=   %00010000	'gpio.4 = input
pos	=   125  	'Center servo on power-up

low	servo1	        'Setup for positive pulse

main:
    pulsout servo1,pos
    serin serpin,N9600,15,nxt,[ID],pos 'Get input
nxt:
    goto main
end

Question:  Now you're going to ask if this can be designed using another PIC micro since you don't have any of the 8-pin PIC12C671s in your parts bin.

Answer: You bet.  Simply remove the define osccal_1k 1, and the adcon1 = 7 and you're in business.  This project will work on any PIC that you can program with PicBasic Pro.

Make sure to change the trisio to trisB = %00010000 to setup portB [or use another port]. For PortB bit 4, simply do this: trisb = %00010000. Redefine the port pins you want to use for the serial input pin, and pulsout pin.

Example:

trisb = %00010000
servo1 var PortB.5     ' Servo control output-pin
serpin var PortB.4     ' Serial control input-pin

Note:  If you're using a PIC that has A/D pins, and you want to use one or all of these pins as digital I/O, you'll need to setup the on-chip A/D configuration register to configure them.  This is the purpose of the adcon1 = 7 in my sample code. The PIC12C671 powers-up with these pins in the default A/D mode.

A Look Under The Hood:

The first line include "modedefs.bas" simply includes the mode definitions file allowing us to use the pre-defined mode N2400 to specify the baud rate.  This isn't 100% necessary, but it makes our code much more readable.  The alternate way to indicate the baud rate would be to simply indicate the mode by using the mode number.  In this case N9600 would be mode 6.  See the PBP manuals serin command page for detailed information on the different serial modes.

The ID number hard-coded into each servo-pod forces each PIC to respond only when it receives its assigned ID number.  Once the correct ID number is received, position data is then accepted, and stored in the byte-variable pos.

The serial input line uses the built-in timeout and label capabilities of PicBasic Pro to allow program execution to continue if no serial data is received within a pre-set time frame.  In this case, the timeout has been set to 15mS as shown below.

serin serpin,N9600,15,nxt,

This forces program execution to wait for 15 milliseconds.  If no serial data is received within 15mS, then goto label nxt.  The nxt label holds a goto instruction that directs program flow back to the main label which resumes sending control pulses to the servo motor, and looking for more incoming serial data.

Using the timeout & label method we can use the timeout for setting up the time between each control pulse, and to make sure we aren't locked in the serial receiving routine waiting for incoming serial data.  We have pretty much killed two birds with one stone by using this method.

Wait For The Servo ID #:

The next thing we need is to force the servo-pod to respond only to positional data that is specifically meant for a certain address by using the data qualifier capabilities of PBP.  The qualifier is the actual ID value we have assigned to each servo-pod as shown below.

ID var byte  'ID number storage variable
ID =   5      'Assign unique ID to servo-pod

Line 1 assigns the byte-variable storage space to hold the physical value or number for the servo-pod ID.  Line 2 writes the physical value of #5 into this RAM byte-variable storage location.  The last part of our serial input line will now wait until the ID number 5 arrives before accepting servo positional data and placing it into the pre-defined RAM storage location pos.

Here's a complete breakdown of how the serial input line functions.

serin serpin,N9600,15,nxt,[ID],pos 'serial in on gpio.4

bulletGet serial input on serpin (GPIO.4).
bulletReceive this data at 9600 baud -- inverted.
bulletWait 15mS for incoming data.
bulletIf no data is received within 15mS, jump to label nxt.
bulletWait for only 15mS to receive the ID.
bulletID received, store servo position data in byte-variable pos.
bulletReturn to "Main" and send the pulse to the servo.

PicBasic Pro allows us to create some very powerful command lines with the unique capability of waiting for specific data, and the timeout, jump to label features.  This single line of code handles many various requirements that are necessary to make the servo-pod successful.

Since the internal control electronics of each servo motor expects to have position data updates at intervals of approximately 60 times per-second (60Hz), the timeout/label helps establish this timing without using additional pause commands or other methods.

Notice from the scope trace below that we have 15mS delays between the servo pulses.  This corresponds to our 15mS delay time waiting for incoming serial data in the serial-input code line.

Above is a screen-capture of a scope trace showing the servo control pulse from a servo-pod.  The frequency changes slightly depending on the actual position data, but stays well within the requirements of the servo.  Normally it will fluctuate between 57-70Hz, (cycles-per-second)...

NOTE: There are other methods to achieve better timing, but why over-complicate a simple device if it works..?

The PULSOUT Command:

The pulsout command uses the positional data received/stored in the byte-variable pos to generate the servo control pulses.  The PIC12C671 is limited to a maximum oscillator speed of 4MHz, hence, the period of the generated pulses will be in 10uS increments.

Example:

Pulsout portb.0, 100 ' Sends a 1mSec pulse out pin b.0. 100 x 0.000010 = 1mS.

But First:

low gpio.5

We must first establish the initial logic state of the output pin to be used with pulsout to make the pulse a positive polarity.  Since the pulsout command will toggle the output pin twice, we need to establish the required initial logic state prior to using the pulsout command for our specific requirements..

Setting the output-pin to logic 0, we know that the pulsout command will toggle the pin from 0 to 1 then back to 0, and meet our requirements for a positive going pulse. If we start with our output pin at logic 1, the outgoing pulse will be the compliment of the pulse shown above in the scope trace - or inverted....

Servo Positional Data:

Now that we have the servo-pod ready to use, we need to figure out how to send positional data to the servo-pod that will let us position the servo motor.  As stated previously -- we know that the pulsout command is dependent on the oscillator frequency, and the pulse duration will be in 10uS increments when used in conjunction with an oscillator frequency of 4MHz.  Since the PIC12C671 maximum operating frequency is 4MHz, we'll have to make due with this resolution.

To determine the values to send a servo-pod -- we need to take the minimum and maximum position values we can send a servo, and divide each one by our actual pulse resolution of 10uS as follows.

The full left position for a servo requires a pulse of 2mS or 0.002. For full right we need a pulse of 1mS or 0.001.

bullet

Data for full left   = 2mS/10uS = 0.002/0.000010 = 200.

bullet

Data for full right = 1mS/10uS = 0.001/0.000010 = 100.

Sending a value of 100 for the positional data will cause the servo motor to go to the full right position by loading the pos variable with this value.  A value of 200 will position the servo to the extreme left.  What will 150 do..?

No Two Servos Are Created Equal:

I have yet to see two servos that are exactly the same.  Position data for one servo, may not send another similar servo to exactly the same position.  You may have to send position data from 20 to 225.  This is really not important, since you can send anything you like that will fit into a single byte-variable storage space such as 0 to 255.

Test your servo motors individually to establish the minimum & maximum rotation of each one.  This is the only way to make sure you're not over-driving some servo motors.  Trying to send a servo farther than it's supposed to go in any direction will cause jittering, above average current consumption, and drain your batteries quickly.

The Test Program:

Now that you're ready to start using the servo-pods, some test code to cycle the servo motors will be necessary.  Here's a quick & simple Basic Stamp routine that will cycle a servo motor attached to a servo-pod hard-coded with the unique ID #5.


' Program to cycle the 8-pin PIC12C671 serial
' servo controller (servo-pod).

cont	var byte
pos	var byte
N9600   con 16468
ID	con 5
pos	=   20

loop:
    for cont = 1 to 210		'Cycle right to left
	serout 0,N9600,[ID,pos]
	pause 10
        pos = pos + 1		'From 20 to 230
    next
	pause 500
    for cont = 1 to 210		'Cycle left to right
	serout 0,N9600,[ID,pos]
	pause 10
	pos = pos - 1		'From 230 to 20
    next
	pause 500
	serout 0,N9600,[ID,230]	'Quick left
	pause 1000
	serout 0,N9600,[ID,125]	'Center
	pause 1000
	serout 0,N9600,[ID,20]	'Quick right
	pause 1000
	goto loop		'Repeat forever

Notice how the ID variable has been assigned a value of 5...?  Try changing this to any other number and see what happens.  If the servo-pod doesn't receive its own unique ID# first, any new positional data is simply ignored, and the servo motor is held firmly in place by the last stored position data in variable pos.  You may also notice that I had to alter the min/max values.  Instead of 100 to 200, I had to use 20 to 230 for full rotation with my particular servos.  You'll see how this changes depending on the servo brands you're using...

This little 8-pin PIC micro makes building these servo control gadgets a breeze, is a very powerful solution for addressable servo motor control, and only requires a single I/O-pin to control as many servo motors as you can afford.

Theoretically, the only real problem you'll have is the total number of devices you can drive with a single serial I/O-pin.

Hint: Line driver ICs to boost the serial signal to accommodate more devices on the single bus.

The Schematic:

Be sure to use a separate power supply for the motor & servo-pod with both circuit grounds tied together.  To interface the servo-pod to the Basic Stamp, the 220 ohm resistor will limit current between the input-pin of the servo-pod and Basic Stamp I/O-pins to 22mA.  For more protection, simply increase this value.

For interfacing directly to the PC serial port, replace the resistor on GP.4 with a 22K.  This will allow direct interface of the servo-pod to your PC serial port.

TIP: Some internal oscillators (especially for the 12C671) may not maintain an oscillator frequency that's as stable as an external solution. If your servo pod acts funny, you may want to use an external 4MHz ceramic resonator or crystal. This will help insure you're getting the correct baud rate. If the baud rate is slightly off - the servo pod will not function 100%. Normally the internal oscillator works fine - but if your servo pod acts weird, give this a look....!

What Now:

The unique feature of the servo-pod is the ability to have many pods with the same address, and to control multiple servos at exactly the same time.  If you have a large animation that requires moving multiple servos to the exact same position, at the exact same time, this is incredibly simple.  Program as many servo-pods with the same address as you need, and address each one at the same time by sending its unique ID followed by the position to move the servo to.

The ID is a byte variable -- so up to 255 unique individual address numbers are available for an ID.  A number from 1 to 255 can be used for an ID, and you can have as many servo-pods with the same ID as you like.  You can have an incredible number of serial servo-pods all sharing a single serial bus data line.

Until the next project -- have fun, and thanks for stopping by....:o]

bullet

Click HERE to purchase PicBasic Compilers - and hardware.

bullet

Click HERE to learn more about the PicBasic compiler.

bullet

Click HERE to return to the PicBasic projects page.

More coming soon, so book-mark the projects page...!

Click HERE to return to the PicBasic Projects Page

Copyright © 1999-2008
Reynolds Electronics