Ramp up to speed for steppers

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.

1 Like

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

1 Like

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;
    }
  }
}
1 Like

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!

1 Like

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..