28BYJ-48 Stepper Motor with ULN2003 driver and Arduino Uno

By | March 1, 2014

First, lets see the little steppers in action! Our main character, StepperBot, is “instructed” to move in a square path on my coffee table, making 90 degree turns at the corners. Turning exactly at the right time and by the right angle is critical avoid falling off and crashing on the floor in an embarrassing pile of messy wires. http://youtu.be/831qjVX6YLA 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-defined 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 off the table, but it typically runs for 10-15 minutes, before that: good enough for me!

What is so special about steppers

A stepper motor can move in accurate, fixed angle increments known as steps. For practical purposes, a stepper motor is a bit like a servo: you can tell it to move to a pre-defined position and can count on getting fairly consistent results with multiple repetitions. Servos though, are usually limited to a 0-180 degree range, while a stepper motor can rotate continuously, similar to a regular DC motor. The advantage of steppers over DC motors is that you can achieve much higher precision and control over the movement. The downside of using steppers is that they are a bit more complex to control than servos and DC motors.

The 28BYJ-48 Stepper Motor Datasheet

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. stepper01 Due to the gear reduction ratio of *approximately* 64:1 it offers 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.

Motor TypeUnipolar stepper motor
Connection Type5 Wire Connection (to the motor controller)
Voltage5-12 Volts DC
Frequency100 Hz
Step modeHalf-step mode recommended (8 step control signal sequence)
Step angleHalf-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 ratioManufacturer specifies 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 confirm their findings. These means that in the recommended half-step mode we will have:64 steps per motor rotation x 63.684 gear ratio = 4076 steps per full revolution (approximately).
Wiring to the ULN2003 controllerA (Blue), B (Pink), C (Yellow), D (Orange), E (Red, Mid-Point)
Weight30g

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 specifies that the preferred method for driving this stepper is using the half-step method, where we first power coil 1 only, then coil 1 and 2 together, then coil 2 only and so on…With 4 coils, this means 8 different signals, like in the table below. 28BYJ-48-Stepper-Motor

Wiring the ULN2003 stepper motor driver to Arduino Uno

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. UNL2003 board On the side you have a motor on / off 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.

Hooking it up to the Arduino

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/off” jumper next to the “-” pin is on. If you power the Arduino from a different battery pack, connect the grounds together.

Arduino stepper code and the AccelStepper library

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 efficiently and getting two of them running at the same time for a differential drive robot is a bit more difficult. 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 efficiently (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 first!

#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);

}//--(end setup )---

void loop() {

  //Change direction when the stepper reaches the target position
  if (stepper1.distanceToGo() == 0) {
    stepper1.moveTo(-stepper1.currentPosition());
  }
  stepper1.run();
}

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

#define motorPin5  8     // IN1 on the ULN2003 driver 2
#define motorPin6  9     // IN2 on the ULN2003 driver 2
#define motorPin7  10    // IN3 on the ULN2003 driver 2
#define motorPin8  11    // IN4 on the ULN2003 driver 2

// 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();
}

22 thoughts on “28BYJ-48 Stepper Motor with ULN2003 driver and Arduino Uno

  1. Wagner

    Excellent post! I really see 42bots becoming a great source for the community!

    Reply
  2. nico

    I can’t download the library, it’s a zip file or something like this?

    Reply
  3. Ted

    ‘accel stepper does not name a type ‘ is the msg I get with the listed last two sketches .

    How can I fix ?

    Reply
    1. Stan Post author

      Hi Ted, I just noticed that the code formatting plug in bothced the flirst line of the sketch with the include statetement. Please try again with the code now.

      Reply
        1. Stan Post author

          Ted, could you double-check that you have the AccelStepper library installed correctly? That is all I can think of right now…

          Reply
          1. Ted

            Hi,

            I may not have it installed at all, I think I just copied the code posted, not sure how or where to go for the accel library installation.
            I’ll have to look back at what it was I actually did….

  4. Ryan

    Very cool thanks for posting this. I just recently received 2 off these stepper motors from amazon and was looking for more information on them. I am going to try and drive them with the AdaFruit motor shield instead of the little circuit boards that came with them.

    Thanks
    -=Ryan

    Reply
  5. Tom

    Hi Stan, the first example has been incredibly useful to me. But is there any way to turn it into blocking code? I need to turn the motor and the press of a button and it won’t work at the moment because it’s not blocking code.
    Cheers,
    Tom

    Reply
    1. Stan Post author

      Hi Tom, I am glad the article helped you. I am not sure exactly what your application is, but I understand you need to run the motors only when some condition is met (related to a button press). I would add some code to the loop that will set a variable, when you press (or depress) the button. Then you check the variable, and only execute the stepper code from the example, when your condition is met.

      Reply
  6. James

    Hi, I too have been working with these model stepper motors and arduino but after a couple of months of trying I have not been able to get good results. It seems to work best at runSpeed(1000) when spinning clockwise and is high torque and silent (the holy grail!) but they often skip or jitter when starting or changing direction so I’ve not found them useful for my robot application. I’ve tried tweaking speed and playing with acceleration settings but I wonder if you’ve had better results? I tried your code but had the same issues (they only run as intended 80% of the time). Any suggestions would be welcome. At present, I’m trying other motors but they are too noisy and have vibration problems. These guys would be perfect if I could get them to work reliably.

    Reply
    1. Stan

      Hi James, I have similar observations. I guess you can’t expect perfection from a $2 dollar stepper motor, shipping included…I find that if you increase the voltage to about 8-12 volts and play with the acceleration settings you can get acceptable results for hobby applications. Also, some units are better quality than others. If you open one up you will see the tiny plastic gears. Easy for them to get misaligned, if you put too much pressure on the shaft. I would definitely not recommend them for any applications, where accuracy and consistency are critical, but as a learning tool for a hobbyist, you can’t beat the price!

      Reply
  7. Mikey

    First, thank you. This got me started with my stepper motor.

    I wrote (modified your first example) a sketch to step +2048, -2048, etc. (about a 360 degree turn of the motor, back and forth). Why is it that the first turn only goes half way? After that first half turn it happily twists back and forth almost exactly 1 revolution. Why only half the first time? I tried this with 180 degress (step=1024) and got the same result, first turn was only 90 degrees.

    Reply
  8. Mihai

    Best stepper motor tutorial ever! I wanted to learn to use a stepper and I found out everything I needed right here. Thanks!

    Reply
  9. Pingback: 3d scanning trashbot for later comparison | ramin assadollahi

  10. Pingback: Project: Polargraph | BotClub

  11. Margi

    Hello,
    I was looking at the first code for the arduino and I was wondering if you can get the code to run only once rather than in an infinite loop. I tried just doing a for loop and it didn’t work. Thanks!

    Reply
  12. sam

    so my left motor wont budge, would that be my programing, wiring or just a bad motor?

    Reply
  13. Erick Garcia

    Great tutorial! Helped me use my stepper motor within minutes. thanks! :D

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *