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
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);
}
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?
#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:
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;
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