bclose

Los mandos de infrarrojos

Controlando Arduino con un mando a distancia IR

Objetivos

 

 

    • Desmitificar la luz infrarroja.
    • Presentar los receptores de infrarojos
    • Aprender a usar un mando IR con tu ARduino
    • Programas de ejemplo
    • Instrucción switch case
 

Material requerido.

Imagen de Arduino UNO

 Arduino UNO o equivalente.

 Breadboard conexiones

 Una Protoboard más cables.

 Receptor infrarojo comercialKeyes, receptor de infrrarojos

Un receptor de infrarrojos integrado como el AX1838HS. Independiente o con breakout board

 

 

Los mandos de infrarrojos

 

Estamos tan acostumbrados a los mandos a distancia infrarrojos que no dedicamos un momento a pensar en ellos y simplemente nos parece normal, algo que a nuestros abuelos les hubiera parecido magia.

Nos parece normal que los equipos electrónicos, televisores, cadenas de música, aires acondicionados, respondan a nuestras instrucciones sin levantarnos del sofá, pero esto no ha sido siempre así, es más, es relativamente reciente, que estos mandos se popularizaron.

Hemos oído que funcionan por infrarrojos y poco más. Me pregunto cuántos usuarios responderían correctamente a la pregunta de que son los infrarrojos y cuál es el principio de funcionamiento de un mando a distancia de este tipo.

Para centrar un poco las ideas, empecemos diciendo que las ondas electromagnéticas se caracterizan, principalmente, por su frecuencia o lo que es lo mismo, por el inverso de ésta que es la longitud de onda.

Son similares a las ondas de sonido.  A las de menor frecuencia las llamamos infrasonidos, y luego vienen las ondas de sonido claro. Un poco más arriba tenemos los ultrasonidos (Nombres sorprendentes, que básicamente significan por debajo y por encima de lo que se oye.

En el espectro electromagnético, nos encontramos enseguida con las ondas de radio y luego con las microondas. Después como veis en este gráfico que he pillado de la Wikipedia viene el infrarrojo (Por debajo del rojo), el espectro de luz visible con los familiares colores (Que solo son una forma en que nuestro cerebro percibe las frecuencias de luz) y luego el ultravioleta (Por encima del violeta, eso es echarle imaginación a los nombres, si señor).

Más arriba en la escala encontramos los rayos X (Cuando el alemán Roentgen  descubrió esta radiación a finales del XIX, no tenía ni idea de que era, y le parecía una buena idea llamarlos Rayos X, o sea desconocidos, y todavía hoy seguimos con este cachondeo) y por último los rayos gamma o cósmicos.

Distribucion de frecuencias

La capacidad energética de la radiación crece rápidamente con la frecuencia y por eso los rayos X y los gamma son muy dañinos para los seres vivos.

Una manera de describir los infrarrojos, seria como una luz con un color diferente, que no vemos, pero luz a pesar de todo.

Una curiosidad no muy conocida, es que seguramente la cámara de tu teléfono móvil, o tableta es capaz de ver, y mostrarte, la radiación IR de tus mandos a distancia. Aquí os pongo un mini video grabado con mi móvil, un iPhone 4S:

La luz infrarroja es adecuada para hacer mandos a distancia porque:

 
  • Utilizan luz en una frecuencia que no tienen consecuencias en los tejidos vivos. Menos impacto que la luz visible.
  • Como solemos ver la tele a oscuras, no se ve cuando usamos el mando.
  • Tiene relativamente poco alcance, pero no solemos ver la tele o tener la cadena de música más allá de 2 o 3 metros.
 

Así que es práctico, sencillo y barato (lo que les encanta a los fabricantes), aunque tienen también inconvenientes.

El principal es que cualquier cosa con una cierta temperatura, incluidos nosotros, emitimos radiación infrarroja. Es por eso que las cámaras IR que veis en las pelis, pueden mostrar nítidamente en plena oscuridad a una persona o animal.

Y esto podría interferir con el mando a distancia IR, lo mismo que cosas como la calefacción, el sol y demás cosas calientes. Así que la solución para evitarlo es modular la señal con una portadora.

La idea básica es mandar un tren de ondas estable (La portadora) y mezclarlo con la información  que queremos enviar (La señal). Este mismo principio se usa con la radio y casi con cualquier señal radioeléctrica que se envié por el aire.

He encontrado este Gif en la página de sbprojects y me ha parecido ideal para mostrar el proceso de modulación y transmisión.

irsignal (1)

El emisor es un sencillo transistor que gobiernan un LED infrarrojo muy similar a los LEDs rojitos normales que hemos usado hasta ahora, solo que diseñados para emitir luz en un color que no vemos.

Un pequeño procesador en el mando gobierna, la generación de la señal y la mezcla con la portadora, para garantizar que nuestra tele no recibe órdenes espurias.

 
  • El proceso de mezclar una señal con la portadora se le llama modular.
  • El inverso, extraer la señal de una onda RF y obtener la señal limpia se llama demodular.
 

El receptor tiene un poco más de complejidad porque, las normas de emisión de IR para mandos a distancia, aparecieron como setas tras una tormenta y poco menos que cada fabricante presento su propia norma.

Al final la industria acabo diseñando unos receptores capaces de recibir y demodular casi cualquier cosa, y como se venden como churros (Porque nos encanta mantener nuestro culo pegado al sofá) valen muy poco y son un prodigio tecnológico.

Un receptor IR típico actual, incluye el receptor, amplificador demodulador y lo que se te ocurra encapsulado y listo para usarse. No os imagináis la cantidad de electrónica que va incluido esta piececita de aspecto inocente.

 

Receptores de IR

 

Un típico receptor de infrarrojos, es el AX-1838HS, que se consigue por poco más de unos euros. En su hoja de normas encontráis este diagrama, y son relativamente fáciles de encontrar, en dos formas. Independientes y montados en un soporte para utilizar sin complicaciones con nuestros Duinos.

AX-1838HS receptor de mando infrarrojo
Receptor infrarojo comercialKeyes, receptor de infrrarojos

El esquema de conexión nuevamente es trivial, pues el AX-1838HS solo tiene 3 pines: Vcc, GND y señal. Como vamos a usar una interrupción para leer la señal es imprescindible, que llevéis el pin de señal a el pin2 de Arduino (La interrupción 0) o al pin3 (La interrupción 1).

Yo lo voy a conectar al pin 2 y así lo reflejan los programas y los ejemplos.

 

Programa de control

 

Para poderlos usar de una forma cómoda, vamos a descargarnos alguna librería, que nos facilite la vida.  De las varias disponibles me ha gustado la de Nico Hood  http: //nicohood.wordpress.com/, por varios motivos.

 
  • Es ligera y muy rápida en decodificar las señales IR y además usa muy poca memoria.
  • Aunque no decodifica todo, acepta las normas de NEC y Panasonic y compatibles, y además tiene un modo de haz lo que puedas que parece ir bastante bien. Lo que nos da un 85% de probabilidades de que reconozca tu mando
  • Funciona por interrupciones, lo que la hace muy ligera y rápida y así vemos un buen ejemplo de uso de estas.
  • Es de las pocas que es capaz de decodificar las señales simultáneas de varios mandos diferentes, con diferentes protocolos cada uno.
 

Lo primero es descargarnos la librería IRLremote.zip, y después instalarla siguiendo el procedimiento habitual que vimos en sesiones anteriores. Una vez hecho para usarla como siempre usamos el importar librería, que os pondrá:

#include "IRLremote.h"

Y para inicializarla:

IRLbegin<IR_ALL>(interruptIR);

Vamos a empezar por un ejemplo que nos recomienda el autor para reconocer el mando a distancia que usamos. Podeis cargarlo con ejemplos IRLremote\ReceiveInterrupt

#include "IRLremote.h"
const int interruptIR = 0;                 // Arduino interrupcion 0: Pin 2

uint8_t IRProtocol = 0;  // Variables para recibir los datos
uint16_t IRAddress = 0;
uint32_t IRCommand = 0;

void setup()
   {     Serial.begin(115200);  // Fijate en la velocidad
         Serial.println("Startup");
         IRLbegin<IR_ALL>(interruptIR);
   }
void loop()
   { 
         uint8_t oldSREG = SREG;  // Parar las interrupciones
         cli();
         if (IRProtocol)          // Si reconoce el protocolo
            {
                 Serial.print("Protocol:");
                 Serial.println(IRProtocol);
                 Serial.print("Address:");
                 Serial.println(IRAddress, HEX);
                 Serial.print("Command:");
                 Serial.println(IRCommand, HEX);
                 IRProtocol = 0;
            }
         SREG = oldSREG;
    }

void IREvent(uint8_t protocol, uint16_t address, uint32_t command)
    {
        IRProtocol = protocol;  // Recogemos los valores y nos volvemos
        IRAddress = address;
        IRCommand = command;
    }

Este programa, simplemente tratará de leer tu mando a distancia y enviar esa información a la consola. Asegúrate de que has puesto la velocidad a 115200:

Recepcion de codigos infrarrojos

Como veréis la rutina de servicio de la interrupción simplemente recoge los valores del protocolo que amablemente reconoce  sobre la marcha la librería. Los valores que presenta son

 
  • Nos informa del modelo de señal que usa nuestro mando. En este momento reconoce 4 protocolos y el autor pide la colaboración ciudadana, para aumentar el número de protocolos disponibles con la librería. Actualmente son:
    • IR_NO_PROTOCOL ,  0
    • IR_USER, 1
    • IR_ALL,  2
    • IR_NEC, 3.
    • IR_PANASONIC,  4
  • Address, dirección de tu mando. Cada mando lleva una dirección para identificarle. Podrías usar más de un mando a distancia para controlar lo que sea, y reconocerlos de forma diferenciada.
  • La orden o identificación del botón pulsado en el mando. Cada botón tiene un código diferente y estos son los códigos que usaras en tu programa para lanzar acciones diferentes en función del botón pulsado.
 

Yo he probado con 5 mandos IR diferentes (Tengo muchos trastos) y me ha reconocido correctamente 4 a la primera. Los que han entrado sin problemas son los de Panasonic, Sony, LG y Keyes.

El que no sabía lo que era, ha sido un mando viejo de una TV Schneider que soy incapaz de saber de dónde ha salido.

 
  • Conviene comentar que si tienes una tele, o VHS o similares que ya no usas, puedes tirar el aparto si quieres pero conserva el mando porque hay muchas probabilidades de que puedas leerlo con tu Arduino.
  • Además tus antiguos cacharros con mando a distancia incluyen esto receptores de IR que puedes desarmar y reutilizar para tus cosas. ( Os recomiendo desarmar solo los aparatos viejos e inútiles, no los que están funcionando, que luego no quiero responsabilidades).
 

Y en este programa está ya implícito todo lo necesario para utilizar un mando IR en tus proyectos. EL resto de la sesión será sencillamente un ejemplo de cómo gestionar esos golpes de teclas con u Swuitch que es una instrucción C++ que hasta ahora no habíamos usado y que nos viene al pelo.

Vamos a montar un circuito con Arduino y 4 LEDs de colores para encerderlos de uno en uno o apagarlos todos de golpe, mediante el mando IR a distancia.

 

Esquema de conexión

 

La conexión será muy sencilla:

Diagrama electronico

Y el esquema de protoboard, cuesta más dibujarlo que montarlo:

 

Esquema de protoboard

 

Programa de control

 

Al principio de esta sesión vimos que ya recibíamos las instrucciones del mando (Espero) y nos ponía en la consola el valor del protocolo, dirección del mando y Commando que corresponde al botón pulsado. Estos comandos son lo que necesitais para diparar vuestro programa

 
  • Si tienes mas de un mando y quieres usarlos, tendras que controlar también la dirección de cada mando.
 

En primer lugar correr el programa anterior para anotar los códigos que corresponden a cada tecla de vuestro mando, y haceros una tabla. No hace falta que anoteis todas las teclas por ahora, pero si al menos las que vayamos a usar.

En mi mando LG el resultado es este:

ArribaAbajoIzquierdaDerechaOK
0x02FD0x827D0xE01F0x609F0x22DD

Y con esto ya podemos escribir el programa de control. Vamos a utilizar la instrucción switch case, que es muy comoda cuando tienes que comprobar muchos valores y tomar acciones en respuesta a una variable. LA idea básica es como esto:

switch (IRCommand)
   {   case 0x02FD:
           Serial.println("Arriba");
           digitalWrite(8, HIGH);
           break;
case 0x827D:
           Serial.println("Abajo");
           digitalWrite(9, HIGH);
           break;
case 0xE01F:
           Serial.println("Izquierda");
           digitalWrite(10, HIGH);
           break;
case 0x609F:
           Serial.println("Derecha");
           digitalWrite(11, HIGH); 
           break;
case 0x22DD:
           Serial.println("OK");
           for (int k =0 ; k <12 ; k++)
                digitalWrite(k, LOW);
            break;
}

Le pasamos a switch la variable, cuyo valor determina la acción, en este caso el comando pulsado. Y después se establece una clausula de case para cada valor posible finalizando con dos puntos. Escribe las instrucciones a ejecutar y finaliza con break.

He puesto a propósito lo del Serial.println() para que veais que podeis poner varias líneas sin necesidad de bloques que ya esta implícito en el case. Y por fin finaliza la clausula con un break.

Puedes incluir una ultima clausula default, sin otro valor para poner una acción que se ejecute si el valor de la variable no coincide con niguno de los caso comprobados mas arriba.

Aquí teneis un programa de ejemplo: Ejemplo 52_3

#include "IRLremote.h"
const int interruptIR = 0;

uint8_t IRProtocol = 0;  // Variables para recibir los datos
uint16_t IRAddress = 0;
uint32_t IRCommand = 0;

void setup() 
   {    Serial.begin(115200);          // Fijate en la velocidad
        for (int i = 8 ; i<12 ; i++)
        pinMode(i, OUTPUT);

        IRLbegin<IR_ALL>(interruptIR);
   }

La unica novedad ha sido hasta aqui, definer como salidas los pines del 8 al 11

void loop()
   {    uint8_t oldSREG = SREG;  // Parar las interrupciones
        cli();
        if (IRProtocol)
          {  
              switch (IRCommand) // Aqui tenemos la clausula switch con sus case:
                  { case 0x02FD:
                        Serial.println("Arriba");
                        digitalWrite(8, HIGH);
                        break;
                    case 0x827D:
                        Serial.println("Abajo");
                        digitalWrite(9, HIGH);
                        break;
                    case 0xE01F:
                         Serial.println("Izquierda");
                         digitalWrite(10, HIGH);
                         break;
                    case 0x609F:
                         Serial.println("Derecha");
                         digitalWrite(11, HIGH);
                         break;
                    case 0x22DD:
                         Serial.println("OK");
                         for (int k =0 ; k <12 ; k++) 
                              digitalWrite(k, LOW);
                         break;
                  }
              IRProtocol = 0;
          }
       SREG = oldSREG; 
    }
void IREvent(uint8_t protocol, uint16_t address, uint32_t command)
   {
        IRProtocol = protocol;  // Recogemos los valores
        IRAddress = address;
        IRCommand = command;
   }

La cláusula switch es muy útil para evitar if else encadenados que al final te hacen perder el hilo. Imagínate si tienes que comprobar todas las posibles teclas del mando.

Aquí teneís un minivideo con el resultado

Por ultimo y antes de terminar, comentar que el autor de la librería recomienda que si vamos a usar un solo mando, sustituyamos la líne

IRLbegin<IR_ALL>(interruptIR);

Por la que corresponda a nuestro modelo, porque ahorraremos en memoria y ganaremso en velocidad en la decodificación de las señales. En mi caso que me reporta el protocolo 3 , IR_NEC sería:

IRLbegin<IR_NEC >(interruptIR);

 

 

 

Resumen de la sesión

 

 

    • Tenemos una idea mas clara de lo que es la luz infrarroja.
    • Hemos presentado los receptore de mandos IR AX-1838HS.
    • Hemos visto que podemos usar los mandos que tengamos disponibles y que nuestro Arduino es capaz de leer la mayoria de ellos
    • Vimos la instruccion switch case
 

 

 

 

 

(151) Comments

    • Ramses

    Buenad tardes,

    Estoy dándole vueltas al código del programa que ponen en esta práctica y no veo de dónde salen IREvent, variable SREG e interruptIR.

    ¿Están definidas en la librería y tienen que ser esos nombres, por fuerza, porque la interrupción busca esos nombres de función y variables?

    Saludos y gracias.

    • Hola Ramses, no he mirado a fondo la libreria pero ten en cuenta que precisamente la idea de la libreria es definir funciones y variables que podomeos usar en nuestros programas y si no encuentras esas funciones cuenta que estan alli. Prueba a editar los ficheros de la libreria (que estan en C normal) y veras como lo encuentras enseguida

  • Bueno parece que se va consiguiendo. El error dice que la declaración typedef num que termina, después de la llave, en un punto y coma, no es correcta. He entrado en el archivo IRLremote.h y he modificado La declaración typedef num es la siguiente:

    typedef enum IRType{
    IR_NO_PROTOCOL, // 0
    IR_USER, // 1
    IR_ALL, // 2
    IR_NEC, // …
    IR_PANASONIC,
    IR_SONY8,
    IR_SONY12,
    IR_SONY15,
    IR_SONY20,
    // add new protocols here
    };

    Es cierto que terminaba en }; no parecía muy correcto esa terminación. He mirado por ahí y parece que debería terminar en lo siguiente
    decode_type_t;

    Ahora ya funciona, pero el programa de control, el primero que está en la página, ahora me da el error de que no está declarada la variable
    IRLbegin(interruptIR);

    Los programas de la carpeta example, funcionan todos pero el de la página no ¿a que puede ser debido?

    • Pues la verdad es que es muy raro porque yo no tengo ningún problema con los programas de las sesiones. De hecho el primero de ellos es uno de los ejemplos que vienen con la librería.

  • Buenas noches

    Estoy haciendo el ejemplo primero que habéis puesto en la página sobre el sensor IR. Pero cuando compilo me da el siguiente mensaje. Obviamente no me funciona. Me podéis echar una mano? La librería que he utilizado es la que se aconseja en esta entrada.

    In file included from /var/folders/m6/6k7sfhd97rs84nsqdb976t6c0000gn/T/arduino_modified_sketch_317775/ir.ino:1:0:
    /Users/minombre/Documents/Arduino/libraries/IRLremote/IRLremote.h:72:1: warning: ‘typedef’ was ignored in this declaration
    };
    ^
    In file included from /Users/minombre/Documents/Arduino/libraries/IRLremote/IRLremote.cpp:24:0:
    /Users/minombre/Documents/Arduino/libraries/IRLremote/IRLremote.h:72:1: warning: ‘typedef’ was ignored in this declaration
    };
    ^

    El Sketch usa 2.564 bytes (7%) del espacio de almacenamiento de programa. El máximo es 32.256 bytes.
    Las variables Globales usan 249 bytes (12%) de la memoria dinámica, dejando 1.799 bytes para las variables locales. El máximo es 2.048 bytes.

    • Hola! Lo he probado y a mi me funciona bien, además es que es un ejemplo de los que viene con la librería. Yo probaría a quitarla y volver a instalarla a ver… O si estás haciendo copiar y pegar de la página, prueba a abrir el ejemplo de la librería desde el IDE. Un saludo.

    • Hoal JCS, con cierta frecuencia los cambios en el IDE arduino y el compilador hacen que las librerias dejen de funcionar ya veces hay que actualizarlas. Prueba a descargar la libreria irlremote de github e instalala para ver si corrije el problema y me cuentas ¿Vale?

      https://github.com/NicoHood/IRLremote

Give a Reply

WordPress Anti-Spam by WP-SpamShield