ESP32 Stepper Motor Controller

PROJECT OVERVIEW:
To make an ESP32 based controller for moving a NEMA23 C-Beam XL Actuator. Limit switches on the actuator will reverse the direction of the stepper when contacted. Additional micro push buttons will do the following: 1) Stop; 2) Speed; 3) Reverse. Power will come from a separate RD-65A power supply with an on-off switch to be mounted in separate the case. All electronics will be compact and fit within a 300x150mm case. Through-wall connectors will be used to pass cabling through the case.
Usual Warnings and Disclaimers
The author of this document is not liable or responsible for any accidents, injuries, equipment damage, property damage, loss of money or loss of time resulting from improper use of electrical or mechanical or software products.
Assembling electrical and mechanical machine components like power supplies, motors, drivers or other electrical and mechanical components involves dealing with high voltage AC (alternating current) or DC (direct current) and other hazardous items which can be extremely dangerous and needs high attention to detail, experience, knowledge of software, electricity, electro-mechanics and mechanics.
BEFORE MAKING ANY CONNECTIONS OR DISCONNECTIONS POWER MUST BE REMOVED FROM THE DEVICE AND THE CONTROLLER. FAILURE TO DO SO WILL VOID ANY AND ALL WARRANTIES.
All Errors and Omissions Excepted - feedback is, of course, welcome!
BILL OF MATERIALS
ENCLOSURE
ELECTRICAL BUILD
ESP32:
We chose to use an ESP32 as the controller. It is easy to program via the Arduino IDE and there are a comprehensive set of libraries to allow for many add-on. Another reason we chose the ESP32 is so that later we can add a webserver to the project allowing for control of the actuator over the Internet. We had a bunch of ESP32-DevKitCs in the lab along with our new, internally designed and developed breakout boards incorporating an inbuilt voltage regulator – so the board selection was easy.
Almost any version of the ESP32 will do – the only real difference will potentially be the pinouts. You can also use standard breadboard instead of our custom designed and built breakout board.
DRV8825
Because the actuator has a NEMA23 Stepper Motor we needed a driver that was able to handle the current. We could have used something like the DM556 Driver (a great driver for higher current applications), but since we wanted the whole project to be compact and the NEMA23 we are using is not high current we went with a DRV8825 Stepper Driver. It can handle up to 2.2A per phase and can run the NEMA23 at the speeds we need. For faster speeds and higher torque the DM556 would be the way to go.
LCD MODULE
We also had some 1.44″ 128×128 Colour TFT LCD Displays in the lab, so we though it would be good to add a nice little display to show speed, direction, location and button presses.
OTHER
Everything else is pretty straight forward, 3 mini breadboards, micro push buttons, and jumper wires. See the BOM for a fuller list.
WIRING LAYOUT
See the fritzing diagram below for a wiring layout of the major components.
ACTUATOR
For the complete build guide for the C-Beam Actuator see the link below:
https://makerhardware.net/wiki/doku.php?id=manuals:c-beam_actuator_kit
CODE
The Sketch for the ESP32 uses a few libraries to make it easy to interface with the display, buttons and motor.
- ezButton – makes the reading of buttons easy as you can set the debouce and etc.
- TFT_eSPI – ESP32s need a special library to write to TFT displays.
- AccelStepper – For motor control.
- logo.h – the Maker Store logo in XBM format (so the TFT can display without the ESP32 having to do any real thinking).
MAIN SKETCH
// MakerStore.com.au
#include <ezButton.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include "logo.h"
#include <AccelStepper.h>
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library for the TFT Screen
ezButton limitSwitch_1(18); // create ezButton object that attach to pin 18
ezButton limitSwitch_2(21); // create ezButton object that attach to pin 21
ezButton redButton(13); // create ezButton object that attach to pin 13
ezButton blueButton(32); // create ezButton object that attach to pin 32
ezButton whiteButton(33); // create ezButton object that attach to pin 33
const int DIR = 2; // Stepper DIR Pin 2
const int STEP = 0; // Stepper STEP Pin 0
AccelStepper stepper(1, STEP, DIR); // Set the Stepper Motor
// Define program variables
int maxSpeed = 1000;
int speed = 500;
int direction = 1;
int action = 0;
void setup() {
limitSwitch_1.setDebounceTime(50); // set debounce time to 50 milliseconds
limitSwitch_2.setDebounceTime(50); // set debounce time to 50 milliseconds
redButton.setDebounceTime(50); // set debounce time to 50 milliseconds
blueButton.setDebounceTime(50); // set debounce time to 50 milliseconds
whiteButton.setDebounceTime(50); // set debounce time to 50 milliseconds
// Initalise the TFT Screen
tft.init();
tft.fillScreen(TFT_BLACK);
tft.drawXBitmap(0, 0, logo, 128, 20, TFT_WHITE);
tft.setCursor(0, 30, 2);
tft.print("SPEED = ");
tft.println(speed);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
stepper.setMaxSpeed(maxSpeed); // set the maximum speed
stepper.setAcceleration(10); // set acceleration
stepper.setSpeed(speed); // set initial speed
stepper.setCurrentPosition(0); // set position to 0
}
void loop() {
// MUST call all the button loop() functions first
limitSwitch_1.loop();
limitSwitch_2.loop();
redButton.loop();
blueButton.loop();
whiteButton.loop();
stepper.setSpeed(speed); // set Stepper speed
// Write the Stepper Position to the screen
tft.setCursor(0, 50, 2);
tft.print("POSITION = ");
tft.setCursor(70, 50, 2);
tft.print(" ");
tft.setCursor(70, 50, 2);
tft.println(stepper.currentPosition());
// All the button actions
// when a button is pressed it calls the case condition below based on the action number
// action = 0 change speed
// action = 1 change direction
// action = 2 stop
// action = 3 nothing (reset action var)
if (limitSwitch_1.isReleased()) {
stepper.setCurrentPosition(0);
action = 1;
}
if (limitSwitch_2.isReleased()) {
action = 1;
}
if (blueButton.isPressed()) {
action = 0;
tft.setCursor(0, 105, 2);
tft.println("BLUE BUTTON ");
}
if (whiteButton.isPressed()) {
action = 1;
tft.setCursor(0, 105, 2);
tft.println("WHITE BUTTON");
}
if (redButton.isPressed()) {
action = 2;
tft.setCursor(0, 105, 2);
tft.println("RED BUTTON ");
}
// Conditions called but the action variable sest by pressing buttons
switch (action) {
case 0: // CHANGE SPEED
if (speed >= 0) direction = 1 ;
else direction = -1;
speed = abs(speed);
if (speed != maxSpeed) {
speed += 100;
} else {
speed = 100;
}
speed *= direction;
tft.setCursor(0, 30, 2);
tft.println(" ");
tft.setCursor(0, 30, 2);
tft.print("SPEED = ");
tft.println(abs(speed));
action = 3;
break;
case 1: //CHANGE DIRECTION
speed *= -1;
tft.setCursor(0, 70, 2);
if (speed > 0) {
tft.println("=> RIGHT");
} else {
tft.println("<= LEFT ");
}
action = 3;
break;
case 2: // STOP
stepper.stop();
tft.setCursor(0, 30, 2);
tft.print("SPEED = ");
tft.println("0 ");
break;
}
// Run thhe Stpper as long as the action case is not 2
if (action != 2) {
stepper.runSpeed();
}
}
LOGO.H FILE
Copy the following into a text file and save as “logo.h” the the same folder as the main sketch.
#define logoWidth 128 // logo width
#define logoHeight 20 // logo height
// Image is stored in this array
PROGMEM const unsigned char logo[] = {
0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0x3F, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x0F, 0x0C, 0x06, 0x00, 0x03, 0x00,
0x00, 0x00, 0xF0, 0xC7, 0x01, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x07, 0x0E,
0x07, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xFF, 0x07, 0x0E, 0x07, 0x04, 0x03, 0x80, 0x00, 0x00, 0x30, 0xC0,
0x01, 0x02, 0x00, 0x18, 0xF0, 0xFF, 0x07, 0x1C, 0xC7, 0x1F, 0xC3, 0xF1,
0xC7, 0x0F, 0x18, 0xC0, 0xE7, 0x8F, 0x3D, 0x7F, 0xF8, 0xE3, 0x07, 0x9E,
0x87, 0x19, 0xE3, 0xB8, 0xC6, 0x0A, 0x38, 0xE0, 0xE5, 0x1E, 0x97, 0xF7,
0xFC, 0xC0, 0x2F, 0xBC, 0x07, 0x38, 0x33, 0x10, 0xCE, 0x00, 0xF0, 0x83,
0x61, 0x98, 0x01, 0xC3, 0xFF, 0x80, 0x3F, 0xFC, 0x07, 0x18, 0x7B, 0x38,
0xC6, 0x00, 0xF0, 0xC7, 0x60, 0x18, 0x03, 0xC3, 0xFF, 0xC0, 0x3F, 0xF6,
0xC6, 0x3F, 0x7F, 0xF8, 0xCF, 0x00, 0x80, 0x86, 0x61, 0x98, 0x81, 0xFF,
0xFF, 0xC0, 0x3F, 0xE6, 0xE6, 0x1F, 0x6F, 0xF8, 0xC3, 0x00, 0x00, 0x8C,
0x61, 0x18, 0x01, 0x7F, 0xF8, 0xC1, 0x07, 0x6E, 0xE6, 0x38, 0xC7, 0x18,
0xC0, 0x00, 0x00, 0x86, 0x60, 0x98, 0x03, 0x03, 0xF0, 0xE3, 0x07, 0x46,
0x66, 0x10, 0xC3, 0x10, 0xC0, 0x00, 0x00, 0x8E, 0x61, 0x98, 0x83, 0x03,
0xF0, 0xE1, 0x07, 0x04, 0xE6, 0x1F, 0x83, 0xF9, 0xC7, 0x00, 0xF8, 0xC7,
0xE7, 0x1F, 0x01, 0xFF, 0xF8, 0xC1, 0x07, 0x06, 0x86, 0x13, 0x83, 0xF1,
0xC3, 0x00, 0xF0, 0x07, 0xC7, 0x0F, 0x03, 0x7E, 0xF8, 0xC0, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x78, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
ENCLOSURE BUILD
The enclosure is a simple box made of 4 pieces of 2060 V-Slot extrusion, 4 IO Corner Brackets and 2 sheets of Perspex.
Slot Covers are used to seat the Perspex sheets into the slots. This makes a snug fit and stops rattling and etc.
If you have a laser cutter to hand then a quick cut will make all the cut-outs nice and neat! Otherwise the holes are drilled and Dremeled into the sheets to allow for the buttons, switch and through-wall connectors.
Just fit the switches, buttons and through-wall connectors and then layout all the electrical parts and make the connections as per the above fritzing diagram.
And that is it! A nice neat project to run a stepper back and forth with switches for limits, speed, change direction and etc.
If you want to see this in action, come on it to the Maker Store display room and have a play!
BONUS: POWER SUPPLY AND ENCLOSURE
In order to power the above you will need a power supply that can supply the logic (at 5v) as well as drive the steppers (12v with decent current). The Mean Well RD-65B is perfect for this project – dual, 5 and 12 volt, output and 65 watts!
Bill of Materials
Enclosure
- 2080 V-Slot – Black (2 x 200mm, 2 x100mm)
- Slot Cover – Red
- 4 x In-Out Corner Bracket – 80mm – Black
- 32 x T-Nuts
- 32 x M5 8mm Cap Head Bolts
- 2 x Sheets Acrylic 3mm thick
CREDITS & LINKS
Thanks to:
- Arduino, Espressif, AccelStepper, TFT_eSPI and etc.
- Most parts can be purchased via the Maker Store links in the BOM.