Translate

viernes, 1 de febrero de 2013

Manejo de motores DC usando PWM

En este tema usaremos nuestros conocimientos del PWM del PIC para guiar un motor de corriente continua (DC). En esta primera entrada simplemente aplicaremos un PWM con un duty variable al motor y observaremos su respuesta (velocidad) usando los codificadores en cuadratura explicados en la entrada anterior.

Obviamente el PIC no puede proporcionar la intensidad necesaria para mover un motor, por lo que necesitaremos algún tipo de driver o interfaz. Para poder manejarlo en las dos direcciones usaremos un driver configurado como un puente en H (H-bridge). Describiremos el popular integrado (aunque no especialmente eficaz) L293D. Otras alternativas basadas en MOSFETs son más eficientes, pero el concepto y la forma de controlar el MOTOR serán comunes.

Ficheros de código asociados a esta entrada:  quad_pwm.c , auto_pwm.c , auto_pwm.m


---------------------------------------------------------------------------------------------------------

Interfaz con el motor: L293 H-bridge

Las dos funciones que nos interesan en nuestro driver son:

  • Capacidad para traducir nuestras señales digitales (del microcontrolador) a corrientes de mayor intensidad y (posiblemente) voltajes mayores.
  • Capacidad de invertir el sentido de la corriente a través del motor para hacerlo girar en ambas direcciones.

La configuración que necesitamos es conocida como un puente en H (H-bridge), reflejada en la figura de la derecha (dicha figura la he sacado de
http://www.mcmanis.com/chuck/robotics/tutorial/h-bridge/index.html, donde también se puede encontrar una buena explicación más detallada sobre como funciona un puente en H.

Vemos como cerrando dos interruptores (arriba-izquierda + abajo-derecha) la corriente fluye en una dirección. Si cerramos (arriba-derecha + abajo-izquierda) se causa un cambio en el sentido de la corriente.  Si se cierran los interruptores de arriba o abajo tenemos un freno del motor. Con todo abierto el motor gira libremente. Obviamente podemos tener un problema gordo (cortocircuito) si cerramos ambos interruptores en un lado. Un puente H encierra una estructura de este estilo pero protegida para evitar las opciones "desafortunadas".


Un integrado muy popular para un H-bridge es el L293 (o su variante L293D). Su esquema está en la figura adjunta (todas las figuras sacadas de su datasheet). El integrado dispone de 2 alimentaciones separadas:





  • Vcc1  (pin 16) --> voltaje lógico  (p.e. 5 o 3.3V)
  • Vcc2  (pin 8)   --> voltaje motor Vm (hasta 36 V)

El resto del integrado está dividido en 2 bloques funcionalmente equivalentes. Cada uno de ellos (situados a cada lado del L293) es un H-bridge completo. Por ejemplo, en la rama de la izquierda disponemos de:
  • Pin ENABLE : interruptor apagado/encendido (pin 1,2 EN)
  • 2 Entradas IN1, IN2 (pines 1A,2A)
  • 2 Salidas:  OUT1, OUT2 (pines 1Y, 2Y).

Un nivel alto/bajo (respecto al voltaje de la lógica) en las entradas IN1, IN2 se traduce en un nivel alto/bajo de las salidas OUT1,OUT2 (pero en voltaje motor Vm y con mucha mayor capacidad de corriente). Cada rama puede dar unos 0.75A de forma continuada y picos de hasta 1A.

Al tener 2 puentes H completos, con un L293 podemos controlar 2 motores DC bidireccionales o 4 motores DC unidireccionales. La figura adjunta (datasheet) refleja el montaje con 1 motor bidireccional en el H-bridge izquierdo y 2 unidireccionales en el derecho:

Es este ejemplo usaremos la configuración de la izquierda para controlar un motor bidireccional. Los diodos son necesarios al manejar cargas inductivas (bobinas o motores) para evitar los picos de corriente inducidas al cortar bruscamente la corriente a la carga. En el L293D pueden ser obviados al disponer de diodos internos (aunque algunos recomiendan no fiarse demasiado de esos diodos internos y usar siempre los diodos externos, por si las moscas). Yo no los he usado en mi montaje (con un L293D) pero tengo que especificar que mis conocimientos de electrónica son casi nulos.

Para el manejo de un motor bidireccional conectaremos los bornes del motor a las salidas OUT1 y OUT2.    Disponemos de 3 entradas digitales para controlar el motor:

              ENABLE (pin 1),  IN1  (pin 2)   e  IN2  (pin 3)

Una configuración típica de control es poner p.e. un 1 lógico en IN1 y un 0 lógico en IN2. Esto provoca un voltaje de Vm en OUT1 (pin3) y 0 en OUT2 (pin6), lo que hace que el motor gire en una dirección. Si invertimos las entradas (IN1=0, IN2=1) tendremos 0V en OUT1 y Vm en OUT2, invirtiendo el sentido del giro. Finalmente, si ambas entradas están al mismo valor  (1/1) o (0/0) tendremos una rápida frenada.

Todo esto con ENABLE (pin1) a un valor alto (1 lógico), es decir, con el puente activado. Si hacemos ENABLE=0 sería como desconectar el puente y estaremos en una configuración de giro libre del motor.

Mientras que la conexión al motor es siempre a través de las dos salidas OUT1 y OUT2, tenemos dos formas posibles de regular la velocidad/sentido del motor usando la señal PWM generada por el microcontrolador, según como conectemos las  tres líneas de control (ENABLE, IN1, IN2):



Opción A) Meter PWM en ENABLE y manejar IN1, IN2 con dos pines digitales para seleccionar la dirección de giro.  El % en ON de la señal PWM establece la fracción de tiempo en la que el puente está dando corriente al motor y por lo tanto determina la velocidad del mismo. Seria equivalente a pedalear un rato y dejarse ir otro. Si estamos pedaleando todo el rato (PWM duty = 100%) iremos al máximo. Si damos 1 pedalada y descansamos 9 (PWM = 10%) iremos mucho más lentos. La dirección (signo) se especifica de forma independiente a través de IN1,IN2.  Puede usarse un solo pin conectado a IN1 y mandar la señal invertida a IN2. Precisaríamos un mínimo de 2 líneas de control.


