Designing with Stepper Motors
Introduction
Having built 8 robots, 6 based on hacked servos for drive motors, it was time to
try something different. The biggest problem with any wheeled robot is getting
the darn thing to travel in a straight line. Since no two DC motors are going
to spin at the same rate, some form of feedback system must be used to detect
and adjust for these differences. I’ve used wheel encoders to count the pulses
and range sensors to monitor the distance from a wall. Given enough time and
code tweaking, you can get these methods to work for you, but again I wanted to
try something different, thus I began my research into the use of stepper
motors. Rather then go into a lot of detail on how stepper motors work, this
article will cover the process I went through to design and build a maze runner
robot using stepper motors.
Concept
Ok, so what is a stepper motor and why do I want it? A stepper motor consists
of several field coils that are energized in a sequential fashion to rotate the
motor’s armature in steps. Each of these steps is very precise and gives you
excellent control of the motor’s movement. The motors I used have almost 1800
steps per rotation, that a lot of precision! To control the robots movement
becomes a simple matter of counting the number of pulses you send to the motors
to travel a desired distance.
Details
Ok first I needed to get some stepper motors. Not knowing a thing about them I
ordered a pair from a surplus center and started playing with them. The specs
sounded good, 400 pulses per revolution and they would run on 5 volts. I built
up a driver circuit on a breadboard using an AT90S2313 micro and an h-bridge
driver. It was thrilling to see the stepper spin around and be able to
precisely control it’s movement, but it was whimpy. There was no way a pair of
these motors would be able to move a robot around, so I did some more research.
When looking for stepper motors, one of the specs you need to look at is the
dynamic torque, which is how much power can be applied when moving the shaft.
The motors I started with were probably NEMA 17. After reading other articles
and newsgroups on robots and steppers, I determined that I needed at least 60
oz.-in. torque or a NEMA 23 motor.
None of the surplus centers I normally use had anything this big. If they did
they were expensive. Even on Ebay a set of 3 CNC steppers would typically go
for more then $50. Fortunately those same people that were recommending NEMA 23
motors also had a source for them. Turns out the Image Writer II, an old dot-
matrix printer for Apple computers have such a stepper motor in them. In fact I
was led to believe that they contained a pair of identical stepper motors in
them, which would be great since I would need two motors for the robot. Back to
Ebay and a quick $3 bid got me a printer! Course I had to pay about $10 in
shipping. Once the printer arrived I opened it up and quickly discovered that
while there are indeed two steppers in there, only one is the big NEMA 23. This
one is in the bottom and moves the print head assembly back and forth. The
other motor is much smaller and spins the platen and tractor feed assembly to
move the paper through the printer.
Before removing the motor from the printer I wanted to see what the drive pulses
looked like that moved the stepper. Since this motor has 6 wires coming out of
it, that tells me it’s a unipolar motor and that 2 of the wires are commons,
while the other 4 wires go to 4 separate coils as shown in figure 1.
Once I had an oscilloscope attached I could see the waveform shown in figure 2.
One of the first things I noticed was that the pulses overlapped each over,
something I hadn’t done with my earlier experiments. This technique is called
half-stepping and allows you to get even more torque out of the motor. The down
side is that you use a little more battery power, since you briefly have two
coils energized instead of only one.
Next step was to develop my own driving circuit and see if I could control the
stepper motor. Using the same 2313 and 4 MOSFET's, I built the basic circuit
you see in figure 3. I wrote a test program that duplicated the 4ms pulse train
the printer driver used and started experimenting. The new motor was a lot more
powerful, I couldn’t stop the shaft while holding it with my fingers! Just for
chuckles I changed the waveform back to driving one coil at a time and noticed
the output torque was significantly reduced, to the point of not being able to
move the robot. So the final design would require half-stepping and a beefier
power source to handle the load. Now that I had the right type of motor I
needed, and a basic idea of what to do with it, I needed another motor. Another
visit to Ebay got me a 2nd printer and I verified that the second
printer had the same stepper motors in it. Now I could start designing the
robot.
Power Supply
All of my previous servo based robots used 3-volt logic on the controller board.
This allowed me to run the entire robot off of 4 AA batteries since the 6-volt
supply would drop down to 4 volts before the power supply couldn’t regulate and
the servos struggle to work. To use the stepper motors a different approach was
required. The MOSFET drivers need more then 3 volts at the gate to turn on and I
also wanted to use a digital compass on this project, so a 5-volt logic
controller was needed. To supply 5 volts to the controller would require either
a fancy step-up/step-down supply with a 6-volt battery, or a higher voltage
battery pack. Knowing the steppers would draw more power over their servo
counterparts I also wanted to use a higher current capacity cell, so a 7.2 volt
sub-c based pack seemed like a good selection. These packs are commonly used in
R/C cars and are readily available for under $20. The only other concern was
noise. If these steppers motors were extremely noisy, then isolated supplies
might be necessary, would mean using optically-isolated drivers and different
supplies for the motors and controller board. I decided to design the power and
driver sections with optical isolators, use a single power supply, but design it
to use two supplies if needed.
Motor Driver System
The driver circuit for the unipolar stepper motor is fairly straight forward.
The common side of both coils are tied to the plus side of the power supply and
N-channel MOSFET’s are used to sink each coil to ground and energize them. The
gates of the MOSFET’s could be driven by the TTL outputs of the microcontroller,
but this is where the isolation comes into play. By using optical-isolators
between the micro-controller and the MOSFET drivers, most of the noise generated
by the motors won’t find it’s way back to the controller. A typical circuit
would now look like figure 4.
From a software standpoint it would be nice to drive all the driver circuits
from the same 8-bit I/O port. This arrangement would also allow all the drivers
to be updated at the same time with a single instruction. A concern I had was
the total current capacity of that single I/O port. In order to keep all 8 coils
turned off, the LED’s in the optical isolators must be on. This means all 8 bits
of the port are sinking current, which would exceed the total current capacity
of the port. So the polarity of the port pins needed to be inverted. The obvious
solution would be to use inverters between the micro and the optical-isolators,
but that would require at least two more IC’s where space was quickly becoming a
premium. By swapping the location of the pullup resistors and the optical-
isolators, the required inversion is satisfied without additional parts. The
final driver circuit in shown in figure 5.
Firmware Development
After the robot was designed and the circuit board was built, I was able
to start working on the firmware to drive the stepper motors. My intent
was to use one of the timer interrupts to generate the waveforms needed
to drive 8 port pins and both motors, and handle it all within the
interrupt service routine (ISR). In doing so it becomes a background task
that I don’t need to deal with as part of the main code. A good design
will minimize the amount of time spent in the ISR and a lookup table
seemed to be the fastest approach to use for this task.
The table would mimic the actual waveform and a simple version would look
something the one to the right. Each column represents the logical state
of one coil in the motor. Each time we advance through the table, a
different coil will get energized.
The real table is more complex since we need to control two motors and I
was planning to use half-stepping for the additional power, so now the
table looks like this. Each nibble drives one motor and since the port
pins are wired the same way, a single “OUT” command will update both
nibbles and both motors.
Two final changes are needed. One is to invert the table, since the driver
circuit works in an inverted fashion. The other change is to reduce current
spikes when each coil is energized, by not allowing both motors to turn on at
the same time. The way I did this was to double the size of the table and only
change one nibble on either side. I wanted to maintain the original timing of
the waveform I observed from the printer board, so each pulse will be 4ms in
duration. Since the lookup table has doubled in size, the timer interrupt will
occur every 2ms. The basic operation of the ISR is to point to the lookup
table and use an index to retrieve the next entry. This 8-bit entry is sent to
the I/O port to update the driver circuits, and the index is incremented to
the next entry in the table.
Now if all we had to do was run the motors all the time, then we’d be done. Of
course we need to start, stop, and turn, so once again things get a little more
complicated. To start and stop the motors I decided to use a global flag that
was set when I want to motors to operate, and cleared when I want to stop.
Within the ISR, the first thing it does is test this flag and exit the ISR if
the flag isn’t set. Other approaches would include starting and stopping the
timer itself to prevent motor updates. Turning and going backwards are little
tougher to handle. To make the motors go in reverse you simply decrement the
index pointer instead of incrementing it, which walks through the lookup table
backwards instead of forward. To let the ISR know if you want to go backwards,
another flag is set by the main code when we want to go backwards and the ISR
will test the flag before incrementing or decrementing the index pointer.
Turning requires one motor going forward and one going backwards. Since both
motors are controlled by a single table, the use of a 2nd table is
the only way to get the motors going in opposite directions. Once again a flag
is used to tell the ISR whether to use the straight table or the turning table.
A summary of the 3 flags is shown in table 4.
| mtrRunning |
mtrTurning |
mtrBackward |
Operation |
| 0 |
X |
X |
Robot is stopped |
| 1 |
0 |
0 |
Robot is going forward |
| 1 |
0 |
1 |
Robot is going backwards |
| 1 |
1 |
0 |
Robot is turning left |
| 1 |
1 |
1 |
Robot is turning right |
Table 4
Once all these routines were in place, it was time to get the robot moving
through the maze. One of the most critical operations is turning, I need to have
precise 90° turns to move the robot around. With the steppers it should be a
simple matter of counting the pulses that are sent to the motors and stop after
a predetermined amount. To test this operation I setup a simple routine that
performs 4 turns with delays between the turns to allow the robot to come to
rest. When the routine is complete the robot should be sitting right where it
started from. After coming up with the proper number of pulses to use for a
single turn I noted that the turns still weren’t consistent. From past
experience with servo motors I had a suspicion that the problem was too much
momentum, the motors were simply turning too fast. By reducing the speed of the
motors during a turn, this may give me the added control I needed. To reduce the
speed of the motors I simply changed the timer interval from 4ms to 8ms to
reduce the pulse rate by half. Now the turns were consistent enough to start
running in the maze.
Final Testing
I was impressed with how straight the robot moved around my 4’x4’ test maze.
Most of the time it could run the entire maze without touching the walls, and
this is without any kind of guidance correction at all. The times that it did
get off track were due to starts and stops that would turn the robot slightly. I
suspect using some form of ramping function to accelerate and de-accelerate the
robot might help, but I didn’t have time to develop anything before the next
maze event. Instead I planned to use range sensors to track my relation to the
nearest walls and adjust the robots direction as needed, something I would have
done anyway, since we can never achieve perfect handling all the time. So the
final routines I added were ones that would align the robot parallel with the
nearest wall after each turn. This precision required further reduction in
turning speed, so the robot wouldn’t turn faster then the range sensor could
update, so I added a quarter-speed routine for the aligning routines.
Conclusions
Working with stepper motors was a very rewarding
project. I now have a very stable robot
that operates smoothly and drives straight as an arrow.
Posted by Kelly Small at
05:27 PM
|
Comments (3)