Can't reach max speed when accelerating using AccelStepper

Hey everyone,

so I want my stepper motor to run at 1 revolution per second while accelerating at the start and decelerating at the end. However, the motor does not seem to reach that speed. What's curious is that if I use the AccelStepper library at a constant speed without accelerating/decelerating, everything works fine. So if I use this code:

#include <AccelStepper.h>

#define X_STEP_PIN         54
#define X_DIR_PIN          55
#define X_ENABLE_PIN       38

int rev = 32*200UL; //single revolution for 1/32 microstepping

AccelStepper stepper = AccelStepper(1, X_STEP_PIN, X_DIR_PIN);

void setup() {
  Serial.begin(115200);
  pinMode(X_STEP_PIN, OUTPUT);
  pinMode(X_DIR_PIN, OUTPUT);
  pinMode(X_ENABLE_PIN, OUTPUT);
  digitalWrite(X_ENABLE_PIN, HIGH);

  stepper.setMaxSpeed(rev); //One revolution per second
  stepper.setSpeed(rev);
  //stepper.moveTo(6*rev);
}


void loop () {
      stepper.runSpeed(); 
}

My stepper motor runs at 1 rev per second. However, if I use this code:

#include <AccelStepper.h>

#define X_STEP_PIN         54
#define X_DIR_PIN          55
#define X_ENABLE_PIN       38

int rev = 32*200UL; //single revolution for 1/32 microstepping

AccelStepper stepper = AccelStepper(1, X_STEP_PIN, X_DIR_PIN);

void setup() {
  Serial.begin(115200);
  pinMode(X_STEP_PIN, OUTPUT);
  pinMode(X_DIR_PIN, OUTPUT);
  pinMode(X_ENABLE_PIN, OUTPUT);
  digitalWrite(X_ENABLE_PIN, HIGH);

  stepper.setMaxSpeed(rev); //One revolution per second
  stepper.setAcceleration(2000);
  stepper.moveTo(6*rev);
}


void loop () {
      stepper.run(); 
}

the motor accelerates -> stays at a constant speed for 6 revolutions -> decelerates. This constant speed in the middle is way below 1 rev per second (maybe like 30% of the desired speed).

I am using an Arduino mega 2560 with a Ramps 1.4, a DRV8825 stepper driver and a Nema 17HS4023. The bridges on the ramps board a configured so that the driver runs at 1/32 microstepping. I am totally new to all of this, so I hope someone can help me solve this problem.

Kind regards.

Welcome to the forum, and thanks for posting your code in tags, much appreciated.

The 2000 may be too low.
You are micro-stepping by 32 and so everything is reduced by a factor of 32.

Try setting your acceleration higher, like 10,000 steps/second/second and also call setSpeed() to what you want it to be. Max speed isn't a speed setting, it's a maximum (as in, not to exceed) speed setting.

Thanks to both of you for helping me.
I've tried to increase the acceleration and called setSpeed() but I'm still hitting a speedlimit. Only when I change run() to runSpeed() I will reach the speed that I want, but in this case the motor is neither accelerating nor decelerating. Here is what I'm experiencing:

And this is the latest code I've tried:

#include <AccelStepper.h>

#define X_STEP_PIN         54
#define X_DIR_PIN          55
#define X_ENABLE_PIN       38

int rev = 32*200UL; //single revolution for 1/32 microstepping

AccelStepper stepper = AccelStepper(1, X_STEP_PIN, X_DIR_PIN);

void setup() {
  Serial.begin(115200);
  pinMode(X_STEP_PIN, OUTPUT);
  pinMode(X_DIR_PIN, OUTPUT);
  pinMode(X_ENABLE_PIN, OUTPUT);
  digitalWrite(X_ENABLE_PIN, HIGH);

  stepper.setMaxSpeed(rev); //One revolution per second
  stepper.setAcceleration(10000);
  stepper.moveTo(6*rev);
}


void loop () {
      stepper.setSpeed(rev);
      stepper.runSpeed(); 
}

Remember that Accelstepper quotes a maximum step rate of around 4000 on an 8-bit AVR at 16MHz

Divide that by 32, and you may find your limit.
Micro stepping is for precision, not speed.

And to mitigate resonance effects.

Well it definitely is, if you use acceleration. It's the speed where the acceleration stops and the motor runs with constant speed at 'maxSpeed'
You should not use setSpeed() when working with acceleration, because run() uses setSpeed() internally.

On an AVR run() needs about 200µs if a step is due. That limits the speed. runSpeed() is faster because it doesn't need to care for acceleration/deceleration.

With microstepping the motor runs smoother. But only full step positions are precise positions.

That's exactly what I thought that setMaxSpeed() should be enough as long as I accelerate quickly enough. So you're saying that the run() function is what's limiting my step rate to about 0.3 revolutions per second, whereas I could reach at least 2 revs per second without accelerating (didn't test beyond that, yet).

Is there any way around it except changing the microstepping? The project is aiming to build a pick and place machine that is manually driven via a GUI. I am not aiming for a high precision but rather for a high step resolution (about 10 µm per step) while the machine is not "too slow" when moving from pick to place position. 1/16 or 1/8 microstepping might be enough to reach this requirement. I'll look into it.

