I have three stepper motors connected to the drv8825 drivers to an arduino uno.

I am using the example code below (from here), which works fine for moving multiple stepper motors at the same time BUT they all move for the same number of steps and in the same direction. I would like to tweak the code so that all of them move at the same time but each one for a different number of steps and in different directions. The motor with the least steps would probably have to wait for the motor with the most steps to finish its movement before going again.

int dirPin = 8;
int stepperPin = 7;
int bdirPin = 6;
int bstepperPin = 5;

void setup() {
 pinMode(dirPin, OUTPUT);
 pinMode(stepperPin, OUTPUT);
 pinMode(bdirPin, OUTPUT);
 pinMode(bstepperPin, OUTPUT);
}
 void step(boolean dir,int steps){
 digitalWrite(dirPin,dir);
 digitalWrite(bdirPin,dir);
 delay(50);
 for(int i=0;i<steps;i++){
 digitalWrite(stepperPin, HIGH);
 digitalWrite(bstepperPin, HIGH);
 delayMicroseconds(800);
 digitalWrite(stepperPin, LOW);
 digitalWrite(bstepperPin, LOW);
 delayMicroseconds(800);
 }
}
void loop(){
 step(true,1600);
 delay(500);
 step(false,1600*5);
 delay(500);
}

Thank you in advance for your help!

migrated from electronics.stackexchange.com Feb 6 '16 at 20:40

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

  • 2
    this is not a question – Brian Drummond Feb 6 '16 at 17:55
up vote 1 down vote accepted

You would first have to provide all the necessary information to your step() function: direction and number of steps for each motor. Then you just have to stop the loop at different points for each motor. You do this by running the loop up to the number of steps of whichever motor needs to run for longer, and making the steps of each motor conditional on the loop index, as follows:

void step(boolean dir0, int steps0,
          boolean dir1, int steps1,
          boolean dir2, int steps2) {
    digitalWrite(dir0Pin, dir0);
    digitalWrite(dir1Pin, dir1);
    digitalWrite(dir2Pin, dir2);
    delay(50);
    int max_steps = max(max(steps0, steps1), steps2);
    for (int i = 0; i < max_steps; i++) {
        if (i < steps0) digitalWrite(stepper0Pin, HIGH);
        if (i < steps1) digitalWrite(stepper1Pin, HIGH);
        if (i < steps2) digitalWrite(stepper2Pin, HIGH);
        delayMicroseconds(800);
        if (i < steps0) digitalWrite(stepper0Pin, LOW);
        if (i < steps1) digitalWrite(stepper1Pin, LOW);
        if (i < steps2) digitalWrite(stepper2Pin, LOW);
        delayMicroseconds(800);
    }
}

It would be more elegant to put the data for all the motors in an array, and you would probably want to do so if you have more than three motors.

You need a struct for each stepper with a timestamp, a position and rate of change and a loop that updates the postion based on rate which is the change in position over some time:

struct stepper {
  unsigned long timestamp;
  int position;
  int rate;
};

// init steppers array

while (keepGoing()) {
  unsigned long now = millis();
  int si;

  delay(10);

  for (si = 0; si < 3; si++) {
    struct stepper *stepper = &steppers[si];

    if (steppers[si].timestamp > now) {
       steppers[si].position += steppers[si].rate;
       steppers[si].timestamp = now + 100;
    }
  }

This is a back-of-a-napkin sketch of course. It is only supposed to illustrate how you can update any number of things concurrently.

The important thing is that you only call delay once. And presumably it would be only a very short delay compared to the unit of time for the rate. In the above example it would adjust the stepper position every 100ms. You would need to experiment with the timing to find a good behavior given the speed of the stepper, speed of the code and maximum permitted rate.

Beware that there is a lot to think about beyond this. For example, you should initialize the timstamps with different timestamps so that the motors are not all running at the same instant and thus try to minimize the total power consumed by the motors at any particular time.

Note that I have never played around with stepper motors but this type of loop is a common programming idiom for handling things concurrently.

  • 1. Your stepper pointer is a good idea: using it would make the code shorter and easier to read. But you forgot to use it... 2. You should not compare timestamps: this is bound to fail when millis() rolls over. You should compare durations instead. – Edgar Bonet Feb 7 '16 at 9:12

I have two ideas:

  • I don't have personal experience working with the AccelStepper Library, but I believe it implements a class that allows you to work with multiple steppers.
  • I plan on controlling two steppers for a project of my own (a self-balancing robot implemented with an STM32 processor), and I plan on using hardware timer interrupts to control the speed of my motors. A quick google search shows that a similar approach is possible with Arduino. You can probably use Timer0, as 1ms is fairly fast for a single step. This has several benefits...
    • The refresh function will run on set intervals, (allowing you to control the speed very precisely.
    • It will run with the correct timing, even if there is a function in loop() that is taking a long time.

Note: do NOT put any delay statements in your interrupt handlers. If you do this, it will probably prevent other interrupts from occurring and cause some API functions (such as millis or micros) to misbehave. In addition, the execution of anything in loop is halted while the interrupt is being handled, meaning that you would effectively stop everything until the interrupt is done. See the caveat in Arduino reference page for delay.

  • This is my first ever StackExchange answer, please let me know if there are any ways in which I can improve it. – Caleb Reister Feb 8 '16 at 7:07
  • 1
    Hi, welcome to arduino.stackexchange, and thanks for this first, constructive answer! You could improve it by giving an algorithm or prototype code for your second idea: judging from the level of the question, it seems the OP would have a hard time building this on his own. Also, it's worth noting that Timer0 is already used by Arduino core to provide timing functions. Buts since only the TIMER0_OVF_vect ISR is used for that purpose, you can still use TIMER0_COMPA_vect and TIMER0_COMPB_vect for the motors. – Edgar Bonet Feb 8 '16 at 8:55
  • I can write some code if I have time. However, it will be untested due to the fact that my Arduino board is broken (although it is probably just the ATMega chip). – Caleb Reister Feb 8 '16 at 16:16

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.