< All Topics
Print

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

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.

Click to Enlarge

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.

Click to Enlarge

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

Copy and Paste the code below into the Arduino IDE and upload to the ESP32.
Arduino
//  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. 

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

Click to Enlarge
Click to Enlarge

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

CREDITS & LINKS

Thanks to:

Table of Contents