Control Servo Motors from a PC to a .35 degree resolution.
Servo motors (supplier, supplier, supplier) are relatively cheap and good for positioning. They have a range of motion usually around 180 degrees--they aren't used for continual rotation (though you can modify them for this purpose). Servos combine a DC motor with a built-in gearbox and feedback control loop. This means that once you set the proper position, then even if you manually push the motor off equilibrium it will return to it. How nice!
However, these servo motors are controlled by a Pulse Width Modulation (PWM) signal. In other words, you send it a 50Hz square wave, but adjust the width of the positive pulses between 0.5msec and 2.5msec to control position. The motor then moves to a position (within it's range) linearly proportional to the width of the pulse. This can be convenient if you are using a microcontroller with PWM primitives, but not if you're using a PC to control it.
So, design requirements are:
- controls at least two servo motors via PWM
- hooks up to a PC via either parallel port or USB
- uses "common" parts, by which I mean, stuff I have lying around.
To start, I found this article by GKDesign about a parallel port servo controller. I like how he
designed the circuit. He uses two 555 oscillators, one to set the 50Hz
loop, and a 100KHz oscillator to drive a down counter, which he uses to
time his output pulses. It's a great idea, and my design will be based on his.
But I have a few
issues with his design:
- He doesn't do any level conversion between the parallel port and the logic/motor. Parallel ports often run at less than 2.3V--as is the case with my laptop--even though the motor must run at least 4.8V!
- His design requires exotic parts, such as an 8-input nand gate, and needs a lot of ICs per modulator. It also uses chips from the 74LS family, which is kind of old-school.
- His circuit will vary the pulse width from 0.5msec to 3.06msec, despite his claims of 0.5msec to 2.5msec!
- Finally (a very minor issue), his circuit controls only one servo.
For lack of a good chip, I simply used some switching transistors as common-emitter amplifiers and a 1K pull-up resistor. It will invert the signal, which means that the computer should send the 1's complement of what it actually wants, but it works well.
If anyone knows of a better way (for instance, a 9x array of transistors in a single IC), I'd like to hear about it.
We need to get an 8-bit value from the parallel port for each independant motor, but the parallel port can only ouput 8-bits at a time. So, we need a way of multiplexing the connection. My solution is not the cleanest, but it will work.
Oversimplified explanation: I create a FIFO of 74hc273 registers with a common clock. Whenever I send a strobe, all of the values move down one register, and the parallel port data is fed into the first. Thus, to set all N registers, I have to send N bytes with strobes.
Realistic explanation: I am only using a two stage FIFO, and the first register is actually in the computer's parallel port (remember, the parallel port latches it's output). Thus, to set both registers, I send (1) The first 8-bit value, (2) a strobe, and (3) the second 8-bit value. A second strobe is not sent.
means that when setting the registers, there is a short time period
during which the registers have the wrong values. However, if this
period is shorter than the servo motors are fast, the worst you will
witness is a small jerk. In my experience, I have not noticed any.
GKDesgin used a 50Hz clock and a 100KHz clock. But, 0.5msec + 256 cycles / 100 KHz = 3.56 msec, not 2.5 msec! So, we instead change the second clock to 128 KHz; 0.5msec + 256 cycles / 128 KHz = 2.5 msec. Also, I implemented this with a 556 instead of two 555s.
Pretty much the same as GKDesign's, except I'm using the 74hc191 timer. Since the 191 has a MAX/MIN output, I can calculate zero without the use of an 8-input NAND. Each modulator requires only three ICs, compared to GKDesign's four. I use two of these, one for each motor.
Tested, and it works.
- The interface to the parallel port (schematic).
- The two oscillators (schematic).
- The pulse width modulator circuit (schematic).
I did my prototype on two 830-pt solderless breadboards, which proved to be quite cramped. Nonetheless it works.
- A picture, and an annotated picture of my prototype.
- A simple test program (pwm-test.tar.bz2).
- A movie (.mov 5.5 MiB) of the testcase program driving two servo motors.