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²");
}
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.
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.
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
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.
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?
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.