Opcion B) Una alternativa, para reducir las líneas de control necesarias sería poner ENABLE permanentemente a 1 (puente siempre activo) y mandar la señal PWM a IN1. A IN2 mandamos la señal PWM invertida. En ese caso un PWM con un 50% ON corresponde a mantener el motor en reposo, ya que la mitad del tiempo estamos empujando para un lado y la otra mitad, para el otro.  Un PWM con 0% ON significa máxima velocidad en una dirección y un 100% máxima velocidad en el otro sentido.  

De esta forma lo que estamos haciendo es manejar signo y magnitud en la misma línea. Para conseguir la señal PWM invertida podemos usar un simple inversor (por ejemplo con un transistor).  

En aquellos PICs con un módulo PWM mejorado (EPWM) podríamos configurar el módulo PWM para que además de generar una señal, cree la complementaria en otro pin. Por ejemplo la complementaria de RC2 aparece en RD5. Esta opción tiene la ventaja de no requerir hardware externo y poder ademas programar tiempos muertos entre subidas y bajadas, lo que puede ser una necesidad para ciertos drivers.
Aunque los PIC 4520 disponen de un módulo EPWM, en nuestros ejemplos vamos a usar un inversor externo, para que el código sea aplicable a otros dispositivos que carezcan de un módulo mejorado. Además así solo precisamos 1 línea para controlar un motor bidireccional (el ENABLE correspondiente lo mantendremos fijo a 1, 5V en nuestro caso):

Tal como hemos dibujado el esquema, en la opción B, ENABLE está siempre a 1. También podríamos conectarlo a un pin del PIC y usarlo como un "embrague". Si lo ponemos a 0, el puente estará desconectado y por lo tanto, independientemente de lo que hagamos con el PWM, el motor estará en una posición de giro libre.

Desde el punto de vista del software, en ambos casos debemos activar el módulo PWM. Estoy usando un oscilador de 20 MHz, por lo que usaré  PR2=255 y PRE = 1 para una frecuencia de PWM de unos 19 KHz. Esto nos permite contar con 10 bits para especificar el ciclo de trabajo, un valor entre 0 y 1023.

  1. Si usamos el montaje A) un PWM de 0 indica parado y 1023 máxima velocidad. El signo (dirección de giro) se controlará independientemente con el valor de otro pin (p.e. RC1 en el esquema anterior).
  2. Si optamos por el montaje B) tendremos 10 bits para guiar el motor, incluyendo dirección. Un valor de 512 lo mantendrá parado, 0 será todo en una dirección y 1023 avante toda en el otro sentido.
