domingo, 29 de enero de 2012

Leer emisora RC Parte 1

    Existen dos posibilidades para leer la información que envía una emisora RC (de radio control).

    Una primera opción es leer la señal PPM en el receptor de la emisora. La ventaja es que esta señal trae codificados todos los canales de la emisora por lo que sólo necesitamos una entrada digital en Arduino. La desventaja es que hay que acceder al interior del receptor e interceptar esta señal. Cada receptor será distinto por lo que puede ser una tarea complicada.

    Otra opción es leer los canales de salida que ya ha separado el receptor. Se corresponden a señales PWM, tantas como canales tiene la emisora. Son las señales que van hacia los servos o los ESC's de los motores. La ventaja es la no invasión del receptor. Desventaja que tenemos que usar en Arduino tantas entradas digitales como canales tiene la emisora.

    Yo he optado por la segunda solución pero con una pequeña implementación para no necesitar tantas entradas de Arduino. En concreto para leer los 8 canales de mi emisora, la Turnigy TGY 9X, sólo necesitaré 3 entradas. ¿Cómo hacer esto? El primer canal lo llevamos a una entrada de Arduino. Además de calcular su lectura lo usaremos para sincronizar el inicio de todas las lecturas. El resto de canales lo que hacemos es sumarlos, los pares por una lado y los impares por otro. De este modo puedo detectar el final del pulso de un canal ya que el siguiente, que va seguido, está en la otra entrada de Arduino.

    Así tendremos el Canal 1 en la entrada PIN 2 de Arduino. Los Canales 2, 4, 6 y 8 sumados y a la entrada PIN 3 de Arduino. Y los Canales 3, 5 y 7 sumados y a la entrada PIN 4 de Arduino. ¿Y cómo sumamos los canales? Muy sencillo. Conectamos un diodo de señal (como el 1N4148) en cada uno de los Canales 2, 4, 6 y 8, la otra patilla de los diodos las unimos a una resistencia de 47K y la otra patilla de la resistencia a GND. Lo mismo con los Canales 3, 5 y 7.

    Una cuestión importante. Esto es así cuando la secuencia de las señales PWM de los canales llevan el orden lógico de 1, 2, 3, 4, 5, 6, 7 y 8. Sin embargo comprobé que mi emisora Turnigy TGY 9X no lleva esa secuencia. Tiene cambiados en orden los canales 2 y 3. Cosa inexplicable que no llego a entender y que por otro lado no sé si es así en otras emisoras. Así en mi caso la secuencia de canales es 1, 3, 2, 4, 5, 6, 7 y 8. Y por tanto mi configuración definitiva es:

- Canal 1 directo a pin 2.
- Canales 3, 4, 6 y 8 a traves de diodos a pin 3.
- Canales 2, 5 y 7 a traves de diodos a pin 4.



    Una vez tenemos las lecturas podemos comprobar el rizado. Con una palanca centrada obtengo una lectura de unos 1450 µs que varía en un rango de hasta 12 µs. Tenemos que alisar esa señal. En la primera versión desarrollada esto lo hago haciendo la media de las últimas X medidas tomadas. Por defecto lo he dejado en 6 por estar en lo que yo creo es el punto de equilibrio. Pero, ¿qué equilibrio? Pues cuantas más medidas utilicemos para hacer la media mejor estamos filtrando la señal. Sin embargo aumentar el número de medidas a promediar produce un retardo de la señal.

    Consultando sobre el tema del filtrado de señales Igor R me informó en los foros de Arduino de que el promedio de los últimos X valores es más bien un método malo. Podéis verlo en filtro paso-bajo con arduino. Así que al tiempo que la versión 1.0 de Leer Radio es totalmente operativa, como el filtrado lo realizo con el promedio de los últimos 6 valores, sigo haciendo pruebas con distintos tipos de filtros digitales.

    Archivo para Arduino 1.0: Leer radio v1.0

    Nota: tras hacer diferentes pruebas con distintos tipos de filtros (Butterworth, Bessel y Chebyshev) de distinto orden y frecuencia de corte concluyo que no percibo una mejoría en el filtrado por lo que finalmente me quedo con el filtrado mediante promedio.

    Al ir trabajando con este código he ido pensando en algunas ideas para mejorar el rizado que tengo que plasmar en forma de código. Cuando lo desarrolle pondré una nueva entrada.

    La nueva entrada ha llegado, podéis verla en Leer emisora RC Parte 2.

