Professional Documents
Culture Documents
28BYJ-48 Stepper Motor With ULN2003 Driver and Arduino Uno
28BYJ-48 Stepper Motor With ULN2003 Driver and Arduino Uno
First, lets see the little steppers in action! Our main character, StepperBot, is “instructed” to move in a square
path on my co븟�ee table, making 90 degree turns at the corners. Turning exactly at the right time and by the
right angle is critical avoid falling o븟� and crashing on the 쓊oor in an embarrassing pile of messy wires.
The robot has no sensors for positioning, orientation, or a way to detect the edges of the table. Movement is
controlled only by the number of pre-de읥�ned steps in each direction hard-coded in the sketch. The motors are
running at approximately 8 volts DC and 15 RPM in this example. One thing that you cannot tell from the video
is how quiet these little steppers run: StepperBot is very stealthy! Eventually, small errors add up over time
and the bot falls o븟� the table, but it typically runs for 10-15 minutes, before that: good enough for me!
The 28BYJ-48 is a small, cheap, 5 volt geared stepping motors. These stepping motors are apparently widely
used to control things like automated blinds, A/C units and are mass produced. Due to the gear reduction
ratio of *approximately* 64:1 it o븟�ers
decent torque for its size at speeds of
about 15 rotations per minute (RPM). With
some software “trickery” to accelerate
gradually and a higher voltage power
source (I tested them with 12 volts DC) I
was able to get about 25+ RPM. These
little steppers can be purchased together
with a small breakout board for the
Arduino compatible ULN2003 stepper
motor driver for less than $5. Quite a
bargain, compared to the price of a geared
DC motor, a DC motor controller and a
wheel encoder! The low cost and small size
makes the 28BYJ-48 an ideal option for
small robotic applications, and an excellent
introduction to stepper motor control with
Arduino. Here are the detailed specs of
the 28BYJ-48 stepper motor.
Frequency 100 Hz
Step angle Half-step mode: 8 step control signal sequence (recommended) 5.625 degrees per step /
64 steps per one revolution of the internal motor shaftFull Step mode: 4 step control
signal sequence 11.25 degrees per step / 32 steps per one revolution of the internal
motor shaft
Gear ratio Manufacturer speci읥�es 64:1. Some patient and diligent people on the Arduino forums have
disassembled the gear train of these little motors and determined that the exact gear ratio
is in fact 63.68395:1. My observations con읥�rm their 읥�ndings. These means that in the
recommended half-step mode we will have:64 steps per motor rotation x 63.684 gear ratio
ULN2003 controller
Weight 30g
The motor has 4 coils of wire that are powered in a sequence to make the magnetic motor shaft spin. When
using the full-step method, 2 of the 4 coils are powered at each step. The default stepper library that comes
pre-installed with the Arduino IDE uses this method. The 28BYH-48 datasheet speci읥�es that the preferred
method for driving this stepper is using the half-step method, where we 읥�rst power coil 1 only, then coil 1 and
2 together, then coil 2 only and so on…With 4 coils, this means 8 di븟�erent signals, like in the table below.
The ULN2003 stepper motor driver board allows you to easily control the 28BYJ-48 stepper motor from a
microcontroller, like the Arduino Uno. One side of the board side has a 5 wire socket where the cable from the
stepper motor hooks up and 4 LEDs to indicate which coil is currently powered. The motor cable only goes in
one way, which always helps. On the side you have a motor on / o븟� jumper (keep it on to enable
power to the stepper). The two pins below the 4 resistors, is where you provide power to the
stepper. Note that powering the stepper from the 5 V rail of the Arduino is not recommended.
A separate 5-12 V 1 Amp power supply or battery pack should be used, as the motor may drain
more current than the microcontroller
can handle and could potentially
damage it. In the middle of the board we
have the ULN2003 chip. At the bottom are
the 4 control inputs that should be
connected to four Arduino digital pins.
Connect the ULN2003 driver IN1, IN2, IN3 and IN4 to digital pin 3, 4, 5 and 6 respectively on the
Arduino Uno. Connect the positive lead from a decent 5-12V battery pack to the “+” pin of the
ULN2003 driver and the ground to the “-” pin. Make sure that the “on/o븟�” jumper next to the “-”
pin is on. If you power the Arduino from a di븟�erent battery pack, connect the grounds together.
The default stepper library that comes pre-installed with the Arduino IDE supports the full-step method only
and has limited features. It does not run the 28BYJ-48 motors very eﺽciently and getting two of them running
at the same time for a di븟�erential drive robot is a bit more diﺽcult. I came across example sketch by 4tronix
that used the half-step method with no additional libraries. Their code worked well and I was able to modify it,
so that I can run two steppers at the same time. Still, I was only able to get my stepper motor spinning fairly
slow and it was getting quite warm, for some reason. Additionally, that sample code uses delays for the steps
and that will cause some issues when we start adding more complex functions in the loop and hook up various
sensors. Then I came across the AccelStepper library. It runs the 28BYJ-48 steppers very eﺽciently
(they never go as hot as with the other options I tried) and also supports acceleration (which
allows the stepper to get to a higher speed). The library uses non blocking code for the steps
and has quite a few other nice features. After some messing around with the documentation
and the examples I got everything up and running. Below is the code that will slowly accelerate
the 28BYJ-48 in one direction, then decelerate to a stop and accelerate in the opposite
direction. Naturally, make sure you download and install the AccelStepper library 읥�rst!
#include <AccelStepper.h>
#define HALFSTEP 8
// Motor pin definitions
#define motorPin1 3 // IN1 on the ULN2003 driver 1
#define motorPin2 4 // IN2 on the ULN2003 driver 1
#define motorPin3 5 // IN3 on the ULN2003 driver 1
#define motorPin4 6 // IN4 on the ULN2003 driver 1
// Initialize with pin sequence IN1‐IN3‐IN2‐IN4 for using the AccelStepper with 28BYJ‐48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
void setup() {
stepper1.setMaxSpeed(1000.0);
stepper1.setAcceleration(100.0);
stepper1.setSpeed(200);
stepper1.moveTo(20000);
void loop() {
The code above will not push this motor to its limit. You can experiment with the acceleration and speed
settings to see what is the best you can squeeze out. Note that for nigher speeds, you will likely need a higher
voltage DC source. If you got your stepper running, here is the code that the StepperBot from the video above
is running. You will need to adjust the speed, as well as the “turnSteps” and “lineSteps” variables based on your
base and wheel sizes, if you want to have your bot moving in a square path.
#include <AccelStepper.h>
#define HALFSTEP 8
// motor pins
#define motorPin1 3 // IN1 on the ULN2003 driver 1
#define motorPin2 4 // IN2 on the ULN2003 driver 1
#define motorPin3 5 // IN3 on the ULN2003 driver 1
#define motorPin4 6 // IN4 on the ULN2003 driver 1
// Initialize with pin sequence IN1‐IN3‐IN2‐IN4 for using the AccelStepper with 28BYJ‐48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
AccelStepper stepper2(HALFSTEP, motorPin5, motorPin7, motorPin6, motorPin8);
// variables
int turnSteps = 2100; // number of steps for a 90 degree turn
int lineSteps = ‐6600; //number of steps to drive straight
int stepperSpeed = 1000; //speed of the stepper (steps per second)
int steps1 = 0; // keep track of the step count for motor 1
int steps2 = 0; // keep track of the step count for motor 2
boolean turn1 = false; //keep track if we are turning or going straight next
boolean turn2 = false; //keep track if we are turning or going straight next
void setup() {
delay(3000); //sime time to put the robot down after swithing it on
stepper1.setMaxSpeed(2000.0);
stepper1.move(1); // I found this necessary
stepper1.setSpeed(stepperSpeed);
stepper2.setMaxSpeed(2000.0);
stepper2.move(‐1); // I found this necessary
stepper2.setSpeed(stepperSpeed);
}
void loop() {
if (steps1 == 0) {
int target = 0;
if (turn1 == true) {
target = turnSteps;
}
else {
target = lineSteps;
}
stepper1.move(target);
stepper1.setSpeed(stepperSpeed);
turn1 = !turn1;
}
if (steps2 == 0) {
int target = 0;
if (turn2 == true) {
target = turnSteps;
}
else {
target = ‐lineSteps;
}
stepper2.move(target);
stepper2.setSpeed(stepperSpeed);
turn2 = !turn2;
}
steps1 = stepper1.distanceToGo();
steps2 = stepper2.distanceToGo();
stepper1.runSpeedToPosition();
stepper2.runSpeedToPosition();
}