viernes, 16 de noviembre de 2018

TMR1 Control de Servomotores


  Control de Servos con PIC16F


Un gran saludo para todos los visitantes  que comparten interés en este mundo de la electrónica y en especial para los aficionados a la programación de microcontroladores PIC. En esta ocasión quiero mostrar como hacer uso del modulo Temporizador TMR1 para controlar mas de un servomotor.
Si no tienes claro de como funciona el modulo TMR1 del microcontrolador PIC16F, te recomiendo revises la siguiente entrada, en donde explico con mayor detalle la operación del modulo:  <TMR1 Configuración y Uso >.
El objetivo en esta sección es utilizar mas de un servomotor, técnicamente hasta ocho servomotores con un solo PIC16F, en donde cada servomotor trabajara en su rango de tiempo asignado para realizar el movimiento, de 0 hasta los 180 grados. 
La programación se realizara utilizando MPLABX y el compilador XC8 ambos disponibles en la pagina de microchip. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo:  <<MPLABX v6.20>>   <<XC8 v2.50>>
Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16.

Acerca del Servomotor
Un servo esta compuesto por un motor DC, una caja reductora y un circuito electrónico de control que nos permite ubicar un eje central de accionamiento en cualquier posición dentro del rango de operación para el cual fue diseñado, en general de 0 a 180° grados. 
Suele contar con tres lineas de conexión, dos corresponden a la alimentación de +V / GND y uno para la señal de control que consiste en un pulso digital con modulación del ancho variable entre 1 y 2 milisegundos a 50 Hz de frecuencia. Observe la siguiente figura que muestra la relación del ancho que tiene el pulso digital con la posición del servomotor.


Fig1. Señal de Control para Servo

La señal de control de un servomotor es prácticamente del tipo PWM (Pulse Width Modulation) y tenemos mente utilizar un microcontrolador como el PIC16F debemos considerar los siguientes aspectos:
  • Por general los Microcontroladores, salvo algunos del tipo DSP poseen una cantidad de pines PWM limitadas, como es el caso del PIC16F88x que solo cuenta solo con dos salidas, y estos comparten el mismo recurso de temporización, por lo que no siempre se ajustaran a ciertas necesidades.
  • Los modulo PWM de un PIC16F, están diseñados para señales PWM con ciclos de trabajo que van de 0 al 100%, mientras que un servo solo requiere para el control un ciclo de trabajo entre el 5 y 10%.
  • El modulo CCP del PIC16F no se diseño para trabajar en baja frecuencia, de tal manera que para una salida de 50Hz, la frecuencia del oscilador no deberia superar los 1MHz.
Tomando en cuenta estas consideraciones vemos que una buena alternativa al uso de un modulo dedicado como el CCP, es utilizar un temporizador con su interrupción, de esta manera es posible controlar hasta ocho servomotores.
 
Señal de control PWM
Ahora veremos como se genera la señal de control PWM para un servomotor aplicando el uso del temporizador TMR1 y su interrupción.
La figura 2 nos muestra la distribución del pulso S1 dentro del periodo de control fijo que tiene el servomotor, donde el ancho del pulso dura entre entre 1 y 2 ms con un periodo fijo de 20 ms.

Fig2. Periodo de la señal PWM
 
Para establecer una salida PWM, nuestro programa utilizara las siguientes variables de control, junto a los cálculos que se muestran en la ecuación 1, estos valores pueden ajustarse en el archivo de cabecera tservo.h
  • tsvnum. Establece la cantidad de salidas PWM a utilizar, de 1 a 8.
  • tsvslot. Es la fracción de tiempo o ranura dentro del periodo en la cual debe enviarse el pulso de control PWM de cada salida, su valor representa los micro-segundos necesarios para un desbordamiento del TMR1 y su calculo obedece a la siguiente ecuación.
Ec1. Calculo de ranura de tiempo en microsegundos
  • TSV.svxpos. Este valor decimal corresponde a la duración del ancho del PWM de cada salida, como valores de referencia se tiene: 0=0 grados, 50= 90 grados y 100=180 grados.
