Hello again!
In the end I managed to solve, even a little, the problem I was talking about: when going fromaaceleration to constant speed. Y tried to use some of the ideas you gave me, but nothing worked well. It finally worked while I was testing different acceleration rates. I wasn't expecting it, but it makes sense: at the last acceleration rate, the motor takes one full turn for each speed step. This makes it have more inertia to go at a constant speed. (in the last version, the motor takes only one step per speed step).
I send here the last version of this program, in case it serves to someone:
/*DESCRIPCION: Control del motor mediante entrada de "p" (play) y "s" (stop) por teclado.
*Ensayo: Aceleración de 300 a 1000 rpm, quedarse en 1000 un rato y decelerar hasta parar.
*
*Versión: 12 Abril 2020
*/
/* INTRODUCIR POR USUARIO AL INICIO: */
/* Velocidades mínima y máxima */
const double w_min = 110.00; //Introducir la velocidad a la que comenzará (en rpm) --> máximo 120rpm
const double w_max = 2500; //Introducir la velocidad que se quiere alcanzar en Vcte (en rpm)
const int n_vueltas = 800; //Numero de vueltas a velocidad constante
const double w_limite = 100; //Valor a partir del cual es obligatorio decelerar para parar, en microSegundos (mirar Excel). i=93.75 es 100rpm
/* Conexiones a pines */
const int dirPin = 8;
const int stepPin = 9;
const int steps = 3200;
const int pinBotonStop = 2;
/*PARAMETROS COMFIGURACION del MOTOR*/
const int microStep=16;
const double step_original=1.8;
double step_final, steps_rev, tiempo_rev_s, tiempo_rev_us;
//double w_min, w_max;
/* VARIABLES GLOBALES */
boolean interrupcion=false;
int estado=0;
double t5=5; // Tasa de aceleración/deceleración (inicial t=0.02)
double t3=3;
double t1=1; // Se utilizan distintas tasas...
double t05=0.5;
double t002=0.02;
double i_act;
int n_1;
boolean entradaPlay=false;
boolean entradaStop=false;
/* MÉTODOS:
* -setup()
* -leerPlay()
* -leerStop()
* -double velocidad_a_i(double w)
* -double i_a_velocidad(double i)
* -aceleracion(double w_min, double w_max)
* -motorVcte(double w_consigna, int n_vueltas)
* -deceleracion(double w_max, double w_min)
* -frenar(double i_velMax, double i_velMin)
* -ensayo(double w_min, double w_max, int n_vueltas)
* -loop() //State Machine
*/
void setup() {
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(1); //Finaliza el tiempo de espera del monitor serial en 1ms (Fin de String)
pinMode(pinBotonStop, INPUT);
attachInterrupt(digitalPinToInterrupt(pinBotonStop), Stop, LOW);
step_final=step_original/microStep;
steps_rev=360.0/step_final;
}
int leerPlay(){
Serial.println( "Pulse la tecla P (mayúscula ó minúscula) cuando quiera comenzar.");
n_1=0; //ascii
if(Serial.available()>0){
n_1=Serial.read(); //n1 es el codigo ascii de lo que lee por teclado
if (n_1==80 || n_1==112){ //Se ha pulsado "P" ó "p"
entradaPlay=true;
}
return n_1;
}
delay(10);
}
void Stop(){
while(pinBotonStop==LOW){
delay(10);
}
entradaStop=true;
estado=2;
Serial.println("Se ha producido una Interrupcion de Stop. Se va a pasar al Estado 2.");
}
double velocidad_a_i(double w){ // Dada una velocidad w, devuelve la i necesaria
tiempo_rev_s=60.0/w;
tiempo_rev_us=tiempo_rev_s/0.000001;
double i=tiempo_rev_us/(2*steps_rev);
return i;
}
double i_a_velocidad(double i){ // Dada una i, devuelve la w en rpm
tiempo_rev_us=i*2.0*steps_rev;
tiempo_rev_s=tiempo_rev_us*0.000001;
double w=60.0/tiempo_rev_s;
return w;
}
void aceleracion(double i_vmin, double i_vmax){ // Tres tramos de aceleración
double tramo = (i_vmax-i_vmin)/4;
double tramo1=i_vmax-tramo; // Tasa alta hasta que alcanza un cuarto de la vmax
double tramo2=i_vmax-3*tramo; // Tasa media hasta la mitad
//Tramo1
for(double i=i_vmin; i>=tramo1; i-=t5){
if(estado!=1) break;
i_act=i;
Serial.println(String("Acel. TiempoDelay: ")+i);
for (int x=0; x < steps/4; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i);
digitalWrite(stepPin, LOW);
delayMicroseconds(i);
}
}
//Tramo2
for(double i=i_act; i>= tramo2; i-=t3){
if(estado!=1) break;
i_act=i;
Serial.println(String("Acel. TiempoDelay: ")+i);
for (int x=0; x < steps/4; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i);
digitalWrite(stepPin, LOW);
delayMicroseconds(i);
}
}
//Tramo3
for(double i=i_act; i>= i_vmax; i-=t05){
if(estado!=1) break;
i_act=i;
Serial.println(String("Acel. TiempoDelay: ")+i);
for (int x=0; x < steps; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i);
digitalWrite(stepPin, LOW);
delayMicroseconds(i);
}
}
}
void motorVcte(double i_vmax, int n_vueltas){
if(estado==1) i_act=i_vmax;
for(int u=n_vueltas; u>=0; u--){
if(estado!=1) break;
Serial.println(String("Velocidad Cte: ")+i_act);
for (int x=0; x < steps; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i_act);
digitalWrite(stepPin, LOW);
delayMicroseconds(i_act);
}
}
}
void deceleracion(double i_vmax, double i_vmin){
for(double i=i_vmax; i<= i_vmin; i+=t1){
if(estado!=1) break;
i_act=i;
Serial.println(String("Decelerando. TiempoDelay= ")+i);
for (int x=0; x < steps; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i);
digitalWrite(stepPin, LOW);
delayMicroseconds(i);
}
}
}
void frenar(double velMax, double velMin){ //Se utiliza sólo en el Estado2, si al pulsar Stop la velocidad actual supera un valor estipulado (i_vlimite).
for(double i=velMax; i<= velMin; i+=t5){
i_act=i;
Serial.println(String("Frenando. TiempoDelay: ")+i);
for (int x=0; x < 1*steps; x++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(i);
digitalWrite(stepPin, LOW);
delayMicroseconds(i);
}
}
}
void ensayo(double w_min, double w_max, int n_vueltas){
double i_vmin=velocidad_a_i(w_min);
double i_vmax=velocidad_a_i(w_max);
aceleracion(i_vmin, i_vmax);
motorVcte(i_vmax, n_vueltas);
deceleracion(i_vmax, i_vmin);
}
void loop(){
double i_limite= velocidad_a_i(w_limite);
/*Maquina de estados:
Estado=0 - Espera a pulsar Play
Estado=1 - Se ha pulsado Play, se inicia el ensayo
Estado=2 - Ha habido una interrupcion (se ha pulsado Stop), decelera y vuelve a estado 0
*/
delay(100);
switch (estado){
case 0: //Espera a play
Serial.println("Estado 0. INICIO.");
leerPlay();
if(entradaPlay){
estado=1;
Serial.println("Has pulsado Play.");
entradaPlay=false;
}
break;
case 1: //Se ha pulsado play, acelera
Serial.println("Estado 1. Se va a realizar el ensayo.");
ensayo(w_min, w_max, n_vueltas); //rpm_vmin, rpm_vmax, numero_vueltas
if(entradaStop==false)estado=0;
break;
case 2: //Ha habido interrupcion
Serial.println("Estado 2. Se ha pulsado Stop. Si la velocidad es mayor a i_limite, se va a frenar de forma controlada hasta parar.");
entradaStop=false;
if(i_act<=i_limite){ //Si la velocidad es mayor a v_limite
frenar(i_act,80); //Se frenará desde la i_act hasta i=80 (hasta w=117.18rpm, para evitar el tramo de resonancia)
}
i_act=0;
estado=0;
break;
}
}
Playing with the oscilloscope I have discovered another problem: despite the fact that I send a pulse frequency as a setpoint, the pulses that really come out of the arduino are somewhat slower. This error increases the higher the pulse frequency. I think it's because of the statements i use in Arduino, and the "efficiendy" of my code.
I have thought about using the arduino timers to make the pulse (instead of the "for statement"), or directly doing everything with LabView and sending the pulses to the driver with RS-232 communication. "But that is another story and shall be told another time."
Thank you all for your time.
G.