AccelStepper Library: Problems when switching between accelerated and constant

I use the phantastic AccelStepper Library by Mike McCauley to control two stepper motors. Sometimes I need the movement to be accelerated, other times to be constant.

My program behaves very strange: When I use a non-accelerated movement followed by an accelerated movement, both steppers move very slow (3 steps per second or so) for about 5 seconds before doing the accelerated movement they should be doing.

The library supports both accelerated and non-accelerated movements.
Generally, accelerated movements work by doing something like this:

stepperL.setMaxSpeed(144);
stepperR.setMaxSpeed(144);
stepperL.setAcceleration(200);
stepperR.setAcceleration(200);
stepperL.move(500);
stepperR.move(500);
void loop() {
  if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
    stepperL.run();
    stepperR.run();
  }
}

Non-accelerated movements (constant speed) work by doing something like this:

stepperL.setSpeed(144);
stepperR.setSpeed(144);
stepperL.move(500);
stepperR.move(500);
void loop() {
  if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
    stepperL.runSpeedToPosition();
    stepperR.runSpeedToPosition();
  }
}

The following is my code which tries to combine the two. If a ist set to 1, I want the movement to be accelerated. Otherwise it should be constant.

#include <AccelStepper.h>

// Define two steppers and the pins they will use
AccelStepper stepperR(1, 9, 8);
AccelStepper stepperL(1, 7, 6);

float acceleration = 200;
boolean accelerationMode = true;
float speedL;
float speedR;

void setup() {
  // Enable/disable pin for steppers
  pinMode(11, OUTPUT);
  digitalWrite(11, LOW); // low = enabled

  // Right motor
  stepperR.setEnablePin(11);
  stepperR.setPinsInverted(false, false, true); // invert direction & enable pin
  stepperR.enableOutputs(); // activate motor - normally happens on construction but since the enable pin is inverted, do it again
  stepperR.setAcceleration(acceleration);
  // Left motor
  stepperL.setEnablePin(11);
  stepperL.setPinsInverted(true, false, true); // invert enable pin
  stepperL.enableOutputs();
  stepperL.setAcceleration(acceleration);
}

void loop() {

  // Simplifying the code here for clarity. Every now and then (by far not at every execution of the loop), a command is executed like this:
  doCommand(stepsLeft, stepsRight, useAcceleration);

  // Are we busy? Set timer so that we can switch off motors after a while.
  if (readyForNextCommand == false) {
    millisSinceMotorUse = millis();
  }
  // When no commands arrive for some time, deactivate the motors.
  if (readyForNextCommand == true && (unsigned long)(millis() - millisSinceMotorUse) > disableMotorIntervall) {
    // Only act if the motors are enabled
    if (digitalRead(11) == LOW) {
      // Deactivate motors
      stepperL.disableOutputs();
      // Tell the server about it
      Serial.write("s");
    }
  }
  
  if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
    // Drive on.
    // With acceleration
    if (accelerationMode == true) {
      stepperL.setMaxSpeed(speedL);
      stepperR.setMaxSpeed(speedR);
      stepperL.run();
      stepperR.run();
    }
    // Without acceleration
    else if (accelerationMode == false){
      stepperL.setSpeed(speedL);
      stepperR.setSpeed(speedR);
      stepperL.runSpeedToPosition();
      stepperR.runSpeedToPosition(); 
    }
  }
}

void doCommand(long l, long r, long a) {
  speedL = 144;
  speedR = 144;  
  // Enable motors
  stepperL.enableOutputs();
  // Use acceleration?
  if (a == 1) {
    accelerationMode = true;
  }
  else if (a == 0) {
    accelerationMode = false;
  }
  stepperL.move(l);
  stepperR.move(r);
}

As stated above, when I use a non-accelerated movement followed by an accelerated movement, both steppers move very slow (3 steps per second or so) for about 5 seconds before doing the accelerated movement they should be doing.

So, if I call doCommand(200,200,0) and then doCommand(200,200,1), the strange slow-mo-movement happens.

Any idea how this is happening?

I wonder are you changing the mode before the previous movement has completed?

I can't figure that out from your code.

Why not write a very short program to explore this problem?

...R

Good idea, Robin2.

I wrote a very simple program that alternates between accelerated and non-accelerated mode. Now the accelerated movements work as expected while the non-accelerated movements are in slow-motion. Any ideas?

#include <AccelStepper.h>

// Define two steppers and the pins they will use
AccelStepper stepperR(1, 9, 8);
AccelStepper stepperL(1, 7, 6);

// Set some variables
float maxSpeed = 400;
float acceleration = 400;
boolean accelerationMode = false;
int accelerationCounter = 0;

