Help controlling multiple nema23 stepper motors with esp32 and motor drivers

Thread Starter

-live wire-

Joined Dec 22, 2017
959
Hi,

This probably isn't super complicated but I have to control 3 stepper motors simultaneously with an esp32 for part of a robotic arm.

These are the nema 23 stepper motors I am using, they are normal open loop 4 wire stepper motors.

These are the motor drivers I am using.

One pin tells the driver which direction to take a step in, where high is clockwise and low is counterclockwise. The other pin is the step pin and takes a 50% duty cycle square wave, and each cycle tells it to take a step. So, the higher the frequency the square wave, the quicker it takes its steps. It is important that it send the square wave for the exact right number of cycles so that the stepper motor takes the right number of steps.

There are 3 motors of these motors, each with a motor driver, all connected to an ESP32. I must simultaneously output the correct square wave to all 3 step pins, as well as the right direction to the 3 direction pins (this is easier because it is just writing it high or low). Code with delays will not work because it will completely stop, and the built in arduino stepper library seems to wait to finish moving one motor before executing the next line of code.

Since the timing is important and must be pretty quick, I would like to do the stepper motor movement on core0 of the ESP32, and have core1 handle serial communication with a computer that decides how to move the arm. However, I am really just having trouble with the PWM and timing aspect of this. I think if I start with just getting the 3 stepper motors working, I can figure out the multithreading stuff.

I have heard of timers and other ways to do the PWM, but I am pretty confused by all that. Right now I am using micros() and this is my code. It mostly works, however when I uploaded a sketch to move all the motors back and forth a certain number of steps, I noticed it would slowly drift from the starting position, indicating that steps are being lost. I need help figuring out if the code is the problem or the hardware is the problem. I also need help fixing this problem. Thanks!

Code:
const int stepPin[] = {27,16,25};//note that index 0 corresponds to base #1, 1 to base #2, 2 to base #3
const int dirPin[] = {14,4,26};//note that index 0 corresponds to base #1, 1 to base #2, 2 to base #3
double stepsPerRotation[] = {200,5*200,/*5.76*/200*4};

int freq[] = {0,0,0};//stepper motor frequency of steps 
bool stepDir[] = {false,false,false};//false = ccw, true = cw
bool stateidk[] = {true,true,true};//state variable to help PWM stepper motor
long pMic[] = {micros(),micros(),micros()};//timer variables to keep track of when to pwm stepper motor
int stepsTaken[] = {0,0,0};
void setup() {
  for (int i = 0; i < 3; i++){
    pinMode(stepPin[i],OUTPUT);
    pinMode(dirPin[i],OUTPUT);
  }
}

void loop() {
  int stt[] = {8,222,500};
  int rpmm[] = {20,15,60};
  moveSteps(stt,rpmm);
  delay(3000);
  for (int i = 0; i < 3; i++){
    stepDir[i] = !stepDir[i];
  }
}

void moveSteps (int stepsToTake[3], int rpm[3]){
  for (int i = 0; i <3; i++){
    stepsTaken[i] = 0;
    freq[i] = rpm[i]*stepsPerRotation[i]/60;
  }
  while (stepsTaken[0]<stepsToTake[0]||stepsTaken[1]<stepsToTake[1]||stepsTaken[2]<stepsToTake[2]){
    for (int i = 0; i < 3; i++){
      digitalWrite(dirPin[i],stepDir[i]);
      if (stepsTaken[i]<stepsToTake[i]&&freq[i]!=0 && micros() - pMic[i] > 1000000/2/freq[i]){
        stateidk[i] = !stateidk[i];  
        if (stateidk[i]){
          stepsTaken[i]++;
        }
        digitalWrite(stepPin[i],stateidk[i]); 
        pMic[i]=micros();
      }  
    }
  }
}
 

MisterBill2

Joined Jan 23, 2018
18,167
Really, controlling three steppers simultaneously IS rather complicated and does demand a lot of processing power, because all of the moves ARE made at the same time. That requires more processing ability and much greater output capability.
BUT there are also schemes to work around the problem quite well. If the three drivers have "enable" inputs, in addition to the step and direction then the solutin is simple: One common "step" output fed to all three drivers, and activating the "enable" command during the time the step command is low, so that on the next and following step pulses all three motors are enabled to step. No complex code or external circuits.
If each motor driver does not have a separate "enable" input, then you would need to implement the enable function with three "AND" gates. In some applications it is far more effective to implement a function in hardware tha to struggle with code.
 
Last edited:

LowQCab

Joined Nov 6, 2012
4,022
"" I noticed it would slowly drift from the starting position, indicating that steps are being lost. ""

You must implement 3 absolute Position-Encoders for feedback,
otherwise any mechanical anomaly that might temporarily disturb, or overload, one of the Motors
will result in the Motor remaining semi-permanently out of sync with the other Motors.

I'm not a Micro-Controller guy, but it seems to me that You should be running a
separate "Slave" Micro-Controller for each Stepper-Motor,
then run the 3-Slaves with a Master-Controller.

The "Number of Steps" is almost inconsequential.
"Positional-Feedback" is what will virtually guarantee the correct Arm-Motion and Positioning.

If the Arm is expected to make very-fast, precision moves,
a P.I.D. algorithm needs to be implemented in
each of the "Slave" Controllers for Acceleration-Control.

The "Slave-Controllers" also need to send feedback to the "Main-Controller" so that
the "Main-Controller" will be notified when the previously Commanded-Motion is complete,
this is so that it will remain stopped, waiting for all 3 Command-Completion-Notifications,
before issuing the next following Position-Command(s).

This is why having only one Controller "ain't gonna get it"..
.
.
.
 
Last edited:

Thread Starter

-live wire-

Joined Dec 22, 2017
959
"" I noticed it would slowly drift from the starting position, indicating that steps are being lost. ""

You must implement 3 absolute Position-Encoders for feedback,
otherwise any mechanical anomaly that might temporarily disturb, or overload, one of the Motors
will result in the Motor remaining semi-permanently out of sync with the other Motors.

I'm not a Micro-Controller guy, but it seems to me that You should be running a
separate "Slave" Micro-Controller for each Stepper-Motor,
then run the 3-Slaves with a Master-Controller.

The "Number of Steps" is almost inconsequential.
"Positional-Feedback" is what will virtually guarantee the correct Arm-Motion and Positioning.

If the Arm is expected to make very-fast, precision moves,
a P.I.D. algorithm needs to be implemented in
each of the "Slave" Controllers for Acceleration-Control.

The "Slave-Controllers" also need to send feedback to the "Main-Controller" so that
the "Main-Controller" will be notified when the previously Commanded-Motion is complete,
this is so that it will remain stopped, waiting for all 3 Command-Completion-Notifications,
before issuing the next following Position-Command(s).

This is why having only one Controller "ain't gonna get it".
.
.
.
.
.
.
Okay, what encoders would you recommend?
 

LowQCab

Joined Nov 6, 2012
4,022
I personally have no idea.
I learned how they work, and why, 20-years ago, but I've never used one.

You are looking for an "absolute" Position-Sensor,
because this type always knows what exact rotational-position that its in,
and, of course, which direction it is turning.

They must be connected to a Micro-Controller to function,
and they simply generate a digital "number" that corresponds to
an exact number of degrees of rotation.
They also keep track of multiple-rotations, equally well, in either direction,
so they can be used directly attached to a Motor-Shaft which is
going to a Reduction-Gear, and then to a Load,
which can provide incredibly fine positional-resolution.
.
.
.
 

MisterBill2

Joined Jan 23, 2018
18,167
The micro controller should have specs as ro the number of counts per revolution. And at least some robots use battery backed up counters to keep track of the positions because of many revolutions of the encoder during operation. At least MOTOMAN robots did.
 

BobTPH

Joined Jun 5, 2013
8,804
You must implement 3 absolute Position-Encoders for feedback,
I have two 3D printers and neither has encoders and yet they accurately track the position over prints lasting many hours.

If your stepper is missing steps, you are probably stepping too quickly.

Note that when moving anything with any mass, you need to ramp the speed up and down for each move.
 

MrChips

Joined Oct 2, 2009
30,703
My 3D printer and CNC machine use stepper motors without encoders.
It really depends on the application. You need to match the motors to the load.
I did work for a major industrial robot company. The application is in automotive manufacturing. We did not use stepper motors. We used DC motors and encoders with servo feedback. The acceleration, speed and holding torque is far superior than that attainable with stepper motors.
 

Ya’akov

Joined Jan 27, 2019
9,068
I have two 3D printers and neither has encoders and yet they accurately track the position over prints lasting many hours.

If your stepper is missing steps, you are probably stepping too quickly.

Note that when moving anything with any mass, you need to ramp the speed up and down for each move.
This is a very important point and if has not been implemented you will have no end of troubles.
 

MaxHeadRoom

Joined Jul 18, 2013
28,617
This probably isn't super complicated but I have to control 3 stepper motors simultaneously with an esp32 for part of a robotic arm.
Interpolated motion of motors is not a trivial task.
Why re-invent the wheel when you can use free interpolated motion control software such as Mach3/4?
You should not need encoders when using steppers.
The one thing though that is traditional with industrial robots, they are typically constructed in a way that they do not require zeroing or finding position at power up.
This means that some method of recording position is required at power off if this is designed in.
Controlling multi-axis in an interpolated fashion requires a multi-axis trajectory controller software.
 
I am using a different approch which works very good on a hotwire CNC machine with 4 Steppers and a 2 axis drilling machine, both with teensy3.2, 3.5, and an experimental robot car working with an ESP32.

For every motor I have a variable for steps and one for delay. Maybe I would rather use arrays for that.

I set timer1 with
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
timer1_attachInterrupt(stepperISR);


In the OnDataRecv function I update these values as given from the transmitter. The pins for EN and DIR are set.

I have a NULLBAND constant that sets a range for desabling the motor.

if (abs(ausschlag0) < NULLBAND) // ausschlag is the difference to the middle.
{
dir_status |= (1 << STEPPER0_EN_BIT); // Enable OFF
digitalWrite(STEPPER0_EN, HIGH);
delay0 = 0; // reset actual delay
}
else
{
dir_status &= ~(1 << STEPPER0_EN_BIT); // Enable ON
}


In the ISR, the delays are decremented while > 0. If the delay reaches IMPULSBREITE ( I use 5), the respective pin for the motor is set high to start the pulse.

if (delay0)
{
if (delay0 == IMPULSBREITE) // Impuls starten
{
digitalWrite(STEPPER0_STEP, HIGH); // Pulse ON
}
delay0--;
}


In the loop, I check if e.g. delayy0 is 0.
if (delay0 == 0)
{
{
digitalWrite(STEPPER0_DIR, (dir_status & (1 << STEPPER0_DIR_BIT))); // Direction
digitalWrite(STEPPER0_EN, (dir_status & (1 << STEPPER0_EN_BIT))); // Enable OFF
digitalWrite(STEPPER0_STEP, LOW); // Pulse OFF
delay0 = steps0; // Update steps for motor 0
}
}


I don't need to drive the stepper motors very fast, and this code runs very well.
 
Top