Acceleration of a stepper motor starting from non-zero speed

Hi. I'm having a trouble with a Nema17 stepper motor controlled by a driver DRV8825 and Arduino UNO.

I want to move a cellphone mounted on a toothed tape in a linear accelerated motion, but not starting from rest, instead starting from an initial speed.

At this moment I've reached to this code, using the SpeedyStepper library, since I've read that AccelStepper doesn't include this function by itself. But it's not working at all. Someone knows if my goal is possible? I would appreciate it if you could also tell me what's wrong with my code.

#include <SpeedyStepper.h>

// Pines de configuración
int stp = 7;  // STEP
int dir = 6;  // DIR
int M0 = 9;
int M1 = 10;
int M2 = 11;
int enb = 13; // ENABLE

// Crear objeto de motor
SpeedyStepper stepper;

// Variables de control
float velocidad_inicial_mm_s = 0.0;  // Velocidad inicial en mm/s
float velocidad_final_mm_s = 20.0;   // Velocidad final (límite) en mm/s
float aceleracion_mm_s2 = 5.0;       // Aceleración en mm/s²
float distancia_mm = 100.0;           // Distancia de movimiento en mm
float mp = 32.0; // Micropasos

// Conversión de pasos por mm
const float PASOS_POR_VUELTA = 200.0;
const float MM_POR_VUELTA = 40.0;
float PASOS_POR_MM = PASOS_POR_VUELTA * mp / MM_POR_VUELTA;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // Configurar pines DRV8825
  pinMode(M0, OUTPUT);
  pinMode(M1, OUTPUT);
  pinMode(M2, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  // microstepping
  digitalWrite(M0, HIGH);
  digitalWrite(M1, HIGH);
  digitalWrite(M2, HIGH);

  // Habilitar motor
  digitalWrite(LED_PIN, LOW);

  // Conectar el motor a los pines STEP y DIR
  stepper.connectToPins(stp, dir);

  // Establecer los pasos por milímetro
  stepper.setStepsPerMillimeter(PASOS_POR_MM);

  // Configurar velocidad y aceleración
  stepper.setSpeedInMillimetersPerSecond(velocidad_final_mm_s);
  stepper.setAccelerationInMillimetersPerSecondPerSecond(aceleracion_mm_s2);

  Serial.println("Sistema listo. Comandos:");
  Serial.println("a - mover a la izquierda");
  Serial.println("b - mover a la derecha");
  Serial.println("c <distancia> - ajustar distancia de movimiento en mm");
  Serial.println("i <velocidad_inicial> - ajustar velocidad inicial en mm/s");
  Serial.println("f <velocidad_final> - ajustar velocidad final en mm/s");
  Serial.println("x <aceleracion> - ajustar aceleración en mm/s²");
  Serial.println("s - detener motor");
}

void loop() {
  if (Serial.available() > 0) {
    char comando = Serial.read();

    if (comando == 's' || comando == 'S') {
      Serial.println("Deteniendo motor...");
      // Detener el motor moviéndolo a la posición actual (de hecho, no se moverá)
      stepper.moveToPositionInMillimeters(stepper.getCurrentPositionInMillimeters());
    } 
    else if (comando == 'a' || comando == 'A') {
      Serial.println("Moviendo a la izquierda...");
      mover('a');
    } 
    else if (comando == 'b' || comando == 'B') {
      Serial.println("Moviendo a la derecha...");
      mover('b');
    } 
    else if (comando == 'c' || comando == 'C') {
      distancia_mm = Serial.parseFloat();
      ajustarDistancia(distancia_mm);
    } 
    else if (comando == 'i' || comando == 'I') {
      velocidad_inicial_mm_s = Serial.parseFloat();
      ajustarVelocidadInicial(velocidad_inicial_mm_s);
    } 
    else if (comando == 'f' || comando == 'F') {
      velocidad_final_mm_s = Serial.parseFloat();
      ajustarVelocidadFinal(velocidad_final_mm_s);
    } 
    else if (comando == 'x' || comando == 'X') {
      aceleracion_mm_s2 = Serial.parseFloat();
      ajustarAceleracion(aceleracion_mm_s2);
    }

  }

  stepper.processMovement(); // Continuar movimiento
}

// --- FUNCIONES AUXILIARES ---

void mover(char direccion) {
  if (direccion == 'a' || direccion == 'A') {
    stepper.moveRelativeInMillimeters(-distancia_mm); // Mover a la izquierda
  } 
  else if (direccion == 'b' || direccion == 'B') {
    stepper.moveRelativeInMillimeters(distancia_mm); // Mover a la derecha
  }

  // Ajustar velocidad y aceleración
  stepper.setSpeedInMillimetersPerSecond(velocidad_final_mm_s); // Velocidad final
  stepper.setAccelerationInMillimetersPerSecondPerSecond(aceleracion_mm_s2); // Aceleración
}

void ajustarDistancia(float valor) {
  distancia_mm = valor;
  Serial.print("Distancia ajustada a: ");
  Serial.print(valor);
  Serial.println(" mm");
}

void ajustarVelocidadInicial(float valor) {
  velocidad_inicial_mm_s = valor;
  stepper.setSpeedInMillimetersPerSecond(velocidad_inicial_mm_s); // Ajustar la velocidad inicial
  Serial.print("Velocidad inicial ajustada a: ");
  Serial.print(valor);
  Serial.println(" mm/s");
}

void ajustarVelocidadFinal(float valor) {
  velocidad_final_mm_s = valor;
  stepper.setSpeedInMillimetersPerSecond(velocidad_final_mm_s); // Velocidad final
  Serial.print("Velocidad final ajustada a: ");
  Serial.print(valor);
  Serial.println(" mm/s");
}

void ajustarAceleracion(float valor) {
  aceleracion_mm_s2 = valor;
  stepper.setAccelerationInMillimetersPerSecondPerSecond(aceleracion_mm_s2); // Aceleración
  Serial.print("Aceleración ajustada a: ");
  Serial.print(valor);
  Serial.println(" mm/s²");
}

thx.

Of course this is possible.

Please describe clearly what your code should do, and what it does instead. Post examples of the debugging printouts.

1 Like

My code compiles and upload successfully, but when I pass the commands to the Serial Monitor, the initial speed is completely ignored and the motion starts at null velocity. So there is no debugging printouts, I think the coding is simply wrong.

Hello,

First of all

....... You should stop doing it and start using for example

char comando = Serial.read();
comando = toupper(comando);

so that you IFs become just

and so on

Then, I didn't understand what was wrong? Can you explain again

  • what you want the system do to
  • what does it actually do (so apparently something it shouldn't)
  • what you send as command to try to do whatever you want to do

Rather than write a general command interpreter, start at the beginning and learn to set speed and acceleration by following the library examples.

Then, work on a very simple program that steps in one direction at various speeds, and learn how to write code that does what you want it to do, for that simple, unidirectional application.

You might find this link useful, as the documentation is poorly written: AccelStepper - The Missing Manual | Details | Hackaday.io

1 Like

Thanks for you reply and observation.

I want the motor to move in a uniformly accelerated motion but starting from a speed other than zero.

Currently, the motor moves in an accelerated motion, but starting from zero speed.

I send the following commands:

  • "c" to define how far I want it to move
  • "i" to define the start speed of the movement
  • "f" to define the limit speed of the movement
  • "x" to define the acceleration of the movement (which will be non-zero until the limit speed is reached, and from that moment on it will be zero until the proximity of the distance defined by "c" is reached, where the system will begin to decelerate)
  • "a" or "b" to define the direction of movement, left or right.

Oh yes, I've already done those examples you mentioned and a few more. I've also read the manual you attached, but I've hit a dead end trying to solve this problem I mentioned.

Ok but I meant what does not work as you want it?
You tried to do it and failed or you just say that you want your stepper to do it without having tested to do it? I don't understand

You aren't giving forum members enough information to help.

Put in debug print statements to see why the program is not performing as expected.

I don't get how you can start from a non-zero speed??

The stepper could be rotating at a constant speed (not zero) and then you ask to change the speed

But what I don't get is why he would need to give the initial speed since the initial speed is basically the one currently set.

BTW

Those function are basically the same...

And BTW again:

You set velocidad_final_mm_s = Serial.parseFloat(); so let's say to the value XXXXX
You then give this value as argument to ajustarVelocidadFinal(velocidad_final_mm_s)
And then again in this function you set velocidad_final_mm_s = valor;

WHY??

I feel like before trying to do anything else, you should clean up your code a bit

What doesn't work the way I want is that the motor moves in an accelerated motion, but starting to move from zero speed. What I want is for the motor to start moving at a constant speed, and then quickly move to an accelerated movement, but starting from that constant speed.

I've already tested it, and it doesn't work, it keeps starting from rest.

Pls pay attention to my previous post.

Also, answer to this:

If you set a speed for the stepper, and then you set a different speed higher than the previous, what happens exactly? The stepper stops and then accelerate??

As I said, when checking and loading the code I don't receive any debug statement since it is loaded correctly. What information can I give you to clarify what my problem is?

YOU put in "debug print statements" at various key points in the code, to see if variable have the values you expect them to have.

That is the most important method of debugging that the Arduino IDE supports.

1 Like

Sorry, you're absolutely right. In a previous version of the code I used another library in which a conversion between step and distance have to be made and I forget to clean it when I wrote the new code. Sorry for that, I will clean the code then pass again to you.

You are correct that at the start, the physical motor speed is of course zero. Starting from a non-zero speed means that the acceleration ramp is calculated from a starting point other than zero.

e.g., in order to avoid a vibration resonance that happens at 400 steps/second (this is from a real system, BTW), you set the initial speed to 450 steps/second, and the final speed to 2,000 steps/second with an acceleration of 50k/steps/second/second. So the speed controller calculates the first step as if the motor were already moving at 450 steps/sec.

Not all step controllers have this feature, but it can be very helpful when it's needed. In the example I showed, if we accelerated from zero, as the motor passed through the region around 400 steps/second, the entire gantry would start shaking, and the motor would lose position.

Yes, that's exactly what's happening. Also, I followed your recommendations and now the code is cleaner. Now I have realized something else, the problem comes down to controlling the acceleration of the engine while it is in motion, is that true?

Ah okay, sorry for the confusion, I understand now. At what points in the code do you find it useful to place the prints? In the "mover" function for example?

Well, with AccelStepper you can accelerate from a constant speed ( set by .maxSpeed ) to a higher speed by changing maxSpeed to a higher value. But with Accelstepper you cannot decelerate to a lower speed. If you set maxSpeed to a lower value, the speed is reduced immediately.
You could try if the MobaTools library meets your needs. With MobaTools you can change the speed at any time while the motor is spinning, and it will accelerate/decelerate to the new speed. But be aware, that MobaTools uses a different method to define the acceleration than AccelStepper or SpeedyStepper.