Today’s Tech Thursday will cover how to control a stepper motor using a stepper motor driver and an Arduino. Stepper motors have the useful property of moving through discrete, precise angular steps, allowing them to be positioned without any encoder feedback required. They also tend to be less expensive than servos, making them a good option for position control.
Stepper Motor Wiring
How to go about wiring a stepper motor depends on the number of wires it has. If you have the datasheet for the motor it’s easy, if not you may need to do some trial and error. The datasheet will usually have diagrams for wiring in series or parallel. Series is the most common configuration, so go with this if you’re unsure. See this page for more information on wiring and troubleshooting of stepper motors: http://www.reprap.org/wiki/Stepper_wiring.
Stepper Motor Driver
A stepper motor driver can handle the motor coil control and usually takes as inputs a step signal and a direction signal. The step signal is a pulse train, and the driver aims to move the stepper motor through one angular step for each pulse received. The number of steps per one motor revolution is dependent on the motor; common values are 100 or 200 steps/revolution (3.6 or 1.8 degrees/rev). If you notice the stepper motor motion is rough or causes a lot of vibration, you can try microstepping to smooth things out. This will be a setting on the driver which allows you to move the motor by 1 step for every e.g. 5 or 10 step inputs and is usually set via dip switches. This leads to much smoother motion at low speeds but requires a larger frequency input to be generated. The direction input is a simple high/low digital signal indicating whether the motor should be spun forward or reverse.
Arduino Pulse Train Generation
The objective of the pulse train is to produce a frequency that corresponds to a desired stepper motor speed. At higher speeds, the pulse train will need to ramp up to the target frequency, as a stepper motor will not be able to instantly jump to a fast speed – there must be an acceleration period. It should also ramp down to zero to avoid a harsh stop. You’ll need to experiment with the system to figure out how quickly you can accelerate the motor. The driver will also have a minimum pulse width (in units of time, e.g. 10 µS) that will need to be exceeded for proper operation. Having access to an oscilloscope will help greatly in setting up your code.
There are several approaches to generating a pulse train from an Arduino, including analogWrite(), bit-banging, and PWM register management. For a detailed guide on these methods you can read https://www.arduino.cc/en/Tutorial/HomePage, but I will discuss them briefly and in the context of stepper motors here.
analogWrite() Method
Using the command analogWrite(pin, duty_cycle[0-255]) will output a square waveform on one of the Arduino’s PWM pins (3, 5, 6, 9, 10, or 11). This is dead simple but unfortunately is not very useful for controlling stepper motors. The problem is that this approach provides no control over the PWM frequency, which is fixed at either 490 or 980 Hz depending on which pin is used. This means only one motor speed is possible using analogWrite(), and depending on the microstep settings your motor may not even be able to accelerate fast enough to match this speed.
Bit-Banging
Bit-banging gives you full control over the output steps. In this approach, you manually toggle a digital output between high and low using digitalWrite() and delay() or delayMicroseconds(). The example code below will produce a pulse train of about 5000 kHz with a 50% duty cycle. Adjusting the delay times will give different frequency outputs. Additional code can be added to ramp up/down the frequency to provide motor acceleration. Be aware that delayMicroseconds() doesn’t work with values higher than 16383, so for values larger than that use delay() instead, which takes milliseconds as an argument.
// pwm pin - this can be any digital output // when bit-banging int pwmPin = 5; int dirPin = 6; //direction signal void setup() { pinMode(pwmPin, OUTPUT); //set pin as output pinMode(dirPin, OUTPUT); //set direction as output digitalWrite(dirPin, HIGH); //write some direction } void loop() { digitalWrite(pwmPin, HIGH); //set pulse high delayMicroseconds(100); //wait 100 microseconds digitalWrite(pwmPin, LOW); //set pulse low delayMicroseconds(100): //wait 100 microseconds }
Bit-banging has the advantage of being very simple while giving you pretty good control over the timing. It also allows you to track the number of pulses that have been output, which is extremely useful for moving the motor through a desired number of steps. Bit-banging does have some disadvantages. At high frequencies bit-banging will require most of the Arduino’s processing time, limiting what else can be accomplished during a compute cycle. Also, the delay() functions can be subject to some chatter and the digital I/O methods take several microseconds, so the time precision is not great. If the Arduino doesn’t need to do much besides generate the pulse train, you can tolerate some timing variations, and you’re not using interrupts, bit-banging is a good approach for stepper motor control.
PWM Register Management
Managing the PWM registers is the most complicated approach but will give you guaranteed frequency outputs without tying up the processor, allowing complex programs to run while the pulse train is generated in the background. The Arduino has several timers: 3 on the Uno and 5 on the Mega for instance. Each of these timers is tied to 2-3 PWM output pins. When selecting a timer, avoid using Timer0 as the Arduino time-related functions such as delay() are dependent on this timer. Some of the timers are 8-bit and some are 16-bit. The 16-bit timers (Timer1 on the Uno and Timers 3, 4, and 5 on the Mega) will give you more options for frequency outputs, as only a discrete selection of frequencies can be produced with this method.
The idea is that by writing directly to the timer’s prescaler and output compare registers, you can select between several PWM modes and set the frequency and pulse high/low time. You can write to the registers on every compute cycle to vary the frequency as desired. One method is to use Fast PWM mode with a constant prescaler and vary the output compare register A to obtain the desired frequency.
A drawback to this method is that you won’t be able to track the number of steps you have output to the stepper motor driver, though you can track the frequency and time to get a close approximation. Another option for tracking pulses is to use an encoder buffer board (http://www.superdroidrobots.com/shop/item.aspx/dual-ls7366r-quadrature-encoder-buffer-breakout-board/1523/) and have it tap into the PWM output to count the number of pulses observed.
For the full contents of the timer registers, see sections 12.9 and 13.11 of the atmega328p datasheet.. Timers 3, 4, and 5 on the Mega have the same registers as Timer1; simply replace the first digit in the bit name (1) to 3, 4, or 5 (for instance, WGM12 becomes WGM32 for timer 3).
For more details on these Arduino pulse train methods and more example code: https://www.arduino.cc/en/Tutorial/HomePage
#techthursday #steppermotors #Arduino