PicManía by RedRaven
 

Búsqueda personalizada

 

PROYECTOS : RECEPTOR RC ASISTIDO por PIC

 
     Como aficionado al Radio-Control de antiguo hacía tiempo que quería acometer algún proyecto sobre el tema. Este es el primero y espero que sea el inicio de una larga serie.

   Este primer proyecto va a ir destinado a interceptar las señales PWM emitidas por el Receptor RC en el modelo y tratarlas con un PIC a gusto del consumidor.

 

Descripción del Proyecto

En un sistema RC simple las distintas lecturas de los controles en la Emisora RC provocan una reacción proporcional en el Receptor RC del modelo que hace posicionarse a los servos conectados a él.

Las lecturas de los controles son codificadas y transmitidas vía RF desde la emisora hasta el receptor. En éste la señal es transformada en una señal pulso PWM cuyo Duty Cycle define el posicionamiento de los servos (ver Controlando un SERVO con el PIC desde nuestro PC)

En el receptor tendremos entonces unas cuantas señales PWM que podremos controlar, mas o menos, desde la Emisora pero siempre sujetas a las especificaciones que el fabricante haya decidido establecer para su producto.

¿Qué hacer si decidimos saltarnos dichas especificaciones? Como puede ser por ejemplo ampliar o reducir los recorridos reales de los servos, o más difícil aún, cambiar la escala de evolución del movimiento del servo de una lineal a un logarítmica por decir algo. O utilizar sensores externos que "modulen" el movimiento o los márgenes de actuación de un servo, pero manteniendo el control remoto sobre él desde la parte emisora.

Éste es el objeto de este proyecto: Interceptar las señales PWM que salen del Receptor RC hacia los servos, insertando entre ambos un PIC que "lee" las señales recibidas y que tiene la capacidad de transmitirlas a los servos tal cual o modificadas según el algoritmo que deseemos.

Se trata de dotar de "inteligencia" a la parte actuadora sobre el servo. Este cerebro recibirá nuestras órdenes pero actuará dependiendo de ciertas interacciones entre éstas ordenes y otros elementos que podremos involucrar a voluntad: sensores, combinaciones con otras señales, posibilidades complejas de maniobras ... etc.

Concretando:

Os pongo un ejemplo muy concreto sobre el que voy a trabajar. Mi equipo es la Hitec Focus 4 con el receptor HFS-04MI. Esta sistema está especialmente diseñado para el control de Aviones RC.

 


 


 

Los tengo equipados con los Servos Hitec HS-300 y HS-311
 


 

Este equipo tiene ciertas características, fijadas por el fabricante, que limitan de alguna forma su propia operatividad.

La primera y principal limitación proviene directamente de ser un avión el objeto controlado y ello debido a que los aviones son especialmente sensibles a muy pequeños movimientos en los planos físicos de control: alerones, profundidad y timón.

Esto requiere que los servos tengan muy poco desplazamiento entre ambos extremos. Esta compresión del "ancho de banda" del movimiento de los servos podría conseguirse mecánicamente pero el fabricante ha decidido "comprimir" la señal PWM disponible en el receptor RC.

Así aunque el Servo sea nominalmente capaz de realizar un desplazamiento completo de 180º de extremo a extremo, es comandado por un PWM comprimido que hace que sus desplazamiento máximo sea solo de 90º, o sea 45º a cada lado del punto medio. Estos desplazamientos máximos de 45º solo se consiguen con el mando control en la emisora en cada uno de los extremos, con el Trimm a tope y con el ajuste ATV de banda al máximo.
 


 

Esto es una de las cosas que vamos a corregir con nuestro proyecto. Vamos a leer la señal PWM recibida y vamos a "amplificarla" haciendo que nuestros servos recuperen su capacidad de giro de 180º.

Igualmente podemos "atenuarlas" y hacer que esos 45º a cada lado se puedan convertir en sólo 25º con el mando control en un extremo, o cualquier ángulo que nos parezca oportuno.

Podemos también hacer que los recorridos de un servo sean a distintas velocidades según a qué lado se muevan o que tengan distintas amplitudes hacia la izquierda que hacia la derecha, como si tuviesen Trimmers individuales a cada lado del centro.

O podemos implementar nuestro propio sistema de compensación de movimientos haciendo uso de varios servos dependiendo de una sola señal ...

O incluso .... dejémoslo estar. La imaginación es nuestro único límite.

Propósitos para los primeros pasos:

Lo primero que vamos a hacer es conectar nuestro PIC a uno de los canales del receptor y leer la señal PWM.

Después vamos a hacer un By-Pass y vamos a retransmitir este PWM de forma absolutamente idéntica al Servo, de forma que parezca que nuestro PIC es transparente, como si no estuviese en medio leyendo la señal del receptor y generando a su vez un PWM especular, para que todo siga funcionando igual.

Y después vamos a implementar algún algoritmo "amplificador" o "atenuador" de esa misma señal de forma que el PWM recibido y el PWM transmitido al servo sean asimétricos y tengamos así la capacidad de modificarlo según nuestra conveniencia.
 
Primera Parte:
 
Bueno, ya tenemos nuestro primer paso dado. En los Propósitos para los primeros pasos decíamos que lo primero era conectar nuestro PIC a uno de los canales del receptor y leer la señal PWM.

Y eso es lo que os presento aquí y ahora.

He montado el siguiente hardware: Una fuente de alimentación de 5V para sustituir al pack de 4 pilas Ni-Cad y no tener que estar dependiendo de su carga mientras trabajo, el receptor Hitec HFS-04MI, uno de los cables alargadores de la conexión de un servo cortado para tener disponible la señal PWM de uno de ellos, un PIC 18F1320 montado con el hardware mínimo, el cristal oscilador y poco más, y un MAX232 conectado al PIC para poder monitorizar lo que ocurre en él desde el PC.

Aquí tenéis una imagen del montaje:
 


 

La señal llega al PIC desde el receptor mediante el cable amarillo, los otros dos son la alimentación del Servo y no los usamos en este momento:
 

 
A continuación he realizado una implementación mas o menos fiel a lo descrito en mi artículo Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT, salvo que en vez de calcular el tiempo en alto he dado un pequeño paso adelante y calculo el tanto por ciento que permanece en alto, sabiendo que el 100% corresponde a un periodo de 20 ms, o lo que es lo mismo a una frecuencia de 50 Hz, que es el estándar para este tipo de servos.

El programa es éste:
 
  Titulo  
  #include <18f1320.h>
#fuses HS,MCLR,PUT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOCPD,NODEBUG,NOWRT
#use delay(clock=20000000)
#use rs232(baud=115200, xmit=PIN_B1, rcv=PIN_B4)

static unsigned int16 ticks, DutyCycleK=0;
static int1 flag_H_TO_L=0;

#int_ext
void ext_isr() {

  if(flag_H_TO_L){
    ticks=get_timer1();
    ext_int_edge(0,L_TO_H);
  }
  else{
    set_timer1(0);
    ext_int_edge(0,H_TO_L);
    ticks=0;
  }
  ++flag_H_TO_L;
}

void main() {

  static unsigned int16 uticks, DutyCycle;


  disable_interrupts(global);
  disable_interrupts(int_timer1);
  disable_interrupts(int_rda);
  disable_interrupts(int_ext);
  disable_interrupts(int_ext1);
  disable_interrupts(int_ext2);
  setup_adc_ports(NO_ANALOGS);
  setup_adc(ADC_OFF);
  setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  setup_timer_0(RTCC_OFF);
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
  setup_timer_2(T2_DISABLED,0,1);
  setup_timer_3(T3_DISABLED);
  port_b_pullups(FALSE);

  delay_ms(1000);

  flag_H_TO_L=0;
  ext_int_edge(0,L_TO_H);
  enable_interrupts(int_ext);

  enable_interrupts(int_rda);
  enable_interrupts(global);

  printf("\r\n18F1320 listen on RS232\r\n");
  printf(" RC PWM Interceptor\r\n>");

  do {

    if((ticks!=0)){
      disable_interrupts(int_ext);
      uticks = ticks; ticks=0;

      DutyCycle = (unsigned int16) uticks * 10 / 5000;

      if(DutyCycleK!=DutyCycle){
        printf("\r\n>%Lu",DutyCycle);
        DutyCycleK=DutyCycleK;
      }

      flag_H_TO_L=0;
      ext_int_edge(0,L_TO_H);
      enable_interrupts(int_ext);
    }
  } while (TRUE);
}
   
 
 

 

 

Con un cristal de 20 Mhz y el Timer1 corriendo con un pre-escaler de 2 tengo un Tick cada 0.4 uS por lo que nuestros 20 ms de 100% de Duty Cycle corresponderían a 50.000 ticks de Timer1.

Por ello DutyCycle = (unsigned int16) uticks * 10 / 5000; corresponden a una sencilla regla de tres para saber qué tanto por ciento corresponden a los ticks que hemos recogido entre los flancos de subida y bajada de nuestro PWM. (Nota: he dividido por 10 el numerador y el denominador y así multiplico por 10 y divido por 5000 en lugar de multiplicar por 100 y dividir por 50.000, estoy pintando con trazo grueso)

La respuesta teórica entre extremos debería ser como lo representado en la imagen inferior:
 


 

O sea la señal PWM variando entre 0.6 ms y 2 ms o lo que es lo mismo entre el 3% y el 10% del Duty Cycle para obtener un movimiento total de 180º.

Sin embargo los resultados obtenidos haciendo un barrido completo con el mando del Joystick de un extremo al otro y volviendo al comienzo son:
 


 

Esto nos lleva a la conclusión de que mi Emisora, con los ajustes actuales, y actuando de extremo a extremo sobre uno de los Joysticks (el de profundidad que es el único que no vuelve al centro automáticamente) solo varía el PWM entre el 6% y el 10% del Duty Cycle, o lo que es lo mismo entre 1.2 ms y 2.0 ms, y que la parte baja del PWM hasta el 3% permanece sin usar.

Asunto éste compatible con lo declarado por el fabricante en su manual de instrucciones relativo a la amplitud de movimientos de un servo con este equipo:
 


 


Esto es lo que pretendo corregir a modo de ejemplo. Leer entre estos 6% y10% y "ampliarlo" hasta el 3% inferior para lograr un recorrido completo del servo.
 
Segunda Parte:
 
Tras el primer paso viene el segundo (no puede ser de otra forma salvo que nos quedemos quietos como el mármol)

Decíamos en nuestros propósitos que el segundo paso sería hacer un By-Pass y vamos a retransmitir este PWM de forma absolutamente idéntica al Servo, de forma que parezca que nuestro PIC es transparente, como si no estuviese en medio leyendo la señal del receptor y generando a su vez un PWM especular, para que todo siga funcionando igual.

Y esto está hecho.

Le he añadido a nuestro hardware un servo conectado al PIC por el pin RB3 y lo he alimentado correspondientemente, tal como puede verse en la fotografía inferior:
 


 


Y ahora con una mínima modificación de nuestro programa anterior tenemos el By-Pass realizado.

Lo primero es añadir un par de líneas a nuestra interrupción detectora del PWM recibido. Cuando recibimos un flanco de subida, inicio del PWM recibido, hacemos lo propio con nuestro PIN del Servo, y lo indicamos mediante el flag_servo_1. De esta forma "sincronizamos" ambos PWM, el emitido por nosotros con el recibido desde el receptor.

Como al mismo tiempo hemos puesto el Timer1 a cero sabemos exactamente donde estamos, y en el main() estamos calculando los Ticks que recibimos, sobre uticks , así que si en el mismo main() miramos el estado del Timer1 en cuanto sobrepase a estos ticks podemos bajar la señal de nuestro PWM generado.

Podríamos hacerlo en la misma interrupción al recibir el flanco de bajada del PWM del Receptor pero he preferido ponerlo en el main() para poder ampliarlo o reducirlo a voluntad. Pero eso ya es tema para el siguiente paso. Y aún no le toca.

El programa completo quedaría así:

 
  Titulo  
  #include <18f1320.h>
#fuses HS,MCLR,PUT,NOWDT,NOPROTECT,BROWNOUT,BORV45,NOLVP,NOCPD,NODEBUG,NOWRT
#use delay(clock=20000000)
#use rs232(baud=115200, xmit=PIN_B1, rcv=PIN_B4)

static unsigned int16 ticks, ticksK;
static int1 flag_H_TO_L=0, flag_servo_1;

#int_ext
void ext_isr() {

  if(flag_H_TO_L){
    ticks=get_timer1();
    ext_int_edge(0,L_TO_H);
  }
  else{
    set_timer1(0);
    ext_int_edge(0,H_TO_L);
    ticks=0;
    output_high(PIN_B3);
    flag_servo_1=1;
  }
  ++flag_H_TO_L;
}

void main() {

  static unsigned int16 uticks;

  disable_interrupts(global);
  disable_interrupts(int_timer1);
  disable_interrupts(int_rda);
  disable_interrupts(int_ext);
  disable_interrupts(int_ext1);
  disable_interrupts(int_ext2);

  setup_adc_ports(NO_ANALOGS);
  setup_adc(ADC_OFF);
  setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  setup_timer_0(RTCC_OFF);
  setup_timer_1(T1_INTERNAL | T1_DIV_BY_2);
  setup_timer_2(T2_DISABLED,0,1);
  setup_timer_3(T3_DISABLED);
  port_b_pullups(FALSE);

  delay_ms(1000);

  flag_H_TO_L=0;
  ext_int_edge(0,L_TO_H);
  enable_interrupts(int_ext);
  flag_servo_1=0;

  enable_interrupts(int_rda);
  enable_interrupts(global);

  printf("\r\n18F1320 listen on RS232\r\n");
  printf(" RC PWM Interceptor\r\n>");

  do {

    if((ticks!=0)){
      uticks = ticks; ticks=0;
      if(uticks != ticksK){
        ticksK=uticks;
      }
      flag_H_TO_L=0;
    }

    if(flag_servo_1==1){
      if(get_timer1()>ticksK){
        output_low(PIN_B3);
        flag_servo_1=0;
      }
    }
  } while (TRUE);
}
  
 
 

 

 
 
 
 
 

 

 

 

Esta página se modificó el 27/12/2008


Esta página usa la letra Ñ

Nota pública importante sobre las consultas al Webmaster de PicManía.


Sugerencias a Picmanía... (que serán leídas pero seguramente no podrán ser contestadas)

Esta página pertenece al grupo de páginas de Diego RedRaven

 

 



Nota: Esta página Web esta repleta de imágenes, textos, logotipos y demás material extraídos de los mas variados medios de los que no soy ni autor ni depositario de los correspondientes derechos de autor, uso y/o reproducción. Si Ud. es depositario de dichos derechos y desea que el material correspondiente sea eliminado de esta Web no dude en ponerse en contacto conmigo mediante e-mail y será inmediatamente retirado. Gracias.
 
Visitas
Totales : 27530 Hoy: 1 Activas: 1 Vistas: 27530

Esta página fue modificada el 07-08-2010 22:42:16

           
 DmSoft WAMP Escribir Unreal