Control PID de velocidad de dos motores por puerto serie

Por Alejandro Alonso Puig
Enero 2.005
mundobot.com


 



El sistema presentado es un control en bucle cerrado de tipo PID (Proporcional Integral Diferencial) que permite controlar la velocidad de dos motores (controles PD) y esclavizarlos (control I) para que ambos motores mantengan una relación de velocidad aún en el caso de que uno se vea forzado por agentes externos a variarla. 

Este sistema de control de motores es aplicable por ejemplo a robots con tracción de tipo diferencial. Simplemente se indica al sistema la velocidad deseada (SetPoint) y la diferencia de velocidad (Bias) que ha de haber entre ambos motores (para poder hacer giros). El sistema se ocupa de todo lo demás.

El sistema es controlable mediante comandos que se envían por puerto serie. Es posible especificar no solo la velocidad y Bias, sino también las ganancias y otros parámetros varios que se verán más adelante.

Adicionalmente el sistema permite obtener los valores de varios de sus parámetros vía puerto serie.

 

HARDWARE

  • Motores: Aunque el sistema es adaptable a diferentes tipos de motores, los utilizados en el banco de pruebas y para los que las ganancias PID están ajustadas por defecto en el programa son los motores con reductora y encoder de Solution Cubed (http://www.solutions-cubed.com). Características: 12V, 200RPM, 3,6kgcm de par, encoder incremental de doble canal (detección del sentido de giro) de 200CPR, que tras la reductora permite obtener 6000CPR. 
    Nota importante: El sistema está preparado para utilizar encoders incrementales de doble canal. Si se utilizan encoders de canal individual será necesario conectarlos a RA4 y RC0, poniendo RB2 y RB3 a masa. No será posible controlar velocidades negativas (marcha atrás o giros absolutos), obteniendo un resultado inestable del controlador en su intento. En cualquier caso sería preferible hacer modificaciones en el código para adaptarlo, ya que sino puede volverse inestable en valores cercanos a cero.

  • Tarjeta de Control: Se ha utilizado la tarjeta Skypic de IEARobotics con un micro PIC16F876 (http://www.iearobotics.com/proyectos/skypic/skypic.html). Dicha tarjeta lleva incorporado el adaptador de niveles TTL-RS232C para poder conectarla al puerto serie de un PC y manejar el sistema desde la aplicación hiperterminal o cualquiera similar.

  • Driver de potencia: Para poder dar la corriente requerida por los motores se ha utilizado un driver MSE-A100 de Microsystems Engineering (http://www.msebilbao.com), basado en el chip L293B, que soporta un par de motores con consumos de 1A continuo y 2A de pico cada uno.

SOFTWARE

El programa que se encuentra en el controlador se ha desarrollado en C++ mediante el compilador cruzado BoostC de Pavel Baranov (http://www.picant.com/c2c/c.html). Se han utilizado adicionalmente librerías para el control del puerto serie del microcontrolador, desarrolladas por Yann Hendrikx. El programa completo autoexplicativo puede descargarse en el link siguiente. Incluye tanto los fuentes en C, como el compilado "motor.hex" (listo para grabar en el microcontrolador) y la versión intermedia en ensamblador "motor.asm" generada por el compilador cruzado:

Para el control desde el PC se utiliza simplemente una aplicación terminal, tal como el Hiperterminal, configurada en modo 9600,n,8,1

Desde el hiperterminal se pueden enviar los comandos de control del sistema:

Establecer velocidad Se envía primero un byte de valor 32 (espacio). A continuación se envía la velocidad en el siguiente byte. el valor 50 (carácter "2") indica velocidad nula. Valores inferiores corresponden a velocidad negativa (marcha atrás) y valores mayores corresponden a velocidad positiva (marcha alante). El programa toma el código enviado y lo multiplica por 10. Es decir, que la velocidad (SetPoint) utilizada por el programa será  (código-50)*10

Dicha velocidad viene medida en ciclos de encoder por cada 10 msg (parámetro Kpause en el programa). Así, dependiendo del encoder utilizado, la velocidad puede variar. Para unos motores con encoder que de N ciclos por revolución del eje (CPR) se tendría que para obtener una velocidad de V revoluciones por minuto (RPM), la velocidad (SetPoint) sería (V * N* Kpause)/60.000 por lo que como código=50+SetPoint/10 entonces, el código a enviar sería código=50+ V * N* Kpause/600.000

Así por ejemplo, para la configuración utilizada en el banco de pruebas, donde N=6.000CPR y Kpause=10, para que los motores fuesen a 100RPM habría que enviar el código de velocidad 50+100*6000*10/600.000=60 (carácter "<" de la tabla ASCII). 

En resumen, pulsando la tecla espaciadora y luego la tecla "<" se pondría el motor a 100RPM positivas.

Cambiar el valor por defecto de Kpause  El valor por defecto de Kpause se puede modificar enviando primero el código 37 (carácter % en la tabla ASCII) y luego el valor, considerando que el valor 50 corresponde a un Kpause nulo. Así, se asigna a Kpause el valor que se envíe restándole 50. Por ejemplo, si se envía el código 60 (carácter "<" de la tabla ASCII), Kpause será 10 (60-50). Si se envían valores menores que 50, Kpause se hará nulo.

Puede ser necesario modificar Kpause dependiendo de las CPR del encoder utilizado. El programa utiliza internamente un registro de 8 bits para cada motor, que cuenta los ciclos procedentes del encoder. Si lar CPR del encoder son muy altas y Kpause es también alto, se podrían producir desbordamientos de los registros falseando las medidas de velocidad. Por ello Kpause ha de tener un valor (en msg) tal que el motor a máxima velocidad no produzca más de 255 ciclos de encoder. Por ejemplo, para un motor de velocidad máxima V revoluciones por minuto (RPM) en el eje y encoder que de N ciclos por revolución del eje (CPR), el valor de Kpause no debe ser superior a (60.000*255)/(V*N)

Así por ejemplo, para la configuración utilizada en el banco de pruebas, donde N=6.000CPR y V=200RPM, el valor de Kpause debiera ser inferior a (60.000* 255)/(200*6.000) = 12'75. Kpause es un numero de un byte, así que sería 12 como máximo.

En resumen, para establecer un Kpause de 20, se pulsaría la tecla % (código 37) y luego la tecla F (código 70)

Bias El valor del Bias indica la velocidad relativa del motor izquierdo respecto del motor derecho. Un Bias positivo hace que el motor izquierdo vaya más rápido que motor derecho y un Bias negativo hace lo contrario. Básicamente para una velocidad establecida (SetPoint), la velocidad de los motores serán:

Vi =SetPoint + Bias/2
Vd =SetPoint - Bias/2

Ganancias   Para variar las ganancias por defecto del controlador PID, primero hay que enviar un código que indique la ganancia a variar:
  • Código 34 (carácter comilla doble (") de la tabla ASCII) para la ganancia Proporcional (Kpro)
  • Código 35 (carácter almohadilla (#) de la tabla ASCII) para la ganancia Integral (Kint)
  • Código 36 (carácter dollar ($) de la tabla ASCII) para la ganancia Diferencial (Kdif)

Tras este código se envía el valor de la ganancia en unidades de 1/50, empezando en el código 50 (código 50 indica ganancia 0). Así por ejemplo, para establecer una ganancia Kint de 0,02 se enviaría primero el código 35 y luego el código 0,02*50+50 = 51

Petición de datos  Enviando el código 38 (carácter & en la tabla ASCII) se activa la petición de datos y enviando el código 39 (carácter ' en la tabla ASCII) se desactiva la petición de datos.

Al activar la petición de datos el controlador empieza a enviar por puerto serie de forma continua los siguientes valores de control del sistema: 

  • SetPoint: Velocidad de referencia
  • PVLeft: velocidad real según encoder del motor izquierdo
  • PVRight: velocidad real según encoder del motor derecho
  • Kpro: Ganancia proporcional en unidades de 1/50, es decir que si muestra 20, la ganancia real usada es 20/50=0,4
  • Kdif: Ganancia diferencial en unidades de 1/50
  • Kint: Ganancia integral en unidades de 1/50
  • Bias
  • Kpause

A continuación se mostrará la utilidad de obtener estos datos en el ordenador para ver el comportamiento del sistema y ajustar adecuadamente las ganancias.

Nota: Las unidades utilizadas son algo liosas, pero ha sido necesario hacerlo así para adecuar el programa a las limitaciones del compilador, entre las que se encuentra la ausencia de variables de coma flotante y la limitación en cuanto al tamaño de los enteros a valores de 16 bits.

Activando la petición de datos se obtienen continuamente los datos de funcionamiento del sistema de control. Esto permite alimentar aplicaciones en el PC para tener información permanente del sistema y llevar los ajustes oportunos. 

A continuación se muestra un método utilizado para ajustar de forma manual las ganancias del controlador.

El método consiste en mantener el motor parado, pero enviarle los valores de Kpro, Kint y Kdif deseados. Se activa la captura de datos del hiperterminal y se indica al motor que se mueva por ejemplo a 100RPM. Tras un par de segundos se detiene el motor y se detiene la captura. 

Se puede utilizar la hoja de cálculo excel siguiente para visualizar los datos capturados:

Se copiarán los datos de la captura y se pegarán en la celda B17, con lo que se dibujará automáticamente la gráfica de comportamiento de ambos motores. Véase un ejemplo:

 

De forma visual se puede ver el comportamiento del controlador e ir ajustando las ganancias hasta obtener interesantes resultados:

 

Ajuste de ganancias

Existen varias teorías de ajuste manual de ganancias de controladores PID sin necesidad de entrar en formulación matemática. Al final de la página se puede acceder a varios enlaces al respecto. Básicamente la metodología que yo he seguido ha sido la siguiente, extraída de las teorías mencionadas.

 

  1. Empezar estableciendo un valor de ganancia proporcional igual o menor que uno y poniendo las demás ganancias a cero. Al anular la ganancia integral se anula la influencia de la velocidad de un motor sobre el otro. Observar con estos valores el resultado. Ejemplo:


  1. Ir subiendo poco a poco el valor de la ganancia proporcional manteniendo las demás ganancias a cero hasta que la gráfica muestre oscilaciones. Ejemplo:


  1. Mantener la ganancia integral a cero y establecer una ganancia diferencial unas 10 veces inferior a la proporcional. 

  2. Observar el resultado e ir subiendo la ganancia diferencial hasta que la gráfica deje de oscilar. Ejemplo:


  1. Teniendo ya las ganancias P y D establecidas, empezar estableciendo una ganancia integral mínima (0,02 es la mínima soportada por el programa) y observar los resultados. Ir subiendo poco a poco la ganancia integral hasta que ambos motores empiecen a oscilar y entrar en resonancia. 

  1. Entonces dividir la ganancia integral por 10 o 20. Se comprobará que la ganancia está adecuadamente ajustada cuando la gráfica se muestre sin oscilaciones y frenando bastante con la mano un motor, el otro se tienda a frenarse progresivamente (Ojo que el consumo de corriente de un motor bloqueado tiende a dispararse. El driver de motores ha de entregar suficiente potencia o se recalentará). Ejemplo:



BIBLIOGRAFÍA

Book "Building your Robot Drive Trains". Dennis Clark and Michael Owings. Ed. TAB Robotics. ISBN 0-007-140850-9. Chapter 8 - Motor Control 201. Closing the loop with feedback.
Book "Mobile Robots". Josephe L. Jones et al. Ed. A.K.Peters. ISBN 1-56881-097-0. Chapter 7; 7.8.2 - Feedback Control Loops
PID Without a PhD (Guia sencilla de algoritmos para control PID y ajuste de ganancias) : http://www.embedded.com/2000/0010/0010feat3.htm 
Adjusting PID Gains: http://www.ctc-control.com/customer/elearning/servotut/adjus.asp
Documentación tarjeta de control SkyPic: http://www.iearobotics.com/proyectos/skypic/skypic.html