Stepper Motor: Acceleration from constant speed

Hi,

I currently have a code that accelerates a motor from 0 to 600RPM and then holds at this speed, I am attempting to hold this speed for 10 seconds before then accelerating to a higher speed. Any tips on how to do so would be much appreciatedhttps://wokwi.com/projects/364072010221261825

#include <AccelStepper.h>

AccelStepper stepper(1,3,2);
float speedMultiplier = 1.00005;
int en = 10;

int steps = 200; //number of steps per revolution
long last = 0;
int lag = 500; //time (ms) interval for display
int dir = 1; //direction of rotation
float rpm, v, oldspeed, a;
int nsteps;
 
void setup() {
  Serial.begin(9600); // define Serial output baud rate
  pinMode(en, OUTPUT);
  digitalWrite(en, HIGH);
  stepper.setMaxSpeed(2000); //max speed 2000 steps/s
  stepper.setAcceleration(50);//acceleration rate(steps/s^2)
  stepper.setSpeed(200);
  Serial.println("Outputs:");
  Serial.println("                           (+ve=clockwise, -ve=counter clockwise)");
  Serial.println("No. of Steps      RPM        Acceleration(steps/s^2)       Speed(steps/s)");
  Serial.println("-------------------------------------------------------------------\n");

}
void loop(){
  stepper.runSpeed();
  stepper.setSpeed(stepper.speed() * speedMultiplier);
      if (stepper.speed()==1000)
      stepper.setSpeed(1000);
      stepper.moveTo(20000);
      stepper.run();
  if (millis() > last + lag) //lag time elapsed since last print
  {
    v = stepper.speed(); //get motor speed (steps/s)
    nsteps = v * lag / pow(10, 3); //No. of steps taken during lag time
    rpm = 60.0 * v / steps; //RPM
    a = (v - oldspeed) * 1000.0 / lag; //Acceleration
    oldspeed = v; //update speed value
    last = millis(); //update last print time


    //Outputs
    //print No. of Steps
    Serial.print(String(nsteps) + "\t\t");
    //print RPM
    Serial.print(String(rpm, 2) + "\t\t");
    //print Acceleration
    Serial.print(String(a, 2) + "\t\t\t");
    //print Speed
    Serial.println(String(v));
  }
}

Current hardware is a A4988 driver and 42-40 NEMA 17 but in the simulation this is represented as a bipolar stepper motor

Please let the IDE format your sketch, then you'll see some structural errors.

If you want to change the speed then set the desired speed. If you want to know when that speed really is reached then watch the actual speed.

Addressing the speed change first...

  1. put each speed in its own function (600 is done)
  2. select speed function
  3. check for target speed
  4. if not reached goto 3
  5. if target reached, start timer
  6. If timer > 10 seconds, next speed function

Here I move the speed600 to its own function and called the function from void loop().

#include <AccelStepper.h>

AccelStepper stepper(1, 3, 2);
float speedMultiplier = 1.00005;
int en = 10;

int steps = 200; //number of steps per revolution
long last = 0;
int lag = 500; //time (ms) interval for display
int dir = 1; //direction of rotation
float rpm, v, oldspeed, a;
int nsteps;

void setup() {
  Serial.begin(9600); // define Serial output baud rate
  pinMode(en, OUTPUT);
  digitalWrite(en, HIGH);
  stepper.setMaxSpeed(2000); //max speed 2000 steps/s
  stepper.setAcceleration(50);//acceleration rate(steps/s^2)
  stepper.setSpeed(200);
  Serial.println("Outputs:");
  Serial.println("                           (+ve=clockwise, -ve=counter clockwise)");
  Serial.println("No. of Steps      RPM        Acceleration(steps/s^2)       Speed(steps/s)");
  Serial.println("-------------------------------------------------------------------\n");
}

void loop() {
  rpm600();
  if (millis() > last + lag) //lag time elapsed since last print
  {
    v = stepper.speed(); //get motor speed (steps/s)
    nsteps = v * lag / pow(10, 3); //No. of steps taken during lag time
    rpm = 60.0 * v / steps; //RPM
    a = (v - oldspeed) * 1000.0 / lag; //Acceleration
    oldspeed = v; //update speed value
    last = millis(); //update last print time

    //Outputs
    //print No. of Steps
    Serial.print(String(nsteps) + "\t\t");
    //print RPM
    Serial.print(String(rpm, 2) + "\t\t");
    //print Acceleration
    Serial.print(String(a, 2) + "\t\t\t");
    //print Speed
    Serial.println(String(v));
  }
}

void rpm600() {
  stepper.runSpeed();
  stepper.setSpeed(stepper.speed() * speedMultiplier);
  if (stepper.speed() == 1000)
    stepper.setSpeed(1000);
  stepper.moveTo(20000);
}
1 Like

The library you are using has some tools to achieve what you are trying to do including implementing acceleration without having to set the speed each time.

I have a question before going deeper: does it matter if the acceleration is constant?

Ideally it would be, however its not a necessity

I'm struggling to implement this as described. No matter what I try the motor accelerates up to 600 rpm and remains there indefinitely

#include <AccelStepper.h>

AccelStepper stepper(1,3,2);
float speedMultiplier = 1.00005;
int en = 10;

int steps = 200; //number of steps per revolution
long last = 0;
int lag = 500; //time (ms) interval for display
int dir = 1; //direction of rotation
float rpm, v, oldspeed, a;
int nsteps;
 
void setup() {
  Serial.begin(9600); // define Serial output baud rate
  pinMode(en, OUTPUT);
  digitalWrite(en, HIGH);
  stepper.setMaxSpeed(2000); //max speed 2000 steps/s
  stepper.setAcceleration(50);//acceleration rate(steps/s^2)

  Serial.println("Outputs:");
  Serial.println("                           (+ve=clockwise, -ve=counter clockwise)");
  Serial.println("No. of Steps      RPM        Acceleration(steps/s^2)       Speed(steps/s)");
  Serial.println("-------------------------------------------------------------------\n");

stepper.move(2000000); 
unsigned long startTime = millis();

}
void loop(){

stepper.run(); 
current = millis();

if(current-startTime > 10000){ // Every 10 seconds increment 250 the maximum speed
   Stepper.maxSpeed()
   stepper.setMaxSpeed(Stepper.maxSpeed()+250); 
   startTime = millis();
}

  if (millis() > last + lag) //lag time elapsed since last print
  {
    v = stepper.speed(); //get motor speed (steps/s)
    nsteps = v * lag / pow(10, 3); //No. of steps taken during lag time
    rpm = 60.0 * v / steps; //RPM
    a = (v - oldspeed) * 1000.0 / lag; //Acceleration
    oldspeed = v; //update speed value
    last = millis(); //update last print time

   

    //Outputs
    //print No. of Steps
    Serial.print(String(nsteps) + "\t\t");
    //print RPM
    Serial.print(String(rpm, 2) + "\t\t");
    //print Acceleration
    Serial.print(String(a, 2) + "\t\t\t");
    //print Speed
    Serial.println(String(v));
  }

}

The library has different functions in case you want movements with acceleration or without acceleration. If you are using acceleration it is recomended to not call setSpeed(), because the run function already calculates automatically the speed for the next speed depending on the acceleration. Messing with setSpeed will make it not constant.

The run() function makes the stepper take a step if a step is due. I have not achieved yet for a stepper motor to run with acceleration forever in a direction , that's why I'm setting move() to an absurd big number.

The program will start at speed 0 and accelerate 50 steps per second.Every 10 seconds it will increase the maximum speed by 250. You might want to check here if the maximum speed has been reached before increasing the speed or adjust the times.

The values you will print might not reflect exactly the desired acceleration. You can learn more on the links provided below.

Lastly AccelStepper also has functions for enablind and disabling the stepper in case you want to use them.

Stepper.setEnablePin(en);

//enable disable the stepper motor.
Stepper.enableOutputs();
Stepper.disableOutputs();

The library is a little bit hard to understand so here are some links you can use to see what each function does:

The missing manual (it has examples).

GitHub of the library with definitions every function.

Let me know if it works.

Thanks for the response, the code looks sound enough to me but when I try to run it I get the following error messages:

sketch.ino: In function 'void loop()':
sketch.ino:32:1: error: 'current' was not declared in this scope
current = millis();
^~~~~~~
sketch.ino:34:12: error: 'startTime' was not declared in this scope
if(current-startTime > 10000){ // Every 10 seconds increment 250 the maximum speed
^~~~~~~~~
sketch.ino:34:12: note: suggested alternative: 'static'
if(current-startTime > 10000){ // Every 10 seconds increment 250 the maximum speed
^~~~~~~~~
static
I'm not too sure why these error messages appear

I forgot to declare the variables.
Declare the variables at the start of the program

int steps = 200; //number of steps per revolution
long last = 0;
int lag = 500; //time (ms) interval for display
int dir = 1; //direction of rotation
float rpm, v, oldspeed, a;
int nsteps;
//Time variables
unsigned long current;
unsigned long startTime;

Then , in the setup variable get the startTime

startTime = millis();

This has removed the error message but now the motor just accelerates at a constant rate indefinitely

Maybe you've reached the maximum speed of your motor.
Try starting with a less maximum speed (500) and see if you see any changes every 10 seconds.

  stepper.setMaxSpeed(500); //max speed 2000 steps/s  in the setup

You can add a debug to see what the current maximum speed is inside your if so:

float currentMaxSpeed; // definition of variable 

........................................................................................

if (millis() > last + lag) //lag time elapsed since last print
  {
    v = stepper.speed(); //get motor speed (steps/s)
    nsteps = v * lag / pow(10, 3); //No. of steps taken during lag time
    rpm = 60.0 * v / steps; //RPM
    a = (v - oldspeed) * 1000.0 / lag; //Acceleration
    oldspeed = v; //update speed value
    last = millis(); //update last print time
    currentMaxSpeed = maxSpeed(); //get the current maxSpeed.

....
 Serial.println(String(currentMaxSpeed));

Also delete this line, i forgot to erase it before sending it.

if(current-startTime > 10000){ // Every 10 seconds increment 250 the maximum speed
   Stepper.maxSpeed()  // DELETE THIS LINE
   stepper.setMaxSpeed(Stepper.maxSpeed()+250); 
   startTime = millis();
}

Thanks for your help. I didn't manage to get the currentMaxSpeed printing to work. However, I did find the issue I was having as to why it accelerated indefinitely. Due to the acceleration being so low, the max speed was increasing before it had been met. However, I upped the time taken until the max speed increased and it now works as desired. Thank you so much for your assistance with this. My only question now is, how to I get the stepper motor to follow the same profile but decelerating back down to 0.

if(current-startTime > 30000){ // Every 10 seconds increment 1000 steps to the maximum speed
   stepper.setMaxSpeed(stepper.maxSpeed()+1000); 
   startTime = millis();
}

if(current-startTime > 30000){
if(!reverse){
stepper.setMaxSpeed(stepper.maxSpeed()+1000); //increase maxSpeed
startTime = millis();
}else { // if reverse is true
stepper.setMaxSpeed(stepper.maxSpeed()-1000); //decrease maxSpeed
startTime = millis();
}

if(stepper.maxSpeed() > 4000) //CHANGE 4000 FOR YOUR DESIRED MAXIMUM SPEED 
{
 reverse = true;
}else if(stepper.maxSpeed() < 0) {
reverse = false;
}

This will go from 0 to 4000 to 0 to 4000 to 0... forever. (maximum speed)
The way it works is: After every change of speed you check if you reached your desired maxSpeed limit or 0, if so you change the value of reverse; if this is false you keep increasing, if its true it starts decreasing every 10seconds.

I added this in and got the same error message as before that:
In function 'void loop()':
error:'reverse' was not declared in this scope

I added declared reverse as an unsigned long variable and it worked as intended, however, the serial monitor now only updates every 30 seconds. I imagine I've defined reverse wrong and this is what is affecting it

Sorry , reverse is a boolean not a long.
boolean reverse = false;
I always forget a lot of stuff when coding.

It shouldn't affect the serial print, i'm not sure about that, make sure you have all the brackets in place '{'

That is because I only made a "speed600" function. You were to replicate that function and create as many "speedXXX()" functions as you desire.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.