Si bien es posible hacer uso de cualquier modulo temporizador que incremente en pasos de un microsegundo (us), el TMR1 posibilita contabilizar hasta los 20000us que tiene el periodo de la señal PWM del servomotor, gracias a su registro de 16-bits. Para determinar los pasos en un PIC16F debemos considerar la relación que tiene el ciclo de instrucción con respecto a la frecuencia de operación: 
Entonces aplicando la formula anterior vemos que para una frecuencia de  8MHZ, los pasos serán de 0.5us y se necesitara un división 1:2 para conseguir incrementos de un 1.0us. (2 * 0.5u).
 
Para llevar a cabo la programación de control para los servomotores, he creado la librería tservo.c, que nos facilitara aplicar el proceso de señalización a todas la salidas de control PWM. Describiré como hacer uso de las dos funciones que contiene esta librería, que son:
  • TSERVOSetup(): Configura la cantidad de pines requeridos para la señalización PWM, cada pin esta asociado al puerto definido en TSVPORT, se numera desde 1 a 8, siendo 1 el pin0 y 8 el pin7.
  • TSERVOHandler(): Esta función es invocada desde la rutina de servicio a la interrupción ISR, cuando finaliza el temporizador y permite controlar el estado de la señalización para cada pin PWM, al final devuelve el valor de tiempo que se requiere para actualizar el temporizador.
El uso de estas funciones dentro del programa principal se resume en las siguientes secciones de código:

 Sección 1: Cabecera tservo.h

/* USER PORT DEFINITION */
#define TSVNUM 2
//Numero de servos a conectar, Máximo 8. 20ms/8 > 2ms.
#define TSVSLOT (65536UL -(20000U/TSVNUM))
//Se puede adicionar un offset +30
#define TSVTIME0 (65536UL - 900U)
//Time offset for -90
#define TSVPORT PORTD
//Puerto servo control <posn>..<pos2><pos1>
#define TSVTRIS TRISD
//Tris Puerto servo
/* END USER PORT DEFINITIOS*/

Sección 2: Programa principal

#include "tservo.h" //Cabecera de la librería servo
void setupMCU(void);
//Prototipo de función
void main(void)
{
    setupMCU();
//Configuración del PIC
    TSERVOSetup();
//Configuración del SERVO
    TSV.sv1pos = 10;
//Ajusta servo al 10%
    TSV.sv2pos = 80;
//Ajusta servo al 80%
    while(1)
    {
        if(tickms)
//Intervalo para la concurrencia
        {
            tickms = 0;
//Limpia bandera
           
//Código del programa principal
                                           
        }
    }   
}
void setupMCU(void)
//Procedimiento de configuracion del MCU
{
    OSCCONbits.IRCF = 0b111;
//Ajusta frecuencia a 8MHz
    while(OSCCONbits.HTS == 0) {};
   
 
    /* CONFIGURACIÓN TIMER1 8MHZ PASOS DE 1US */
    T1CONbits.T1CKPS = 1;  
//Pre-escala 1:2
    T1CONbits.TMR1CS = 0;  
//Modo temporizador
    T1CONbits.TMR1ON = 1;  
//Activa el modulo
    PIR1bits.TMR1IF = 0;   
//Limpia bandera
    PIE1bits.TMR1IE = 1;   
//Activa interrupción timer1
   
INTCONbits.PEIE = 1;
    INTCONbits.GIE = 1;
}
 
Sección 3: Rutina de Interrupción.

void __interrupt() isr(void) //Rutina de servicio de interrupción
{
    uint16_t res;
    if(PIR1bits.TMR1IF)
//Evento cuando finaliza el temporizador
    {
        res = TSERVOHandler();
//Función de control PWM
        T1CONbits.TMR1ON = 0;
//Para el temporizador
        TMR1L = (uint8_t) res;
//Recarga el temporizador
        TMR1H = (uint8_t) (res >> 8);
        PIR1bits.TMR1IF = 0; 
//Limpia la bandera
        T1CONbits.TMR1ON = 1;
//Inicia el temporizador
    } 
}

 
La función de control TSERVOHandler() administra el estado de cada pin en función del numero de servomotores definidos en TSVNUM,  determinando de forma automática en cambio de estado logico con base a los limites establecidos para a cada ranura de tiempo dentro del periodo PWM. Con esta técnica es posible asignar entre uno y ocho ranuras de tiempo dentro del periodo de 20ms que utiliza un servomotor. Comprenderá mejor este punto observando la distribución de tiempos que se ilustran en las siguientes figuras.

