Servomotores controlados por PWM

Le llamamos servomotor a un tipo de actuador que tiene un eje rotatorio que es capaz de quedarse quieto en una posición determinada. Controlamos la posición de dicho eje enviando periódicamente pulsos de una duración específica al control del servo, figuras 1 y 2.

Foto del HS-805BB y señal de control.
Figura 1. Servomotor HS-805BB+ con el eje de rotación a un extremo de sus posibilidades y la señal de control que lo posiciona así.
Foto del HS-805BB y señal de control.
Figura 2. El mismo servo de la figura 1, ahora con el eje de rotación al otro extremo de sus posibilidades, y su respectiva señal de control.

Para realizar las pruebas de esta entrada usé:

  • Un servomotor HS-805BB+.
  • Un servomotor HS-311.
  • Un PIC16F887.
  • Un módulo de conversión USB-USART (el que está etiquetado con el número 4 en la entrada “Comunicación RS232 a través del USB“).
  • La versión 2 del programador para el PIC16F887 que está en la entrada “Programador para los PIC16F88x“.
  • Una fuente externa de 5 V (HF20W-TL-A).
  • Ubuntu 16.04 con GtkTerm.
  • MPLAB X IDE v4.05 con la modalidad gratuita del compilador XC8 v1.45.

Te ofrezco dos circuitos de prueba para que elijas uno: El de la figura 3 requiere que le pongas un PIC16F887 ya programado. El circuito de la figura 4 incluye un programador que describí en la entrada “Programador para los PIC16F88x“.

Diagrama eléctrico del circuito de prueba.
Figura 3. Diagrama del circuito de pruebas. Requiere que programes el PIC antes de ponerlo en el prototipo. Observa que el módulo UsbUsart puede proporcionar energía par el PIC, pero el servo requiere que uses una FUENTE EXTERNA.
Diagrama del circuito de prueba que incluye programador.
Diagrama del circuito de prueba. También puedes usar este circuito para programar el PIC. Observa que el módulo UsbUsart puede proporcionar energía par el PIC, pero el servo requiere que uses una FUENTE EXTERNA.

pwm.c es el código que deberás programar en el PIC:

#include <xc.h>
#pragma config FOSC=INTRC_CLKOUT
#pragma config WDTE=OFF

unsigned int recibe(void);

void main(void)
{
 unsigned char n, cadena[]="¿PR2? ";
 unsigned int CicloUtil;
 
 OSCCON=0x28; // Oscilador interno a 250 kHz.
 TRISCbits.TRISC1=0; // Permite la salida del PWM.
 // Configuración de la comunicación serie.
 TXSTA=0x26;
 RCSTA=0x90;
 SPBRG=12;
 // Espera un byte desde la PC para sincronizarse.
 while (PIR1bits.RCIF!=1) asm("NOP"); 
 n=RCREG;
 // Transmite el texto que solicita el valor para PR2.
 for (n=0; n<7; n++)
 {
  while (PIR1bits.TXIF!=1) asm("NOP");
  TXREG=cadena[n];
  asm("NOP");
 }
 // Recibe como cadena el valor para PR2,
 // lo convierte en numérico y lo asigna.
 while (PIR1bits.RCIF!=1) asm("NOP"); 
 // Establece el periodo PWM.
 PR2=(unsigned char)recibe();
 T2CON=0x05; // Activa el temporizador 2, factor de escala de 4.
 CCP2CON=0x2F; // Módulo CCP en modo PWM.
 CCPR2L=0x17; // Ciclo útil que pone el eje del servo a la mitad.
 // Ciclo infinito que permite el ajuste del ciclo útil.
 while(1)
 {
  if (PIR1bits.RCIF==1)
  {
   CicloUtil=recibe();
   CCPR2L=(unsigned char)(CicloUtil>>2);
   if ((CicloUtil&0x1)==0) CCP2CONbits.DC2B0=0; else CCP2CONbits.DC2B0=1;
   if ((CicloUtil&0x2)==0) CCP2CONbits.DC2B1=0; else CCP2CONbits.DC2B1=1;
  }
 }
}

// Obtiene una cadena de caracteres a través de la USART,
// y los convierte a números decimales.
unsigned int recibe(void)
{
 unsigned char c;
 unsigned int n;
 
 n=0;
 c=RCREG;
 while (c!=13)
 {
  n*=10; // Peso de acuerdo a la posición.
  n+=(c-'0'); // ASCII a decimal y suma.
  while(PIR1bits.RCIF!=1) asm("NOP");
  c=RCREG;
 }
 while(PIR1bits.TXIF!=1) asm("NOP");
 TXREG='\n';
 return n;
}

Usaremos GtkTerm para enviar comandos al PIC. Configuralo para mostrar eco y establecer la velocidad a 1200 bps, figura 5.

Captura de pantalla que muestra la configuración de GtkTerm.
Figura 5. Captura de pantalla que muestra la configuración de GtkTerm: eco activo, TtyUSB0 a 1200 bps. También se observan algunos valores usados en la prueba que describo a continuación.