Anyways, thanks to everyone for helping so far!

Yes, you're right. That's exactly the limit that I'm experiencing. It is limiting the motor to about 0.6 revolutions per second for 32 microstepping.

See what you can do without the library - controlling a stepper directly isn't especially tricky.

To expand on what @wildbill said, here is Robin2's simple stepper program that will show how to control a stepper without a library.

There is also a non-blocking version.

You may also want to investigate the MobaTools stepper library. You may be able to get more speed with that library than Accelstepper.

That's exactly what I'm doing at the moment. :smile: Thanks, you two. I will keep you up to date

You may also be interested in Robin2's Simple acceleration code.

hmmm. That's not what I remember, but I'll defer to you since it's been a while since I used both.

If you are building a pick and place machine spending another $30 for a high-speed arduino-IDE-programmable microcontroller is a rather small investion.

A teensy 4.0 or 4.1 runs at 600 MHz.

I connected my Teensy 4.1 to the oscilloscope and checked where the limit is
using this code

/*Example sketch to control a stepper motor with DRV8825 stepper motor driver, AccelStepper library and Arduino: acceleration and deceleration. More info: https://www.makerguides.com */

// Include the AccelStepper library:
#include <AccelStepper.h>

// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 3
#define stepPin 2
#define motorInterfaceType 1

// Create a new instance of the AccelStepper class:
AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

void setup() {
  // Set the maximum speed and acceleration:
  stepper.setMaxSpeed(250000);
  stepper.setAcceleration(100000);
}

void loop() {
  // Set the target position:
  stepper.moveTo(2000000);
  // Run to target position with set speed and acceleration/deceleration:
  stepper.runToPosition();
  //stepper.run();

  delay(1000);

  // Move back to zero:
  stepper.moveTo(0);
  stepper.runToPosition();

  delay(1000);
}

I hit the ceiling at 250 kHz.
This means 250000 / (32 * 200) = 39 rev per second = 2340 rpm

https://www.pjrc.com/store/teensy41.html

best regards Stefan

it seems to be a problem of the CPU-speed

I took your code-example and just added serial-debug-output to see the real numbers
even with a medium acceleration of 4000

With a Teensy 4.1

with using stepper.run() which does use acceleration

I get this snapshots of current-position and speed

Setup-Start bt_tama
"2:" stepper.currentPosition()=1
"3:" stepper.speed()=110.26
"2:" stepper.currentPosition()=546
"3:" stepper.speed()=2090.87
"2:" stepper.currentPosition()=2095
"3:" stepper.speed()=4094.26
"2:" stepper.currentPosition()=4650
"3:" stepper.speed()=6099.31
"2:" stepper.currentPosition()=7845
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=11050
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=14255
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=17460
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=20665
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=23871
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=27076
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=30281
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=33484
"3:" stepper.speed()=6270.58
"2:" stepper.currentPosition()=36125
"3:" stepper.speed()=4265.47
"2:" stepper.currentPosition()=37760
"3:" stepper.speed()=2261.75
"2:" stepper.currentPosition()=38391
"3:" stepper.speed()=260.81
"2:" stepper.currentPosition()=38400
"3:" stepper.speed()=0.00
"2:" stepper.currentPosition()=38400
"3:" stepper.speed()=0.00

using stepper.runSpeed() does not accelerate but uses the speed specified with stepper.setSpeed() immidiately from the first step on

Setup-Start bt_tama
"2:" stepper.currentPosition()=1
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=3206
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=6411
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=9616
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=12821
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=16026
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=19231
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=22436
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=25642
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=28847
"3:" stepper.speed()=6400.00
"2:" stepper.currentPosition()=32052

This is the code I used on the Teensy 4.1

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *

https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


#include <AccelStepper.h>

#define X_STEP_PIN         2
#define X_DIR_PIN          3
#define X_ENABLE_PIN       4

int rev = 32 * 200UL; //single revolution for 1/32 microstepping

AccelStepper stepper = AccelStepper(1, X_STEP_PIN, X_DIR_PIN);

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start bt_tama");
  stepper.setMaxSpeed(rev); //One revolution per second
  stepper.setAcceleration(4000);
  stepper.moveTo(6 * rev);
  stepper.setSpeed(rev);
}

unsigned long myCounter = 0;

void loop () {
  myCounter++;
  //stepper.setSpeed(rev);
  stepper.runSpeed();
  //stepper.run();
  dbgi("2:", stepper.currentPosition(), 500);
  dbgi("3:", stepper.speed(), 500);
  //dbgi("4:", myCounter, 500);
}

additionally I tested an Arduino Uno ang got the same results as you
with stepper.run() the speed was below the set maximum

then I tested your code with an Seeeduino XIAO

which did not reach the required speed of 6400 steps per second with stepper.run()
measured with my oscilloscope the Seeediuno XIAO reached only 6290 steps per second

best regards Stefan

Hey Stefan,

sorry for the late reply. I actually changed my microstepping because the stepping resolution is more than sufficient in 8 instead of 32 microstepping and therefore can get higher speeds without buying new electronics.

Anyway, thank you for your reply and experiment. It's really interesting to know what the problem actually was, and it's always good to know your limits.