19 comentarios:

  1. Cualquier comentario, aporte o consulta es bienvenido.

    ResponderEliminar
  2. Hola, buen artículo! Ando detrás de hacer lo mismo que tú para luego mezclar canales y controlar los servos para hacer el quadrotor radio control.
    La cuestion es que no me ha quedado claro como conectas los canales sumados al arduino. Por ejemplo, para el pin 3, cada uno de los canales a través de un diodo, y la salida de cada diodo al pin 3 y de ahí una resistencia a tierra?
    Un saludos!

    ResponderEliminar
  3. Hola David.
    Así es, tal como dices. Debería haber hecho un pequeño dibujo pero no tengo ningún programa que me permita hacerlo fácilmente. Me alegro de que te sea de utilidad mi artículo.

    ResponderEliminar
  4. Me he decidido, me he instalado el software Fritzing y he hecho el esquema de conexión entre el receptor de la emisora RC y Arduino. Está añadido en el artículo.

    ResponderEliminar
  5. He estado leyendo el codigo y me parece absolutamente increible. Yo intentaba leer los pulsos de mi radio (4 canales) con cuatro funciones pulsein() y tenia problemas horribles cuando mi radio se apagaba o se perdia la señal.

    Si he entendido bien algo del codigo, tu no utilizas para nada la funcion pulsein. Simplemente mides en cada caso el tiempo transcurrido desde la ultima señal de nivel bajo hasta la nueva señar de nivel bajo. Por supuesto añadiendo a esto el tema de las señales superpuestas y los filtrados.

    Francamente con lo que yo se de programacion no tengo capacidad para hacer eso, temo no poder terminar mi proyecto.

    ResponderEliminar
  6. Hola marcesve.
    Ánimo hombre, de los errores se aprende mucho. Mi código que ves terminado lleva muchas horas de pruebas, entender el funcionamiento de la emisora, consultar mucho por la red, darle vueltas a la cabeza (y más que le estoy dando para mejorarlo) y planteamiento y depuración de la programación.
    Por el momento con lo que dices veo que has entendido bien cómo funciona el código.
    Con pulsein() no puede funcionarte bien ya que tras detectar el primer canal el segundo ya lo tenemos en HIGH y por tanto pasará todo un ciclo de 20 milisegundos hasta que veamos en el canal 2 un LOW-HIGH-LOW con el que funciona pulsein().

    ResponderEliminar
  7. Buenas Cheyenne.
    Quería preguntarte, ya que estoy bastante pez en programación, qué es lo que debo añadir en tu código para la RC, para usar esas elcturas para controlar los motores...perdona que agual sea una pregunta demasiado básia pero ando un poco perdido aún aunque poco a poco voy enterandome de las cosas.
    Gracias por anticipado

    ResponderEliminar
  8. Hola Edwin.
    Ten en cuenta que cuando abordas un proyecto como este hay que aprender nociones básicas para programar que te permitan entender y adaptar códigos ajenos a lo que tú necesitas en tu programa. No siempre es fácil copiar códigos de aquí y allá y que funcionen como quieres.
    En Leer Emisora RC Parte 2 tienes el código con su explicación de cómo funciona para leer los canales de la emisora y en Control Motores Parte 2 el código con sus características y explicación para manejar 4 motores brushless.

    ResponderEliminar
  9. hola,tambien se puede con el receptor PWM? o es para PPM?

    ResponderEliminar
  10. Este código lee las señales de cada canal (PWM). La señal PPM es una codificación de todos los canales en una solo línea y no siempre es accesible. Por ejemplo en mi emisora Turnigy TGY 9X no se puede acceder a la señal PPM.

    ResponderEliminar
  11. gracias por el articulo, saludos :)

    ResponderEliminar
  12. hola una pregunta como ves los modulos xbee para controlarlo?

    ResponderEliminar
  13. Hola que tal?, ante todo quiero felicitarte por el tema, muy bueno. Me quedo una pregunta, como te diste cuenta que en tu emisora estaba cambiado el orden de los canales, es mas, cual seria la forma mas facil de saber si esto es asi en mi emisora? gracias

    ResponderEliminar
  14. Hola Luis.

    Al seguir el orden normal vi que algo no cuadraba así que hice un pequeño programa para leer secuencialmente todas las entradas y escribir en la consola su estado.

    ResponderEliminar
    Respuestas
    1. Hola, muchisimas gracias por tus aportes
      Podrias compartir ese programa que mencionas para leer secuencialmente todas las entradas y escribir su estado en la consola.

      Eliminar
  15. Que tal mi pana! Despues de leer este articulo sobre la lectura de las emisoras RC estuve investigando hasta que di con la solucion. Todo lo que tu comentas es cierto sobre el hecho de el rizado se produce es en la precisión de la medición del tiempo.

    Yo estoy haciendo mi Quad con un Arduino Mega 2560 y lo primero que pude determinar que el rizado se producía mucho más al usar la librería PinChangeInt.h, es ahí donde me dispuse a generar una estrategia para usar los pines de interrupción propios del arduino Mega que son 6, ya que mediante la funcion attachInterrupt era muy pequeño el rizado, pero habían varios problemas:
    1. Los pines de I2C son de interrupcion y son usados para el MPU6050. Pero me quedan 4 pines de interrupcion.
    2. La libreria de Jeff Rowberg "MPU6050_6Axis_MotionApps20.h", la mejor en mi parecer usa el pin 2 para leer la MPU6050 mediante interrupciones, con lo que solo tendria 3 canales dispuestos para interrupciones.

    Entonces lo que razone fue lo siguiente:
    Como el pin 2 esta siendo usado no para medir el tiempo de flancos de subida y baja sino para detectar un nivel logico alto, usare otro pin para esta interrupcion mediante la libreria PinChangeInt.h, dejando disponibles los 4 pines interrupcion que necesito para mi 4 Canales de Radio Control.
    Pues, esto funciono a la perfeccion.
    Lo que obtuve fue una variacion de los canales bastante pequeña.
    Lo siguiente que hice fue redondear los valores recibidos de cada canal mediante la funcion floor() de C++.
    Paso 1: #define RC_REDONDEO_BASE 50
    Paso 2: Roll=floor(ch1/RC_REDONDEO_BASE)*RC_REDONDEO_BASE;

    Con esto obtuve un valor extremadamente limpio en cada canal.
    Espero les sirva a todos. Saludos

    ResponderEliminar
  16. Hola Martin.

    Buen aporte. Siempre pensé en el tema de interrupciones como otra posibilidad pero no me llegué a meter. Veo que controlas de programación más que yo, usando instrucciones de C++. Por curiosidad, ¿sabes exactamente cómo redondea los valores la función floor() comparado con lo que utilizo yo del promedio de los últimos X (yo uso 6) valores?
    Por último, antes de hacer el redondeo, ¿has comprobado en cuántos microsegundos se te queda el rizado?

    ResponderEliminar
    Respuestas
    1. Que tal Cheyenne! Mira no he hecho ese estudio como tal, pero tratare de verificar el tiempo de rizado.Respecto a la funcion floor() de C, como su nombre lo dice redondea por debajo es decir que si tienes un 4,5 el lo redondea a 4.
      Tambien puedes usar la funcion ceil() que como su nombre lo dice redondea por arriba, un 4,5 te lo redondea a 5.
      Saludos! Gracias por tus aportes, me ayudaron mucho cuando estaba súper perdido.

      Eliminar
  17. Este comentario ha sido eliminado por el autor.

    ResponderEliminar