Estoy tratando de controlar un fader motorizado (potenciómetro de deslizamiento lineal) usando un Arduino.
El control PID da buenos resultados para "saltar" a una posición de destino específica, pero el seguimiento de las rampas es un problema, no es nada suave. El movimiento es muy desigual, no importa lo que intente.
Aquí hay un gráfico de la posición de referencia, la posición medida y la salida del motor al rastrear una rampa:
Y aquí hay un video de esa misma prueba.
En los sistemas comerciales, parece mucho más suave, mira esto .
Detalles :
El fader del motor es un Alps RSA0N11M9A0K . Para conducirlo, estoy usando un puente H ST L293D , alimentado por una fuente de alimentación regulada de 10 V CC ( XL6009 ).
En el Arduino UNO (ATmega328P), estoy usando los pines 9 y 10, con una frecuencia PWM de 31.372 kHz para que sea inaudible (Timer1 con un prescaler de 1, TCCR1B = (TCCR1B & 0b11111000) | 0b001
).
El potenciómetro está conectado entre tierra y 5V, con el limpiador yendo a ADC0, como de costumbre.
El controlador :
estoy usando un controlador PID simple con anti-windup, que se actualiza a una velocidad de 1 kHz (Ts = 1e-3 s):
float update(int16_t input) {
int16_t error = setpoint - input;
int16_t newIntegral = integral + error;
float output = k_p * error
+ k_i * newIntegral * Ts
+ k_d * (input - previousInput) / Ts;
if (output > maxOutput)
output = maxOutput;
else if (output < -maxOutput)
output = -maxOutput;
else
integral = newIntegral;
previousInput = input;
return output;
}
La salida del controlador es un valor de -127 a 127. La salida PWM se genera de la siguiente manera:
const int8_t knee = 48;
uint8_t activation(int8_t val) {
if (val == 0)
return 0;
else {
return map(val, 0, 127, 2 * knee, 255);
}
}
void writeMotor(int8_t val) {
if (val >= 0) {
analogWrite(forward, activation(val));
digitalWrite(backward, 0);
} else {
analogWrite(backward, activation(-val));
digitalWrite(forward, 0);
}
}
Agregué 48 a la señal PWM de 7 bits, porque ahí es donde el motor comienza a moverse a 31 kHz, y luego lo escalo a un número de 8 bits (porque eso es lo que la analogWrite
función espera):
Lo que he intentado :
he intentado agregar un filtro EMA a la entrada, a la señal de control, al componente derivado del controlador PID, pero fue en vano. También intenté reducir la resolución de la entrada analógica, usando histéresis para evitar que cambie entre dos valores cuando está parado. Esto no parece afectar nada. Aumentar el paso de tiempo a 10 ms tampoco parece ayudar.
También intenté hacer una identificación del sistema en MATLAB, e intenté ajustarlo en Simulink (siguiendo esta serie de videos ). Obtuve un modelo con un ajuste del 91%, pero no sabía cómo lidiar con las no linealidades de entrada y salida del modelo MATLAB, cómo afectan el ajuste PID y cómo implementarlo en el Arduino.
Lo último que he intentado es hacer dos controladores diferentes: uno para grandes saltos en la posición de referencia y otro para pequeños errores al rastrear una rampa. Esto parece ayudar un poco, porque entonces puedo aumentar el coeficiente integral al rastrear, sin aumentar el sobreimpulso al saltar.
Sin embargo, al aumentar la ganancia integral (y proporcional), el motor ahora siempre está haciendo algo, incluso cuando debe estar parado y la referencia no cambia. (Realmente no se mueve, pero puedes sentirlo vibrar).
Prácticamente no tengo ganancia derivada, porque aumentarlo más alto que 1e-4 parece hacerlo aún más espasmódico, y realmente no noto ninguna diferencia entre 0 y 1e-4.
Supongo que necesita más potencia para superar la fricción estática, entonces la fricción dinámica es menor, por lo que se sobrepasa, por lo que impulsa el motor hacia atrás, haciendo que se detenga nuevamente, luego tiene que superar la fricción estática nuevamente, dispara hacia adelante nuevamente etc.
¿Cómo superan este problema los controladores comerciales?
Mi experiencia :
estoy en mi tercer año de licenciatura en Ingeniería Eléctrica, he seguido cursos sobre teoría de control, procesamiento de señal digital, control LQR, etc., así que tengo algunos antecedentes teóricos, pero tengo problemas para aplicar todas esas teorías a Este sistema del mundo real.
Editar :
he probado las mediciones del sensor de bucle abierto, como recomendó laptop2d, y estoy bastante sorprendido con los resultados: a altas frecuencias PWM, hay picos desagradables en las lecturas. A 490 Hz, no hay ninguno.
Y esto está en un ciclo de trabajo constante, por lo que no puedo imaginar qué tipo de ruido obtengo cuando el motor está invirtiendo la dirección muy rápidamente.
Así que tendré que encontrar una manera de filtrar ese ruido antes de comenzar a trabajar en el controlador nuevamente.
Edición 2 : el
uso de un filtro de promedio móvil exponencial no fue suficiente para filtrar el ruido.
He intentado con polos en 0.25, 0.50 y 0.75. Los postes pequeños no tuvieron mucho efecto, y los postes más grandes agregaron demasiada latencia, por lo que tuve que reducir las ganancias para mantenerlo estable, lo que resultó en un peor rendimiento general.
He agregado un condensador de 0.1 µF a través del potenciómetro (entre el limpiador y la tierra), y eso parece limpiarlo.
Por ahora, funciona lo suficientemente bien. Mientras tanto, estoy leyendo el periódico publicado por Tim Wescott .
Gracias por toda tu ayuda.
This device is suitable for use in switching applications at frequencies up to 5 kHz.
Pero las características eléctricas en la página 3 sugieren un máximo absoluto de 690 kHz si suma todos los retrasos. (4 líneas inferiores) Personalmente, iría mucho más lento que eso, pero creo que 31kHz debería ser adecuado ... si no fuera por la nota en la página 1.