Hello - I just wanted to post something here for anyone searching for an RPM counter for stepper motors using the AccelStepper library.
Previous threads on the subject make use of AccelStepper's currentPosition() or distanceToGo() to retrieve motor positions and compare them over a fixed interval of time.
However, there's a simpler function to retrieve the latest speed setting of the motor: speed()
It seems like a stupid thing to overlook since it's right in the library's class documentation, but it's a feature that was added later. That may be why previous threads on the subject never mentioned it - I've only just discovered it after using AccelStepper over three years ago on a project.
The .speed() class returns the motor's speed in steps per second, so to get the RPMs, you just need to know your steps per revolution.
So if you have your driver microstepping at 1600 steps per revolution, you can get the current running speed in RPMs like this:
int RPM = ((motor_1.speed() * 60) / 1600)
speed() returns the most recent programmed speed setting, so it's not actually returning the steps taken by the driver. That means if you have missed steps, it won't be reported in your RPM count. It does however adjust with programmed acceleration/deceleration. So as your motor is ramping up or down, your RPM read will adjust accordingly - this is also useful to know it will work with manual motor speed adjustment via an encoder.
To retrieve and print your RPMs via serial at a fixed interval without using delay (to avoid blocking), you'll want to use the millis() function. The following is an example of an RPM counter that will return values for RPMs and total revolutions every 500ms:
// Note: these don't all have to be global variables, feel free to stick them in the main function if they're not being used anywhere else. startMillis should remain global though since that will be set outside of the RPM counting function.
int SPR = 1600; //driver steps per revolution
unsigned long startMillis;
unsigned long currentMillis;
int period = 500;
int RPMs;
int REVs;
void setup() {
// Place your AccelStepper driver settings here. Speed/accel parameters can be set here or elsewhere.
startMillis = millis();
}
void rpmCounter() {
currentMillis = millis();
if (currentMillis - startMillis >= period) {
RPMs = abs(round((stepper1.speed() * 60) / float(SPR)));
REVs = abs(round(stepper1.currentPosition() / float(SPR)));
Serial.print("RPM: ");
Serial.println(RPMs);
Serial.print("Total Revolutions: ");
Serial.println(REVs);
startMillis = currentMillis;
};
};
void loop() {
// Call your RPM counter here whilst running motors. Higher step rate may cause performance issues if the MCU isn't performing these functions at an equal or higher frequency. A dual core MCU like the ESP32 can be used to run RPM counting on one core and motor functions isolated to the other.
motor_1.run();
rpmCounter();
}
Hopefully this is helpful to anyone using the slightly less elegant method of taking two step positions to calculate.