Controlling a stepper motor via WiFi with an ESP8266 and Android

The idea of this work is to control the rotation direction, speed and position of a NEMA23 stepper motor remotely via WiFi. The application running in Android should send the parameters to the ESP8266 and this microcontroller would send the signals to the driver of the motor.

You can download the code in C for the ESP8266 here and the code in App Inventor for the application in Android to communicate with the ESP8266 here.

Stepper motor

Stepper motors are widely used in 3D printers so there is a large variety of models and manufacturers. The acronym NEMA stands for National Electrical Manufacturers Association and the nomenclature after the name refers to the size of the motor. It should be standarized so 23 would correspond to 2.3 x 2.3 inches, but most manufacturers do not follow these exact dimensions and, though they are close to the correct size, there may be differences. The selected motor for this application is a JK57HS56-2804 with the following data:

Step Angle: 1.8 degrees
Motor Length: 56 mm (close to 2.3 inches)
Current per phase: 2.8 A
Resistance per phase: 0.9 ohm
Inductance per phase: 2.5 mH
Holding Torque: 1.26 N·m
Number of Leads: 4
Detent Torque: 350 g.cm
Rotor Inertia: 280 g·cm^2
Mass: 0.68 Kg

The interesting parameters in most applications are the current per phase which will condition the selection of the driver and the holding torque that would be determined by the application of the motor. In this case, we need a fairly high torque to move the rig described in this paper which consists on a horizontal rod and a vertical shaft connected directly to the stepper motor.

Driver DRV8825

The driver to control the rotation of a bipolar motor with four leads is a DRV8825 with a maximum current rating of 2.5 A as long as the circuit is refrigerated. Otherwise, the temperature protection will prevent the integrated circuit (IC) from working continuously. I used a forced ventilation with a small fan connected to 12 VDC and the current through the coils reached 2 A. All information about this driver can be found in the Pololu web page, but the most important is the connection pinout:

It is important to notice that both NOT_RESET and NOT_SLEEP are connected to high (or 5 V). I didn’t connect the 100 \muF capacitor to the power supply that was set to 25-30 V. The inputs M0, M1 and M2 are connected to low or high depending on the selected microstepping. There is a nice table in the Pololu web page and in the datasheet of the IC, however, I have to say the microstepping doesn’t work as expected: for instance, when you set a 1/16 microstep, the motor will turn for correctly for 8 microsteps and then it will jolt to the final position without continuing with the 8 remaining microsteps. This behavior seems to be common to the DRV8825 as it is also commented by Moritz Walker in his web page.

ESP8266 – NODEMCU

Finally, the STEP and DIR pins are connected to the GPIO4 (general purpose input-output 4) and GPIO5, respectively, of the ESP8266 microcontroller. The next figure shows the layout of the NODEMCU v1.0 which is a development board for the ESP8266 microcontroller. GPIO4 and GPIO5 are pins D2 and D1 respectively. When programming the NODEMCU, these pins should be defined as outputs. The DIR pin would be high to turn the motor clockwise and the STEP pin would receive a square wave with a predefined frequency to control the rotation speed. The higher the frequency, the higher the angular speed, so this square wave will be also a parameter that has to be defined.

Resultado de imagen de nodemcu ESP8266 pinout

The NODEMCU is natively programmed in LUA, however, I am more familiar with C and the Arduino IDE, so there is a possibility of using these tools with a plugin for Arduino, you just need to follow the instructions detailed here.

Now, the ESP8266 will work as a soft access point so it will create its own Wi-Fi network and we will connect our mobile app to this network and pass data to the MCU as shown in the next figure taken from this excellent page.

ESP8266 operating in the Soft Access Point mode

To do so, it is necessary to include this piece of code which also includes the definition of the pins as outputs and the additional variables that define the movement of the stepper motor.

 

#include "ESP8266WiFi.h"        //I can connect to a Wifi
#include "ESP8266WebServer.h"   //I can be a server 'cos I have the class ESP8266WebServer available
#include "WiFiClient.h"

const char *ssid = "ESPap";  //Credentials to register network defined by the SSID (Service Set IDentifier)
const char *password = "yourpassword"; //and the second one a password if you wish to use it.
ESP8266WebServer server(80);    //Class ESP8266WebServer and default port for HTTP

const int dirPin = 5; //This pin corresponds to GPIO5 (D1) (Yellow wire) https://nodemcu.readthedocs.io/en/latest/en/modules/gpio/
const int stepPin = 4; //This pin corresponds to GPIO4 (D2) (Orange wire)
int steps = 0; //This variable is related to the number of turns. If microstepping is disabled, 200 corresponds to a complete turn.
int stepDelay = 0; //This variable is the pulse duration in milliseconds and it is related to the rotation speed. Without microstepping, 1.8º are stepDelay ms.
bool dir = HIGH; //Rotation direction. HIGH is clockwise.

// Configure NODEMCU as Access Point
Serial.print("Configuring access point...");
WiFi.softAP(ssid); //Password is not necessary
IPAddress myIP = WiFi.softAPIP(); //Get the IP assigned to itself.
Serial.print("AP IP address: "); //This is written in the PC console.
Serial.println(myIP);

void setup() {
pinMode(dirPin, OUTPUT); // Pins are outputs
pinMode(stepPin, OUTPUT);

delay(1000);
Serial.begin(115200); //I can debbug through the serial port

The address will be written in the PC console, however, it has always been 192.168.4.1 whenever I have used it.

Now, we have to define the handling functions that will be accessed in the path of the server. For instance, the root path direct to a function called handleRootPath and the /init path to another function called handleInit.

server.on("/", handleRootPath); 
server.on("/Init", handleInit); 

server.begin(); //Let's call the begin method on the server object to start the server.
Serial.println("HTTP server started");

And this code finishes the void setup() function.

Finally, the server is started. The loop function will only have a recursive function called:

void loop() {
 server.handleClient(); 
}

that will handle the incoming of HTTP requests.

The function in the root path will inform that everything is ok when accessed by returning the code 200 and a plain text.

void handleRootPath() {
 server.send(200, "text/plain", "Ready, player one.");
}

The other function will parse the data sent by the app in the mobile phone and will send the outcome to pins DIR and STEP defined previously in the code and returns a message to the app showing that everything has been understood.

void handleInit() {// Handler. 192.168.XXX.XXX/Init?Dir=HIGH&Delay=5&Steps=200 (One turn clockwise in one second)
steps = 0; //Motor stopped if the arguments are wrong.
stepDelay = 0;
String message = "Initialization with: ";

if (server.hasArg("Dir")) {
 digitalWrite(dirPin, server.arg("Dir") == "HIGH"); //This is a cunning way of checking the value of the argument Dir.
 message += "Direction: ";
 message += server.arg("Dir");
 }
 if (server.hasArg("Delay")) {
 stepDelay = (server.arg("Delay")).toInt(); //Converts the string to integer.
 message += " Delay: ";
 message += server.arg("Delay");
 }
 if (server.hasArg("Steps")) {
 steps = (server.arg("Steps")).toInt();
 message += " Steps: ";
 message += server.arg("Steps");
 }
 server.send(200, "text/plain", message); //It's better to return something so the browser don't get frustrated+ 
 
 for (int i = 0; i < steps; i++) { //Create a square wave signal with the incoming data.
 digitalWrite(stepPin, HIGH);
 delay(stepDelay);
 digitalWrite(stepPin, LOW);
 delay(stepDelay);
 }
 
}

The data is sent as arguments in the URL 192.168.XXX.XXX/Init?Dir=HIGH&Delay=5&Steps=200 (One turn clockwise in one second).

Now, the objective of the app in the mobile phone is simply create the string with the URL based on the preferences of the user. This is easily done with MIT AppInventor.

AppInventor

The first step is to define the layout of the application and the elements in the screen. We need a button to connect to the access point defined by the NODEMCU, and another button to send the data introduced in two textboxes. The decision on what direction of rotation is done by ticking the desired choice in two check boxes.