Servo Motors: Theory, Hardware,
and HC11 code

Back to articles.

Back to code examples.

Last updated:


I've seen raging debates on comp.robotics and other forums about the definition of a robot. I don't claim to have the end-all definition, but I will claim that a facet in any definition of a robot is motion. One thing (among many) that sets robots apart from other electronic and microprocessor projects is movement. Before we get bogged down in the robot definition quagmire, wrapped around the axle with philosophical subtleties, let's take a look at movement.

One method of an electronic device achieving movement is the use of motors. A versatile and easy-to-use type of motor is the servo motor. What is a servo motor? The kind of servo motor we are going to look into is a motor which has a feedback mechanism to sense it's position. The control input to a servo motor tells it to be in a certain position, and logic built into the servo motor will position it. A typical servo consists of a DC motor, a gearhead, a potentiometer for position feedback, and a small circuit to read the pot and position the motor. Physically, servos have limit stops to restrict their range of motion. After we learn how to use servos as designed, we'll look at modifications to a servo which is commonly used for robots.

Let's look at a widely-used servo motor: the Futaba FP-S148. It is found in many radio-controlled vehicles and is a real workhorse in the hobby field. One factor is price. The S148 is carried by local hobby stores for about $25 each, and can also be found through mail-order, such as Tower Hobbies (1- 800-637-4989) for $15.99, or 3 for $44.97 (that's $14.99 each for those of you whose calculators are buried somewhere on your desk or bench). The S148 weighs 1.5 oz, is 0.77" x 1.59" x 1.58", has a 180-degree range, and produces 42 oz.-in. of torque (according to the current Tower catalog). Of course you can find numerous other servos from Futaba, Airtronics, Cox, Royal Titan, and others, as well as "house" brands. Prices range from under $15 to well over $100 each. Variations in size, torque, speed, bearings, and construction (regular versus heavy-duty) account for the wide price range. For my use in robots, the S148 is a good general-purpose motor, I always try to have a few on hand on my work-bench.

OK, suppose we have a servo, an S148. It has 3 wires and can turn 180-degrees. How? Of the 3 wires, black is ground, red is the motor's voltage, and white is the control line. The voltage is typically 5 volts; I'm not sure what the recommended voltage range is. The control line requires a pulse width modulated (PWM) signal. A PWM signal can be generated easily either using hardware, or in software. There are 2 factors when dealing with a PWM signal, frequency and duty cycle. For the S148, the frequency should be in about 33 Hz, or 30 mS in width.

True duty cycle is the ratio of high time over total time, in our example about 20%. However, with servos, the length of the high time is what indicates the servo's position. The actual frequency of the signal is not critical. Rather than look up some specs, let's build a simple hardware circuit to test the ranges of both frequency and high time for the S148. We need 2 oscillators, one in an astable (continuos) mode to generate the frequency, and a second in a mono-stable (one- shot) mode to generate the high time. We can easily do this with a 555 timer, or better yet, we can use a 556 timer which is 2 555s in a single chip. We can use 2 potentiometers to adjust the 2 parameters. The following circuit will test the S148 servo:

The left half of the 556 generates the frequency, the right half is the one-shot which generates the high time. I could easily spend a whole article discussing 555 timer theory-- they are fascinating devices. But for our purposes, let's use the circuit to test the parameters of the S148. The 250K pot (P1) will adjust the PWM frequency and the 5K pot (P2) will adjust the high time. With this circuit I get the following results using a servo and monitoring the PWM signal on an oscilloscope:

Frequency High-time Condition
0.84 mS (1) 0.3 mS min P1, min P2
5.8 mS (2) 5.6 mS min P1, max P2
155 mS 0.36 mS max P1, min P2
155 mS 5.6 mS max P1, max P2
30 mS 2.3 mS servo left
30 mS 0.36 mS(3) servo right
30 mS 1.2 mS servo middle
60 mS 2.3 mS servo left
60 mS 0.36 mS(3) servo right
60 mS 1.2 mS servo middle
92 mS various max servo freq
13 mS various min servo freq
Notes: 1) With P1 at zero ohms, the left half of the 556 did not oscillate. The value is the minimum frequency I was able to achieve an oscillation.
2) The high time is longer than the frequency. The one-shot nature of the circuit keeps the signal high over multiple cycles.
3) The minimum high time produced by this circuit did not turn the servo completely to the right.

From this data we can draw the following conclusions: A high time from 0 mS to 2.3 mS will control the servo position from right (clockwise) to left (ccw). The middle signal of 1.2 mS is halfway, so the control signal is linear. The servo will operate correctly in a frequency range from 13 mS to 92 mS (77 Hz to 11 Hz), and the frequency does not alter the position to high time relationship. I also measured the time it took for the servo to swing from one extreme to the other. It took 3/4 of a second.

With this circuit, we can replace the 250 K pot with the appropriate resistor to hard-wire the frequency at something from 25 mS to 75 mS (I like to be conservative), and use the 5K pot to control the servo. A nice 1 chip solution. To control 3 servos you can use a second 556 chip with both sides configured like the right side above and trigger all 3 one-shots with the left side of the first 556.

Before I run out of room here, let's also look at a software solution for generating a PWM servo control signal with a 68HC11E1 in a BOTBoard, in bootstrap mode. We will use interrupts from the free running timer, which happens to turn over and can generate an interrupt every 32.768 mS (using an 8 MHz crystal). This fits very nicely into the working frequency range of the S148. The software will generate a continuous PWM signal by simply writing the high time value to a timer compare register. The BOTBoard has 4 servo connectors on it. Here's the assembly language to drive 2 servos using the first 2 BOTBoard connectors:

* BOTBoard servo motor program
*
* setup the interrupt vector in RAM
	ORG $B600
	ldx	IntJmp
	stx	$100-48
	ldaa	IntJmp+2
	staa	$100-48+2
*
* Initialize the interrupts
	ldx	#$1000
	ldaa	#$00
	staa	$0c,x	;Out compares off
	staa	$21,x ;In captures off
	staa	$22,x ;Timer interrupts
	ldaa	#$FF
	staa	$23,x	;Clear interrupts
	ldaa	#$F0
	staa	$20,x	;T2 T3, set to 1
	ldaa	#$60
	staa	$0b,x	;Force T2 T3 to 1
	ldaa	#$50
	staa	$20,x	;T2 T3 set toggle
	ldaa	#$80
	staa	$24,x ;Timer o-flow int
	staa	$25,x ;Clear interrupt
	cli		;Enable interrupts

Main:
*
* your code goes here...
*
* Here is an example of setting
* timers 2 and 3 to move the servos
* to different positions.  By
* changing these 2 timer values, the
* resulting PWM signal will change,
* thus repositioning the servos.
*
	ldx	#$0A50
	stx	$1018	 ;Set Timer 2
	ldx	#$07D0
	stx	$101a	 ;Set Timer 3
	bra Main

IntJmp:
* Needed to set the RAM jump vector
	jmp	Interrupt

Interrupt:
*
* This code will be executed every
* 32.768 mS.  We will set both timer
* lines 2 and 3 to be high, and set
* them to toggle low when the free
* running timer equals the values
* set in the timer 2 and 3 registers
*
	ldx	#$1000
	ldaa	#$00
	staa	$21,x ;In captures off
	ldaa	#$F0
	staa	$20,x	;T2 T3, set to 1
	ldaa	#$60
	staa	$0b,x	;Force T2 T3 to 1
	ldaa	#$50
	staa	$20,x	;T2 T3 set toggle
	ldaa	#$80
	staa	$25,x ;Clear interrupt
	rti

One last piece of information; how to use a servo to drive a robot: With a stock S148 we can just move back and forth through a 180-degree range; not good for robot wheels. As documented in detail by various people, including myself in my A Simple Robot Using the 68HC11 Processor article, a servo can be easily modified for continuous rotation. The brief explanation is to: Open the servo, remove the pot and replace it with 2 resistors to simulate the pot at it's midpoint. Also remove the hard stop to allow free rotation. Reassemble the servo. With the pot replaced by resistors, any PWM signal which will turn the servo left of center will cause the servo to continuously turn to the left since the feedback value will not reflect the servo's movement. Continuous turning to the right can also be achieved. To stop the modified servo, you must find the correct PWM high time to match the resistor feedback. For different servos, using the same resistor values, I have to use slightly different values due to the tolerances involved.

Please note that the continuous-rotation modification cannot be easily done on any servo; on some the gear does not have teeth all the way around, which is not good. This is why, once I found the S148 was a good choice for this modification, I've stuck with it.

Also for use with BOTBoards, the S148 wires need to be switched around; you must switch the black and the red wires. The wires can be removed from the connector with a very small screw driver, good eyesight, and a steady hand. The BOTBoard compatible order is white, black, red, from close to the HC11 out.

Putting it all together
Take two S148 servos, a BOTBoard, the code from above, and 4 batteries. Strap together somehow and you've got a functioning robot. Look for my articles in the second and third issues of The Robotics Practitioner, which will detail and expand the HC11 code shown above, and will provide a complete simple robot setup and program.

I have these articles on-line at:

The first of these articles uses HC11 code to drive servos in the same manner used here. The second of these articles uses a much more elegant and easy method to control the servo motors.

I hope this is helpful. Please e-mail me with questions, problems, and hopefully sucess stories...