Después de conectar todo y configurar el GtkTerm, puedes iniciar las pruebas:

  • Oprime intro para avisar al PIC que la PC está lista.
  • Responde 255 intro cuando veas que el PIC te pregunta, a través de GtkTerm, el valor para el registro PR2 (duración del periodo de la modulación). Esto hara que el eje del servo se coloque aproximadamente a la mitad de su recorrido.
  • Teclea 40 intro y observa que el eje gira hasta un extremo. Si al quedarse quieto el eje escuchas que el mecanismo hace “ruidos extraños”  prueba con un valor ligeramente mayor.
  • Teclea 148 intro y observa que el eje gira hasta el otro extremo. Si al quedarse quieto el eje escuchas que el mecanismo hace “ruidos extraños”  prueba con un valor ligeramente menor.
  • Obtén posiciones intermedias al teclear números intermedios, por ejemplo 100 y 50.

Consideraciones para obtener las constantes que aparecen en el programa y las pruebas:

  • El núcleo del PIC, el temporizador 2, el módulo CCP (que contiene al modulador por ancho de pulso, PWM), y la USART usan como base de tiempo para realizar sus operaciones el oscilador principal. Para satisfacer simultaneamente todas las necesidades, elegí la frecuencia de 250 kHz (Fosc=250 kHz).
  • 1200 bps para la comunicación serie son suficientes para la poca información que moveremos, representan una velocidad muy alta comparada con nuestra velocidad al teclear en el GtekTerm, y se pueden configurar con un error mínimo (valor calculado para SPBRG = 12.02, valor programado = 12).
  • Cuando el módulo CCP trabaja en modo PWM, requiere del uso conjunto del temporizador 2.
  • El periodo de la modulación se establece a partir del valor del registro PR2 y del factor de pre-escala del temporizador 2:

PeriodoPWM=\left [ (PR2)+1 \right ]\bullet4\bullet PreEscaladorTmr2/ Fosc

  • Ya que usé un factor de escala de 4 y una frecuencia del oscilador principal de 250 kHz, cuándo ordeno un valor de 255 para PR2 obtengo un periodo para la  modulación de 16.4 ms, y por tanto una frecuencia de aproximadamente 61 Hz (la única “pista” que tenía para establecer esta frecuencia, era la mención en diferentes sitios de Internet que dicen “algunos servos se controlan con PWM a una frecuencia cercana a 50 Hz”).
  • El ancho del pulso se establece con el registro CCPR2L y 2 bits del registro CCP2CON (DC2B0 y DC2B1). La parte más significativa se maneja en CCPR2L y al final se forma un número de 10 bits (Num10Bits).

AnchoDePulso=Num10Bits \bullet PreEscaladorTmr2 / Fosc

  • Al dar un valor de 40 a Num10Bits en la fórmula anterior se obtiene una duración para el pulso de 640 us. Con 148 se obtienen 2368 us. Observa las pantallas de osciloscopio en las figuras 1 y 2.
  • A final de cuentas: tanto el periodo de la modulación, como la duración del pulso, se establecen contando pulsos del oscilador principal que pasan a través del pre-escalador de TMR2. Por lo que la única forma de aprovechar los 10 bits del PWM, es dando un valor de 255 a PR2.

Para que puedas seguir experimentando te recomiendo que consultes la hoja de datos del servo que usas; y anexo unas figuras relacionadas con los registros usados en pwm.c.

OSCCON, registro para controlar el oscilador principal.
Figura 6. OSCCON, registro para controlar el oscilador principal. La imagen original pertenece a Microchip y está en la página 64 de la hoja de datos del PIC16F887.
TXSTA, registro para configurar el transmisor de la USART.
Figura 7. TXSTA, registro para configurar el transmisor de la USART. Observa que el bit TRMT es sólo de lectura, ya que escribí el contenido de TXSTA en una sola asignación, use el valor que tendría TRMT al reiniciar el PIC. La imagen original pertenece a Microchip y está en la página 157 de la hoja de datos del PIC16F887.
RCSTA, registro para habilitar el puerto serie y configurar el receptor de la USART.
Figura 8. RCSTA, registro para habilitar el puerto serie y configurar el receptor de la USART. La imagen original pertenece a Microchip y está en la página 158 de la hoja de datos del PIC16F887.
Fórmulas para determinar la velocidad de la comunicación serie.
Figura 9. Fórmulas para determinar la velocidad de la comunicación serie. La imagen original pertenece a Microchip y está en la página 160 de la hoja de datos del PIC16F887.
T2CON, registro para controlar el temporizador 2.
Figura 10. T2CON, registro para controlar el temporizador 2. La imagen original pertenece a Microchip y está en la página 84 de la hoja de datos del PIC16F887.
 CCP2CON, registro para controlar el segundo módulo CCP.
Figura 11. CCP2CON, registro para controlar el segundo módulo CCP que contiene un modulador por ancho de pulso. La imagen original pertenece a Microchip y está en la página 123 de la hoja de datos del PIC16F887.

Puedes encontrar más información de PWM y ejemplos en ensamblador para controlar los servos en: el capítulo 8 (sección 8.3) de Microcontroladores PIC16, fundamentos y aplicaciones.

¡Hasta la próxima!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *