I would like my program to make my steppers have a slowish ramp-up to full speed. I’m using the stock program in the ArduinoCode library with a potentiometer. Can I get some suggestions on how to program this capability?
Sure. The speed of stepper motors is based on the quiet time between steps. Start with a delay of 100 and every time you do a step, reduce the delay value by 1 second, or any small value until delay gets to zero.
Easier with Accelstepper library or one of its variants.
What speed is full speed? And how fast do you want to accelerate/ramp up?
Assuming 200steps/rev and full speed of 1000RPM, top speed would be 1000*200/60=3333steps/sec
. With Stepper.h, you could ramp up over 10 seconds with a traditional sort of acceleration at 333.3steps/sec/sec
, or +1step/sec/3ms
. So maybe something like
const int maxSpeed = 1000L * stepsPerRevolution / 60;
void loop() {
for (int speed = 0; speed <= maxSpeed; ++speed) {
// calculate for 3ms speed changes
int nextSteps = (speed * 3) / 1000;
myStepper.setSpeed(speed);
myStepper.step(nextSteps);
delayMicroseconds(3000);
}
for (int speed = maxSpeed; speed >0; --speed) {
// calculate for 3ms speed changes
int nextSteps = (speed * 3) / 1000;
myStepper.setSpeed(speed);
myStepper.step(-nextSteps);
delayMicroseconds(3000);
}
}
dropped into stepper-motor-example.ino - Wokwi ESP32, STM32, Arduino Simulator
I’d say the top RPM is ~200. Im looking for a ramp up time of approximately 2 seconds. Can I just insert the code section (with appropriate adjustments)? Exactly where should I l,ace it within the existing code? Thanx
Where's your code that reads your 0-100% pot and does 0-200RPM with your stepper?
At 200RPM and 200steps/rev, that is a top speed of 667 steps/sec, and ramping that over 2 secs would be the same 333steps/sec/sec.
I'd think that if you are doing it with a pot, you'd want to be responsive and you'd re-write the stepping to be non-blocking. Then in loop() you'd change the speed from a stepperSpeed towards targetStepsPerSec by 1step/sec each 3000us.
Here's a completely untested snippet for adjusting the stepperSpeed:
int stepperSpeed =0;
...
void adjustSpeed(int targetStepsPerSec){
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if(now - last >= interval){
last = now;
if(targetStepsPerSec > stepperSpeed){
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
}
}
Here is the existing code:
`#define potmeterPin A0
// defins pins numbers
#include <Stepper.h>;
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;
int p;
float delay_time=50;
void setup() {
Serial.begin(9600);
// sets the two pins as Outputs
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
pinMode(enPin,OUTPUT);
digitalWrite(enPin,HIGH);
// Set 500Dir to home switch
digitalWrite(dirPin,LOW); //enables te motor to move in a particular direction
}
void loop(){
p = analogRead(potmeterPin);
delay_time = map(p,0,1023,90,1023);
6
;motorStep(1);
}
void motorStep( int MAX){
for(int x = 0; x < MAX; x++){
digitalWrite(stepPin,HIGH);
delayMicroseconds(delay_time);
digitalWrite(stepPin,LOW);
delayMicroseconds(delay_time);
}
}
Ah, you're using a stepper driver and not the Stepper.h library.
You could take this line out:
You could also take out this delay for more speed:
digitalWrite(stepPin,HIGH);
delayMicroseconds(delay_time); // <<<<<<< unneeded with modern stepper drivers
digitalWrite(stepPin,LOW);
If you want to calculate the ramp in-process while stepping, you need to be careful about how much the stepping blocks.
Maybe something like this untested code would help:
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return; // turn off with negative
if (now - last >= stepInterval) {
last = now;
digitalWrite(stepPin,HIGH);
digitalWrite(stepPin,LOW);
stepCount++;
retval = true;
}
return retval;
}
Dave X, where should I insert the untested code? It says StepCount was not declared in this scope.
Oh, you don't need stepCount. It was leftover from fiddling with this code:
Just delete it.
Sorry to say, adding that piece of code had no affect. Here is the code as presently configured:
orry to say that bit of code did not lead to a motor ramp-up. Here is the completed program:
#define potmeterPin A0
// defins pins numbers
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return; // turn off with negative
if (now - last >= stepInterval) {
last = now;
digitalWrite(stepPin,HIGH);
digitalWrite(stepPin,LOW);
retval = true;
}
return retval;
}
int p;
float delay_time=50;
void setup() {
Serial.begin(9600);
// sets the two pins as Outputs
pinMode(stepPin,OUTPUT);
pinMode(dirPin,OUTPUT);
pinMode(enPin,OUTPUT);
digitalWrite(enPin,HIGH);
// Set 500Dir to home switch
digitalWrite(dirPin,LOW); //enables te motor to move in a particular direction
}
void loop(){
p = analogRead(potmeterPin);
delay_time = map(p,0,1023,80,1023);
6
;motorStep(1);
}
void motorStep( int MAX){
for(int x = 0; x < MAX; x++){
digitalWrite(stepPin,HIGH);
digitalWrite(stepPin,LOW);
delayMicroseconds(delay_time);
}
}
Reply[Close](https://forum.arduino.cc/t/ramp-up-to-speed-for-steppers/1212952/10)`Use code tags to format code for the forum`
If you want to use ramping you need add a way to calculate the ramping. Somewhat like the adjustSpeed() function in #6, but since your code isn't using stepper.h's speed/step stuff, you need it to calculate and update delay_time
.
Something like:
int stepperSpeed =0;
void adjustSpeed(int targetStepsPerSec){
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if(now - last >= interval){
last = now;
if(targetStepsPerSec > stepperSpeed){
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
delay_time = 1000000UL/stepperSpeed;
}
}
Or you could always use a stepper library that does the acceleration/ramping, as per #3.
The stepAsNeeded(delayTime)
function is a non-blocking alternative to motorStep. so you should be able to re-write your loop to read the pot, set the target, adjust the delay, and step as needed:
void loop() {
int target_speed = 0;
p = analogRead(potmeterPin);
target_speed = map(p, 0, 1023, 80, 1023); // steps per sec
// ; motorStep(1);
adjustSpeed(target_speed);
stepAsNeeded(delay_time) ;
}
Taken together, it becomes something like:
#define potmeterPin A0
// defins pins numbers
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;
int p;
float delay_time = 50;
void setup() {
Serial.begin(9600);
// sets the two pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
// Set 500Dir to home switch
digitalWrite(dirPin, LOW); //enables te motor to move in a particular direction
}
void loop() {
int target_speed = 0;
p = analogRead(potmeterPin);
target_speed = map(p, 0, 1023, 80, 1023); // steps per sec
// ; motorStep(1);
adjustSpeed(target_speed);
stepAsNeeded(delay_time) ;
}
void motorStep( int MAX) {
for (int x = 0; x < MAX; x++) {
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delayMicroseconds(delay_time);
}
}
int stepperSpeed =0;
void adjustSpeed(int targetStepsPerSec){
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if(now - last >= interval){
last = now;
if(targetStepsPerSec > stepperSpeed){
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
delay_time = 1000000UL/stepperSpeed;
}
}
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return; // turn off with negative
if (now - last >= stepInterval) {
// Serial.print('s');
last = now;
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
retval = true;
}
return retval;
}
Which seems to ramp in Wokwi with a diagram.json file of
{
"version": 1,
"author": "DaveX",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 0.6, "left": -77.4, "attrs": {} },
{ "type": "wokwi-a4988", "id": "drv1", "top": -129.6, "left": 168, "attrs": {} },
{
"type": "wokwi-stepper-motor",
"id": "stepper1",
"top": -179.87,
"left": 256.89,
"rotate": 90,
"attrs": { "size": "17" }
},
{
"type": "wokwi-slide-potentiometer",
"id": "pot1",
"top": 101,
"left": 287,
"attrs": { "travelLength": "30" }
}
],
"connections": [
[ "drv1:SLEEP", "drv1:RESET", "green", [ "h-19.2", "v-9.6" ] ],
[ "drv1:ENABLE", "uno:8", "green", [ "h-76.8", "v134.4" ] ],
[ "drv1:DIR", "uno:2", "green", [ "h0" ] ],
[ "drv1:2B", "stepper1:A-", "green", [ "h0" ] ],
[ "drv1:2A", "stepper1:A+", "green", [ "h0" ] ],
[ "drv1:1A", "stepper1:B+", "green", [ "h0" ] ],
[ "drv1:1B", "stepper1:B-", "green", [ "h0" ] ],
[ "uno:A0", "pot1:SIG", "green", [ "v76.7", "h128.6", "v-105.6", "h28.8" ] ],
[ "drv1:STEP", "uno:5", "green", [ "h-48", "v9.6" ] ]
],
"dependencies": {}
}
It would need some special handling for 0 RPM because of the delay_time = 1000000UL/stepperSpeed;
Also, what driver are you using? the A4988's enable pin is active low, so you would need to switch this to LOW:
Im using a cheap Chinese 3.5 amp/phase driver. Im not using the enable function.
Ah. I tried guessing at your setup from your #11 code, and wasted some time debugging enPin.
These things would be easier and quicker if folks followed these forum guidelines.
Im sorry for breaking protocol. I am relatively unskilled at this. My set up is an Arduino clone and the driver is a standard imported driver. The motor is bi-polar. I'm not employing the enable circuit, so there only three wires coming off the arduino; step, direction, and +5v.
The program works now, and ramps up slowly. I can adjust that ramp time by adjusting the const unsigned long interval.
A problem is that the top speed is now too low. I tried changing the target speed but that dose not change the speed like it used to.
Here is the code:
#define potmeterPin A0
// defins pins numbers
const int stepPin = 5;
const int dirPin = 2;
const int enPin = 8;
int p;
float delay_time = 50;
void setup() {
Serial.begin(9600);
// sets the two pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
// Set 500Dir to home switch
digitalWrite(dirPin, LOW); //enables te motor to move in a particular direction
}
void loop() {
int target_speed = 0;
p = analogRead(potmeterPin);
target_speed = map(p, 0, 1023, 80, 1023); // steps per sec
// ; motorStep(1);
adjustSpeed(target_speed);
stepAsNeeded(delay_time) ;
}
void motorStep( int MAX) {
for (int x = 0; x < MAX; x++) {
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delayMicroseconds(delay_time);
}
}
int stepperSpeed =0;
void adjustSpeed(int targetStepsPerSec){
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if(now - last >= interval){
last = now;
if(targetStepsPerSec > stepperSpeed){
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
delay_time = 1000000UL/stepperSpeed;
}
}
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return; // turn off with negative
if (now - last >= stepInterval) {
// Serial.print('s');
last = now;
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
retval = true;
}
return retval;
// put your setup code here, to run once:
}
My question would be how to adjust/increase the top speed?
Thank you for your help. I am truly trying to learn and appreciate your taking time here.
I changed the stepper resolution and increased the max_speed value and got the speed I was looking for. The pot doesn't work but that is OK.
thank you
So it looks like it should reach 300RPM: 300RPM*200Step/rev/(1min/60s)=1000steps/sec
which is less than the maps's 1023steps/sec
I tried to see how fast it would go, and changed a few ints to longs or unsigned longs, and didn't check the pot and recalculate each step and got the code to work above an unfeasible 30000 RPM to 3000RPM 12000RPM:
#define potmeterPin A0
// defins pins numbers
const int stepPin = A2;
const int dirPin = 2;
const int enPin = 8;
int p;
float delay_time =20;
long topSpeed = (300L*200)/60; // steps/sec = Rev/min*steps/rev /(sec/min)
unsigned long stepperSpeed =0;
void setup() {
Serial.begin(9600);
// sets the two pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
// Set 500Dir to home switch
digitalWrite(dirPin, LOW); //enables te motor to move in a particular direction
}
long target_speed = 0;
void loop() {
static int lastP=0;
unsigned long now = millis();
static unsigned long lastUI = 0;
if(now - lastUI >= 100){
p = analogRead(potmeterPin);
lastUI = now;
}
if(p != lastP) {
lastP = p;
target_speed = map(p, 0, 1023, 1, 1023UL*100); // steps per sec
}
// ; motorStep(1);
if(target_speed != stepperSpeed){
adjustSpeed(target_speed);
}
stepAsNeeded(delay_time) ;
//stepAsNeeded(1000); // 1000000/(300*200/60 steps/sec)
report();
}
void motorStep( int MAX) {
for (int x = 0; x < MAX; x++) {
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delayMicroseconds(delay_time);
}
}
void adjustSpeed(long targetStepsPerSec){
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if(now - last >= interval){
last = now;
if(targetStepsPerSec > stepperSpeed){
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
delay_time = 1000000UL/stepperSpeed;
}
}
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return; // turn off with negative
if (now - last >= stepInterval) {
// Serial.print('s');
last = now;
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
retval = true;
}
return retval;
// put your setup code here, to run once:
}
void report(void){
const int interval=1000;
static unsigned long last = -interval;
unsigned long now = millis();
if(now - last >= interval){
last += interval;
Serial.print(" target:");
Serial.print(target_speed);
Serial.print(" ramped:");
Serial.print(stepperSpeed);
Serial.print(" us:");
Serial.print(delay_time);
Serial.print(" freq:");
Serial.print(1000000UL/delay_time);
Serial.print(" StepPhasefreq:");
Serial.print(1000000UL/delay_time/4);
Serial.println();
}
}
stepAsNeeded() is declared to return an integer but you don't consistently return an integer - have you got compiler warnings turned on? Well worth doing so and reading them!
Oops. Since I don't have the OP's hardware, I was trying it
with the example setup in stepper-driver-a4988.ino - Wokwi ESP32, STM32, Arduino Simulator in a the Wokwi simulator, and don't get compiler warnings.
I'd initially planned the return value to indicate if a step was taken or not, since I wish AccelStepper's step() did so, but I didn't make use of it.
Here's a current copy with the extra retval and faster serial (ETA: plus the other compiler warnings solved) :
#define potmeterPin A0
// defins pins numbers
const int stepPin = A2;
const int dirPin = 2;
const int enPin = 8;
int p;
float delay_time = 1e9;
long topSpeed = (300L * 200) / 60; // steps/sec = Rev/min*steps/rev /(sec/min)
unsigned long stepperSpeed = 0;
void setup() {
Serial.begin(115200);
// sets the two pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
digitalWrite(enPin, LOW);
// Set 500Dir to home switch
digitalWrite(dirPin, LOW); //enables te motor to move in a particular direction
}
unsigned long target_speed = 0;
void loop() {
static int lastP = -1;
unsigned long now = millis();
static unsigned long lastUI = 0;
if (now - lastUI >= 100) {
p = analogRead(potmeterPin);
lastUI = now;
}
if (p != lastP) {
lastP = p;
target_speed = map(p, 0, 1023, 0, 40000); // steps per sec
}
// ; motorStep(1);
if (target_speed != stepperSpeed) {
adjustSpeed(target_speed);
}
stepAsNeeded(delay_time) ;
//stepAsNeeded(1000); // 1000000/(300*200/60 steps/sec)
report();
}
void motorStep( int MAX) {
for (int x = 0; x < MAX; x++) {
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delayMicroseconds(delay_time);
}
}
void adjustSpeed(unsigned long targetStepsPerSec) {
static unsigned long last = 0;
unsigned long now = micros();
const unsigned long interval = 3000;
if (now - last >= interval) {
last = now;
if (targetStepsPerSec > stepperSpeed) {
++stepperSpeed;
} else if (targetStepsPerSec < stepperSpeed) {
--stepperSpeed;
}
if(stepperSpeed>0){
delay_time = 1000000UL / stepperSpeed;
}
else{
delay_time =1e9;
}
}
}
int stepAsNeeded(long stepInterval) {
static unsigned long last = 0;
unsigned long now = micros();
bool retval = false;
if (stepInterval < 0 ) return retval; // turn off with negative
if ((signed long) (now - last) >= stepInterval) {
// Serial.print('s');
// last = now;
last += stepInterval;
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
retval = true;
}
return retval;
}
void report(void) {
const int interval = 1000;
static unsigned long last = -interval;
unsigned long now = millis();
if (now - last >= interval) {
last += interval;
Serial.print(" target:");
Serial.print(target_speed);
Serial.print(" ramped:");
Serial.print(stepperSpeed);
Serial.print(" us:");
Serial.print(delay_time);
Serial.print(" freq:");
Serial.print(1000000UL / delay_time);
Serial.print(" StepPhasefreq:");
Serial.print(1000000UL / delay_time / 4);
Serial.println();
}
}
gentlemen, I loaded the code into the arduino and get no motor movement. i checked that I got the full code in post#19 and it was all there. I Tried twice and then reloaded the old code and it worked. Im, not sure what the problem is..