ESP8266 NodeMCU with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)

In this guide, you’ll learn how to control a stepper motor with the ESP8266 NodeMCU board. We’ll use the 28BYJ-48 unipolar stepper motor with the ULN2003 motor driver. We’ll program the ESP8266 board using Arduino IDE.

ESP8266 NodeMCU with Stepper Motor 28BYJ-48 and ULN2003 Motor Driver Arduino IDE

We have a similar tutorial for the ESP32 board: ESP32 with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)

Parts Required

To follow this tutorial, you need the following parts:

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Introducing Stepper Motors

A stepper motor is a brushless DC electric motor that divides a full rotation into a number of steps. It moves one step at a time, and each step is the same size. This allows us to rotate the motor by a precise angle to a precise position. The stepper motor can rotate clockwise or counterclockwise.

The following picture shows two 28BYJ-48 stepper motors.

28BYJ-48 Stepper Motors

Stepper motors are made of internal coils that make the motor shaft move in steps in one direction or the other when current is applied to the coils in a specific way.

There are two types of stepper motors: unipolar and bipolar stepper motors.

In this article, we won’t detail how the stepper motors are made and how they work internally. To learn in more detail how they work and the differences between each type of stepper motor, we recommend reading this article by the DroneBotWorkshop blog.

28BYJ-48 Stepper Motor

There are several stepper motors with different specifications. This tutorial will cover the widely used 28BYJ-48 unipolar stepper motor with the ULN2003 motor driver.

28BYJ-48 connected to ULN2003 Motor Driver 01 module

28BYJ-48 Stepper Motor Features

Features of the stepper motor (for more details, consult the datasheet):

  • Rated voltage: 5V DC
  • Number of phases: 4
  • Speed variation ratio: 1/64
  • Stride angle: 5.625º/64
  • Frequency: 100Hz

The 28BYJ-48 stepper motor has a total of four coils. One end of the coils is connected to 5V, which corresponds to the motor’s red wire. The other end of the coils corresponds to the wires with blue, pink, yellow, and orange color. Energizing the coils in a logical sequence makes the motor move one step in one direction or the other.

28BYJ-48 stepper motor coils

The 28BYJ-48 Stepper Motor has a stride angle of 5.625°/64 in half-step mode. This means that the motor has a step angle of 5.625º—so it needs 360º/5.625º = 64 steps in half-step mode. In full-step mode: 64/2 = 32 steps to complete one rotation.

However, the output shaft is driven via a 64:1 gear ratio. This means that the shaft (visible outside the motor) will complete rotation if the motor inside rotates 64 times. This means that the motor will have to move 32×64 = 2048 steps for the shaft to complete one full rotation. This means that you’ll have a precision of 360º/2048 steps = 0.18º/step.

So, in summary:

  • Total steps per revolution = 2048 steps
  • Step angle = 0.18º/step

If you’re using a different stepper motor, please consult the datasheet.

ULN2003 Motor Driver

To interface the stepper motor with the ESP8266 NodeMCU board, we’ll use the ULN2003 motor driver, as shown in the figure below. The 28BYJ-48 stepper motor is many times sold together with the ULN2003 motor driver.

ULN2003 Motor Driver 01 module board

The module comes with a connector that makes it easy and simple to connect the motor to the module. It has four input pins to control the coils that make the stepper motor move. The four LEDs provide a visual interface of the coils’ state.

ULN2003 Motor Driver Labels

There are pins to connect VCC and GND, and a jumper cap that acts as an ON/OFF switch to power the stepper motor—if you remove the jumper, there is no power reaching the motor. You can use those pins to wire a physical switch.

ULN2003 Motor Driver Pinout

The following table shows the module pinout:

IN1Control the motor: connect to a microcontroller digital pin
IN2Control the motor: connect to a microcontroller digital pin
IN3Control the motor: connect to a microcontroller digital pin
IN4Control the motor: connect to a microcontroller digital pin
VCCPowers the motor
GNDCommon GND
Motor connectorConnect the motor connector

Wire Stepper Motor to the ESP8266 Board

In this section, we’ll connect the stepper motor to the ESP8266 via the ULN2003 motor driver.

We’ll connect IN1, IN2, IN3, and IN4 to GPIOs 5, 4, 14, and 12. You can use any other suitable digital pins (check our ESP8266 pinout reference guide).

You can follow the next schematic diagram.

ESP8266 with Stepper Motor 28BYJ-48 and ULN2003A Schematic Diagram Wiring

Note: You should power the motor driver using an external 5V power supply.

Motor DriverESP8266
IN1GPIO 5
IN2GPIO 4
IN3GPIO 14
IN4GPIO 12

Installing the AccelStepper Library

There are different ways to control stepper motors with a microcontroller. To control the stepper motor with the ESP8266, we’ll use the AccelStepper library. This library allows you to easily move the motor a defined number of steps, set its speed, acceleration, and much more.

The library has great documentation explaining how to use its methods. You can check it here.

Follow the next steps to install the library in your Arduino IDE.

  1. Go to Sketch > Include Library > Manage Libraries…
  2. Search for “accelstepper”.
  3. Install the AccelStepper library by Mike McCauley. We’re using version 1.61.0.
Install AccelStepper Library Arduino IDE

Control Stepper Motor with the ESP8266 – Code

Copy the following code to your Arduino IDE. In this example, the motor will make one clockwise rotation and a counterclockwise rotation over and over again.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-stepper-motor-28byj-48-uln2003/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
  
  Based on Stepper Motor Control - one revolution by Tom Igoe
*/

#include <AccelStepper.h>

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution

// ULN2003 Motor Driver Pins
#define IN1 5
#define IN2 4
#define IN3 14
#define IN4 12

// initialize the stepper library
AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);

void setup() {
  // initialize the serial port
  Serial.begin(115200);
  
  // set the speed and acceleration
  stepper.setMaxSpeed(500);
  stepper.setAcceleration(100);
  // set target position
  stepper.moveTo(stepsPerRevolution);
}

void loop() {
  // check current stepper motor position to invert direction
  if (stepper.distanceToGo() == 0){
    stepper.moveTo(-stepper.currentPosition());
    Serial.println("Changing direction");
  }
  // move the stepper motor (one step at a time)
  stepper.run();
}

View raw code

We adapted this sketch from the examples provided by the library (File > Examples > AccelStepper > Bounce).

How the Code Works

First, include the AccelStepper.h library.

#include <AccelStepper.h>

Define the steps per revolution of your stepper motor—in our case, it’s 2048:

const int stepsPerRevolution = 2048;  // change this to fit the number of steps per revolution

Define the motor input pins. In this example, we’re connecting to GPIOs 5, 4, 14, and 12, but you can use any other suitable GPIOs.

#define IN1 5
#define IN2 4
#define IN3 14
#define IN4 12

Initialize an instance of the AccelStepper library called stepper. Pass as arguments: AccelStepper::HALF4WIRE to indicate we’re controlling the stepper motor with four wires, and the input pins. In the case of the 28BYJ-48 stepper motor, the order of the pins is IN1, IN3, IN2, IN4—it might be different for your motor.

AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);

In the setup(), initialize the Serial Monitor at a baud rate of 115200.

Serial.begin(115200);

Set the stepper motor maximum speed using the setMaxSpeed() method. Pass as argument the speed in steps per second.

stepper.setMaxSpeed(500);

As mentioned in the documentation, the setMaxSpeed() method sets the maximum permitted speed. The run() function will accelerate up to the speed set by this function.

Set the acceleration using the setAcceleration() method. Pass as argument the acceleration in steps per second per second.

stepper.setAcceleration(100);

Then, use the moveTo() method to set a target position. Then, the run() function will try to move the motor (at most one step per call) from the current position to the target position set by the most recent call to this function. We’re setting the target position to 2048 (which is a complete turn in case of this motor).