Fig3. Ranuras de tiempo PWM para 2 Servomotores

Fig4. Ranuras de tiempo PWM para 4 Servomotores

Fig5. Ranuras de tiempo PWM para 8 Servomotores

Conexión del Servo 
Como mencionamos anteriormente un servo suele contar con tres lineas de conexión, dos corresponden a la alimentación de energía y una para el control de posición. La siguiente figura ilustra la disposición de los pines y colores utilizados por algunos fabricantes.
Fig6. Puerto de conexión servo

Mas allá de la disposición de pines para un servomotor, es importante considerar aspectos técnicos que son proporcionados por el fabricante y que deben considerarse durante la etapa de diseño de un circuito electrónico.
 
Programa de control PIC16F
En este apartado veremos como crear un programa que nos permite controlar de forma independiente la posición de dos servomotores utilizando dos potenciómetros. El código del programa principal contiene procedimientos adicionales necesarios para el funcionamiento de este programa, estos incluyen la lectura ADC y la concurrencia de tareas con el TMR0.

El programa principal ingresa en un bucle continuo para ejecutar tareas cada milisegundo, estas tareas permiten destellar un LED y hacer lectura de los dos canales analógico ADC para cargar la variable de control de posición sv1pos y sv2pos. Cabe resaltar que ninguna de estas tareas representa un proceso bloqueante, la codificación utiliza una técnica de programación por estados, si quieres conocer mas detalles al respecto puedes revisar la siguiente publicación.
Fig7. Circuito para control de dos servomotores

Alternativamente a los potenciómetros que se observan en el esquema de circuito de la figura 7, podemos utilizar un modulo joystick y una estructura de movimiento de dos ejes como el que se observa en la figura 8.

Fig8. Joystick y Servo para 2-ejes
 

Conectado estos modulo a nuestro PIc16F887 conseguiremos ensayar el funcionamiento del programa de manera simple y rápida, observe como quedo el circuito de prueba.

Fig9. Circuito de Prueba PIC16F887

Aquí dejo el enlace para descargar el programa, mismo que se encuentra en formato gzip, para descomprimir y abrirlo desde MPLABX:
Si quieres ver como compilar e implementar los proyectos de este blog, en MPLABX mira este vídeo.

Conclusiones y Recomendaciones
Pudimos ver mediante un ejemplo como hacer uso del TMR1 para controlar hasta ocho servomotores utilizando las funciones presentes en la librería tservo,  Adicionalmente quiero comentar los siguientes aspectos con relación al tema:
  • Es posible adaptar esta técnica de control para servomotores utilizando temporizadores de 8-bit como el modulo TMR0 o TMR2, pronto actualizare la publicación con un ejemplo de uso para el caso.
  • Si bien se recomienda utilizar múltiplos de 4MHZ para la frecuencia del cristal, es posible emplear valore diferentes como ser 10MHZ o 20MHz, donde el control de pasos no siempre serán múltiplos exactos de 1us, si bien la frecuencia de control PWM para el servomotor es de 50Hz, estos pueden operar en el rango de 40Hz hasta los 400Hz.
  • La latencia de las interrupciones puede provocar oscilaciones en el movimiento del servomotor cuando la rutina ISR atiende otras fuentes de interrupciones. Debe analizar a detalle la implicación que conlleva atender cada unos de los eventos.

Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo visto pueda ser útil en tu formación y el proyecto que desarrollas.

Atentamente, Pablo Zárate Arancibia  email: pablinza@me.com / pablinzte@gmail.com, @pablinzar

Santa Cruz de la Sierra - Bolivia

No hay comentarios.:

Publicar un comentario