Controlling several Steppers using millis()

Hello,

my first question I am asking in this forum. I just got started with building more complex arduino projects.

Right now I am setting up a few steppers that are already working and have a built in delay. Now I am trying to get rid of the delay so I am not blocking my whole microcontroller because while the motors are moving there will be a heater turning on and off at certain points.
I wanted to replace delay() with millis() but somehow I don’t know how to change the code I already have to make it work. So far the code compiles and the steppers get powered but do not move so far. (I tried it with one stepper for the moment and with only two steps to first get my head around it until I start to write the whole code.)

I attach the code that makes the steppers work and the new one where I followed the instructions of “Several things at the same time” (http://forum.arduino.cc/index.php?topic=223286.0) to combine it with my code. phoenix_2 is the so far working one

// the working one including delay()
#include <AccelStepper.h>

// leading steppers
AccelStepper stepperAa(1, 5, 4);
// Arm stepper left
AccelStepper stepperB(1,9, 8);
 
int state = 0;

// {StepperAa, stepperB}

long position1[2] = { 1600, 1600 };
long position2[2] = { 0, 0 };
long position3[2] = { -1600, 0 };
long position4[2] = { 0, 0 };

void setup()
{

   // Set all default speeds and accelerations
   stepperAa.setMaxSpeed(6000);
   stepperAa.setAcceleration(600);
   stepperB.setMaxSpeed(6000);
   stepperB.setAcceleration(600);
}

void loop()
{  
     
     if (stepperAa.distanceToGo() == 0 && stepperB.distanceToGo() == 0) 
   
   {
    if (state == 0) 
    {
      stepperAa.moveTo(position1[0]);
      stepperB.moveTo(position1[1]);
      delay(5000);
    }
    
    if (state == 1) 
    {
      stepperAa.moveTo(position2[0]);
      stepperB.moveTo(position2[1]);
      delay(5000);
    }

    if (state == 2)
    {
      stepperAa.moveTo(position3[0]);
      stepperB.moveTo(position3[1]);
      delay(5000);
    }
  
    if (state == 3) 
    {
      stepperAa.moveTo(position4[0]);
      stepperB.moveTo(position4[1]);
      delay(1000);
    }
    
    state++;

   }
     
   stepperAa.run();
   stepperB.run();
}

and phoenix_2_millis the one where I tried to use millis().

// the not working one including millis()

#include <AccelStepper.h>

// leading steppers
AccelStepper StepperAa(1, 5, 4);
// Arm stepper left
//AccelStepper StepperB(1,9, 8);
 
//int state = 0;

// {StepperAa, stepperB}

long position1[2] = { 1600, 1600 };
long position2[2] = { 0, 0 };
long position3[2] = { -1600, 0 };
long position4[2] = { 0, 0 };

// ---------------------interval ---------------------

const int StepperAaInterval = 5000;
const int StepperBInterval = 5000;

// ---------------------millis ---------------------

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousStepperAaMillis = 0;   // will store last time the steppers were updated
unsigned long previousStepperBMillis = 0;


//================================================================================

void setup()
{

  Serial.begin(115200);
  Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino"); 

 
   // Set all default speeds and accelerations
   StepperAa.setMaxSpeed(6000);
   StepperAa.setAcceleration(600);
 //  StepperB.setMaxSpeed(6000);
 //  StepperB.setAcceleration(600);
}


//================================================================================

void loop()
{  


    currentMillis = millis();   // capture the latest value of millis()
                              //   this is equivalent to noting the time from a clock
                              //   use the same time for all LED flashes to keep them synchronized
  
  StepperAa.run();  // call the functions that do the work
//  StepperB.run();
}

//========================================

void run() {

StepperAa.run();
  if (StepperAa.distanceToGo() == 0)
  {
    if (currentMillis - previousStepperAaMillis >= StepperAaInterval) {
      StepperAa.moveTo(position1[0]);
       previousStepperAaMillis += StepperAaInterval;
    }
  }
  else {
    if (currentMillis - previousStepperAaMillis >= StepperAaInterval) {
       StepperAa.distanceToGo() == 0;
       previousStepperAaMillis += StepperAaInterval;
    }
  }    

    if (StepperAa.distanceToGo() == 0)
  {
    if (currentMillis - previousStepperAaMillis >= StepperAaInterval) {
      StepperAa.moveTo(position2[0]);
       previousStepperAaMillis += StepperAaInterval;
    }
  }
  else {
    if (currentMillis - previousStepperAaMillis >= StepperAaInterval) {
       StepperAa.distanceToGo() == 0;
       previousStepperAaMillis += StepperAaInterval;
    }
  }    
StepperAa.run();
  
}

It would be awesome if someone knows where I made a mistake and can point me in the right direction.

Best
Julius

phoenix_2_millis.ino (3.4 KB)

phoenix_2.ino (1.45 KB)

Please post your code using code tags if you want ppl to mind your topic, ppl are less prone to download and inspect it. Have you read this guide?

The second example in this Simple Stepper Code uses millis() and micros() for non-blocking control of the motor. The concept can easily be extended to several motors.

...R Stepper Motor Basics

your use of millis() timing looks ok, but you never call your run function.

void loop()
{
  currentMillis = millis();   // capture the latest value of millis()
                              //   this is equivalent to noting the time from a clock
                              //   use the same time for all LED flashes to keep them synchronized

  run();    // call your function <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

  StepperAa.run();  // call the functions that do the work
  //  StepperB.run();
}

Thank you for the quick responses. I have read the examples you postet before but they dont really help me or tell me stuff I already figured out.

Calling the run function helped at least to move the stepper to the first position. I might try to figure out how the stepper goes to next ones as well and how to create a loop out of it.

So my code looks now like this and it is compiling but the steppers are not running. Any ideas?

#include <AccelStepper.h>

// leading steppers
AccelStepper StepperAa(1, 5, 4);
// Arm stepper left
AccelStepper StepperB(1,9, 8);


// {StepperAa, stepperB}

long position1[2] = { 1600, 1600 };
long position2[2] = { 0, 0 };
long position3[2] = { -1600, 0 };
long position4[2] = { 0, 0 };

// ---------------------interval ---------------------

unsigned long Interval = 1000;
//const int StepperBInterval = 1000;

// ---------------------millis ---------------------

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousMillis = 0;   // will store last time the steppers were updated
// unsigned long previousStepperBMillis = 0;


//================================================================================

void setup()
{
  // Set all default speeds and accelerations
  StepperAa.setMaxSpeed(6000);
  StepperAa.setAcceleration(600);
  StepperB.setMaxSpeed(6000);
  StepperB.setAcceleration(600);

  Serial.begin(115200);
  Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino"); 
}


//================================================================================

void loop()
{  

  currentMillis = millis();   // capture the latest value of millis()
                              //   this is equivalent to noting the time from a clock

   run(); //call your function
   StepperAa.run();  // call the functions that do the work
   StepperB.run();
}

//========================================

void run() {

   if (StepperAa.distanceToGo() == 0 && StepperB.distanceToGo() == 0)    
   {
    if (currentMillis - previousMillis >= Interval) {
       StepperAa.moveTo(position1[0]);
       StepperB.moveTo(position1[1]);
     
      previousMillis = currentMillis;
    }
    
     if (currentMillis - previousMillis >= Interval) {
        StepperAa.moveTo(position2[0]);
        StepperB.moveTo(position2[1]);
        
        previousMillis = currentMillis;
     }
    
      if (currentMillis - previousMillis >= Interval) {
        StepperAa.moveTo(position3[0]);
        StepperB.moveTo(position3[1]);
        
        previousMillis = currentMillis;
    }
    
      if (currentMillis - previousMillis >= Interval) {
        StepperAa.moveTo(position4[0]);
        StepperB.moveTo(position4[1]);
        previousMillis = currentMillis; 
   }
     

}
}

Good job getting the timers to work. But you only need one.

You left out a important part of the original sketch, the State Machine Think of it as a way to schedule things.

Oh, And don't forget you are already in the loop() :)

JuliusDigital: So my code looks now like this and it is compiling but the steppers are not running. Any ideas?

The lines of code from 70 to 88 will never be called because the work will have been done by lines 63 to 68.

I don't understand why you are using millis() - you seem to be trying to get something to happen once per second, but I'm not sure what?

Are you trying to get the motors to move some distance and then have an interval before the next movement starts? If so I would program that like this pseudo code

void loop() {
   if (millis() - prevMoveEnd >= interval) {
       stepper.moveTo()
       stepperMoving = true;
   }
   if (stepper.distanceToGo == 0 and stepperMoving == true) {
       prevMoveEnd = millis();
       interval = nextInterval;
       stepperMoving = false;
   }
   stepper.run()
}

...R

try to add separate millis variables like stepperAPrevTime, StepperAcurrentTime for code in #5

Thanks for all the advice. I figured it out with the help of a friend. It now looks like this and is working so far.

#include <AccelStepper.h>

// leading steppers
AccelStepper StepperAa(1, 9, 8);
AccelStepper StepperAb(1, 11, 10);
// Arm stepper left
AccelStepper StepperB(1,5, 4);
AccelStepper StepperC(1, 7, 6);





int state = 0;

// {StepperAa, stepperB}

long position1[3] = { 1600, 1600, 0};
long position2[3] = { 0, 0, 0};
long position3[3] = { -1600, 0, -1600 };
long position4[3] = { 0, 0, 0 };

// ---------------------interval ---------------------

unsigned long Interval = 1000*60;

// ---------------------millis ---------------------

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousMillis = 0;   // will store last time the steppers were updated
// unsigned long previousStepperBMillis = 0;


//================================================================================

void setup()
{
  // Set all default speeds and accelerations
  StepperAa.setMaxSpeed(6000);
  StepperAa.setAcceleration(600);
  StepperAb.setMaxSpeed(6000);
  StepperAb.setAcceleration(600);
  StepperB.setMaxSpeed(6000);
  StepperB.setAcceleration(600);
  StepperC.setMaxSpeed(6000);
  StepperC.setAcceleration(600);



  Serial.begin(115200);
}


//================================================================================

void loop()
{  
   currentMillis = millis();    // capture the latest value of millis()
                                // this is equivalent to noting the time from a clock

   run(); //call your function
   StepperAa.run();// call the functions that do the work
   StepperAb.run(); 
   StepperB.run();
   StepperC.run();
}

//========================================

void run() {

  if (currentMillis - previousMillis >= Interval) {
    
     if (StepperAa.distanceToGo() == 0 && StepperB.distanceToGo() == 0) {

        if (state == 0) {
            StepperAa.moveTo(position1[0]);
            StepperAb.moveTo(position1[0]);
            StepperB.moveTo(position1[1]);
            StepperC.moveTo(position1[2]);

       

            
            Interval = 1000*300;
        } 
        if (state == 1) {
            StepperAa.moveTo(position2[0]);
            StepperAb.moveTo(position2[0]);
            StepperB.moveTo(position2[1]);
            StepperC.moveTo(position2[2]);


           
            Interval = 1000*60; 
        }
        if (state == 2) {
            StepperAa.moveTo(position3[0]);
            StepperAb.moveTo(position3[0]);
            StepperB.moveTo(position3[1]);
            StepperC.moveTo(position3[2]);




            Interval = 1000*300;
        }
        if (state == 3) {
            StepperAa.moveTo(position4[0]);
            StepperAb.moveTo(position4[0]);
            StepperB.moveTo(position4[1]);
            StepperC.moveTo(position4[2]);



            Interval = 1000*60;
        }
  
        Serial.println(state);

        if (state < 3) {
          state++;
         } else {
          state = 0;
         }

          previousMillis = currentMillis;
    }
  }
}

That looks like a good scheme.

It would not work any better but it might be easier to follow in 6 months time if you give names to the states. You can use an ENUM to do that or you could use a char variable and make the States the first letter of each name. For example if the first action is "Drain" and the second action is "Fill" (completely made-up names) then you could have something like

if (state == 'D') {
   // do stuff
   state = 'F'
}

The code in this link (Reply #15) illustrates the use of an ENUM.

...R