[Part 1 begins a look at how to interface with some common robotics-type sensors and actuators, and how these can be tied into an example system (in this case, the author's E-2 Autonomous Submarine Project).]
3.4 Stepper Motor Controller
Stepper motors are useful for relatively low-speed, intermediate-torque drive and positioning applications, particularly where accurate sub-revolution rotor position control is necessary. Motors of this type are commonly used to drive the reels on electromechanical slot machines (one-armed bandits), to position floppy disk drive heads, operate trainable camera platforms, and to power the drive wheels of small mobile robots. In times of yore, they were also used to position hard disk heads, though such applications have long ago been taken over by voice-coil type mechanisms.
Stepper motors are simple and cheap to use, and you don't need to have a fully closed-loop controller to use them accurately. Servomotors are much faster, but for guaranteeable positioning accuracy, you need to have a position encoder on the shaft to provide feedback on the actuator's position. By contrast, as long as you don't stray outside your system's nominal acceleration profile (see the following), a stepper-based system can reliably maintain its position indefinitely without recalibration.
There are several types of stepper motors, with varying electrical drive requirements. However, by far the most common type of motor to be found on the surplus market (or scavenged from unwanted computer equipment) is the four-pole unipolar type14, so this is the type our circuit is designed to use. Without further ado, here's the schematic15:
Figure 3-5: Stepper motor control circuit.
This project uses the ULN2803 octal high-voltage, high-current Darlington array to switch the stepper coils. This chip is readily available for around $0.75 in small quantities, and it is a handy solution for driving moderate loads. Until recently, one could often find this chip, or its close relatives, in commercial stepper motor applications such as inkjet printers and both sheet-fed and flatbed scanners. At present, however, it appears to be in decline as application-specific microcontrollers with high-current drivers on-chip take over its market space.
On the subject of prices, you'll notice that I've specified an NTSC colorburst crystal as the clock source, despite the fact that the tiny26L is rated at up to 8 MHz for a 5 V supply voltage. I chose the 3.579545 MHz value, although it's not a nice integer to work with, because these crystals are available everywhere and are often cheaper than other speeds. Chances are you have several in your junkbox already, in fact. You'll also find that application notes for microcontrollers almost always give precalculated example timing constant values (e.g., for setting the baud rate of a UART) for this base clock speed.
Our example stepper controller module also has two active-low limit switch inputs. These are optionally used to signal end-of-travel in the increment and decrement step directions. Note that JP4, which selects between 5 V or 12 V drive for the stepper coils, is intended to be a wire link for factory configuration, rather than a user-changeable jumper. If you are using the device in 5 V drive mode, you should alter or remove ZD1; you can also omit C2, since it serves no function if you're driving the motor off the +5 V rail.
The controller operates in one of two modes: "drive" or "train." In drive mode, you simply specify a speed and direction, and the motor turns in that direction until commanded to stop. Optionally, you can request that it travel until either of the limit switches is triggered. Train mode is intended for positioning applications. In this mode, you command the stepper controller to seek to a specific offset from the current position, and it will automatically seek to that position while you carry out other tasks. The stepper will automatically cut off if it hits the high limit switch while seeking forwards, or the low limit switch while seeking backwards.
Note that the limit switches are permanently associated with specific seek directions. The "low" limit switch is only enforced for "backwards" seeking, and the "high" limit switch is only enforced for "forwards" seeking. The reasons for this are twofold: First, an external force - say, water rushing past a submarine's rudder - might turn the stepper past the make-point for the limit switch, before it reaches a mechanical stop.
Second, switches are practically never perfect - in other words, the displacement required to make a contact isn't necessarily the displacement required to break it. You might need to push the arm of a microswitch two steps in to penetrate the oxide layer on its contacts; the first step in the other direction might leave the cleaned metal contact surfaces still touching. Or you might be using a reed switch—you need to bring the magnet to a certain proximity to close the switch, but a weaker field will suffice to hold the switch closed. In any of these sorts of cases, it could require one or more "extra" reverse steps to clear the limit condition.
The stepper controller accepts 8-bit command bytes, optionally followed by additional data. Essentially the same serial reception code is used in all the projects in this book, so it deserves a little additional study here. To begin with, please note that my choice of I/O pin assignments was by no means arbitrary. The AVR's pin-state-change interrupts are useful, but not very intelligent. On the tiny26L, there are only two such interrupts: PCINT0, which (if enabled) fires on state-changes for pins PB0-PB3, and PCINT1, which fires on state-changes for pins PA3, PA6, PA7, and PB4-PB7. When one of these interrupts fires, there is no direct way of determining which pin caused the interrupt; you have to maintain a shadow copy of the port registers and compare them to determine which pin(s) changed state.
Fortunately, when an alternate function is enabled for a pin, that pin will no longer generate state-change interrupts (note that there are a couple of exceptions to this rule). Even more fortunately, the three USI signals used for SPI-style communications are mapped to pins PB0-PB2. Thus, by configuring the USI in three-wire mode, PCINT0 will fire only if PB3 changes state. Since the USI in the tiny26L doesn't implement slave select logic in hardware, we need to do it in software—and as a result of all the discussion in the previous paragraph, it makes excellent sense to use PB3 as the SPI select line, since it has a state-change interrupt all to itself.
14. When faced with an unknown stepper motor of small to intermediate size, a very reliable gamble to play is as follows: if it has more than four wires, it's probably a four-pole unipolar motor, 0.9 degrees per step, and likely rated for either 5 V or 12 V operation. There are vast numbers of motors constructed with these characteristics.
15. The alternate function for pin 1 is misprinted here as NOSI—it should be MOSI. This is an unimportant typographical error in the atmel.lbr library supplied by Cadsoft as part of the EAGLE package.