stepper.moveTo(stepsPerRevolution);

In the loop(), we’ll rotate the stepper motor clockwise and counterclockwise.

First, we check if the motor has already achieved its target position. To do that, we can use the distanceToGo() function that returns the steps from the current position to the target position.

When the motor reaches its target position, it means that the distanceToGo() function will return 0 and the following if statement will be true.

if (stepper.distanceToGo() == 0){

When the motor reaches its target position, we set a new target position—which is the same as the current position but in the opposite direction.

stepper.moveTo(-stepper.currentPosition());

Finally, call stepper.run() to move the motor one step at a time in the loop().

stepper.run();

Here’s an explanation about the run() method provided by the library documentation: “The run() function polls the motor and step it if a step is due, implementing accelerations and decelerations to achieve the target position. You must call this as frequently as possible, but at least once per minimum step time interval, preferably in your main loop. Note that each call to run() will make at most one step, and then only when a step is due, based on the current speed and the time since the last step”.

Demonstration

Upload the code to your board. After uploading, the motor will make one clockwise rotation and a counterclockwise rotation over and over again. It starts the rotation at a lower speed until reaching the desired speed before reaching the target position.

You can watch a quick video demonstration:


Wrapping Up

This tutorial was a getting started guide for stepper motors with the ESP8266. Stepper motors move one step at a time and allow you to position the motor shaft at a specific angle.

In a future tutorial, we’ll show you how to create a web server to control the stepper motor remotely with the ESP8266. So, stay tuned.

We hope you find this tutorial useful.

Learn more about the ESP8266 with our resources:

Thanks for reading.



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Enjoyed this project? Stay updated by subscribing our newsletter!

9 thoughts on “ESP8266 NodeMCU with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)”

  1. Superb work… Like always. I have only one question. Is this sketch somehow limited to port 80? If I tryed with other port then 80 the program doesn’t work… Thanks for all the great work =)

    Reply
  2. Thanks for another great tutorial. Arduino has a blocking stepper library that I think gets installed by default. However, this is not a good one for the ESP8266 due to the fact that the ESP has a watchdog timer running by default and doesn’t like blocking code. So if you move just a little bit, then it will work, but if you move a lot, the WDT resets the board. A non-blocking library like your accelStepper is the way to go for sure.

    Reply
  3. You say that the code gives 2048 steps / rev, but at half-step it would give 4096 steps / rev. THe code sets up the motor as:
    AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4);
    which, if I understand correctly, defines a half-step sequence. Which is correct?

    Reply
  4. I am trying to put together a small project where in a stepper motor is turned 360 one revolution hourly at the top of the hour. Do you have any tutorials that give the basics on that ?Thanks

    Reply
  5. Hi
    I downloaded the AccelStepper library.
    The only weird thing is that it’s not by Mike McCauley, it’s by Patrick Wasp. The documentation is the same as far as I can see. The programs also look the same. I just hope that I have the right library.

    Reply
  6. Hello!

    I have collected all of the required parts to follow this tutorial. But I have brought a 12V 28BYJ-48 stepper motor mistakenly. Which changes should I make to follow this tutorial?

    In my opinion, replacing the 5V DC power supply with a 12 DC power supply should be the only change I need to make. Though I can not be sure, as I have a very little experience with this.

    Thank you.

    Reply
  7. Hi Sara/Rui, I just started fooling with one of these; initially using a nano to make sure all was well. Since my end desire is to use it remotely via wifi, your (another great) tutorial got me going in that direction. Oddly I wanted to see if I could make a half revolution by changing the statement stepper.moveTo(stepsPerRevolution); to stepper.moveTo(stepsPerRevolution/2); .That seemed to work but when the ESP was reset the motor moved 1/4 a revolution, then 1/2 revolution after that. Another interesting observation is that when it starts, it starts ccw, instead of cw. Most examples I see seem to indicate that the motor usually starts cw then when a negative number is applied to stepper.moveto it then goes ccw. Any thoughts on that?

    Reply

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.