Per Stenebo
2019-10-27 17:43:25
2020-06-04 18:06:02

Unipolar stepper motor with driver
Description on how to connect and code for a 28BYJ-48 and ULN2003 with a Raspberry Pi.
28BYJ-48 is a 5 VDC unipolar stepper motor. ULN2003 is the main component on the driver board. This circuit is fed from a 5 VDC power supply but the signal connections can handle both 3.3 volt (like from a Raspberry Pi) and 5 volt (like from an Arduino).
There are plenty of tutorials about this motor, some even with this driver board, but none (as fas as I know) with this exact combination of motor, driver and controller. As I was new to this kind of motor I have spent many hours searching and testing, an effort I hope to save someone else with this page.
External resources
I have bought these as a Luxorparts kit from Kjell & Co.
Most info, images and code compiled from the following sources:
| instructables.com | Raspberry Pi Tutorials | seeedstudio.com | 42bots.com |
Wiring
GPIO pin | Driver pin | Motor wire |
---|---|---|
GPIO #4 | IN1 | Blue |
GPIO #17 | IN2 | Pink |
GPIO #23 | IN3 | Yellow |
GPIO #24 | IN4 | Orange |
Connection chart with separate power sources (recommended):
Connection chart with common power source:
You can of course choose any available GPIO pin but you need to adjust the code accordingly. Remember that driving stepper motors is all about signal order, keep track of your changes.
You can (and should) have a separate power supply for the controller and the driver/motor. If so, remember to connect a ground wire between the controller and the driver so they have a common reference.
The LEDs and the resistors (330 Ω) on the breadboard are just for fun (and for troubleshooting). You can skip these.
The capacitor (100uF 50V) are also optional, it mitigates power surges from the motor, causing voltage drops to the controller. Use separate power supplies instead.
Troubleshooting
Resistance between motor wires, motor disconnected from the driver board:
Orange Red 21,9 Ω
Yellow Red 21,8 Ω
Pink Red 21,7 Ω
Blue Red 21,7 Ω
Blue Pink 43,4 Ω
Blue Yellow 43,4 Ω
Blue Orange 43,5 Ω
Pink Yellow 43,3 Ω
Pink Orange 43,5 Ω
Orange Yellow 43,5 Ω
The motor includes a gearbox with high ratio, about 63:1. When using the default delay of 5 ms between each step, the visible gear still turns quite slow. The high ratio also makes the gear somewhat self-locking. The gears will break if you try to turn the motor from the visible shaft.
Code for python 3 (preferred)
#!/usr/bin/python3 # coding: utf-8 ''' sudo apt install python3-dev python3-rpi.gpio Run with: python3 stepper.py ''' import sys, signal, time import RPi.GPIO as GPIO #----------------------------------------------------------------------- # Functions (inline) #----------------------------------------------------------------------- # Manage ctrl+c def signal_handler(signal, frame): GPIO.cleanup() print ('Script terminated by Ctrl+C') # Terminate script sys.exit(0) signal.signal(signal.SIGINT, signal_handler) #----------------------------------------------------------------------- # GPIO setup #----------------------------------------------------------------------- GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) # Adjust if different coil_A_1_pin = 4 # blue coil_A_2_pin = 17 # pink coil_B_1_pin = 23 # yellow coil_B_2_pin = 24 # orange StepCount = 8 Seq = [0,1,2,3,4,5,6,7] Seq[0] = [1,0,0,0] Seq[1] = [1,1,0,0] Seq[2] = [0,1,0,0] Seq[3] = [0,1,1,0] Seq[4] = [0,0,1,0] Seq[5] = [0,0,1,1] Seq[6] = [0,0,0,1] Seq[7] = [1,0,0,1] GPIO.setup(coil_A_1_pin, GPIO.OUT) GPIO.setup(coil_A_2_pin, GPIO.OUT) GPIO.setup(coil_B_1_pin, GPIO.OUT) GPIO.setup(coil_B_2_pin, GPIO.OUT) def setStep(w1, w2, w3, w4): GPIO.output(coil_A_1_pin, w1) GPIO.output(coil_A_2_pin, w2) GPIO.output(coil_B_1_pin, w3) GPIO.output(coil_B_2_pin, w4) def forward(delay, steps): for i in range(steps): for j in range(StepCount): setStep(Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3]) time.sleep(delay) #input("Fwd seq #%d : %s %s %s %s" % (j, Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3])) def backwards(delay, steps): for i in range(steps): for j in reversed(range(StepCount)): setStep(Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3]) time.sleep(delay) #input("Rev seq #%d : %s %s %s %s" % (j, Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3])) #----------------------------------------------------------------------- # Main #----------------------------------------------------------------------- if __name__ == '__main__': setStep(0, 0, 0, 0) delay = input("Time Delay (ms) [5]? ") if not delay: delay = 5 else: delay = int(delay) steps_fwd = input("How many steps forward? [100] ") if not steps_fwd: steps_fwd = 100 else: steps_fwd = int(steps_fwd) steps_rev = input("How many steps backward? [100] ") if not steps_rev: steps_rev = 100 else: steps_rev = int(steps_rev) while True: forward(delay / 1000.0, steps_fwd) setStep(0, 0, 0, 0) time.sleep(0.5) backwards(delay / 1000.0, steps_rev) setStep(0, 0, 0, 0) time.sleep(0.5)
Code for python 2
#!/usr/bin/python2.7 # coding: utf-8 ''' sudo apt install python-dev python-rpi.gpio Run with: python2 stepper.py ''' import sys, signal, time import RPi.GPIO as GPIO #----------------------------------------------------------------------- # Functions (inline) #----------------------------------------------------------------------- # Manage ctrl+c def signal_handler(signal, frame): GPIO.cleanup() print ('Script terminated by Ctrl+C') # Terminate script sys.exit(0) signal.signal(signal.SIGINT, signal_handler) #----------------------------------------------------------------------- # GPIO setup #----------------------------------------------------------------------- GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) # Adjust if different coil_A_1_pin = 4 # blue coil_A_2_pin = 17 # pink coil_B_1_pin = 23 # yellow coil_B_2_pin = 24 # orange StepCount = 8 Seq = range(0, StepCount) Seq[0] = [1,0,0,0] Seq[1] = [1,1,0,0] Seq[2] = [0,1,0,0] Seq[3] = [0,1,1,0] Seq[4] = [0,0,1,0] Seq[5] = [0,0,1,1] Seq[6] = [0,0,0,1] Seq[7] = [1,0,0,1] GPIO.setup(coil_A_1_pin, GPIO.OUT) GPIO.setup(coil_A_2_pin, GPIO.OUT) GPIO.setup(coil_B_1_pin, GPIO.OUT) GPIO.setup(coil_B_2_pin, GPIO.OUT) def setStep(w1, w2, w3, w4): GPIO.output(coil_A_1_pin, w1) GPIO.output(coil_A_2_pin, w2) GPIO.output(coil_B_1_pin, w3) GPIO.output(coil_B_2_pin, w4) def forward(delay, steps): for i in range(steps): for j in range(StepCount): setStep(Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3]) time.sleep(delay) #raw_input("Fwd seq #%d : %s %s %s %s" % (j, Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3])) def backwards(delay, steps): for i in range(steps): for j in reversed(range(StepCount)): setStep(Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3]) time.sleep(delay) #raw_input("Rev seq #%d : %s %s %s %s" % (j, Seq[j][0], Seq[j][1], Seq[j][2], Seq[j][3])) #----------------------------------------------------------------------- # Main #----------------------------------------------------------------------- if __name__ == '__main__': setStep(0, 0, 0, 0) delay = raw_input("Time Delay (ms) [5]? ") if not delay: delay = 5 else: delay = int(delay) steps_fwd = raw_input("How many steps forward? [100] ") if not steps_fwd: steps_fwd = 100 else: steps_fwd = int(steps_fwd) steps_rev = raw_input("How many steps backward? [100] ") if not steps_rev: steps_rev = 100 else: steps_rev = int(steps_rev) while True: forward(delay / 1000.0, steps_fwd) setStep(0, 0, 0, 0) time.sleep(0.5) backwards(delay / 1000.0, steps_rev) setStep(0, 0, 0, 0) time.sleep(0.5)
More images
Tip: Right-click on the image and select "Show image in new tab" to view it in full size.