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 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.

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 Type Unipolar stepper motor
Connection Type 5 Wire Connection (to the motor controller)
Voltage 5-12 Volts DC
Frequency 100 Hz
Step mode Half-step mode recommended (8 step control signal sequence)
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 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 controller A (Blue), B (Pink), C (Yellow), D (Orange), E (Red, Mid-Point)
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 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();
}



Tagged with: , , ,

67 Comments on “28BYJ-48 Stepper Motor with ULN2003 driver and Arduino Uno

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

    How can I fix ?

    • 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.

          • 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….

  2. 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

  3. 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

    • 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.

    • Hi Tom,

      Just came across your thread while exploring the Accel Library. If it is just one motor turning at a time you can use the runToNewPosition function.

      Cheers,
      Kev

  4. 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.

    • 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!

  5. 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.

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

  7. 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!

  8. Hi Stan,

    you did a nice job figuring out parameters and using the AccelStepper library
    Could you tell me, why the initialising sequence for pins is IN1-3-2-4.? My first guess woud be IN 1-2-3-4

    Bye
    Chris

    • Hi Chris, it is just the arrangement of the wires in the connector out of the ULN2003 and the connector of this particular motor. If the two coils are A and B, then you are supposed to initialize them like this: A1, A2, B1, B2 for AccelStepper. In the case of the 28BYJ-48 motor coil “A” would be IN1 and IN3, corresponding to the blue and yellow wires and coil “B” will be IN2 and IN4.

  9. Thanks for your great article. I love these motors – have been using them since my PICAXE days, but swapping to ARDUINO and using the Acccelstepper library has simplified their use even more – especially loved the acceleration feature. My use is purely hobby level, so not too fussed at occasional slippage problem, but they have good torque, a fair usable speed and with their equally cheap ULN 2003, I have over 20 sets just lying around for quick projects.
    Cheers,
    Derrick

  10. Stan – many thanks for a fantastic tutorial!
    You explained everything and provided all the references. Great Job!
    You set me on the right track to using my 28BYJ-48 with an Arduino and the AcceStepper library. I will be referencing your post in my own blog.

    Neil

  11. Hi Stan,
    I wanted to use 4 of the 28BYJ-4 (with the ULN2003 Controller) to drive my robot platform. ( http://www.amazon.com/Emgreat-4-wheel-Chassis-Encoder-Arduino/dp/B00GSIRHEU/ref=pd_sim_t_2?ie=UTF8&refRID=0EHCVAMYZMW25NK7FMKR ).
    Would it be as simple as multiplying your code X 2 or do you see it as more complex. Before I get too deep in this to find out later it’s hardly doable I decided to ask for your opinion first.
    I am thinking of sending a pulse to both left wheels then to the right wheels. Programming turns may be a bit difficult.
    What do you think based on your experience.
    thanks in advance.
    Gilles

    • Hi Gilles, I have not tried running four steppers at the same time, but I see no reason why the last example can’t be scaled to accommodate that. Obviously, the code moves the stepper one at a time, so it is not ideal if you need very high precision and coordination. You likely will not use $4 dollar motors, if that was the case anyway. Good luck and post back your results, if you don’t mind…

  12. Hello, i want to ask. Can this code be used to avoid obstacle? Or I have to modify the code? I’m sorry, I’m an amateur about robotic. Hehehe. Do you mind to reply to my email? I want to ask some questions if you don’t mind. Thank you so much 🙂

  13. i have a question. that driver is only for the 5 wires stepper motor

    what if I use 4 wires stepper motor for that driver.. how to I connect? or Does it impossible?

    Thank yoiu

  14. Hi,
    Thank you for this great tutorial! I have the question, if you have an overview for all commands of the library and what they do.
    Thank you!

  15. Finally a realy comprehesice tutorial about stepper motors. Got it through Github. Too bad you are not somewhere higher direct in Google with it. Looking for such tutorila fow a while now, but always through Google. Thanks for sharing, Matija

  16. I have what looks like exactly the same motor and board but my “+” is not connected to anything else on the board. I have to connect 5v to both the 2 (normally) jumpered pins before anything happens. Do you think this is just a bad copy I have, maybe?

  17. Why do you say that the gear ratio is *approximately* 64:1? I counted the teeth on the gears, and it’s exactly 64:1

    gear on motor shaft has 9 teeth.
    there are three reduction gears, with 32/11 teeth, 22/9 teeth, 27/8 teeth. The gear connected to the external shaft has 24 teeth. The external shaft has eight teeth. This gives a reduction ratio of 1/9 * 32/11 * 22/9 * 27/8 * 24 / 8 * 8, which is exactly equal to 64.
    Where does that weird 63.68395 number come from?

  18. Hi, great article. Can these ULN2003 Driver Boards drive a non-steppe motor ? I have few mini motors and I was wondering if they’d be any good for them ? I just built a larger robot using some L298N motor shields and they are pretty unreliable, I was wondering if I could swap them out and use these little ULN2003 Driver Boards

  19. i installed your first code along with the Accel Stepper.h but get a compile error as the following 3 lines.
    as: unrecognized option ‘-mmcu=avr5’
    exit status 1
    Error compiling.

    What am I doing wrong?
    thank-you

  20. I would like to know what type of small errors sum up bringing the robot to fall off the table: are they related to the rotations (not exactly 90 degrees) or to the distances in straight line (I mean between one rotation and another)?
    Thanks for the help.

    • Hi Andrea, many small errors add up: differences in the friction of the two wheels, small misalignment in the motors, skipped steps. In order to get better accuracy you will need what is called a closed loop system, where you have an independent way to measure the distance traveled with, for example, a wheel encoder.

  21. Sorry,I am newbie, I would like to add for 2 sensor using IR sensor for following line, could you give me solution. Many Thank

  22. Hello Stan,
    Great article. I have a question though. You mentioned that the source Voltage can be 5-12 V.
    I don’t think you can use a 12V power supply on a 5V motor without risking to overheat or even damaging the coils unless you limit the current to about 165mA per coil and I believe the driver does not have this feature. How do you limit the current in your application to avoid damages to the motor?
    Thanks,
    Javier

  23. Arduino: 1.8.0 (Windows 8.1), Board: “Arduino/Genuino Uno”

    G:\abc123\abc123.ino:6:26: fatal error: AccelStepper.h: No such file or directory

    #include

    ^

    compilation terminated.

    exit status 1
    Error compiling for board Arduino/Genuino Uno.

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.
    i face this error may you help me please

  24. It’s awesome! How did you accelerated 28BYJ-48 to 25+ RPM? What software “trickery” do you use to make it that fast?

    I’m making CNC plotter for my graduation project and I need to speed it up to debug without pain.

    • I still don’t understand how you did it, Stan?
      My motor has 4 RPM, that’s so awful truth for me! Why? Did I brought fake 28BYJ-48-5V motors (all four of them are tested)?
      I’m using large acceleration (10000) via library to easily measure time that delayed since start of rotation, and in other way: to measure exact number of rotations made in 1 minute. Summarizing, AccelStepper’s speed of 1500 steps/sec and larger doesn’t change real speed of shaft, smaller library’s speed can make shaft’s speed low.
      I have 4 real rotations per minute, but 14 seconds per one rotation – so as further I move, it goes slower?

      Can you please help me?

  25. What would be the best way to use run(), runSpeed(), or runSpeedToPosition() from outside of the loop()?

    I’m trying to use it with Blynk.

  26. hi! greetings from Indonesia,
    thankyou so much for this article, can you tell me how i write arduino code , if i need to make some input then the motor can rotate for specified degree?
    for example : ” case A : if input = 1 then rotate 720 degree (2x rotation)”
    cas B : if input = 0.5 then rotate 360 degree (1x rotation)”

    i really hope you get me, thank you once again 🙂

  27. hi
    thanks for sharing.
    i encounter a problem : i don’t know how to invert the direction of the movement.
    depending on which button i will press first then the stepper will go in that direction no matter which of the 2 buttons i press (back or forward)
    is there a specific proper way to invert the direction ? should i set speed to negative or something ?

    my fragment of code :

    case btnRIGHT:{
    lcd.print(“GO! “);
    stepper1.stop();
    stepper1.moveTo(20000);
    stepper1.run();
    break;
    }
    case btnLEFT:{
    lcd.print(“BACK “);
    stepper1.stop();
    stepper1.moveTo(-20000);
    stepper1.run();
    break;
    }

  28. Hi!
    Thank you for the great information you’ve posted.
    I’m designing a gripper for a robotic arm using a stepper motor. I’d like to modify your first code such that
    1) The stepper motor rotates to a certain angle( x number of steps) to open up the gripper
    2) Then the motor rotates in the opposite direction (y number of steps) to be able to hold the “predefined size” object
    3) And at this point I don’t want it to open again, so it could hold on to the object.
    I was able to modify your code to obtain the first two but the problem is I don’t know how to “STOP” the loop when the motor reaches the “y number of steps”.
    I moved the commands from the “loop” function to “setup” (and made the “loop” empty) in order to force it run only once but the motor doesn’t even move when I do this.
    Would you please let me know your suggestions? I don’t know much about programming and Arduino.

    Thank you!

  29. I have 3D Printers that work with the NEMA17 Steppers. My question is, can a person use these smaller steppers in the same way at relatively the same speeds? I realize these are lighter servos, but I am hoping for higher response and faster movement than your example. Thanks for the great tutorial.

  30. There’s a bit of variation in the gear ratios in these steppers, despite the fact that they all share the same exact model number. Some have an exact 64:1 ratio, some have an approximate 64:1 ratio, and some have an approximate 16:1 ratio.

  31. Thanks. Worked great first time!
    Modified to run two motors and two ULNs.
    Noted that as I increased supply voltage, current increases also. My two motors draw 500mA with no load.

  32. Arduino’s I can handle as I have coding/playing with them for q few years. The real problem for me is finding the hardware!! Where the heck do you get yours from? p.s. Great post BTW.

  33. Thanks for the intro. One thing though; I noticed you mentioned having heat issues with some other methods of running this motor/driver. I am actually experiencing this with your solution described here; After running the motor for a few minutes it gets to hot to touch, which I don’t really understand. What is to expect?

    • Expect ALL motors to get hot, large or small. Most stepper motor drivers have heat sinks that can burn you if touched. These motors are tiny but excessive heat is standard. Use thermal shielding tape perhaps?

  34. Thank you very much for this comprehensive and detailed explanation and guidance.
    Also for someone whose native language is not English, like me, this description is easy to understand.

  35. Hello sir do you have a code for clockwise rotation then stop and move to counterclockwise direction then stop. Because i will command the stepper motor with the result of the height using ultrasonic sensor.

  36. Hi sir I am trying to interface the motor with the help of l293d to interfaced 8051 microcontroller, now I used Texas-msp430 module can I connect the same L293d in this project to run motor please reply me

Leave a Reply

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

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.