Running Multiple Steppers it one time

Am trying to write Arduino code to control few stepper motors from my c++ app through serial communication. the code i wrote seems to be ok but it gives strange type of output when i send serial command from my c++ app or Arduino IDE serial monitor.

code

#include <AccelStepper.h>
    // BaudRate
    #define BAUD 9600

     #define NO_OF_STEPPERS 3  // total # of stepper motors  + 1 , as our motor count star from 1 not from 0 , 

    struct steppers_struct {
      int stepper_id = 0;  // stepper no
      bool status = false;  // status bool 
      int steps_2_move = 0;  // steps the motor needs to move.

    };
    steppers_struct  steppers_rack[NO_OF_STEPPERS]; // init structure

    // Step and Dir pins Array 
    int step_pin_m[NO_OF_STEPPERS];
    int dir_pin_m[NO_OF_STEPPERS];
    int enable_pin_m[NO_OF_STEPPERS];

    // AcceStepper Stepper Array
    AccelStepper stepper_m[NO_OF_STEPPERS];

    // Driver A4988
    #define motorInterfaceType 1

    // Buffer
    char buf[80];

    // Readline funtion load buffer
    int readline(int readch, char *buffer, int len) {
        static int pos = 0;
        int rpos;

        if (readch > 0) {
            switch (readch) {
                case '\r': // Ignore CR
                    break;
                case '\n': // Return on new-line
                    rpos = pos;
                    pos = 0;  // Reset position index ready for next time
                    return rpos;
                default:
                    if (pos < len-1) {
                        buffer[pos++] = readch;
                        buffer[pos] = 0;
                    }
            }
        }
        return 0;
    }

    // Setup 
    void setup() {
        Serial.begin(BAUD);  // init serial

      // stepper dir and step pins. 
      step_pin_m[1] = 2;
      dir_pin_m[1] = 5;
      enable_pin_m[1] = 8; // on CNC shield v3 its pin 8

      step_pin_m[2] = 3;
      dir_pin_m[2] = 6;
      enable_pin_m[2] = 8; // on CNC shield v3 its pin 8


      for(int i=1; i<=NO_OF_STEPPERS; i++)
      {
          stepper_m[i] = AccelStepper(motorInterfaceType, step_pin_m[i], dir_pin_m[i]);   
          stepper_m[i].setMaxSpeed(1000);
          stepper_m[i].setSpeed(1000);  
          pinMode(enable_pin_m[i], OUTPUT);   // Enable Motors
          Serial.print("AccelStepper initalized..");Serial.print("\n");     
      }

      // Some LED
     // pinMode(53, OUTPUT); // Red LED it D53
     // pinMode(52, OUTPUT); // Green LED it D52  
    }


    void loop() {
       // Serial Read Start
       if (readline(Serial.read(), buf, 80) > 0) {
      // command format 1:100;2:200;3:300
      // Read each command pair 

        char* command = strtok(buf, ";");
          while (command != 0)
          {
        // Split the command in two values
        char* separator = strchr(command, ':');
        if (separator != 0)
        {
            // Actually split the string in 2: replace ':' with 0
            *separator = 0;
            int stepperId = atoi(command);
            ++separator;
            int stepperSteps = atoi(separator);

            // Steppers id stars from 1
            if(stepperId != 0){   

            steppers_rack[stepperId].stepper_id = stepperId;
            steppers_rack[stepperId].steps_2_move = stepperSteps;
            if(stepperSteps != 0){
                steppers_rack[stepperId].status = true;
            }else{
                steppers_rack[stepperId].status = false;
            }
               //   Serial.print(" stepper id: "); Serial.print(steppers_rack[stepperId].stepper_id); Serial.print(" stepper steps: "); Serial.print(steppers_rack[stepperId].steps_2_move); Serial.print("\n");    // output OK.
            }   

        } // if end
        // Find the next command in input string
        command = strtok(0, ";");

        }  // while end   
       } // Serial Read End

    // Problems start here when i try to use or change stepper structure data. 

     // Loop on Stepper_Struct
      for(int i=1; i<=NO_OF_STEPPERS; i++)
      {   
        if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
   Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : ");  Serial.print(steppers_rack[i].steps_2_move);  Serial.print(" status : ");   Serial.print(steppers_rack[i].status);  Serial.print("\n");  // Output not OK
    delay(500);   
              // Lets move stepper motor one step it time so that all motors looks moving it same time , sync
              stepper_m[i].move(1); // this states to move one step ahead
              stepper_m[i].runToPosition();
              steppers_rack[i].steps_2_move -- ;  // deducted one step from the total step motors is told to take
            if(steppers_rack[i].steps_2_move == 0){
              steppers_rack[i].status = false;
            }
        }  // if end
      }  // for end
    } // loop end

so here are few known issues am experiencing with it

  1. first when i send command (1:3;2:3) from Arduino Serial Monitor then it not display any output , i have to send it two times then i see output in serial Monitor.

  2. another main issue is strange output i get when i sent command : 1:3;2:3 ( mean stepper 1 move 3 steps and stepper 2 also move 3 steps )

 stepper id : 14897 Steps to move : 14848 status : 51
 stepper id : 14897 Steps to move : 59 status : 51
 stepper id : 14897 Steps to move : 12858 status : 51
 stepper id : 14897 Steps to move : 12857 status : 51
 stepper id : 14897 Steps to move : 12856 status : 51
 stepper id : 1 Steps to move : 372 status : 1
 stepper id : 49 Steps to move : 12855 status : 51
 stepper id : 1 Steps to move : 371 status : 1
 stepper id : 49 Steps to move : 12854 status : 51

so am not sure from where these big numbers 14897 , 51 , 49 etc are coming ?

so any idea what am doing wrong and to make the code working so that i can sync multiple stepper motors.

sorry i had to add all code in case someone try to run and debug it

The first thing that I notice is that you are reading from the serial port before you see if anything is actually available to be read.

The serial input basics tutorial may have information of value.

ok thanks i have fixed output issue it was caused due to for loop

i<=NO_OF_STEPPERS

had to change it to

i<NO_OF_STEPPERS

now one another issue raised that Stepper loop is very slow i mean it take about 1 sec to step motor , i wonder how can faster the stepping speed

#include <AccelStepper.h>
// BaudRate
#define BAUD 9600

#define NO_OF_STEPPERS 3  // total # of stepper motors  + 1

struct steppers_struct {
  int stepper_id = 0;  // stepper no
  bool status = false;  // status bool 
  int steps_2_move = 0;  // steps the motor needs to move.
  
};
steppers_struct  steppers_rack[NO_OF_STEPPERS]; // init structure

// Step and Dir pins Array 
int step_pin_m[NO_OF_STEPPERS];
int dir_pin_m[NO_OF_STEPPERS];
int enable_pin_m[NO_OF_STEPPERS];

// AcceStepper Stepper Array
AccelStepper stepper_m[NO_OF_STEPPERS];

// Driver A4988
#define motorInterfaceType 1

// Buffer
char buf[80];

// Readline funtion load buffer
int readline(int readch, char *buffer, int len) {
    static int pos = 0;
    int rpos;

    if (readch > 0) {
        switch (readch) {
            case '\r': // Ignore CR
                break;
            case '\n': // Return on new-line
                rpos = pos;
                pos = 0;  // Reset position index ready for next time
                return rpos;
            default:
                if (pos < len-1) {
                    buffer[pos++] = readch;
                    buffer[pos] = 0;
                }
        }
    }
    return 0;
}

// Setup 
void setup() {
    Serial.begin(BAUD);  // init serial
    
  // stepper dir and step pins. 
  step_pin_m[1] = 2;
  dir_pin_m[1] = 5;
  enable_pin_m[1] = 8; // on CNC shield v3 its pin 8

  step_pin_m[2] = 3;
  dir_pin_m[2] = 6;
  enable_pin_m[2] = 8; // on CNC shield v3 its pin 8
  

  for(int i=1; i<NO_OF_STEPPERS; i++)
  {
      stepper_m[i] = AccelStepper(motorInterfaceType, step_pin_m[i], dir_pin_m[i]);   
      stepper_m[i].setMaxSpeed(1000);
      stepper_m[i].setSpeed(1000);  
      pinMode(enable_pin_m[i], OUTPUT);   // Enable Motors
      Serial.print("AccelStepper initalized..");Serial.print("\n");     
  }
  
  // Some LED
 // pinMode(53, OUTPUT); // Red LED it D53
 // pinMode(52, OUTPUT); // Green LED it D52  
}


void loop() {
 //Serial.print("it top ");
   // Serial Read Start
   if (readline(Serial.read(), buf, 80) > 0) {
  // command format 1:100;2:200;3:300
  // Read each command pair 
  
    char* command = strtok(buf, ";");
      while (command != 0)
      {
    // Split the command in two values
    char* separator = strchr(command, ':');
    if (separator != 0)
    {
        // Actually split the string in 2: replace ':' with 0
        *separator = 0;
        int stepperId = atoi(command);
        ++separator;
        int stepperSteps = atoi(separator);
           
        // Steppers id stars from 1
        if(stepperId != 0){   
          
        steppers_rack[stepperId].stepper_id = stepperId;
        steppers_rack[stepperId].steps_2_move = stepperSteps;
        if(stepperSteps != 0){
            steppers_rack[stepperId].status = true;
        }else{
            steppers_rack[stepperId].status = false;
        }
           //   Serial.print(" stepper id: "); Serial.print(steppers_rack[stepperId].stepper_id); Serial.print(" stepper steps: "); Serial.print(steppers_rack[stepperId].steps_2_move); Serial.print("\n");    // output OK.
        }   
         
    } // if end
    // Find the next command in input string
    command = strtok(0, ";");

    }  // while end   
   } // Serial Read End

 // Loop on Stepper_Struct
  for(int i=1; i<NO_OF_STEPPERS; i++)
  {
    if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
//Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : ");  Serial.print(steppers_rack[i].steps_2_move);  Serial.print(" status : ");   Serial.print(steppers_rack[i].status);  Serial.print("\n");  // Output not OK
          
          unsigned long StartTime = millis();     
          stepper_m[i].move(1); // this states to move one step ahead
          stepper_m[i].runToPosition();
          steppers_rack[i].steps_2_move --; 
        
       if(steppers_rack[i].steps_2_move == 0){
          steppers_rack[i].status = false;
        }
         unsigned long CurrentTime = millis();    
         unsigned long ElapsedTime = CurrentTime - StartTime;
        Serial.print("\n loop time :  "); Serial.print(ElapsedTime); Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id);  Serial.print("\n \n");
    }  // if end
  }  // for end
   


} // loop end

zelda546:
now one another issue raised that Stepper loop is very slow

You need to post the complete program.

If you use delay() you can expect things to be slow because it blocks the Arduino so that nothing else is done during the delay(). Have a look at how the timing is managed without blocking in the SECOND example in this Simple Stepper Code

...R
Stepper Motor Basics

Robin2:
You need to post the complete program.

ok sorry about it , that i have added working code in my 2nd reply, i have not used Delay function anywhere in code , but the loop on stepper_rack structure where am trying to move motors by single steps so that they look all sync is very very slow ,

can you please check if that due to Accellib or some other issue because i checked code it other points its ok and fast but it slow down it that one place where id do

          stepper_m[i].move(1); // this states to move one step ahead
          stepper_m[i].runToPosition();

zelda546:
ok sorry about it , that i have added working code in my 2nd reply,

I can't figure which code you are referring to. Please just post the complete program in your next Reply so the Thread can be read from top to bottom without the reader needing to back track.

...R

ok here is full code

#include <AccelStepper.h>
// BaudRate
#define BAUD 9600

#define NO_OF_STEPPERS 3  // total # of stepper motors  + 1

struct steppers_struct {
  int stepper_id = 0;  // stepper no
  bool status = false;  // status bool 
  int steps_2_move = 0;  // steps the motor needs to move.
  
};
steppers_struct  steppers_rack[NO_OF_STEPPERS]; // init structure

// Step and Dir pins Array 
int step_pin_m[NO_OF_STEPPERS];
int dir_pin_m[NO_OF_STEPPERS];
int enable_pin_m[NO_OF_STEPPERS];

// AcceStepper Stepper Array
AccelStepper stepper_m[NO_OF_STEPPERS];

// Driver A4988
#define motorInterfaceType 1

// Buffer
char buf[80];

// Readline funtion load buffer
int readline(int readch, char *buffer, int len) {
    static int pos = 0;
    int rpos;

    if (readch > 0) {
        switch (readch) {
            case '\r': // Ignore CR
                break;
            case '\n': // Return on new-line
                rpos = pos;
                pos = 0;  // Reset position index ready for next time
                return rpos;
            default:
                if (pos < len-1) {
                    buffer[pos++] = readch;
                    buffer[pos] = 0;
                }
        }
    }
    return 0;
}

// Setup 
void setup() {
    Serial.begin(BAUD);  // init serial
    
  // stepper dir and step pins. 
  step_pin_m[1] = 2;
  dir_pin_m[1] = 5;
  enable_pin_m[1] = 8; // on CNC shield v3 its pin 8

  step_pin_m[2] = 3;
  dir_pin_m[2] = 6;
  enable_pin_m[2] = 8; // on CNC shield v3 its pin 8
  

  for(int i=1; i<NO_OF_STEPPERS; i++)
  {
      stepper_m[i] = AccelStepper(motorInterfaceType, step_pin_m[i], dir_pin_m[i]);   
      stepper_m[i].setMaxSpeed(1000);
      stepper_m[i].setSpeed(1000);  
      pinMode(enable_pin_m[i], OUTPUT);   // Enable Motors
      Serial.print("AccelStepper initalized..");Serial.print("\n");     
  }
  
  // Some LED
 // pinMode(53, OUTPUT); // Red LED it D53
 // pinMode(52, OUTPUT); // Green LED it D52  
}


void loop() {
 //Serial.print("it top ");
   // Serial Read Start
   if (readline(Serial.read(), buf, 80) > 0) {
  // command format 1:100;2:200;3:300
  // Read each command pair 
  
    char* command = strtok(buf, ";");
      while (command != 0)
      {
    // Split the command in two values
    char* separator = strchr(command, ':');
    if (separator != 0)
    {
        // Actually split the string in 2: replace ':' with 0
        *separator = 0;
        int stepperId = atoi(command);
        ++separator;
        int stepperSteps = atoi(separator);
           
        // Steppers id stars from 1
        if(stepperId != 0){   
          
        steppers_rack[stepperId].stepper_id = stepperId;
        steppers_rack[stepperId].steps_2_move = stepperSteps;
        if(stepperSteps != 0){
            steppers_rack[stepperId].status = true;
        }else{
            steppers_rack[stepperId].status = false;
        }
           //   Serial.print(" stepper id: "); Serial.print(steppers_rack[stepperId].stepper_id); Serial.print(" stepper steps: "); Serial.print(steppers_rack[stepperId].steps_2_move); Serial.print("\n");    // output OK.
        }   
         
    } // if end
    // Find the next command in input string
    command = strtok(0, ";");

    }  // while end   
   } // Serial Read End

 // Loop on Stepper_Struct
  for(int i=1; i<NO_OF_STEPPERS; i++)
  {
    if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
//Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : ");  Serial.print(steppers_rack[i].steps_2_move);  Serial.print(" status : ");   Serial.print(steppers_rack[i].status);  Serial.print("\n");  // Output not OK
          
          unsigned long StartTime = millis();     
          stepper_m[i].move(1); // this states to move one step ahead
          stepper_m[i].runToPosition();
          steppers_rack[i].steps_2_move --; 
        
       if(steppers_rack[i].steps_2_move == 0){
          steppers_rack[i].status = false;
        }
         unsigned long CurrentTime = millis();    
         unsigned long ElapsedTime = CurrentTime - StartTime;
        Serial.print("\n loop time :  "); Serial.print(ElapsedTime); Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id);  Serial.print("\n \n");
    }  // if end
  }  // for end
   


} // loop end

from Arduino Serial Monitor you will have to send commands in format like , motor # : no of steps to take

1:5;2:5

the above command mean stepper motor # 1 take 5 steps ; stepper motor # 2 take 5 steps too
you can increase it like 1:10;2:5;3:10 etc ...

Issue : problem is the stepper motor takes steps very slow , probably take one sec to take one step , so not sure its problem is Accelstepper library or something else

It is very hard to figure out what's going on because you have all the code bundled into loop().

My guess is that reading the commands is getting in the way of the step process.

As far as I can see you have three separate concepts within your program

  • reading data from the serial port
  • parsing the data
  • making the steppers move according to the parsed data.

Put each of those concepts into a separate function and then you will be able to test each one separately and identify where there may be a bottleneck.

Also I can't figure out in macro terms how the program is supposed to work. Is it the case that normally the motors lie idle. Then someone sends a command and the motors execute that command and return to the idle state (keeping in mind that the idle state may only last for a few millisecs). OR, are new commands supposed to be read while the motors (perhaps only some of them) are moving and the reading process should not interfere with the motion?

A few of thoughts come to mind. I assume you have less than 26 stepper motors so just send a single character as the ID and you can convert it to a number much faster than using atoi().

Use a higher baud rate.

If every message can contain a number of steps for every motor (even if it is 0) then you don't need any ID numbers - the order of the numbers will suffice. But you might need to balance that Arduino convenience against the time taken to transmit longer messages.

The Arduino Serial Input Buffer is 64 bytes long and life will be simpler if the maximum command length is below that.

For greater reliability add start- and end-markers to your messages so that there is no risk of the Arduino either missing something or confusing something. Have a look at the 3rd example in Serial Input Basics

You don't seem to be using the AccelStepper library so why reference it at the top of your program?

...R
Planning and Implementing a Program

Stepper Motor Basics
Simple Stepper Code

thanks for the info :slight_smile:

You don't seem to be using the AccelStepper library so why reference it at the top of your program?

am using AccelStepper Lib , you can check the for loop

 // Loop on Stepper_Struct
  for(int i=1; i<NO_OF_STEPPERS; i++)
  {
    if(steppers_rack[i].steps_2_move != 0 && steppers_rack[i].status == true){
//Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id); Serial.print(" Steps to move : ");  Serial.print(steppers_rack[i].steps_2_move);  Serial.print(" status : ");   Serial.print(steppers_rack[i].status);  Serial.print("\n");  // Output not OK
          
          unsigned long StartTime = millis();     
          stepper_m[i].move(1); // this states to move one step ahead
          stepper_m[i].runToPosition();
          steppers_rack[i].steps_2_move --; 
        
       if(steppers_rack[i].steps_2_move == 0){
          steppers_rack[i].status = false;
        }
         unsigned long CurrentTime = millis();    
         unsigned long ElapsedTime = CurrentTime - StartTime;
        Serial.print("\n loop time :  "); Serial.print(ElapsedTime); Serial.print(" stepper id : ");  Serial.print(steppers_rack[i].stepper_id);  Serial.print("\n \n");
    }  // if end
  }  // for end

zelda546:
am using AccelStepper Lib , you can check the for loop

Sorry, I missed that. As I said earlier your program is hard to follow.

The function runToPosition() blocks the Arduino until it completes. It is not suitable if you want multiple motors to move at the same time. You need to use the function run() and it cannot be used in the same way. Study the examples that come with the Accelstepper library.

You have not commented on the other suggestions I made in Reply #8

...R

Robin2:
Sorry, I missed that. As I said earlier your program is hard to follow.

The function runToPosition() blocks the Arduino until it completes. It is not suitable if you want multiple motors to move at the same time. You need to use the function run() and it cannot be used in the same way. Study the examples that come with the Accelstepper library.

...R

yes you were right runtoposition() function block arduino , i found example which is helpful i will implement to see how it goes :: AccelStepper: AFMotor_MultiStepper.pde

You have not commented on the other suggestions I made in Reply #8

yes thanks for the great info i updated my code earlier it was blocking code , now it not block arduino while reading commands from serial. am studying the material you provided in your comments very helpful . thanks for it :slight_smile: