martes, 28 de agosto de 2012

Control motores Parte 2

    Como continuación a Control motores Parte 1 escribo esta entrada en la que explico el cambio en la concepción del código que permite tener una gran precisión en los tiempos, sumamente importantes para que las señales enviadas a los variadores produzcan una regulación suave y precisa. Es tan grande el cambio en la concepción del programa y su precisión que paso a la versión 2.0.

    El código está preparado para el control de los 4 motores si bien su estructura permite de forma fácil ampliarlo para el control de más motores o servos.

    Para no aburrir con todo el largo proceso de prueba y error de las distintas formas que se me ocurría y que finalmente no funcionaban, paso a describir el funcionamiento de la opción adoptada.
    Hay que tener en cuenta que donde necesitamos gran precisión es en el tiempo que están activadas (en HIGH) las salidas. El tiempo de ciclo de 20 ms no tiene gran importancia que tenga pequeñas variaciones, de hecho las hay de una emisora a otra (en mi emisora Turnigy TGY 9X tengo calculado unos 19 ms) y si movemos varias palancas de la emisora a la vez el tiempo de ciclo de cada canal puede variar en algún milisegundo. Es más, podéis hacer la prueba en el código a cambiar el tiempo de ciclo en

if (micros() - TiempoControlCiclo >= 20000)

y en lugar de los 20000 µs poner valores mayores o inferiores. Si lo probáis con un servo con tiempos inferiores (por ejemplo 5000) veréis que al intentar mover la palanca del servo su respuesta es más limpia y no tiembla tanto ya que está actualizando su posición más veces por segundo (el cuádruple para un tiempo de 5000). En cambio si hacemos la prueba con valores más grandes, por ejemplo 50000, comprobamos que podemos mover más fácilmente la palanca de su posición ya que el servo está actualizándose menos veces por segundo, en nuestro ejemplo 2,5 veces más lento.

    Para conseguir la mayor precisión en tiempo en el HIGH tenemos que utilizar la instrucción delaymicroseconds() que tiene una precisión de 1 µs. Si utilizamos la función micros() su precisión es de 4 µs. La idea es ordenar los pulsos de menor a mayor, activar todas las salidas e ir desactivándolas con los delay. El tema es que esas instrucciones llevan un tiempo ejecutarlas además de que no se puede utilizar el delay si queremos que sea de 0 segundos. La solución es decalar los pulsos, es la constante "Retardo" que establezco en 10 µs. Así siempre podemos utilizar la instrucción delaymicroseconds() cuyo valor para cada salida se calcula según el pulso, el retardo y el tiempo de ejecución de las instrucciones que ha sido calculado empíricamente. Los cálculos de ordenar los pulsos y recalcular los tiempos de delay se calculan antes de establecer los HIGH de modo que conseguimos tener unos tiempos muy precisos para los pulsos. Además todo el código es ejecutado en un tiempo reducido, unos 32 µs los primeros cálculos más el decalaje (para 4 motores son 30 µs) más el tiempo del mayor pulso que en el caso de motores es de unos 2000 µs y para servos 2500 µs.

    Aquí tenéis el código con algún comentario que espero sea suficiente para entenderlo. Mi idea a medio plazo es sacar otra versión preparada para manejar algunos servos además de los 4 motores.

Archivo para Arduino 1.0.1: Control motores v2.0

martes, 24 de julio de 2012

Leer emisora RC Parte 2

    Como continuación a Leer emisora RC Parte 1 escribo esta entrada en la que explico las mejoras necesarias que he introducido en el código. Son varios los cambios introducidos que producen una estabilidad muy grande en la medición de los canales y por eso paso a la versión 2.0.

    Recordemos que el código original tenía unas variaciones en las mediciones que oscilaban en unos 12 µs. Aunque pueda parecer poco con las pruebas que he ido haciendo es relativamente importante. Si en 20 ms o 40 ms (uno o dos ciclos) se produce esa variación brusca le estamos indicando al programa del cuadricóptero que queríamos esa variación brusca, los PID se pondrán en marcha y las señales finales a los motores también. Uno o dos ciclos más tarde estaremos indicando un cambio brusco en dirección contrario. El resultado será que no conseguiremos un ajuste fino del cuadricóptero ni una buena estabilidad. El suavizado de las lecturas mediante el promedio de las últimas lecturas (6 por defecto) aminora estos efectos pero tras estudiar el problema a fondo podemos mejorarlo mucho más.

    En primer lugar tenemos que estudiar por qué se produce esa variación en las medidas y he encontrado dos causas. Lo primero es pensar en la precisión de la propia emisora pero elimino esta posibilidad ya que cualquier motor con su ESC o servo funciona con una precisión y estabilidad exquisita cuando se maneja directamente con la emisora.
    Causas encontradas:
    La primera es la precisión en la medición del tiempo. La función micros() tiene una medición mínima de 4 µs, esto es, no nos da lecturas de por ejemplo 9 µs, 10 µs o 11 µs. Nos da lecturas de 8 µs o 12 µs. Sobre esta función no podemos hacer directamente nada.
    La segunda es la velocidad en la ejecución del código. Para muchas cosas Arduino es suficientemente rápido pero en casos como el que nos lleva vemos que se vuelve lento. Vamos con la pequeña parte del código en la que esto se produce:

  while (digitalRead(2) == 1) {
    if ((micros() - TiempoParcial1) > 2000) {
       ErrorRadio = true;
       break;
    }
    else {
      ErrorRadio = false;
    }
  }

    Aunque son muy pocas instrucciones cada una de ellas lleva algún microsegundo ejecutarla. El problema es que al estar todo dentro de un while el tiempo de ejecución no es fijo. Pongamos que el micro ejecuta la primera instrucción, el while. Lee la entrada y ve que es 1. Entonces sigue ejecutando todo el resto de instrucciones de modo que si nada más ejecutar la primera la entrada pasa a 0 no se dará cuenta hasta que vuelva otra vez al while lo que supone añadir el tiempo de ejecutar todas las instrucciones. Y eso para Arduino son unos cuantos microsegundos. En el siguiente ciclo sin embargo puede pasar que justo cuando la entrada cambia a 0 es cuando se ejecuta el while por lo que saldrá ya del mismo sin apenas pérdida de tiempo.

    Aleatoriamente las dos causas se van sumando o restando. Entre la anulación máxima o la suma máxima tenemos esa variación de 12 µs (que en alguna lectura esporádica llega incluso a 16 µs).

    Entonces, ¿qué podemos hacer? Sobre la precisión de micros() directamente nada. Y en la serie de instrucciones del while todas son necesarias y no conozco ninguna forma de optimizarlo salvo la instrucción (digitalRead(2) == 1). Esta instrucción del IDE está compuesta por una docena de instrucciones del micro. Las mediciones que he realizado me da que el tiempo de ejecución para la instrucción a = digitalRead(2) es de 4,8 µs. Hay otra forma de leer una entrada que es con los registros del micro. Para un Atmega 168/328 la instrucción es a = bitRead(PIND, 2) y he calculado un tiempo de ejecución de tan solo 0,06 µs. Utilizando esto el ahorro de tiempo es muy importante. Una prueba preliminar simplemente cambiando esta instrucción hace que el rizado en la medición baje a 8 µs con muchas zonas de 4 µs. Es más esporádica una variación de 12 µs. Pero además el rizado es menos caótico haciendo que el promedio de lecturas sea más estable.
    Sólo hay un problema y es que el mapeo de pines puede ser distinto y de hecho lo es de un micro a otro en el IDE. En concreto para los micros Atmega 8/168/328 el mapeo es el mismo pero en el Atmega 2560 cambia y en el Atmega 32U4 de la nueva placa Leonardo también. La instrucción sólo está probada para Atmega 8/168/328 pero anoto cómo debería ser para los otros micros aunque repito que no lo he probado:

                            Cualquier micro       Atmega 8/168/328          Atmega 2560            Atmega 32U4

Pin digital 2        digitalRead(2)        bitRead(PIND, 2)         bitRead(PINE, 4)       bitRead(PIND, 1)
Pin digital 3        digitalRead(3)        bitRead(PIND, 3)         bitRead(PINE, 5)       bitRead(PIND, 0)
Pin digital 4        digitalRead(4)        bitRead(PIND, 4)         bitRead(PING, 5)       bitRead(PIND, 4)

    Implementada esta mejora y con el promedio de los últimos 6 valores tomados se consigue tener un rizado máximo de unos 2 µs. Aunque tengo en mente otra posible mejora a nivel de filtrado por el momento considero el código totalmente operativo aunque más adelante tal vez me ponga a mejorarlo.

    Por último, como este código es el que usaremos como base de tiempos en el código completo del cuadricóptero hay que tener previsto un sustituto ante fallo de la emisora. Así, si se produce algún fallo la variable ErrorRadio se vuelve true pero tenemos que, además de seguir intentando volver a leer la emisora, establecer una rutina que haga que el resto del código siga ejecutándose cada 20 ms. Con tan sólo tres líneas de código ha quedado implementado

Archivo para Arduino 1.0.1: Leer radio v2.0

Control motores Parte 1

    Tal y como ya se ha comentado en Motores el tipo de los mismos es brushless y su control se realiza mediante los ESC. La forma de controlar un ESC es la misma que la de un servo ya que los dos elementos están pensados para ser manejados directamente desde una emisora RC.

    La forma más sencilla de manejarlos desde Arduino es con la libraría Servo.h. Sin embargo esta librería funciona mediante interrupciones y en mi código quiero evitarlas. ¿Por qué? Porque las interrupciones afectan a la precisión en la medición de tiempos algo que es vital en el cuadricóptero. Por un lado estoy tratando de eliminar al máximo el rizado que se produce en la lectura de los canales de la emisora RC, si se produce una interrupción en un momento cercano a la toma de tiempos éstos varían produciendo rizados mayores.

     Por tanto el código que estoy desarrollando tendrá un tiempo de ciclo de 20 ms que es el que tiene las señales de la emisora RC y por tanto el de los ESC (para los motores). Las lecturas del AHRS también se realizan cada 20 ms. En cada ciclo realizaremos todas las operaciones de forma secuencial y no será necesario utilizar interrupciones.

    Esta primera versión del código es poco eficiente ya que adolece de los mismos fallos que se producen en Leer emisora RC en cuanto a la precisión de tiempos y el rizado que se produce sobre el que también estoy trabajando. Sin embargo lo expongo para que se vea el proceso básico de programación y así también será más fácil seguir la programación del código mejorado para cuando lo tenga implementado.

    Archivo para Arduino 1.0.1: Control motores v1.0

    Tenéis una nueva entrada en Control motores Parte 2 en donde he desarrollado un nuevo código muy preciso.

domingo, 27 de mayo de 2012

Batería

Mucho se ha avanzado en el desarrollo de baterías y sin embargo se sigue investigando ya que todavía distan de ser el elemento con las características que nos gustaría que tuviera. ¿Cuáles son las características esenciales de una batería?
- La tensión.
- La capacidad: la cantidad de energía que puede acumular.
- El peso.
- Intensidad de descarga.
- Tiempo de carga.

- La tensión: las distintas tecnologías existentes almacenan energía eléctrica primariamente a niveles de tensión relativamente bajos, entre 1 V y 4 V aproximadamente. Para la mayoría de usos se necesitan tensiones mayores. La solución es que construyen las baterías con varias celdas en serie de modo que la tensión total es la suma de las tensiones de todas las celdas. En los procesos de carga y descarga las tensiones van aumentando y disminuyendo respectivamente. Tener variaciones en la tensión de alimentación en principio no es bueno sin embargo tiene su pequeña ventaja y es que estas variaciones nos sirven para detectar el estado de carga de la batería y sabremos cuándo hay que terminar la carga o la descarga.

- La capacidad: es la cantidad de energía que almacena. Suele expresarse en mAh (miliamperios hora). Así, una batería de 2.600 mAh nos puede suministrar 2.600 mA durante una hora. Sabiendo el consumo medio que le vamos a solicitar podremos calcular el tiempo aproximado que nos durará. Si con esa batería estamos consumiendo 0,8 A el tiempo que nos durará será 2.600 / 800 = 3,25 horas (3 horas y 15 minutos).

- El peso: es un dato muy importante ya que una batería actualmente tiene un peso considerable para la cantidad de energía que puede almacenar. En general será una limitación en muchas aplicaciones y en particular en vehículos, ya sean terrestres y sobretodo aéreos, supone una gran limitación ya que gran parte de la energía de la batería se gasta en tener que transportar el propio peso de la batería. Y eso que podemos considerar el gran avance que han supuesto las batería de tecnología lipo (polímero de litio) que han reducido el peso considerablemente con respecto a las tecnologías existentes hasta entonces. Planteo un pequeño cálculo rápido para hacernos a la idea del gran peso de una batería para la energía que almacena. La compararemos con la energía que produce el gasoil. Aproximadamente un kg de gasoil puede producir unos 40 MJ (megajulios). El rendimiento de un motor térmico diesel puede llegar hasta un máximo de un 45%. Esto hace que de un kg de gasoil en nuestro motor aprovecharemos 40 x 0,45 = 18 MJ. Por otro lado una batería lipo de 5000 mAh y 3S pesa unos 390 g. La energía que almacena es 5 x 11,1 = 55,5 Wh. Por kg la energía almacenada será 55,5 / 0,39 = 142,3 Wh que son unos 0,5 MJ. Los motores brushless pueden tener un rendimiento del 80% lo que hace que el aprovechamiento final sea de 0,5 x 0,8 = 0,4 MJ. Si comparamos el aprovechamiento del gasoil y de una batería lipo tenemos 18 / 0,4 = 45 veces. En términos de combustible y su peso vemos que a la tecnología de almacenamiento eléctrico le falta mucho, tendrían que disminuir en 45 veces el peso de una batería. Es uno de los grandes retos tecnológicos actuales.

- Intensidad de descarga: cada batería tiene una intensidad máxima que puede suministrar que se expresa en el número de veces la intensidad nominal. Nosotros tenemos en mente que nos interesa una batería con la mayor intensidad de descarga. Pero a nivel práctico hay que tener un par de consideraciones. La primera y en general para las aplicaciones de las baterías, no todos los usos necesitan priorizar la posibilidad de una gran descarga. Hay casos en los que se necesita una descarga muy baja a base de mejorar otras características como una baja autodescarga.
    En el caso de aeromodelos hay que tener muy presente que no siempre la batería con mayor intensidad de descarga será la mejor ya que aumentar esto hace aumentar también el peso de la batería. Mi recomendación es que si se construye un aeromodelo (en nuestro caso un cuadricóptero) para vuelo acrobático por supuesto que buscaremos una batería de alta intensidad de descarga; para que no aporte excesivo peso a nuestro cuadricóptero tendremos que ajustar su capacidad y tendremos vuelos de corta duración, hablamos de 6 ó 7 minutos.
    Pero si lo que queremos es vuelos tranquilos y aumentar el tiempo de vuelo (por ejemplo para uso en fotografía o vídeo aéreo) lo que haremos es elegir una batería con la mínima intensidad de descarga para que sea más ligera. El peso ahorrado lo podremos utilizar en aumentar la capacidad de la batería. Por supuesto siempre hay que tener en cuenta que la batería sea capaz de suministrar la intensidad requerida por los motores, la suma de los cuatro en el caso de un cuadricóptero.

- Tiempo de carga: interesa que sea lo más corto posible. Pero hay que saber que cuanto más apuremos el tiempo de carga y lo hagamos a una intensidad mayor, más se acorta la vida de nuestra batería.

Con estos parámetros pasamos a concretar los que tienen las baterías lipo ampliamente usadas en la actualidad.
La tensión nominal de una celda básica es de 3,7 V. Cuando está totalmente cargada llega a 4,2 V (momento en el que hay que dejar de cargar) y al descargarse nunca hay que dejar que baje de los 3 V ya que se destruye sin opción a ser recuperada. Para tener tensiones mayores se unen en serie varias celdas y se expresa con el número de celdas seguido de una S mayúscula. Así las más usadas, una batería 3S tiene 3 celdas en serie y por tanto una tensión nominal de 3 x 3,7 = 11,1 V.
La capacidad, el peso y la intensidad de descarga son tres parámetros estrechamente relacionados. Si queremos mejorar alguno nos empeorará otro.
El tiempo de carga depende de la intensidad a la que realicemos la carga. La intensidad máxima a la que se puede cargar viene expresada mediante un número seguido de una C mayúscula. La mayoría de las lipo actuales suelen ser 2C, es decir, admiten una intensidad de carga de 2 veces la capacidad nominal. Una lipo de 2600 mAh y 2C podremos cargarla a 2 x 2,6 = 5,2 A. Sin embargo apurar esta intensidad de carga acortará la vida de nuestra batería. Yo recomiendo cargarlas a 1C.

Por último hay que extremar las precauciones con las lipo debido al riesgo potencial que tienen. En determinadas circunstancias pueden llegar incluso a explotar. Es imperativo comprar una bolsa aislante especial en la que meteremos la batería siempre que vayamos a cargarla. No me extiendo en este tema pero os recomiendo que hagáis algunas búsquedas en Google sobre las precauciones que hay que tomar con las lipo.

lunes, 30 de abril de 2012

ESC Parte 1

Probablemente ya sabes lo que es un ESC. En cualquier caso lo explico de forma rápida. Un ESC (Electronic Speed Control) es un equipo que lee la señal PWM de salida de una emisora RC y la convierte  a la señal de potencia necesaria para alimentar un motor brushless. El ESC también nos permite el control de la velocidad del motor. La señal de control al ESC, típicamente la salida de los canales de una emisora RC, es la que reproduciremos desde nuestro Arduino.

Dos son las características principales que hay que tener en cuenta para la elección de un ESC.
En primer lugar el rango de tensión con el que está preparado para funcionar, normalmente expresado en las celdas de baterías lipo. Lo más común es un ESC para un rango entre 2S y 4S. En el caso de cuadricópteros lo más normal es con baterías lipo de 3S. Proyectos más ambiciosos de cuadricópteros de mayores tamaños para llevar más peso pueden proyectarse con baterías 4S.
La segunda característica es la intensidad capaz de suministrar. Este dato va directamente relacionado con las características de los motores seleccionados. Como es lógico nuestro ESC tiene que ser capaz de suministrar como mínimo la intensidad máxima del motor elegido, siempre teniendo en cuenta un pequeño margen de seguridad.

En mi caso como expliqué en Motores el consumo de los Turnigy 2209 a máxima potencia en continuo es de 12 A y el máximo puntual de 15 A. Por tanto mi elección de ESC es el Turnigy Sentry 18 A, con capacidad de 18 A en continuo y un pico puntual de hasta 22 A.
Siento no poder poner el enlace de este modelo de ESC pero es que Hobbyking ha dejado de fabricarlos, al menos no se encuentran en su catálogo de la web. Tal es así que yo había adquirido dos unidades de este modelo para hacer las primeras pruebas y al ir a comprar los otros dos tuve que coger el modelo Turnigy Plush 18 A. La diferencia es mínima, referente a otra característica de los ESC que explicaré un poco más adelante.

Otro aspecto de los ESC es que pueden llevar integrado un BEC, Battery Eliminator Circuit, traducido Circuito Eliminador de Batería. Así es, para nuestros motores necesitamos una batería por ejemplo de 3S que da 11,1 V. Sin embargo la alimentación de los servos y la electrónica de control se hace con 5 V. Pues bien, en lugar de poner otra batería que nos suministre esos 5 V la eliminamos y el BEC es quien nos los va a proporcionar.

Una última opción que puede llevar un ESC es el conector para la "Monitorización de descarga balanceada". Este conector está estandarizado y se denomina JST-XH. Es el mismo conector que traen las baterías lipo para la carga balanceada. Así conectaremos ESC y lipo con esta conexión de modo que el ESC estará midiendo continuamente la tensión de cada una de las celdas de la lipo. Cuando cualquiera de las celdas baje hasta los 3 voltios el ESC reducirá potencia a los motores protegiendo nuestra lipo de una descarga mayor que la haría inservible sin opción de recuperarla.

Los ESC de intensidades bajas y para tensiones sobre 3S o 4S como mucho el BEC suele ser lineal, es decir, lleva un regulador de tensión que hace que la diferencia de tensión de la lipo con los 5 V que suministra por la intensidad que circula la disipa en forma de calor. Sin duda es pérdida de energía que estamos sufriendo aunque no sea mucha comparada con la potencia consumida por los motores. Para evitar esta pérdida de energía están los BEC conmutados (en inglés switch). Su función es la misma pero su rendimiento energético está cercano al 100%. Muy útil cuando el consumo a través de los 5 V empieza a ser importante y sobre todo cuando la lipo es de 4S o superior.

Si nuestro ESC no tiene BEC o si es lineal y por las características de nuestro montaje nos supone una pérdida de energía a tener en cuenta podemos hacernos con un BEC externo. Comercialmente se denominan SBEC o UBEC, depende de fabricantes. En los dos casos son un BEC de conmutación.

Tenéis una nueva entrada en ESC Parte 2.

sábado, 7 de abril de 2012

Motores

Tras documentarse un poco se llega enseguida a la conclusión de que los motores a utilizar conviene que sean de baja velocidad. Un cuadricóptero no está pensado para volar muy rápido así que no necesitamos altas r.p.m. que nos producirán vibraciones innecesarias. Por supuesto no me detengo a explicar que los motores tienen que ser de tipo brushless, los mejores para estos usos con diferencia.

Yo compré los Turnigy 2209. Vienen con completos accesorios. Tienen un Kv de 1050 lo que creo no está mal para un motor 3S. Hay que tener en cuenta este punto, nos interesa que el motor sea de baja velocidad para que produzca pocas vibraciones, pero para eso no nos tenemos que fijar únicamente en el dato de Kv, también hay que fijarse en la tensión de alimentación. El Turnigy 2209 puede ir bien para un cuadricóptero con su Kv de 1050 ya que se alimenta a 3S (11,1 V). Esto hace una velocidad máxima de 1050 x 11,1 = 11.655 r.p.m. Siempre es mejor que sea más baja pero en este caso no está del todo mal. Sin embargo un Kv de 1050 en un motor 4S (14,8 V) tendrá una velocidad máxima de 1050 x 14,8 = 15.540 r.p.m. lo que empiezan a ser muchas revoluciones.
En general creo que a la hora de diseñar nuestro cuadricóptero debemos tomar como punto de partida motores con un Kv inferior a 1000 si son 3S y un Kv inferior a 750 si son 4S.

Sobre el empuje que producen, aunque el dato no viene en las características técnicas, si nos guiamos por los datos ofrecidos por algún usuario estos motores están dimensionados para trabajar a máxima potencia en continuo con un consumo de 12 A lo que nos ofrecerá unos 600 gramos de empuje. El pico de intensidad admitido es de 15 A lo que nos dará unos 750 gramos de empuje para momentos puntuales.

Como dato empírico de otros usuarios suele darse como bueno que el empuje de los motores sea el doble del peso del cuadricóptero en orden de marcha. El empuje total en continuo tenemos 600 x 4 = 2,4 kg lo que nos deja un peso para el cuadricóptero en orden de marcha de 1,2 kg. Suficiente para llevar el chasis, electrónica, motores, etc., y algo de peso extra como una cámara de fotos además de una buena batería.

En otro artículo daré explicación más detallada de todos los pesos.

domingo, 26 de febrero de 2012

AHRS 9DOF Razor IMU Parte 2

Como ya comenté en AHRS 9DOF Razor IMU Parte 1, la adaptación del código de Mongoose no termina de funcionar todo lo bien que cabría esperar. Como ha pasado tiempo desde que empecé con este tema en la página de Sparkfun vi que ya tienen -por fin- actualizado el código así que me he puesto a hacer pruebas. Bueno, realmente no es que lo haya actualizado Sparkfun, creo que lo ha hecho uno o varios usuarios, ya sabéis, esa es la maravilla de Arduino, su comunidad que trabaja gratuitamente compartiendo. Toda su información original la podéis encontrar en

https://dev.qu.tu-berlin.de/projects/sf-razor-9dof-ahrs

Como no podía ser de otra manera ha sido coger el código tal cual, subirlo a la tarjeta y funcionar a la primera. He hecho un primer cálculo del tiempo de ejecución del bucle (sin el envío de datos) y está en torno a los 10 ms, alguna vez da lectura de 11 ms. Tenemos prácticamente 5 ms más que con el código de Mongoose lo que sin duda es mucho tiempo. Esto me va a permitir poder enviar los datos de los ángulos y los datos de los sensores que necesite (probablemente sólo el acelerómetro) sin problemas. Voy a seguir con mi método de envío de datos ya explicado en la Parte 1 de manera que el tiempo de envío de todos los datos será tan bajo que me permitirá bajar la velocidad de transmisión que con el código Mongoose tenía en 115.200 bps. Bajar la velocidad siempre es bueno ya que se tienen menos problemas de transmisión. Una vez montado el cuadricóptero seguro que habrá mucho ruido producido por los ESC y los motores así que calcularé cuál es la velocidad más baja que me permita enviar todos los datos que requiero. Un primer cálculo teórico aproximado estimo que si envío los ángulos y los datos del acelerómetro la trama puede tener en torno a 17 bytes. Ajustando a un máximo de 9 ms (20 ms del tiempo de ciclo menos 11 ms máximo del tiempo de ejecución) y estimando unos 10 bits por byte tenemos 17 * 10 / 0,009 = 18.889 bps. Cualquier velocidad superior a esa -con suficiente margen, no tomaremos 19.200 bps- nos será válida.

El código viene con varias opciones de envío de datos por el puerto serie, pudiendo activar uno u otro. Con el mismo criterio he añadido un output_EnviarArduino() para activar el envío de los datos que quiero en mi formato, esto es, los tres ángulos y los tres datos del acelerómetro multiplicados por 100 para tener precisión de 1 centésima y poder enviar cada dato con tan solo 2 bytes. Subo todos los archivos, también los de Processing con el que al activar la salida de datos

int output_mode = OUTPUT__MODE_ANGLES_TEXT 1

en lugar de la mía

int output_mode = OUTPUT__MODE_EnviarArduino;

podremos ver en Processing gráficamente la posición de nuestro AHRS.

También veréis una sección en la que se pueden calibrar los sensores. El enlace explica muy bien cómo hacerlo.

Archivo para 9DOF Razor: Razor AHRS
Archivo para leer los datos enviados: Leer 9DOF Razor v1.0.1

    Hay una nueva entrada en AHRS 9DOF Razor IMU Parte 3.

domingo, 12 de febrero de 2012

AHRS 9DOF Razor IMU Parte 1

Mis esfuerzos no quise centrarlos en el desarrollo del AHRS. Tiré la casa por la ventana y me compré el de Sparkfun con 9 grados de libertad. Debo indicar que tube algún que otro problema. Al cargar el código no daba lecturas correctas. Leyendo mucho pude saber que este IMU de Sparkfun tiene varios modelos puesto que lo van actualizando a nivel hardware. Pues bien, en aquellos momentos habían sacado una nueva tarjeta en la que incluían otro gyro, esa tarjeta era la mía, pero el código no estaba actualizado.

Al final encontré un código, el que han desarrollado para la tarjeta Mongoose, que ya lo habían adaptado para el nuevo gyro. La tarjeta Mongoose es prácticamente igual que la de Sparkfun solo que además le han añadido un sensor de presión para tener un control de la altura. Y además sale a menor precio. De haberlo sabido antes me habría comprado esta tarjeta. La web de la tarjeta Mongoose es ckdevices y el código original puede descargarse en mongoose-9dof-imu. Sin embargo este código no nos funcionará tal cual con la tarjeta de Sparkfun, tuve que hacerle unas modificaciones como las de anular las lecturas del sensor de presión y alguna más para adaptarlo a Arduino 1.0. El código final que funciona es el siguiente:

 Archivo para Arduino 1.0: Mongoose9DOF

Sin embargo a este código le encuentro sus pegas. Tal vez sea porque no he hecho una adaptación perfecta del código. Cada ciclo toma las lecturas del gyro y acelerómetro pero las del magnetómetro las toma cada 5 ciclos. El tiempo de ejecución del código he calculado que está en torno a 8 ó 9 ms pero el ciclo que toma la lectura del magnetómetro aumenta hasta los 14 ó 15 ms. No sé si esto es normal, intuyo que no, como he dicho antes tal vez sea por una mala adaptación por mi parte del código. La cuestión es que quedan tan sólo unos 5 ms para el envío por puerto serie de los datos. Con el método que viene programado el envío de los tres ángulos aún haciéndolo a 115.200 bps ya desborda el tiempo de ciclo de 20 ms. Así que desarrollé un pequeño protocolo que me permitiera enviar los ángulos con menos caracteres. Este protocolo se activa mediante #define EnviarArduino 1 y elaboro un byte para la transmisión de los signos de los tres ángulos y dos bytes más para cada uno de los ángulos. En total, teniendo la misma precisión de 1 centésima de grado, envío los tres ángulos con un protocolo de 8 bytes. La forma original envía más o menos bytes en función del valor numérico de los ángulos y si tienen signo negativo y en el peor de los casos puede llegar a tener hasta 24 bytes. La reducción es importante y permite enviar más datos o bien bajar la velocidad del puerto serie. Por el momento no está implementado con esta forma reducida el envío de los datos de los sensores, en concreto puede ser de utilidad el envío del acelerómetro que tal vez permitiría saber si el cuadricóptero se está desplazando para poder dejarlo quieto en el aire. Cuando el proyecto esté más avanzado y llegue el momento haré este tipo de pruebas.

NOTA: recientemente he visto en la página de Sparkfun que ya tienen actualizado su código, además viene con una aplicación para Processing para ver visualmente los datos enviados. Preveo que puede estar más optimizado y no tener los problemas del tiempo de ejecución del Mongoose así que aunque por el momento puede servir este código con el tiempo estudiaré el nuevo y le implementaré mi protocolo de envío de datos.
Podéis ver el nuevo código con un mejor funcionamiento en AHRS 9DOF Razor IMU Parte 2

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.

Las bases del desarrollo

    Lo que pretendo es llegar a hacer volar un cuadricóptero de fabricación modular propia bajo mis criterios de "lo quiero desarrollar yo" - "qué esfuerzo conlleva".
    Así, de las distintas partes que forman el proyecto a grandes rasgos resumo mis intenciones:

- Emisora RC: comprarla, por supuesto. Lo anoto porque incluso he llegado a leer quien se plantea desarrollar una. Yo adquirí el modelo Turnigy TGY 9X comprado en Hobbyking, un sitio muy interesante para adquirir material de radio control. La emisora cuenta con 8 canales y sólo cuesta 30 €. Ha revolucionado el mercado de las emisoras.

- Centro de control: plataforma Arduino. Desarrollo de la programación.

- AHRS: mis esfuerzos no los he dirigido a desarrollarlo. Decidí comprar uno desarrollado, el AHRS 9 DOF Razor de Sparkfun. Si pudiera retroceder en el tiempo probablemente compraría otro que he descubierto a posteriori, el Mongoose 9DoF IMU with Barometric Pressure Sensor. Es igual que el anterior pero además incluye un sensor barométrico y es más económico.

- Estructura: tenía pensado fabricarla pero finalmente he decidido comprarla al ver una que me ha convencido por su apariencia y precio en Hobbyking, es el HobbyKing Quadcopter Frame V1. Por sus poco más de 11 € creo que merece la pena.

Preámbulos


NOTA: el desarrollo de este cuadricóptero no está completado, dispongo de poco tiempo y todavía no vuela. Sin embargo probablemente encontrarás mucha información útil para el desarrollo de tu quad.

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

    Aunque este blog lo empiezo a desarrollar en Enero de 2012, todo comienza en Enero de 2011. En esas Navidades se han extendido mucho por los comercios los helicópteros coaxiales de pequeño tamaño. A unos precios muy aceptables encontramos helicópteros indoor (para interiores) con control por infrarrojos. Son de fácil manejo ya que incorporan electrónica con control por gyro. Este sensor junto con la electrónica que gestiona su información hace que el vuelo sea muy sencillo. Por último el precio asequible de estos helicópteros ha venido propiciado por los bajos precios a los que encontramos los sensores inerciales (gyros y acelerómetros) debido a su gran difusión en las consolas de videojuegos (el pistoletazo fue la Wii).
    Y aquí tenéis el helicóptero que compré, el Syma S107.


    A partir de ese momento empiezan a atraerme los cuadricópteros. Tras muchas búsquedas en Google y mucha información leída descubro la plataforma Arduino ideal para la programación electrónica.

    Además de toda la información que voy recopilando sobre el desarrollo de cuadricópteros empiezo a  aprender a programar en el entorno Arduino. Al disponer de nociones generales sobre programación avanzo a una velocidad para mí más que aceptable en poder realizar programaciones. Por supuesto sin olvidar la ayuda prestada por los diferentes usuarios del foro de Arduino: allí soy Cheyenne.

    Y a la parte de programación hay que añadir unos conocimientos de electrónica que me hacen poder avanzar más rápidamente en algunos puntos.