Control PID de fader de motor

Estoy tratando de controlar un fader motorizado (potenciómetro deslizante 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 fluido. El movimiento es muy brusco, 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 seguir una rampa:Seguimiento de una rampa

Y aquí hay un video de esa misma prueba.

En los sistemas comerciales, parece mucho más fluido, mira esto .

Detalles :
El motor fader es un Alps RSA0N11M9A0K . Para manejarlo, 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 preescalador de 1, TCCR1B = (TCCR1B & 0b11111000) | 0b001).
El potenciómetro está cableado entre tierra y 5V, con el limpiaparabrisas 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 amplí a un número de 8 bits (porque eso es lo que espera la función) analogWrite:Velocidad PWM

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 cambiara entre dos valores cuando estaba estacionaria. 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 seguir 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 debería estar estacionario y la referencia no cambia. (Realmente no se mueve, pero puedes sentirlo vibrar).
Prácticamente no tengo ganancia derivada, porque aumentarla por encima de 1e-4 parece hacerla aún más entrecortada, y realmente no noto ninguna diferencia entre 0 y 1e-4.

Mi conjetura es que necesita más potencia para superar la fricción estática, entonces la fricción dinámica es menor, por lo que se excede, por lo que impulsa el motor hacia atrás, lo que hace que se detenga nuevamente, luego tiene que superar la fricción estática nuevamente, se dispara hacia adelante nuevamente , etc.

¿Cómo superan este problema los controladores comerciales?

Mis antecedentes :
Estoy en mi tercer año de licenciatura en Ingeniería Eléctrica, he seguido cursos sobre teoría de control, procesamiento de señales digitales, 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 :
probé las mediciones del sensor de circuito abierto, como recomendó laptop2d, y estoy bastante sorprendido con los resultados: en frecuencias PWM altas, hay picos desagradables en las lecturas. A 490 Hz, no hay ninguno.
Y esto es en un ciclo de trabajo constante, por lo que no puedo imaginar qué tipo de ruido obtengo cuando el motor invierte la dirección muy rápidamente.

ingrese la descripción de la imagen aquí

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.

EMA

He probado con bastones en 0,25, 0,50 y 0,75. Los polos pequeños no tuvieron mucho efecto y los polos 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.

Agregué un capacitor de 0.1 µF a través del potenciómetro (entre el limpiaparabrisas y tierra), y eso parece limpiarlo.

Por ahora, funciona bastante bien. Mientras tanto, estoy leyendo el artículo publicado por Tim Wescott .
Gracias por toda tu ayuda.

¿Puedes controlar 31KHz pwm con precisión?
@Hasanalattar: No, las frecuencias que puedo usar están en el segundo gráfico (prescaler de 1, 8, 64, 256, 1024). Los 4 kHz y 500 Hz son audibles, por lo que producen un pitido molesto, que me gustaría evitar. Eso deja 31 kHz, 120 Hz y 30 Hz. Y los dos últimos son demasiado lentos, creo. La resolución de PWM es de 8 bits, pero estoy usando menos, porque mi señal de control es de solo 7 bits y solo uso valores de PWM superiores a 96.
El puente H que vinculó está en la primera página de la hoja de datos: 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ían ser adecuados... si no fuera por la nota en la página 1.
Sin embargo, eso supone un ciclo de trabajo fijo. (o un ciclo de trabajo "no me importa" para la frecuencia máxima absoluta para "simplemente moverlo"; notará que es asimétrico) Los ciclos de trabajo alto y bajo pueden producir algunos pulsos muy estrechos, entonces, ¿qué tan anchos son en comparación con el parte inferior de la página 3?
Los motores de marcha atrás pueden ser problemáticos si tiene una reacción en su sistema mecánico. Un PID controlado por tasa podría ser mejor en esta aplicación, valdría la pena intentarlo de todos modos, pero en algunos casos pueden ser más ruidosos.
No estoy seguro si es su problema, pero si la marca de tiempo puede variar, creo que debería agregar error * Ts a la integral, no solo error, y no multiplicar la integral por Ts. (Si Ts es siempre una constante entonces no importa)

Respuestas (4)

Un sistema de control es tan bueno como su sensor, ejecute el circuito abierto del sensor y elimine 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 es ruidoso, entonces mejore el rendimiento del sensor obteniendo un nuevo sensor o poniéndolo 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 lazo de control diferente. Los PID son sistemas de primer orden y no son muy buenos en el control de velocidad.

Gracias, de hecho, hay mucho ruido con frecuencias PWM más altas, así que tendré que encontrar una manera de mejorar eso. ¿Tienes algún consejo sobre cómo hacer eso?
Utilice un filtro, mecánico o digital. Si no puede hacer eso, tal vez los sensores paralelos serían buenos. meta.stackexchange.com/questions/126180/…

Tiene razón en que el problema se debe a la fricción, o posiblemente a una combinación de fricción y reacción. Su gráfico de velocidad promedio versus 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 hacer frente a 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 por ahí. Lo que he hecho en el pasado con cosas como esta es que cuando la señal de accionamiento del motor de mi controlador PID cae por debajo de cierto umbral (probablemente de 60 a 70 conteos en su caso) empiezo a pulsar el accionamiento del motor en el umbral, con un deber ciclo que hace que el accionamiento medio sea igual a la salida del PID. Generalmente uso un modulador sigma-delta-ish para esto porque se puede implementar en muy pocas líneas, pero puedes elegir lo que funcione para ti.

Parece que la mayor parte del ruido proviene de la señal de la unidad PWM.

¿Has probado a 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 más tiempo para asentarse. Pero no importa cuál sea la posición, la sincronización de la captura reducirá los picos porque la cantidad de compensación permanecerá aproximadamente igual en el mismo punto del ciclo PWM.

Así que tendré que encontrar una manera de filtrar ese ruido antes de comenzar a trabajar en el controlador nuevamente.

Podría filtrar el ruido del sensor (o cualquier otra medida/variable ruidosa) en el código con algo como esto (filtrado de paso bajo):

S filtrado [ k ] = α S filtrado [ k 1 ] + ( 1 α ) S crudo [ k ]

Dónde 0 << α 1 . Cuanto más cerca de 1, más suave se verá, pero también agrega más retraso, comience con un valor de 0.9, por ejemplo, y vea cómo se comporta.

Lo he intentado, pero no es suficiente para deshacerse de los picos y agrega demasiado retraso.
@tttapa Ya veo. ¿Qué valor para alfa probaste? (0.8,0.9) Va a requerir algunos ajustes, que es posible que ya haya hecho, solo se preguntaba.
Actualicé mi publicación original para agregar un gráfico de los filtros EMA que probé. También probé 0.9, y fue incluso peor que el 0.75, las ganancias tienen que ser mucho más bajas debido a la demora. Creo que voy a usar una EMA limitada para limpiar el ruido del ADC, pero por ahora el capacitor es suficiente.