En nuestros ejemplos usaremos preferentemente el montaje B) por lo que trabajaremos con un valor entre 0 y 1023, con 512 indicando reposo. De todas formas el siguiente código permite (usando un #define) optar por luna u otra opción:

#define PWM_TO_ENABLE
#define DIR_PIN PORTCbits.RC1
 
void set_pwm1(uint16 duty)
{

 #ifdef PWM_TO_ENABLE   // transform range [0,1023] into [-1023,-1023]
   if (duty<512) { duty<<=1; duty=1024-duty; DIR_PIN=0;}  //"Negative"
   else {duty-=512; duty<<=1; DIR_PIN=1; }         //"Positive"
 #endif

 // Set duty
 CCP1CONbits.DC1B0=(duty& 0x01); duty>>=1;
 CCP1CONbits.DC1B1=(duty& 0x01); duty>>=1;
 CCPR1L=duty;
}


En caso de definir PWM_TO_ENABLE a partir de un valor entre 0 y 1023 se obtiene un valor entre -1023 y 1023. El signo se usa para poner el pin que gobierna la dirección a 0/1 y el modulo se envía al PWM. Obviamente si se usa el define PWM_TO_ENABLE es preciso hacer las conexiones indicadas en el montaje A). 


La parte de lectura de los encoder en cuadratura para saber la velocidad del motor es igual que antes. En la parte de hardware conectaremos las conexiones de chA y chB a los pines RB0 y RB1, declarados como entradas.  Respecto al código para leer los codificadores en cuadratura es el mismo que el explicado en la entrada anterior, usando la interrupción INT0 de alta prioridad para detectar los cambios en el canal A. 

Respecto al timer para la rutina del servo podríamos haber seguido usando el TMR0. Sin embargo, el módulo PWM tiene corriendo el timer TMR2. Sería un desperdicio no usar la interrupción del TMR2 para el código del servo. De esta forma liberamos el timer TMR0.

La única pega es que al ser un timer de 8 bits la interrupción de TMR2 va a saltar demasiado a menudo. Para reducir el problema podemos usar el POSTSCALER del TMR2. Dicho POSTSCALER no altera la frecuencia del PWM pero sí cada cuanto salta la correspondiente interrupción. Si usamos el valor máximo de 1:16 para el postscaler, la interrupción saltará con una frecuencia de:

               (Fosc/4)/(256*16) = 1221 Hz    para Fosc = 20 MHz

Es posible que esto sea aún demasiado rápido para nuestros objetivos. Imaginad que deseamos una frecuencia parecida a la anterior, de unos 50 Hz. Lo que podemos hacer es tener un contador dentro de la interrupción y sólo cada cierto número de interrupciones se ejecutaría. Tanteando, con un POSTSCALER de 15 y un contador de 26 la frecuencia del servo sera:

                    F_TMR2 =  (Fosc/4)/(256*15)
                    F_servo = F_TMR2/26 = 50.08

muy parecida a los 50 Hz deseados.

En el programa principal, habilitaríamos el timer TMR2 y el modulo PWM (usando rutinas del C18)

   OpenPWM1(255);   
   OpenTimer2(TIMER_INT_OFF & T2_PS_1_1 & T2_POST_1_15);

Esto arranca el timer TMR2 con PRE=1 y POST=15 (OpenTimer) y pone PR2=255 (OpenPWM), lo que corresponde a una frecuencia Fpwm del orden de  19 KHz con 10 bits de resolución.
  
El postscaler de 15, junto con un contador hasta 26 dentro de la interrupción garantiza que la rutina del servo entra 50 veces por segundo. Al igual que antes, en la rutina del servo solo calculamos la velocidad (delta) e incrementamos la posición del motor:

// Low priority interruption
#pragma interruptlow low_ISR
void low_ISR (void)
{
 uint8 temp;

 if (TMR2_flag)   // ISR TMR2 (servo)
  {
   cont_servo++;
   if (cont_servo==26)
    {    
     temp=quad; delta=temp-last_quad; last_quad=temp;  // delta = delta counter
     if (delta>128) delta-=256; else if (delta<-128) delta+=256;  // rollover
     pos=pos+delta;                                   // increment position
     cont_servo=0;
    }
   TMR2_flag=0;
  }  
}

Al igual que antes, la interfaz de programa será a través del puerto serie. El programa nos indica que valor del duty estamos usando en el PWM y la velocidad conseguida por el el motor (leída a través de los encoders de cuadratura).

Inicialmente el PWM se arranca con un valor 512 (motor parado). A través del terminal del puerto serie se puede incrementar (pulsando '+') o decrementar ('-') el PWM y observar su efecto (velocidad) sobre el motor. En principio los incrementos están en unidades, pero pueden hacerse saltar de 2 en 2, 4, 8 o 10. Para ello hay que pulsar '2','4','8','a' en el terminal. Tras por ejemplo pulsar '8' en el terminal, todos los incrementos ('+' o '-') serán en saltos de 8.

La velocidad se muestra en ticks/ciclo del servo y también en º/segundo.

En el video siguiente mostramos como funciona la interfaz a través del puerto serie, incrementando el ciclo ON del PWM mientras observamos su efecto sobre el giro del motor usando una cámara WEB.  Podemos observar un efecto de aliasing provocado por la frecuencia de muestreo de 25 fps de la cámara WEB. 






Caracterizar comportamiento de un motor

Finalmente el programa auto_pwm.c es una pequeña variación del anterior. En lugar de que el usuario seleccione el ciclo de trabajo del PWM y vea su efecto el programa va barriendo dicha variable desde 0 a 1023 y de 1023 a 0 una y otra vez. Tras cada cambio se deja un retraso (para que se alcance y estabilice la nueva velocidad) y se lee la velocidad del motor. Ambos datos (PWM + vel) se mandan por el puerto serie para ser recogidos en nuestro PC por un programa en MATLAB que ira graficando los resultados. Como el receptor de los datos ahora no es una persona es mucho más eficaz mandar dichos datos en binario. Para ello se ha construido un paquete de datos muy sencillo compuesto por:
  • 'A' à indica inicio paquete
  • 2 bytes con el valor de PWM como entero de 16 bits sin signo
  • 2 bytes con la velocidad medida en un ciclo del servo (16 bits con signo)
  • 1 byte con un contador de mensajes que se incrementa a cada mensaje y sirve para que nuestro programa en el PC pueda detectar paquetes perdidos.
  • 'Z' à carácter de fin de paquete.
El programa de MATLAB abre el puerto serie, lee los paquetes y va pintando los datos recibidos en una gráfica representando PWM (entrada) en el eje X frente a velocidad del motor (salida) en el eje Y. En dicha gráfica influirán aspectos del motor, carga, voltaje suministrado, driver usado, tipo de esquema (A o B) utilizado, etc.

En las gráficas siguientes podemos observar las diferencias de comportamiento entre varios montajes y motores. Las dos primeras gráficas usan el motor Maxon GM-20 con los montajes B (izquierda) y A (derecha). La tercera gráfica (abajo) muestra el comportamiento del motor de Pololu (montaje B).  Vemos que el motor Maxon con la opción B) (gráfica de la izquierda) tiene un comportamiento casi lineal. Lo único que se aprecia es una pequeña zona muerta (dead-band) alrededor del cero. Hay una banda de unos +/-10 donde un PWM "no nulo" (distinto de 512) no es capaz de hacer mover al motor. Si hicieramos zoom sobre ella veríamos que no es está exactamente centrada en 512 como debería, tal vez por asimetrías en el comportamiento del driver al subir o bajar sus salidas. Considerar todos estos datos podría ser interesante si queremos controlar el motor, aunque en este caso, al tratarse de un motor muy ligero, la zona muerta es casi inexistente y sería posible ignorarla.

En la figura de la derecha, por el contrario, el mismo motor muestra un comportamiento distinto usando el montaje A). En este caso la velocidad del motor es fuertemente no lineal con respecto al PWM aplicado. También se aprecia claramente un fenómeno de "histéresis", más marcado que en el otro caso.



Pololu (montaje B)

La influencia de la zona muerta puede ser muy importante para motores más grandes y peor ajustados a los que les cueste más girar. La figura de abajo muestra el comportamiento del motor de Pololu en el esquema B). El comportamiento es lineal, pero en este caso no deberíamos dejar de considerar la banda muerta si queremos controlar con precisión el motor.

En el video siguiente se muestra el funcionamiento del programa MATLAB cuando en el PIC tenemos ejecutandose el código correspondiente a auto_pwm.c. El video ilustra como se van generando las gráficas anteriores.



12 comentarios:

  1. HOLA AMIGO TENGO UNA DUDA, TENGO UN PIC 18F4550 Y NECESITO GENERAR MAS SALIDAS PWM PUESTO QU ESTE PIC SOLO TIENE 2, TIENES IDEA DE COMO HACERLO? MUCHAS GRACIAS

    ResponderEliminar
    Respuestas
    1. Hola que tal, quizás ya lo resolviste pero si aún lo necesitas. Estuve mucho tiempo trabajando con esos microcontroladores, ese cuenta con 2 PWM pero no los puedes trabajar a distinta frecuencia si no mal recuerdo. La forma de generar otro es mediante interrupciones y timers, puedes calcular el periodo para que ajustes el valor de los pre y pos-escaladores procurando que te de un valor lo mas grande posible, ahora el ciclo de servicio lo calculas en proporción al periodo y es lo que le cargarías al timer, cuando entre a la interrupción de overflow cambias de estado el bit de salida (que puede ser de cualquier puerto digital disponible) después cargarías el resto que te faltaría para completar el periodo; nuevamente cambiarías el bit de salida y cargarías nuevamente el valor del tiempo en alto.... Espero darme a entender y principalmente que aún te haya servido.

      Eliminar
  2. Te hago una consulta... el montaje B qué ventaja tiene?

    Es decír, tienes que tener la frecuencia ajustada a las RPM del rotor del motor para que sea eficiente.
    ¿Es esa la idea? Repeler y atraer las bobinas en sus puntos muertos? Gracias!

    ResponderEliminar
  3. Mi idea es que en el montaje A estamos usando el ENABLE en una función que no era la suya. Para usar un simil, en el montaje A regulamos nuestra velocidad a base de pedalear durante un rato a tope (ENABLE=1) y dejarse ir durante el resto (ENABLE=0). En el montaje B sería como pedalear todo el rato con más o menos energía dependiendo de nuestro objetivo.

    Como puedes ver en las gráficas el comportamiento (PWM duty -> velocidad) es más lineal usando el montaje B). Mi intuición es que en el caso A) controlas menos como se comporta el motor al dejarle ir libre cuando haces ENABLE=0. De todas formas si es importante un control exacto seria bueno hacer algún tipo de calibración previa como comento para ver como se comporta el motor dado en una u otyra configuración.

    Lo que no entiendo de tu pregunta es lo de ajustar la frecuencia a las RPM del motor. ¿A qué frecuencia te refieres ahí?

    Espero haberte aclarado algo,

    Antonio

    ResponderEliminar
  4. muy buen día una consulta que me ronda, entiendo lo del PWM del microcontrolador y sus características pero cual seria la idea usar un PWM de un pic para manejar un motor si tengo que usar una interrupción para bajar la frecuencia. No seria mejor usar un PWM por software y listo. Digo esto porque tengo rato con la duda. Es mas preciso si lo hago como tu indicas con el PWM del pic mas la interrupcion?Gracias por el aporte y saludoss

    ResponderEliminar
    Respuestas
    1. Creo que estás confundiendo el uso del PWM con la interrupción del TMR2.
      Lo de usar la interrupción del TMR2 no tiene nada que ver con el PWM.
      La interrupción es para ejecutar el código de control del motor, típicamente unas decenas o centenares de veces por segundo, dependiendo de la aplicación.
      En cualquier sistema de control vas a tener que ejecutar cada cierto tiempo un "servo-código" que monitorize las respuestas de los sensores, decida que hacer y actúe sobre los actuadores (valga la redundancia). Entre estos actuadores puede haber alguno que se controle con PWM, pero no tiene porque ser así.

      La confusión puede venir porque yo uso el TMR2 (asociado al PWM cuando este está funcionando) para lanzar la interrupción del "servo-código". Esto es sólo una cuestión de ahorrar recursos. Como el TMR2 está en marcha por tener funcionando un PWM, lo aprovecho para correr el "servo-código" a intervalos regulares y así me ahorro gastar otro timer.

      Antonio

      Eliminar
  5. Amigo,tengo un motor dc de 24 voltios,250 watts,14 amperios,2500 rpm,lo alimentan dos baterias de plomo de 12 volt cada una de 5 amp.Necesito un variador de velocidad para impulsar una scooter que estoy construyendo.Las ruedas tienen un diàmetro de 24 cms.Podrìa usted fabricarme un variador de velocidad anàlogo ?Mi mail es beltranenter@yahoo.com

    ResponderEliminar
  6. saludos como realizo el grafico del montaje A

    ResponderEliminar
  7. Hola, buen dia. Excelente aportacion. Pero quisiera saber si podrias asesorarme un poco, voy a realizar el mismo proyecto. Con los mismos componentes L293 y un 7404. Yo usare un Pic de texas instruments que es el Tiva C TM4C23C Pero necesito usar Code Composer Studio, no se si el mismo codio me serviria? Saludos y muchas gracias.

    ResponderEliminar
  8. Hola, buen dia. Excelente aportacion. Pero quisiera saber si podrias asesorarme un poco, voy a realizar el mismo proyecto. Con los mismos componentes L293 y un 7404. Yo usare un Pic de texas instruments que es el Tiva C TM4C23C Pero necesito usar Code Composer Studio, no se si el mismo codio me serviria? Saludos y muchas gracias.

    ResponderEliminar
  9. amigo a que te refieres en el montaje B con meter pwm invertido?

    ResponderEliminar