stopping and starting with accelstepper

hi

i think i’m trying to do a simple thing but i can’t quite work it out. i’ve tried to adapt several examples i’ve looked at in the IDE and on the forum, so far to no avail.

i have 3 steppers, each with its own big easy driver, controlled via the accepstepper library. each motor needs to run for X steps, then pause X time, then restart again. i have it working fine as a constant loop - i.e. no pause - but as soon as i start trying to put a delay in the timings all go to pot and the motors are stopping and starting when i don’t want them to.

this is the code i am working with. if someone could give me a pointer as to where the delay should go (or if i should even use a delay) i’d be very grateful.

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);
AccelStepper stepper2(1, 6, 5);
AccelStepper stepper3(1, 10, 9);

void setup()
{  
 
   pinMode(3, OUTPUT);       //MS3 - stepper1
   digitalWrite(3, LOW);
   pinMode(4, OUTPUT);       //MS2 - stepper1
   digitalWrite(4, LOW); 
   pinMode(7, OUTPUT);       //MS3 - stepper2
   digitalWrite(7, LOW);
   pinMode(8, OUTPUT);       //MS2 - stepper2
   digitalWrite(8, LOW);
   pinMode(11, OUTPUT);       //MS3 - stepper3
   digitalWrite(11, LOW);
   pinMode(12, OUTPUT);       //MS2 - stepper3
   digitalWrite(12, LOW);
  
   
   pinMode(1, OUTPUT);       //direction
   digitalWrite(1, LOW);
   pinMode(2, OUTPUT); 
   digitalWrite(2, HIGH);
   pinMode(5, OUTPUT);       //direction
   digitalWrite(5, LOW);
   pinMode(6, OUTPUT); 
   digitalWrite(6, HIGH);
   pinMode(9, OUTPUT);       //direction
   digitalWrite(9, LOW);
   pinMode(10, OUTPUT); 
   digitalWrite(10, HIGH);
   
   

   stepper1.setMaxSpeed(895);   //kepler 10-b
   stepper1.setAcceleration(40); 
   //stepper1.move(1000); 
  
   
   
   stepper2.setMaxSpeed(919); //55 cnc e
   stepper2.setAcceleration(40); 
   //stepper2.move(1200);
  
   
   
   stepper3.setMaxSpeed(686); //GJ 1132b
   stepper3.setAcceleration(40); 
   //stepper3.move(1000); 
  
   

}

void loop()
{  
  
   if (stepper1.distanceToGo() == 0)
   {
     stepper1.move(1000);
   }
  
    if (stepper2.distanceToGo() == 0)
    {
      stepper2.move(1200);
    }
    
   if (stepper3.distanceToGo() == 0)
     {
      stepper3.move(1000); 
     }
      
      
    stepper1.run();
    stepper2.run();
    stepper3.run();
   
 
   
}

You can't use delay() because it blocks everything else. Use mills() to manage timing without blocking as illsutrated in Several Things at a Time

You should ensure that loop() can repeat hundreds or thousands of times per second so that stepper.run() is called often

I don't know what you want to achieve so I can't give more precise advice.

For example do you want to stop the motors in the middle of a move? Or do you just want to put a pause after they have all finished and before the next moves start?

...R
Stepper Motor Basics

thanks for the response. i want them to complete the steps (say 20000) then pause for x seconds (say 60) then repeat ad infinitum.

i'll take a look at the millis way, but shortcuts always appreciated :smiley:

blamski:
i'll take a look at the millis way, but shortcuts always appreciated :smiley:

If you can find a shorter way I will be interested :slight_smile:

...R

the shortest way is getting someone else to do it for you :grin:

some progress made, following the useful tutorial here - millis() Tutorial: Arduino Multitasking - Bald Engineer

my code is below, adapted from the example to fit my project. only that the steppers seem to move only 1 step at a time with a pause of 2 secs between each step. what am i missing? does ‘stepper1.move(1000)’ need to be in the loop?

thanks

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);
AccelStepper stepper2(1, 6, 5);
AccelStepper stepper3(1, 10, 9);

// each "event" (stepper) gets their own tracking variable
unsigned long previousMillisstep1=0;
unsigned long previousMillisstep2=0;
unsigned long previousMillisstep3=0;
 
// intervals for each stepper
int intervalstep1 = 2000;
int intervalstep2 = 2000;
int intervalstep3 = 2000;
 
 
void setup() 
{  
 
   pinMode(3, OUTPUT);       //MS3 - stepper1
   digitalWrite(3, LOW);
   pinMode(4, OUTPUT);       //MS2 - stepper1
   digitalWrite(4, LOW); 
   pinMode(7, OUTPUT);       //MS3 - stepper2
   digitalWrite(7, LOW);
   pinMode(8, OUTPUT);       //MS2 - stepper2
   digitalWrite(8, LOW);
   pinMode(11, OUTPUT);       //MS3 - stepper3
   digitalWrite(11, LOW);
   pinMode(12, OUTPUT);       //MS2 - stepper3
   digitalWrite(12, LOW);
  
   
   pinMode(1, OUTPUT);       //direction
   digitalWrite(1, LOW);
   pinMode(2, OUTPUT); 
   digitalWrite(2, HIGH);
   pinMode(5, OUTPUT);       //direction
   digitalWrite(5, LOW);
   pinMode(6, OUTPUT); 
   digitalWrite(6, HIGH);
   pinMode(9, OUTPUT);       //direction
   digitalWrite(9, LOW);
   pinMode(10, OUTPUT); 
   digitalWrite(10, HIGH);
   
   

   
   stepper1.setMaxSpeed(895);   //kepler 10-b
   stepper1.setAcceleration(40); 
   stepper1.move(1000); 
   
   stepper2.setMaxSpeed(919); //55 cnc e
   stepper2.setAcceleration(40); 
   stepper2.move(1200);
   
   stepper3.setMaxSpeed(686); //GJ 1132b
   stepper3.setAcceleration(40); 
   stepper3.move(1000); 

}
void loop() {
   // get current time stamp
   // only need one for both if-statements
   unsigned long currentMillis = millis();
 
 
   if ((unsigned long)(currentMillis - previousMillisstep1) >= intervalstep1) {
    digitalWrite(1, LOW);
   stepper1.run();
      previousMillisstep1 = currentMillis;
   }
 
  if ((unsigned long)(currentMillis - previousMillisstep2) >= intervalstep2) {
    digitalWrite(5, LOW);
   stepper2.run();
      previousMillisstep2 = currentMillis;
  }
  
    if ((unsigned long)(currentMillis - previousMillisstep3) >= intervalstep3) {
    digitalWrite(5, LOW);
   stepper3.run();
      previousMillisstep3 = currentMillis;
  }
}

That is certainly NOT the way to do it.

stepper.move() only tells the library what the destination is. It does not cause any moves to happen. stepper.run() is what causes a move to happen if a move is due (depending on the speed required).

I think you need something like this (not tested)

if (stepper.distanceToGo() == 0) and timerStarted == false {
   stepperStoppedMillis = millis();
   timerStarted = true;
}
if (millis() - stepperStoppedMillis >= stoppedInterval) {
   stepper.move(20000);
   timerStarted = false;
}
stepper.run();

...R

apologies. i hadn't seen this post of yours before asking in the other thread aswell. (the other tthread seemed appropriate as my questions were more programming related than motor related, but apologies if that was the wrong call).

so i need to declare 'stepperStoppedMillis' before the set up, right?

i'll give it a go. thanks.

blamski:
so i need to declare 'stepperStoppedMillis' before the set up, right?

Yes. Make it unsigned long.
You also need to define timerStarted as boolean.

And you probably need a different one of each of these for your 3 motors.

...R

i’ve got this far following your (much appreciated) advice. i’ve defined timerStarted as a boolean as you said, and have checked the reference to see that i’m doing it correctly. however when i try to compile the code i get an error stating ‘error: label ‘timerStarted’ used but not defined’. i’ve been unable to find out how to recify this

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);

unsigned long currentTime;
unsigned long loopTime;
unsigned long stepperStoppedMillis;
unsigned long stoppedInterval;

boolean timerStarted = true;

void setup()
{
  
  pinMode(3, OUTPUT);       //MS3 - stepper1
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);       //MS2 - stepper1
  pinMode(1, OUTPUT);       //direction
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT); 
  digitalWrite(2, HIGH);
 
 
  stepper1.setMaxSpeed(895);   //kepler 10-b
  stepper1.setAcceleration(40); 
  stepper1.move(1000); 
  
  currentTime = millis();
 
}


void loop()
{
if (stepper1.distanceToGo() == 0) and timerStarted == false; {
  stepperStoppedMillis = millis();
  timerStarted = true;
}
if (millis() - stepperStoppedMillis >= stoppedInterval) {
  stepper1.move(20000);
  timerStarted = false;
}
stepper1.run();

}

in case any one out there is still intrested i got this far so far. i resolved the error with the ‘timerStarted’ boolean and got to upload the code. again, i’ve tried a few things but the motor just sits there not spinning. i tried a little debugging using serial.print and got the following values from the following statements

stepperStoppedMillis - goes up and up and up and…
currentTime - remains at 0
stepper1.distanceToGo - remains at 0
timerStarted - always reads 1 (true)

i think i infer from this that for some reason the stepper ‘thinks’ it has got where it needs to go, the current time is not updating, and the stepper is stopped for ever, never triggering the threshold set by stoppedInterval.

i just wish i could work out why

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);

unsigned long currentTime;
//unsigned long loopTime;
unsigned long stepperStoppedMillis;
unsigned long stoppedInterval = 5000;

boolean timerStarted = false;

void setup()
{

  pinMode(3, OUTPUT);       //MS3 - stepper1
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);       //MS2 - stepper1
  pinMode(1, OUTPUT);       //direction
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);


  stepper1.setMaxSpeed(895);   //kepler 10-b
  stepper1.setAcceleration(40);
  //stepper1.move(1000);

  currentTime = millis();
  
  
  Serial.begin(9600);

}


void loop()
{
  if (stepper1.distanceToGo() == 0 && timerStarted == false); 
  {
    stepperStoppedMillis = millis();
    timerStarted = true;
  }
  if (millis() - stepperStoppedMillis >= stoppedInterval) 
  {
    stepper1.move(2000);
    timerStarted = false;
  }
  stepper1.run();
  Serial.println(timerStarted);

}

The semicolon at the end of this line is a mistake

  if (stepper1.distanceToGo() == 0 && timerStarted == false);

You need to guard the timer expiry test with timerStarted like this:

  if (timerStarted && millis() - stepperStoppedMillis >= stoppedInterval)

MarkT:
You need to guard the timer expiry test with timerStarted like this:

  if (timerStarted && millis() - stepperStoppedMillis >= stoppedInterval)

That's a good idea.

...R

i have this code now. the result is that the motor spins, increases velocity after 2 seconds, then keeps on spinning. i guess its close…

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);

unsigned long currentTime;
//unsigned long loopTime;
unsigned long stepperStoppedMillis;
unsigned long stoppedInterval = 5000;

boolean timerStarted = false;

void setup()
{

  pinMode(3, OUTPUT);       //MS3 - stepper1
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);       //MS2 - stepper1
  pinMode(1, OUTPUT);       //direction
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);


  stepper1.setMaxSpeed(895);   //kepler 10-b
  stepper1.setAcceleration(40);
  //stepper1.move(1000);

  currentTime = millis();
  
  
  Serial.begin(9600);

}


void loop()
{
   if (timerStarted && millis() - stepperStoppedMillis >= stoppedInterval) 
  {
    stepperStoppedMillis = millis();
    timerStarted = true;
  }
  if (millis() - stepperStoppedMillis >= stoppedInterval) 
  {
    stepper1.move(2000);
    timerStarted = false;
  }
  stepper1.run();
  Serial.println(timerStarted);

}

i also have this simpler experiment that i was working on in the meantime and which has some success. i get the motor to repeat its steps, however the pause (intervalStep1) appears to begin to count from the beginning of the motor movement, not from when it stops. i imagine i would need to implement ‘distanceToGo()’ and a boolean… would that be the right line of thinking?

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);

unsigned long currentTime;
//unsigned long loopTime;
unsigned long stepperStoppedMillis;
unsigned long stoppedInterval = 5000;

boolean timerStarted = false;

void setup()
{

  pinMode(3, OUTPUT);       //MS3 - stepper1
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);       //MS2 - stepper1
  pinMode(1, OUTPUT);       //direction
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT);
  digitalWrite(2, HIGH);


  stepper1.setMaxSpeed(895);   //kepler 10-b
  stepper1.setAcceleration(40);
  //stepper1.move(1000);

  currentTime = millis();
  
  
  Serial.begin(9600);

}


void loop()
{
   if (timerStarted && millis() - stepperStoppedMillis >= stoppedInterval) 
  {
    stepperStoppedMillis = millis();
    timerStarted = true;
  }
  if (millis() - stepperStoppedMillis >= stoppedInterval) 
  {
    stepper1.move(2000);
    timerStarted = false;
  }
  stepper1.run();
  Serial.println(timerStarted);

}

blamski:
i have this code now.

That is not what I suggested in Reply #6

...R

unless i'm missing something, the only thing that has changed - apart form the addition of a serial.print - is the change in the way that the timer expiry test is performed, which you agreed was a good idea.

of course, me missing something is very possible, but i don't see any other differences with my beginner's eyes.

This line

if (stepper.distanceToGo() == 0) and timerStarted == false {

And I have just realized you have put @MarkT's suggestion on the wrong line.

It should be like this

void loop()
{

   if (stepper.distanceToGo() == 0 && timerStarted == false)
  {
    stepperStoppedMillis = millis();
    timerStarted = true;
  }
  if (timerStarted == true && millis() - stepperStoppedMillis >= stoppedInterval)
  {
    stepper1.move(2000);
    timerStarted = false;
  }
  stepper1.run();
  Serial.println(timerStarted);

}

...R

i have been unable to get the code using the boolean timerStarted to function satisfactorily. the motor will accelerate, then a couple of seconds later accelerate some more, and then a little more, and then spin continuously.

seeing as i only have a day left, i went back to work some more on earlier ideas and suggestions and have some code which is for the most part working. i get the motors to spin at the speeds i want, with the acceleration i want, and with pauses between rotations.

but now i found another confusing issue. as you can see in the code below the ‘intervalstep’ declared at the top is set to 32000. anything up to 32000 works fine, but if i go over then nothing happens - i.e. if i set the intervalstep to 33000 the motors will not move again after the couple of revolutions stipulated in the setup(). this is a bit of an issue as i actually need in the running of the piece to have both the number of steps and the intervals increased by a factor of 10.

if anybody else needs to work on something with shorter spin and rest durations then please feel free to use this. and thanks and big Karma to all those who have helped.

#include <AccelStepper.h>

AccelStepper stepper1(1, 2, 1);
AccelStepper stepper2(1, 6, 5);
AccelStepper stepper3(1, 10, 9);


unsigned long previousMillisstep1 = 0;
unsigned long previousMillisstep2 = 0;
unsigned long previousMillisstep3 = 0;

int intervalstep1 = 32000;
int intervalstep2 = 32000;
int intervalstep3 = 32000;



void setup()
{
  
  // set to half step

  pinMode(3, OUTPUT);       
  digitalWrite(3, LOW);
  pinMode(4, OUTPUT);      
  digitalWrite(4, LOW);
  pinMode(7, OUTPUT);       
  digitalWrite(7, LOW);
  pinMode(8, OUTPUT);      
  digitalWrite(8, LOW);
  pinMode(11, OUTPUT);      
  digitalWrite(11, LOW);
  pinMode(12, OUTPUT);      
  digitalWrite(12, LOW);
  
  // set step and direction

  pinMode(1, OUTPUT);      
  digitalWrite(1, LOW);
  pinMode(2, OUTPUT);      
  digitalWrite(2, HIGH);
  pinMode(5, OUTPUT);      
  digitalWrite(5, LOW);
  pinMode(6, OUTPUT);
  digitalWrite(6, HIGH);
  pinMode(9, OUTPUT);      
  digitalWrite(9, LOW);
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  
  // set speed, acceleration + spin 2 revolutions on start-up

  stepper1.setMaxSpeed(895);
  stepper1.setAcceleration(40);
  stepper1.move(800);
  stepper2.setMaxSpeed(919);
  stepper2.setAcceleration(40);
  stepper2.move(800);
  stepper3.setMaxSpeed(686);
  stepper3.setAcceleration(40);
  stepper3.move(800);

}

void loop() {

  unsigned long currentMillis1 = millis();

  if ((unsigned long)(currentMillis1 - previousMillisstep1) >= intervalstep1)
  
  {
    previousMillisstep1 = currentMillis1;
    
    stepper1.move(5000);
   
  }
  
   unsigned long currentMillis2 = millis();
  
   if ((unsigned long)(currentMillis2 - previousMillisstep2) >= intervalstep2)
  
  {
    previousMillisstep2 = currentMillis2;
    
    stepper2.move(5000);
  }
  
    
   unsigned long currentMillis3 = millis();
  
   if ((unsigned long)(currentMillis3 - previousMillisstep3) >= intervalstep3)
  
  {
    previousMillisstep3 = currentMillis3;
    
    stepper3.move(5000);
  }
  
  stepper1.run();
  stepper2.run();
  stepper3.run();

}

ah, ok.... i fixed it. changing 'int intervalstep' to 'unsigned long intervalstep' obviously allows me to use bigger numbers.

i'm going to consider this SOLVED

thanks everyone

another question:

my project requires that at the end of each revolution cycle the stepper motor positions the thing it is spinning exactly infront of a camera. however, i have noticed that instead of doing one complete cycle of 400 steps (i'm using half-stepping) it seems to be doing something like 402, or 403. a tiny amount but one that over time adds up to the device being nowhere near the camera at all.

i have read that starting and stopping a motor fast using the accelstepper library can lead to the occasional missed step. i am using an acceleration (and deceleration) value of 60. does anyone have experience of how working with acceleration times can affect the accuracy of stepper positioning?

i'm using the accelstepper library and the big easy driver.