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.Respuestas:
Un sistema de control es tan bueno como su sensor, ejecute el circuito abierto del sensor y retire la entrada de control. Cree su propia entrada al sensor y deslícela lentamente (o encuentre una manera de deslizarla lentamente de manera confiable) mientras toma datos de posición para asegurarse de que no sea el sensor. Si el sensor hace ruido, entonces mejore el rendimiento del sensor obteniendo un sensor nuevo o en paralelo, o filtrando la salida del sensor . Es posible que necesite un sensor con mayor resolución.
Si el sensor no es ruidoso, deberá obtener un bucle de control diferente. Los PID son sistemas de primer orden y no son realmente buenos para el control de velocidad.
fuente
Tiene razón en que el problema es de fricción, o posiblemente una combinación de fricción y reacción. Su diagrama de velocidad promedio vs. ciclo de trabajo para varios anchos de pulso es característico de un sistema con fricción. Este documento explica lo que está viendo y tiene un compendio de soluciones que se han utilizado desde siempre para tratar los problemas. No los habrá visto en su plan de estudios de ingeniería porque son difíciles de analizar; básicamente tienes que jugar con ellos caso por caso para que funcionen.
No sé qué hacen los controladores comerciales, aunque sospecho que hay una variedad de soluciones disponibles. Lo que he hecho en el pasado con cosas como esta es cuando la señal del motor que sale de mi controlador PID cae por debajo de algún umbral (probablemente de 60 a 70 en su caso) Empiezo a pulsar el motor en el umbral, con un deber ciclo que hace que la unidad promedio sea igual a la salida PID. Por lo general, utilizo un modulador sigma-delta-ish para esto porque se puede implementar en muy pocas líneas, pero puede elegir lo que funcione para usted.
fuente
Parece que la mayor parte del ruido proviene de la señal de la unidad PWM.
¿Has intentado sincronizar la captura ADC con el ciclo PWM? La mayoría de los microcontroladores tienen una forma de activar la captura de ADC en el temporizador, por lo que siempre puede activar en el mismo punto del ciclo.
Para obtener el ruido más bajo, la posición de muestreo óptima sería justo antes de encender el motor, porque entonces los picos han tenido el mayor tiempo para asentarse. Pero no importa cuál sea la posición, sincronizar la captura reducirá los picos porque la cantidad de desplazamiento permanecerá aproximadamente igual en el mismo punto del ciclo PWM.
fuente
Puede filtrar el ruido del sensor (o cualquier otra medición / variable ruidosa) en código con algo como esto (filtrado de paso bajo):
fuente