void setup() {
 
  // Enable/disable pin for steppers
  pinMode(11, OUTPUT);
  digitalWrite(11, LOW); // low = enabled

  // Right motor
  stepperR.setEnablePin(11);
  stepperR.setPinsInverted(false, false, true); // invert direction & enable pin
  stepperR.enableOutputs(); // activate motor - normally happens on construction but since the enable pin is inverted, do it again
  stepperR.setAcceleration(acceleration);
  stepperR.setMaxSpeed(maxSpeed);
  // Left motor
  stepperL.setEnablePin(11);
  stepperL.setPinsInverted(true, false, true); // invert enable pin
  stepperL.enableOutputs();
  stepperL.setAcceleration(acceleration);
  stepperL.setMaxSpeed(maxSpeed);
}

void loop() {
 
  // When motors stand still, call the function that lets them run.
  if (stepperL.distanceToGo() == 0 && stepperR.distanceToGo() == 0) {
    doCommand(100,100);
  }

  // Otherwise, drive on.
  if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
    // With acceleration
    if (accelerationMode == true) {
      stepperL.run();
      stepperR.run();
    }
    // Without acceleration
    else if (accelerationMode == false){
      stepperL.runSpeed();
      stepperR.runSpeed(); 
    }
  }
}

void doCommand(long l, long r) {
  // Alternate between accelerated and non-accelerated mode.
  if (accelerationCounter % 2 == 0) {
    accelerationMode = true;
  }
  else {
    accelerationMode = false;
  }
  accelerationCounter++;
  // Use acceleration?
  if (accelerationMode == true) {
    stepperL.setMaxSpeed(maxSpeed);
    stepperR.setMaxSpeed(maxSpeed);
  }
  else if (accelerationMode == false) {
    stepperL.setSpeed(maxSpeed);
    stepperR.setSpeed(maxSpeed);
  }
  // Register step command for motors
  stepperL.move(l);
  stepperR.move(r);
}

By the way, the AccelStepper website says, "DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS". I am not sure what lists he is referring to, though, and could not find any.

I'm not sure that this line is needed - I think it will stop automatically when it reaches the target

if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {

I wonder if you should use runSpeedToPosition() rather than runSpeed()

I don't know if that would have any effect on the speed.

Have you tried accelerated and non-accelerated motion in two separate programs?

...R

I solved the problem by

  • calling setSpeed() and setMaxSpeed() in the Loop and thus constantly instead of only when a movement is ordered.
  • using runSpeedToPosition() instead of runSpeed() (good guess, Robin2)
  • calling stop() before ordering a new movement.

I'm glad it works but I think there is room for improvement in the AccelStepper documentation. Better description of the functions would help preventing this trial-and-error approach :). That said, I'm still glad AccelStepper exists.

Below is the working code of my previous simplified program which alternates between accelerated and non-accelerated movement.

#include <AccelStepper.h>

// Define two steppers and the pins they will use
AccelStepper stepperL(1, 7, 6);
AccelStepper stepperR(1, 9, 8);

// Set some variables
float maxSpeed = 400;
float acceleration = 100;
boolean accelerationMode = false;
int accelerationCounter = 0;

void setup() {
 
  // Enable/disable pin for steppers
  pinMode(11, OUTPUT);
  digitalWrite(11, LOW); // low = enabled

  // Right motor
  stepperR.setEnablePin(11);
  stepperR.setPinsInverted(false, false, true); // invert direction & enable pin
  stepperR.enableOutputs(); // activate motor - normally happens on construction but since the enable pin is inverted, do it again
  stepperR.setAcceleration(acceleration);
  stepperR.setMaxSpeed(maxSpeed);
  // Left motor
  stepperL.setEnablePin(11);
  stepperL.setPinsInverted(true, false, true); // invert enable pin
  stepperL.enableOutputs();
  stepperL.setAcceleration(acceleration);
  stepperL.setMaxSpeed(maxSpeed);
}

void loop() {
 
  // When motors stand still, call the function that lets them run.
  if (stepperL.distanceToGo() == 0 && stepperR.distanceToGo() == 0) {
    doCommand(100,100);
  }

  // Otherwise, drive on.
  if (stepperL.distanceToGo() != 0 || stepperR.distanceToGo() != 0) {
    // With acceleration
    if (accelerationMode == true) {
      stepperL.setMaxSpeed(maxSpeed);
      stepperR.setMaxSpeed(maxSpeed);
      stepperL.run();
      stepperR.run();
    }
    // Without acceleration
    else if (accelerationMode == false){
      stepperL.setSpeed(maxSpeed);
      stepperR.setSpeed(maxSpeed);
      stepperL.runSpeedToPosition();
      stepperR.runSpeedToPosition(); 
    }
  }
}

void doCommand(long l, long r) {
  stepperL.stop();
  stepperR.stop();
  // Alternate between accelerated and non-accelerated mode.
  if (accelerationCounter % 2 == 0) {
    accelerationMode = true;
  }
  else {
    accelerationMode = false;
  }
  accelerationCounter++;
  // Register step command for motors
  stepperL.move(l);
  stepperR.move(r);
}

I know this thread is a few months old, but on the main AccelStepper library page there is a link to the Google Groups page for AccelStepper.

The forum there has a number of people experienced with the library, helping with issue like this.

I will say the library is fantastic for what it does, but it does have a somewhat steep learning curve for some of the features.