Controlling 4 stepper motors to move simultaneously, using ESP32

Hi All!

Help required please!

I'm working on a project where I am controlling 4 stepper motors, and 3 DC motors using an ESP32, and a Bluetooth Serial Port app.
I have got the electronics, circuitry and code working BUT my 4 Stepper Motors (S1-S4) move one at a time (S2 only starts moving when S1 has completed it's movement, and so on till S4), but I need them to move simultaneously.
Coding unfortunately is my Achilles heel, and the person who did the initial coding is no longer available to help.
I would be grateful if someone could point me in the right direction, and possibly some sample links, or sample codes.
(I could share the existing code if that helps)
I'd be grateful for any assistance!
Thank You!

Nothing we can do but make guesses utill we see the code.
In the IDE click on Edit, then Copy for Forum, that will copy your code. Then come here and just do a paste.

1 Like
#include "BluetoothSerial.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

// Bluetooth Serial Object (Handle)
BluetoothSerial SerialBT;

#define stepper1_step 25  //35
#define stepper2_step 27  //34
#define stepper3_step 13  //vn pin 39
#define stepper4_step 14  //vp pin  36
#define RST 33
#define SLP 32

//DC Motor1
// #define IN1 2 //used for IR
#define IN2 4
#define PWM1 15

//DC Motor2
#define IN3 16
#define IN4 5
#define PWM2 17

//DC Motor3
#define IN5 19
#define IN6 23
#define PWM3 18

//Limit_Switch
#define LS1 26  //27
#define LS2 4   //14
#define LS3 16  //12
#define LS4 5   //13
#define IR_SENSOR 2

#define DIR2 0
#define EN2 1
#define DIR1 2
#define EN1 3
#define EN4 4
#define DIR4 5
#define DIR3 6
#define EN3 7

#define rotation_stepper_max_position 100
#define to_and_fro_stepper_max_position 70
#define tilt_stepper_max_position 45
#define up_down_stepper_max_position 70


#include <Adafruit_PCF8574.h>
Adafruit_PCF8574 pcf;

const unsigned int MAX_MESSAGE_LENGTH = 50;
volatile uint32_t ui32position, ui32rpm;
volatile uint32_t ui32s1_position, ui32s2_position, ui32s3_position, ui32s4_position, ui32d1_rpm, ui32d2_rpm, ui32d3_rpm, ui32ir_counter;
char *type;
char *position;
char *rpm;
char *s1_position, *s2_position, *s3_position, *s4_position, *d1_rpm, *d2_rpm, *d3_rpm, *ir_counter;

bool LS1_interrupt = 0;
bool LS2_interrupt = 0;
bool LS3_interrupt = 0;
bool LS4_interrupt = 0;
bool IR_interrupt = 0;

int to_and_fro_stepper_last_position = 60, to_and_fro_stepper_current_position = 0, rotation_stepper_last_position = 90, rotation_stepper_current_position = 0, tilt_stepper_last_position = 44, tilt_stepper_current_position = 0, up_down_stepper_last_position = 60, up_down_stepper_current_position = 0;



void to_and_fro_stepper(int position) {
  float period;
  int difference;
  int dir;
  int step;
  to_and_fro_stepper_current_position = position;
  period = (300 / 60.0) * 200;
  // period = (1 / period) * 10 ^ 6;
  period = 1000000 / period;

  pcf.digitalWrite(EN1, LOW);

  if (to_and_fro_stepper_last_position > to_and_fro_stepper_current_position) {
    pcf.digitalWrite(DIR1, 0);
    dir = 0;
  }
  if (to_and_fro_stepper_last_position < to_and_fro_stepper_current_position) {
    pcf.digitalWrite(DIR1, 1);
    dir = 1;
  }
  difference = abs(to_and_fro_stepper_last_position - to_and_fro_stepper_current_position);
  step = difference * 4100 / 70;

  for (int i = 0; i < step; i++) {
    if (LS1_interrupt == 1) {
      Serial.println("LS1_Interrupt");
      LS1_interrupt = 0;
      delay(200);
      if (digitalRead(LS1) == 0) {
        if (dir == 0) {
          to_and_fro_stepper_current_position = 0;
        } else if (dir == 1) {
          to_and_fro_stepper_current_position = to_and_fro_stepper_max_position;
        }
        break;
      }
    }

    if (dir == 0 && to_and_fro_stepper_current_position < 0) {
      to_and_fro_stepper_current_position = 0;
      break;
    }
    if (dir == 1 && to_and_fro_stepper_current_position > to_and_fro_stepper_max_position) {
      to_and_fro_stepper_current_position = to_and_fro_stepper_max_position;
      break;
    }
    // These four lines result in 1 step:
    digitalWrite(stepper1_step, LOW);
    delayMicroseconds(period);
    digitalWrite(stepper1_step, HIGH);
    delayMicroseconds(period);
  }
  // pcf.digitalWrite(EN1, HIGH);
  Serial.print("period");
  Serial.println(period);
  // if (dir == 0) {
  //   to_and_fro_stepper_current_position = to_and_fro_stepper_current_position - step;
  // } else if (dir == 1) {
  //   to_and_fro_stepper_current_position = to_and_fro_stepper_current_position + step;
  // }
  to_and_fro_stepper_last_position = to_and_fro_stepper_current_position;
  Serial.print("to_and_fro_stepper_current_position");
  Serial.println(to_and_fro_stepper_current_position);
}


void rotation_stepper(int position) {
  float period;
  int difference = 0;
  int dir;
  int step;
  rotation_stepper_current_position = position;
  period = (54 / 60.0) * 200;
  // period = (1 / period) * 10 ^ 6;
  period = 1000000 / period;

  pcf.digitalWrite(EN2, LOW);

  if (rotation_stepper_last_position > rotation_stepper_current_position) {
    pcf.digitalWrite(DIR2, 0);
    dir = 0;
  }
  if (rotation_stepper_last_position < rotation_stepper_current_position) {
    pcf.digitalWrite(DIR2, 1);
    dir = 1;
  }
  difference = abs(rotation_stepper_last_position - rotation_stepper_current_position);
  step = difference * 616 / 100;

  for (int i = 0; i < step; i++) {
    if (LS2_interrupt == 1) {
      LS2_interrupt = 0;
      delay(200);
      if (digitalRead(LS2) == 0) {
        Serial.println("LS2_Interrupt");
        if (dir == 0) {
          rotation_stepper_current_position = 0;
          break;
        }
        if (dir == 1) {
          rotation_stepper_current_position = rotation_stepper_max_position;
          break;
        }
      }
    }


    if (dir == 0 && rotation_stepper_current_position < 0) {
      rotation_stepper_current_position = 0;
      break;
    }
    if (dir == 1 && rotation_stepper_current_position > rotation_stepper_max_position) {
      rotation_stepper_current_position = rotation_stepper_max_position;
      break;
    }

    // These four lines result in 1 step:
    digitalWrite(stepper2_step, LOW);
    delayMicroseconds(period);
    digitalWrite(stepper2_step, HIGH);
    delayMicroseconds(period);
  }
  // pcf.digitalWrite(EN2, HIGH);
  Serial.print("period");
  Serial.println(period);
  // if (dir == 0) {
  //   rotation_current_position = rotation_current_position - step;
  // } else if (dir == 1) {
  //   rotation_current_position = rotation_current_position + step;
  // }
  rotation_stepper_last_position = rotation_stepper_current_position;
  Serial.print("rotation_stepper_current_position");
  Serial.println(rotation_stepper_current_position);
}

void tilt_stepper(int position) {
  float period;
  int difference = 0;
  int dir;
  int step;
  tilt_stepper_current_position = position;
  period = (495 / 60.0) * 200;
  // period = (1 / period) * 10 ^ 6;
  period = 1000000 / period;

  pcf.digitalWrite(EN3, LOW);


  if (tilt_stepper_last_position > tilt_stepper_current_position) {
    pcf.digitalWrite(DIR3, 0);
    dir = 0;
  }
  if (tilt_stepper_last_position < tilt_stepper_current_position) {
    pcf.digitalWrite(DIR3, 1);
    dir = 1;
  }
  difference = abs(tilt_stepper_last_position - tilt_stepper_current_position);
  step = difference * 45000 / 45;


  for (int i = 0; i < step; i++) {
    if (LS3_interrupt == 1) {
      LS3_interrupt = 0;
      Serial.println("LS3_Interrupt");
      delay(200);
      if (digitalRead(LS3) == 0) {

        if (dir == 0) {
          tilt_stepper_current_position = 0;
          break;
        } else if (dir == 1) {
          tilt_stepper_current_position = tilt_stepper_max_position;
          break;
        }
      }
    }
    if (dir == 0 && tilt_stepper_current_position < 0) {
      tilt_stepper_current_position = 0;
      break;
    }
    if (dir == 1 && tilt_stepper_current_position > tilt_stepper_max_position) {
      tilt_stepper_current_position = tilt_stepper_max_position;
      break;
    }

    // These four lines result in 1 step:
    digitalWrite(stepper3_step, LOW);
    delayMicroseconds(period);
    digitalWrite(stepper3_step, HIGH);
    delayMicroseconds(period);
  }
  // pcf.digitalWrite(EN3, HIGH);
  Serial.print("period");
  Serial.println(period);
  tilt_stepper_last_position = tilt_stepper_current_position;
  // if (dir == 0) {
  //   tilt_stepper_current_position = tilt_stepper_current_position - step;
  // } else if (dir == 1) {
  //   tilt_stepper_current_position = tilt_stepper_current_position + step;
  // }
  Serial.print("tilt_stepper_current_position");
  Serial.println(tilt_stepper_current_position);
}

void up_down_stepper(int position) {
  float period;
  int difference = 0;
  int dir;
  int step;
  up_down_stepper_current_position = position;
  period = (325 / 60.0) * 200;
  // period = (1 / period) * 10 ^ 6;
  period = 1000000 / period;

  pcf.digitalWrite(EN4, LOW);

  if (up_down_stepper_last_position > up_down_stepper_current_position) {
    pcf.digitalWrite(DIR4, 0);
    dir = 0;
  }
  if (up_down_stepper_last_position < up_down_stepper_current_position) {
    pcf.digitalWrite(DIR4, 1);
    dir = 1;
  }
  difference = abs(up_down_stepper_last_position - up_down_stepper_current_position);
  step = difference * 17500 / 70;


  for (int i = 0; i < step; i++) {
    if (LS4_interrupt == 1) {
      Serial.println("LS4_Interrupt");
      LS4_interrupt = 0;
      delay(200);
      if (digitalRead(LS4) == 0) {
        if (dir == 0) {
          up_down_stepper_current_position = 0;
          break;
        } else if (dir == 1) {
          up_down_stepper_current_position = up_down_stepper_max_position;
          break;
        }
      }
    }

    if (dir == 0 && up_down_stepper_current_position < 0) {
      up_down_stepper_current_position = 0;
      break;
    }
    if (dir == 1 && up_down_stepper_current_position > up_down_stepper_max_position) {
      up_down_stepper_current_position = up_down_stepper_max_position;
      break;
    }

    // These four lines result in 1 step:
    digitalWrite(stepper4_step, LOW);
    delayMicroseconds(period);
    digitalWrite(stepper4_step, HIGH);
    delayMicroseconds(period);
  }
  // pcf.digitalWrite(EN4, HIGH);
  Serial.print("period");
  Serial.println(period);
  // if (dir == 0) {
  //   up_down_stepper_current_position = up_down_stepper_current_position - step;
  // } else if (dir == 1) {
  //   up_down_stepper_current_position = up_down_stepper_current_position + step;
  // }
  up_down_stepper_last_position = up_down_stepper_current_position;
  Serial.print("up_down_stepper_current_position");
  Serial.println(up_down_stepper_current_position);
}

void dc_motor1_on(int time) {

  // if (dir == 1) {

  //   digitalWrite(IN1, 1);
  //   digitalWrite(IN2, 0);
  //   analogWrite(PWM1, speed);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN1, 0);
  //   digitalWrite(IN2, 1);
  //   analogWrite(PWM1, speed);
  // }
  analogWrite(PWM1, 255);
  delay(time * 1000);
  analogWrite(PWM1, 0);
}

void dc_motor1_on_continious(int speed) {

  // if (dir == 1) {

  //   digitalWrite(IN1, 1);
  //   digitalWrite(IN2, 0);
  //   analogWrite(PWM1, speed);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN1, 0);
  //   digitalWrite(IN2, 1);
  //   analogWrite(PWM1, speed);
  // }
  analogWrite(PWM1, speed);
}

void dc_motor1_off() {
  // digitalWrite(IN1, 0);
  // digitalWrite(IN2, 0);
  analogWrite(PWM1, 0);
}

void dc_motor2_on(int time) {

  // if (dir == 1) {

  //   digitalWrite(IN3, 1);
  //   digitalWrite(IN4, 0);
  //   analogWrite(PWM2, speed);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN3, 0);
  //   digitalWrite(IN4, 1);
  //   analogWrite(PWM2, speed);
  // }
  analogWrite(PWM2, 255);
  delay(time * 1000);
  analogWrite(PWM2, 0);
}

void dc_motor2_on_continious(int speed) {

  // if (dir == 1) {

  //   digitalWrite(IN3, 1);
  //   digitalWrite(IN4, 0);
  //   analogWrite(PWM2, speed);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN3, 0);
  //   digitalWrite(IN4, 1);
  //   analogWrite(PWM2, speed);
  // }
  analogWrite(PWM2, speed);
}

void dc_motor2_off() {
  // digitalWrite(IN3, 0);
  // digitalWrite(IN4, 0);
  analogWrite(PWM2, 0);
}

void dc_motor3_on(int time) {

  // if (dir == 1) {

  //   digitalWrite(IN5, 1);
  //   digitalWrite(IN6, 0);
  //   analogWrite(PWM3, 255);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN5, 0);
  //   digitalWrite(IN6, 1);
  //   analogWrite(PWM3, 255);
  // }

  digitalWrite(IN5, 1);
  digitalWrite(IN6, 0);
  analogWrite(PWM3, 255);

  delay(time * 1000);
  dc_motor3_off();
}
void dc_motor3_on_continious(int speed) {

  // if (dir == 1) {

  //   digitalWrite(IN5, 1);
  //   digitalWrite(IN6, 0);
  //   analogWrite(PWM3, 255);
  // }

  // if (dir == 0) {
  //   digitalWrite(IN5, 0);
  //   digitalWrite(IN6, 1);
  //   analogWrite(PWM3, 255);
  // }
  digitalWrite(IN5, 1);
  digitalWrite(IN6, 0);
  analogWrite(PWM3, speed);
}
void dc_motor3_off() {
  digitalWrite(IN5, 0);
  digitalWrite(IN6, 0);
  analogWrite(PWM3, 0);
}

void home() {
  to_and_fro_stepper(70);
  delay(1000);
  to_and_fro_stepper(0);
  delay(1000);
  rotation_stepper(100);
  delay(1000);
  rotation_stepper(0);
  delay(1000);
  tilt_stepper(45);
  delay(1000);
  tilt_stepper(0);
  delay(1000);
  up_down_stepper(70);
  delay(1000);
  up_down_stepper(0);
  delay(1000);
  dc_motor1_on_continious(255);
  delay(1000);
  dc_motor2_on_continious(255);
  delay(1000);
}
void IRAM_ATTR LS1_ISR() {
  LS1_interrupt = 1;
}
void IRAM_ATTR LS2_ISR() {
  LS2_interrupt = 1;
}
void IRAM_ATTR LS3_ISR() {
  LS3_interrupt = 1;
}
void IRAM_ATTR LS4_ISR() {
  LS4_interrupt = 1;
}

void IRAM_ATTR IR_ISR() {
  IR_interrupt = 1;
}



void setup() {
  // put your setup code here, to run once:
  pinMode(stepper1_step, OUTPUT);
  pinMode(stepper2_step, OUTPUT);
  pinMode(stepper3_step, OUTPUT);
  pinMode(stepper4_step, OUTPUT);

  // pinMode(IN1, OUTPUT);
  // pinMode(IN2, OUTPUT);
  pinMode(PWM1, OUTPUT);

  // pinMode(IN3, OUTPUT);
  // pinMode(IN4, OUTPUT);
  pinMode(PWM2, OUTPUT);

  pinMode(IN5, OUTPUT);
  pinMode(IN6, OUTPUT);
  pinMode(PWM3, OUTPUT);

  pinMode(RST, OUTPUT);
  pinMode(SLP, OUTPUT);
  digitalWrite(RST, 1);
  digitalWrite(SLP, 1);

  pinMode(LS1, INPUT);
  pinMode(LS2, INPUT);
  pinMode(LS3, INPUT);
  pinMode(LS4, INPUT);
  pinMode(IR_SENSOR, INPUT);

  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(LS1), LS1_ISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(LS2), LS2_ISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(LS3), LS3_ISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(LS4), LS4_ISR, FALLING);
  attachInterrupt(digitalPinToInterrupt(IR_SENSOR), IR_ISR, FALLING);  //

  if (!pcf.begin(0x20, &Wire)) {
    Serial.println("Couldn't find PCF8574");
    while (1)
      ;
  }
  for (uint8_t p = 0; p < 8; p++) {
    pcf.pinMode(p, OUTPUT);
  }

  SerialBT.begin("Tennis");  //Bluetooth device name
  Serial.println("The device with name \"%s\" is started.\nNow you can pair it with Bluetooth!\n");
  home();
}



void loop() {
  // Read The Received Bytes & Add Them To Message (RxBuffer) Array
  if (SerialBT.available()) {
    static char message[MAX_MESSAGE_LENGTH];
    static unsigned int message_pos = 0;
    char inByte = SerialBT.read();
    //Message coming in (check not terminating character) and guard for over message size
    if (inByte != '\n' && (message_pos < MAX_MESSAGE_LENGTH - 1)) {
      //Add the incoming byte to our message
      message[message_pos] = inByte;
      // Serial.println(message[message_pos]);
      message_pos++;
    }
    //Full message received...
    else {
      //Add null character to string
      message[message_pos] = '\0';

      //Print the message (or do other things)
      Serial.println(message);

      //Reset for the next message
      message_pos = 0;
      type = strtok(message, ":");
      s1_position = strtok(NULL, ":");
      s2_position = strtok(NULL, ":");
      s3_position = strtok(NULL, ":");
      s4_position = strtok(NULL, ":");
      d1_rpm = strtok(NULL, ":");
      d2_rpm = strtok(NULL, ":");
      d3_rpm = strtok(NULL, ":");
      ir_counter = strtok(NULL, ":");
      ui32s1_position = atoi(s1_position);
      ui32s2_position = atoi(s2_position);
      ui32s3_position = atoi(s3_position);
      ui32s4_position = atoi(s4_position);
      ui32d1_rpm = atoi(d1_rpm);
      ui32d2_rpm = atoi(d2_rpm);
      ui32d3_rpm = atoi(d3_rpm);
      ui32ir_counter = atoi(ir_counter);
      if (strcmp(type, "M") == 0) {
        dc_motor3_off();
        to_and_fro_stepper(ui32s1_position);
        rotation_stepper(ui32s2_position);
        tilt_stepper(ui32s3_position);
        up_down_stepper(ui32s4_position);
        dc_motor1_on_continious(ui32d1_rpm);
        dc_motor2_on_continious(ui32d2_rpm);
        dc_motor3_on_continious(ui32d3_rpm);
      }
      // type = strtok(message, ":");
      // position = strtok(NULL, ":");
      // Serial.println(type);
      // Serial.println(position);
      // ui32position = atoi(position);
      // Serial.println(ui32position);
      // if (strcmp(type, "S1") == 0) {
      //   to_and_fro_stepper(ui32position);
      // } else if (strcmp(type, "S2") == 0) {
      //   rotation_stepper(ui32position);
      // } else if (strcmp(type, "S3") == 0) {
      //   tilt_stepper(ui32position);
      // } else if (strcmp(type, "S4") == 0) {
      //   up_down_stepper(ui32position);
      // } else if (strcmp(type, "D1") == 0) {
      //   dc_motor1_on(ui32position);  //speed
      // } else if (strcmp(type, "D1ON") == 0) {
      //   dc_motor1_on_continious(ui32position);  //time
      // } else if (strcmp(type, "D1OFF") == 0) {
      //   dc_motor1_off();
      // } else if (strcmp(type, "D2") == 0) {
      //   dc_motor2_on(ui32position);  //speed
      // } else if (strcmp(type, "D2ON") == 0) {
      //   dc_motor2_on_continious(ui32position);  //time
      // } else if (strcmp(type, "D2OFF") == 0) {
      //   dc_motor2_off();
      // } else if (strcmp(type, "D3") == 0) {
      //   dc_motor3_on(ui32position);  //direction
      // } else if (strcmp(type, "D3ON") == 0) {
      //   dc_motor3_on_continious(ui32position);  //direction
      // } else if (strcmp(type, "D3OFF") == 0) {
      //   dc_motor3_off();
      // } else if (strcmp(type, "HOME") == 0) {
      //   home();
      // }
      memset(message, 0, MAX_MESSAGE_LENGTH);
    }
  }
  if (IR_interrupt == 1) {
    delay(1000);
    ui32ir_counter--;
    Serial.print("IR_COUNT:");
    Serial.println(ui32ir_counter);
    IR_interrupt = 0;
  }
  if (ui32ir_counter < 1) {
    ui32ir_counter=0;
    dc_motor3_off();
  }
}

Thanks! I couldn't figure out how to post the code!

The general idea is to get rid of for-loops and delay. I'm not familiar with steppers but you let make stepper 1 one step, next let stepper 2 make on step etc.

It doesn't sound like you're using an Arduino Nano ESP32 and the topic is more generic than just the microcontroller and hence your topic has been moved to a more suitable category on the forum.

1 Like

Most of that program is written to completely monopolize the processor and prevent anything else from happening simultaneously.

To make things work "simultaneously" the code running the motors needs to be able to share the processor with other code running other things.

Consider these:

seems like an awful lot of code. could you explain what it's intended to do

if you want to move multiple stepper motor at one time, presumably starting and ending at the same time, make sense to determine which requires the largest # of steps and time to reach it's enpoint.

the other steppers will then step at some sub-multiple of that "master" motor

either that or determine the time needed to move the master and step the other motors at the appropriate times for their steps

the main code

  • determines a w, x, y, z position,
  • drives the steppers to the position
  • repeats

The is another detail to clarify:

Are your for stepper-motors required to run in coordinated motion?
where coordinated means all four motors start at the same time and regardless of how many steps each motor rotates all four motors must stop at the same time.
or
will it be sufficient if all motors start at the same time but finish rotating at different points in time?

the first requires a multidimensional bresenham-algorithm
the second can be done by a stepper-motorlibrary called MobaTools

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.