domingo, 26 de agosto de 2012

Mostrando canción en LCD con Arduino (I)

En la última imagen del post anterior se podía ver cómo la canción que se reproducía actualmente en la radio online se mostraba en una pantalla LCD. En este post explicaré cómo lo estoy haciendo y aprovecharé para introducir la comunicación en serie entre el RPi y el Arduino.

No me voy a extender mucho describiendo el Arduino, ya que hay muchísima información disponible en la red. Básicamente es una plataforma basada en un microcontrolador AVR cuyo diseño es completamente libre así como su IDE y SDK. Se utiliza mucho en multitud de proyectos relacionados con la electrónica e incluso con la robótica, por ejemplo para controlar impresoras 3D, resolver cubos de Rubik o realizar mediciones mediante diversos sensores. Su consumo es muy reducido y puede funcionar incluso con una pila de 9V.

Debido a la gran cantidad de librerías que existen para Arduino, es relativamente sencillo controlar muchos dispositivos como pantallas LCD, matrices de LEDs, sensores de todo tipo, motores, etc. Además, es posible extenderlo con otros circuitos denominados shields, que le dotan de más posibilidades. Existen shields que incluyen conexión de red, conexión Bluetooth, lector de tarjetas SD, incluso conexión GSM.

En mi caso, para la prueba he usado un Arduino Duelillamove (el de toda la vida) con un shield LCD Keypad, que incluye un pequeño display LCD de 16 caracteres y 2 líneas y 4 botones programables.

IMG_0405

Ambos dispositivos los compré en eBay, que suelen salir más baratos que en tiendas de electrónica online. Para conectarlos basta con encajar el shield en la parte superior del Arduino, como muestra la imagen:

IMG_0411

En realidad, el shield lo único que hace es conectar de forma sencilla y sin soldaduras la pantalla y los botones con el Arduino, lo que es bastante más cómodo para las pruebas que conectar todo a mano, ya que queda más compacto. Seguramente más adelante usaré directamente una pantalla y unos botones o un receptor de IR para controlar la radio con un mando a distancia. Las pantallas de este tipo se pueden encontrar muy baratas por eBay. Yo tengo una pequeña colección Risa.

IMG_0406

Aquí podéis ver una pantalla de 20x4 caracteres en la parte de abajo a la derecha, y varias de 16x2 de diferentes colores. Seguramente acabe utilizando la de 20x4, que permite mostrar más información al usuario de la radio.

También existen otro tipo de pantallas que pueden ser más apropiadas para otros proyectos. Por un lado están las matrices de LEDs, que son más complicadas de programar, ya que las librerías no están tan depuradas y se trabaja a muy bajo nivel. En mi caso utilicé este tipo de pantalla para un proyecto ya acabado de reloj despertador con Arduino.

IMG_0407

Como se puede ver en la imagen, la pantalla es simplemente una matriz de LEDs que pueden estar o no iluminados. También existen matrices de LEDs RGB que permiten elegir el color de cada LED, aunque son bastante más caras.

Otro tipo de pantallas son las de segmentos, parecidas a las de las calculadoras.

IMG_0408

La imagen de arriba es simplemente un termómetro usando un Arduino y un sensor de temperatura LM35 (a la derecha del display).

Existen aún más tipos de pantalla. Las hay incluso gráficas, como la de muchas calculadoras avanzadas. Sin embargo, para la radio, las pantallas de caracteres me parecen mas adecuadas y me permiten aprovechar material ya comprado.

Para empezar a trabajar con el Arduino, simplemente hay que descargarse el IDE desde la página oficial, descomprimirlo en donde deseemos y ejecutarlo. Ahora podemos conectar al PC el Arduino y se instalará automáticamente. Por último podemos cargar un programa de prueba desde Archivo –> Ejemplos. Yo he elegido Blink:

image

Con el Arduino conectado basta con pulsar en cargar (el icono con la flecha hacia la derecha de la parte superior de la interfaz) y el IDE se encarga de programar el Arduino de reiniciarlo para ejecutar el programa.

Una vez probado el funcionamiento, he realizado un pequeño programa para permitir que el Arduino muestre el artista y la canción que se está reproduciendo en el display del shield. Pongo el código y lo comento a continuación:

  1: #include <LiquidCrystal.h>   
  2: #include <LCDKeypad.h>   
  3:     
  4: LCDKeypad lcd;   
  5: String serialIn;   
  6: String serialOut;   
  7: boolean serialComplete = false;   
  8:     
  9: void setup(){  
 10:   Serial.begin(9600);  
 11:     
 12:   lcd.begin(16,2);  
 13:   lcd.clear();  
 14:   lcd.print("Arduino Radio");  
 15:   lcd.setCursor(0,1);  
 16:   lcd.print("V 0.0");  
 17:   serialIn.reserve(200);  
 18:     
 19:   Serial.println("INITOK");   
 20: }  
 21:    
 22: void loop(){  
 23:   if(serialComplete){  
 24:      Serial.println(serialIn);  
 25:      if (serialIn.startsWith("UP")){  
 26:        lcd.setCursor(0,0);  
 27:        lcd.print("                ");  
 28:        lcd.setCursor(0,0);  
 29:        lcd.print(serialIn.substring(3));  
 30:          
 31:        Serial.println("OK");  
 32:      }  
 33:        
 34:      else if (serialIn.startsWith("DW")){;  
 35:        lcd.setCursor(0,1);  
 36:        lcd.print("                ");  
 37:        lcd.setCursor(0,1);  
 38:        lcd.print(serialIn.substring(3));  
 39:          
 40:        Serial.println("OK");  
 41:      }  
 42:        
 43:      else{  
 44:        Serial.println("KO");  
 45:      }  
 46:    
 47:      serialIn = "";  
 48:      serialComplete = false;  
 49:   }  
 50:   Serial.println("Loop");  
 51:   delay(1000);  
 52: }  
 53:    
 54:    
 55: // Reads the serial input and stores in serialIn  
 56: void serialEvent() {  
 57:   while (Serial.available()) {  
 58:     // get the new byte:  
 59:     char inChar = (char)Serial.read();   
 60:     // add it to the inputString:  
 61:     if(inChar != '\n'){  
 62:       serialIn += inChar;  
 63:     }  
 64:     // if the incoming character is a newline, set a flag  
 65:     // so the main loop can do something about it:  
 66:     if (inChar == '\n') {  
 67:       serialComplete = true;  
 68:     }  
 69:   }  
 70: }



Las dos primeras líneas cargan las librerías necesarias para controlar la pantalla LCD y el Shield LCDKeypad. Esta versión del LCDKeypad hereda de LiquidCrystal, así que es posible utilizar todas las funciones de LiquidCristal desde la librería LCDKeypad). En principio LiquidCrystal.h no es necesario incluirlo, aunque habrá que hacerlo cuando cambiemos el shield por una pantalla independiente.


Las líneas 4 a 7 declaran las variables globales que vamos a utilizar, en concreto un objeto LCDKeypad que representa nuestro shield, dos cadenas para poder recibir y enviar texto a través del puerto serie y un booleano que nos indique si la transmisión de datos ha terminado o no.


La función setup (líneas 9 a 20) se ejecuta una sola vez en cuanto se enciende el Arduino, y se suele usar para inicializar el sistema. En mi caso, inicio la conexión serie a 9600 baudios (línea 10), inicializo el display (línea 12) indicando que el display es de 16 caracteres y dos líneas.


En la línea 13 borro cualquier carácter que pudiera haber en la pantalla y a continuación escribo Arduino Radio (por defecto el cursor está en la posición 0,0 después de un clear), me desplazo a la columna 1 y escribo la versión.


En la línea 17 reservo 200bytes para la cadena de entrada y envío un INITOK por el puerto serie para que el dispositivo receptor (en este caso el RPi) sepa que el Arduino ya se ha inicializado.


Una vez ejecutada la función setup, Arduino ejecuta de forma periódica la función loop (líneas 22 a 52). En ella primero comprobamos que se haya recibido un envío por puerto serie (de lo que se encarga la función serialEvent que se puede ver más abajo). En ese caso, mira los dos primeros caracteres:


Si los caracteres son “UP” escribe el resto de la cadena en la línea superior de la pantalla y envía un “OK”.


Si los caracteres son “DW” escribe el resto de la cadena en la línea inferior de la pantalla y envía un “OK”.


Si los caracteres no son ni “UP” ni “DW”, no hace nada y envía “KO” por el puerto serie, para indicar que no se ha procesado el mensaje.


Por último, borra la cadena de entrada para poder utilizarla de nuevo, y pone la variable serialComplete a false para prepararse para el siguiente envío del RPi. La última línea de la función es un delay de 1s para que no esté ejecutando continuamente el bucle, sino que espere un segundo entre ejecuciones.


La función serialEvent (líneas 56 a 70) se activa cuando Arduino detecta datos entrando por el puerto serie. En este caso lo que hacemos es almacenar los datos en la cadena serialIn y activar la variable serialComplete una vez que hayamos terminado la cadena (en nuestro caso, al recibir un carácter de salto de línea).


La idea de este programa de ejemplo, es que podamos parsear el artista y la canción (o lo que queramos) desde el RPi, y lo vayamos enviando al Arduino por el puerto serie, actuando el Arduino como un simple controlador de la pantalla, que procese las órdenes que le llegan y muestre la información en el display. Más adelante podremos introducir otras órdenes más complejas y dejar que el Arduino se encargue de actualizar el display. Por ejemplo podríamos utilizar un comando desde el RPi para obtener la cobertura Wifi, y enviar un comando al Arduino como:


WF 78%


Y que éste de encargase de actualizar sólo la zona de la pantalla donde se muestra la cobertura Wifi, evitando actualizar toda la pantalla.


Si ejecutamos este programa en el IDE de Arduino, podemos activar el monitor serie y ver cómo efectivamente, se recibe el INITOK, el Loop en cada bucle y como procesa las órdenes (que le podemos escribir directamente en el monitor):


image


En el siguiente post veremos cómo reproducir emisoras con el MPD y MPC, cómo extraer los datos de la canción y cómo enviarlos a RPi utilizando Python.


Aprovecho para comentar que lo más seguro es que los códigos que vaya colgando no sean lo más correcto en cuanto a programación, tolerancia a fallos y demás. Conforme vaya avanzando en el proyecto iré puliendo los códigos, pero se agradece cualquier comentario y/o crítica constructiva que pueda servir para mejorar.

Instalando MPD y MPC para reproducir streams de audio

Una vez configurado el sonido en el RPi, necesitamos algún reproductor que nos permita cargar y reproducir las radios online. Cuando usaba Linux, solía utilizar los que venían en los reproductores gráficos como Exaile, Amarock o Rhythmbox. También existía un programa especializado, Streamtuner, que permitía elegir emisoras de radio de varias fuentes (Xiph, Shoutcast, etc.). En nuestro caso, sin embargo, es más cómodo un reproductor de consola, ya que no tendremos un monitor en el que mostrar la interfaz gráfica del reproductor, ni un ratón para interactuar con ella.

Mi idea es utilizar un pequeño mando IR como el de la imagen, o botones físicos y utilizar el Arduino para detectar las pulsaciones y comunicarlas al RPi mediante conexión serie. En el RPi, mediante un programa (en principio en Python), recoger las pulsaciones, realizar las acciones necesarias sobre el reproductor y responder al Arduino, ya sea que todo ha ido bien o que se ha producido algún error.

IMG_0403

Por este motivo estuve mirando varios reproductores de consola para Linux que fuesen compatibles con streams de audio, ya que parece que no hay nada especialmente pensado para la radio online. Algunas de las opciones que he encontrado son:

mpg123, lo recomiendan en varios sitios y al parecer su uso es tan sencillo como escribir mpg123 y la dirección del stream de audio. Tiene el inconveniente de no ser un demonio, por lo que tendríamos que utilizar algún sistema de terminal virtual como screen para las pruebas. Tampoco soporta listas de reproducción pls o m3u, aunque podríamos generar en un fichero de texto o en una pequeña base de datos las estaciones que queramos escuchar y luego invocar al reproductor con el stream correspondiente al seleccionar una. Una pequeña tabla con SQLite valdría perfectamente.

mplayer, es uno de los reproductores más populares de Linux, y también soporta stream de audio y listas de reproducción- Su funcionamiento sería muy parecido al de mpg123. Además hay tutoriales de como usarlo para escuchar radios por consola.

MOC, es un reproductor basado en NCurses, que es un sistema de interfaces en modo texto para consola de Linux. El inconveniente para nosotros es precisamente el que esté basado en NCurses, ya que no tenemos un display de 80x25, sino de 20x4 como máximo, por lo que se queda muy corto para mostrar esta interfaz. Sin embargo, al parecer también puede usarse directamente mediante comandos.

MPD y MPC, el primero es la abreviatura de Music Player Daemon y el segundo de Music Player Client. MPD es un demonio que se queda activo en segundo plano y mediante MPC podemos añadir, eliminar, reproducir pistas, etc. Un aspecto que me ha gustado bastante es que es posible obtener fácilmente la información de la canción (artista, álbum, título, etc.), por lo que es muy sencillo parsearla y enviarla al Arduino para que muestre la canción actual en el display:

IMG_0404

Por ahora he elegido MPD y MPC y he conseguido mostrar sin problemas el artista y la canción con el display (contaré como en próximos posts). Sin embargo, sigo abierto a probar otras alternativas. De hecho, si alguien quiere recomendar alguna de las demás opciones u otra que no haya contemplado aún, por favor, que lo haga en los comentarios.

Activar Wifi en RaspberryPi

Ya comentamos que aunque el RPi lleva conexión de red cableada, nuestra idea era utilizarlo mediante un Wifi USB, en concreto un OvisLink EVO-W541USB:

IMG_0401

Por suerte, su chipset es Atheros, con lo que para hacerlo funcionar, basta con descargar el firmware:

sudo apt-get install firmware-atheros wicd wicd-curses

También he seleccionado wicd y wicd-curses, que es un gestor de conexiones que nos permitirá conectarnos fácilmente mediante la consola a redes wifi.

Una vez instalado (no recuerdo si fue necesario reiniciar el RPi, creo que no), ejecutamos wicd-curses para conectarnos a nuestra red.

image

Para ello sólo hay que seleccionar nuestra red, pulsar la flecha derecha para configurarla, y pulsar C para conectarse a ella. En las opciones de conexión es conveniente pulsar en “Conectar automáticamente a la red” para que no tengamos que volver a repetir el proceso en el futuro. También se puede establecer una IP fija para que siempre se conecte con la misma IP y no tengamos que buscarla a la hora de conectarnos al RPi por SSH, en mi caso, lo hice reservando la IP en mi router pero también se puede hacer en Wicd.

Ahora sólo habría que desconectar el cable de red y comprobar que seguimos con conexión:

image

PD: En los foros de RPi comentan que determinados Wifi USB no funcionan correctamente dado que necesitan más energía de la que puede suministrar el RPi, por lo que recomiendan usar un HUB USB autoalimentado. En mi caso no ha sido necesario, pero más vale prevenir.

Configurando Raspbian

Una vez instalado Raspbian por primera vez es conveniente realizar una configuración mínima para poder trabajar con él más fácilmente. Yo he hecho lo siguiente:

Para empezar conecté un ratón y un teclado al RPi, un cable de red directo al router, la tarjeta con Raspbian instalado y un HDMI a mi monitor. Después de conectarlo todo, encendemos el RPi conectándole una fuente de alimentación (En mi caso el cargador del móvil funcionó perfectamente, aunque compré el RPi con un transformador de 5V 1A para ir sobrado).

Si no hay problemas, RPi arrancará y al finalizar mostrará un menú de configuración. Si no lo muestra basta con teclear en la terminal:

sudo raspi-config

En este menú podemos cambiar varios parámetros útiles. En mi caso modifiqué el layout del teclado para ponerlo en español (opción configure_keyboard). Configuré también el idioma del sistema (change_locale), el GMT (change_timezone), la contraseña (por defecto es raspberry) y activé el SSH, muy útil para poder controlar después nuestro RPi sin necesidad de conectarle nada. Hay más opciones, pero estas son las fundamentales para mi proyecto.

Una vez hecho esto, pulsamos en Finish y ya tenemos Raspbian listo para usar.

Como lo hemos conectado por cable a Internet, podemos aprovechar para actualizar el sistema. Para ello basta con escribir:

sudo apt-get update

sudo apt-get upgrade

Y esperar un rato a que actualice paquetes. En mi caso me preguntó actualizar ciertos scripts del sistema y elegí la opción por defecto de mantener la versión actual.

Si hemos activado el servidor SSH, podemos comprobar también que es posible acceder al RPi desde otro PC. Para ello usamos cualquier cliente de SSH (yo utilizo Kitty en Windows). Ahora bien, ¿con qué IP podemos acceder al RPi?. Hay varias formas de averiguarlo:

  1. Desde la terminal tecleamos ifconfig y nos fijamos en la ip del campo inet addr de la interfaz de red (eth0).
  2. Desde nuestro router accedemos a la opción de DHCP y seguramente tendremos una lista de los dispositivos conectados:

image

En cuanto podamos acceder por SSH a nuestro RPi, ya no será necesario conectarle teclado, ratón o pantalla, por lo que nos resultará bastante más cómodo trabajar con él.

Instalando Raspbian en Raspberry Pi

Una de las primeras cosas que haremos será instalar la distribución oficial del RPi para hacerlo funcionar. A diferencia de la instalación de un sistema operativo en un PC convencional, la instalación en el RPi es mediante un volcado directo del sistema a la tarjeta de memoria (que hará de disco principal del sistema). Aún así, los pasos son incluso más sencillos que en una instalación “normal”.

En mi caso he utilizado Windows 7 para instalar RaspBian, aunque se puede hacer en cualquier otro SO (MacOs, Linux).

  1. Accedemos a la sección de descargas de la página oficial de RPi: http://www.raspberrypi.org/downloads Una vez allí elegimos la opción Raspbian, que es la que nos recomiendan y la descargamos, ya sea mediante un Torrent o por descarga directa.image
  2. Si estamos utilizando Windows, descargamos el programa Win32DiskImager, que nos permitirá grabar la imagen en la tarjeta de memoria.
  3. Introducimos la tarjeta de memoria en un lector de tarjetas en nuestro PC y apuntamos la letra que le asigna Windows.
  4. Ejecutamos Win32DiskImager (no necesita instalación) y seleccionamos la imagen de Raspbian que hemos descargado previamente y la letra que Windows asignó a nuestra tarjeta (es importante no confundirse ya que podríamos equivocarnos e instalar Raspbian en el disco duro del PC y perder nuestros datos). Pulsamos en Write y esperamos a que termine de copiar los archivos.
  5. Una vez terminado el proceso de copia, sacamos la tarjeta del PC, la metemos en el RPi, y ya podríamos usarlo.

Radio Wifi con Raspberry Pi y Arduino

Hace tiempo que me llegó el mini ordenador Raspberry Pi. Llevaba bastantes meses siguiendo el proyecto y me pareció muy interesante, por lo que en cuanto salió a la venta compré uno para cacharrear con él cuando tuviese más tiempo.

Aunque para un uso normal como PC, Raspberry Pi (de ahora en adelante RPi) queda algo corto de potencia para tareas comunes como navegar por Internet (Su CPU es un ARM a 700MHz), su pequeño tamaño, bajo consumo y bajo precio lo hacen ideal para un montón de proyectos: Servidor de archivos, NAS, PC para dejar compartiendo torrents 24 horas (su consumo ronda 1W, incluso algo menos) y muchísimas cosas más.

Mi proyecto es construirme una radio que permita reproducir emisoras online. Mi idea es utilizar el Raspberry Pi con su distribución Linux oficial e instalarle algún reproductor que permita reproducir streams de audio (emisoras) de manera sencilla. Dado que el RPi tiene una salida de audio analógica (mini-jack), la idea es que sea él el que se encargue de reproducir y conectarle unos altavoces antiguos para amplificar la señal y poder oírla.

RPi también tiene un puerto de red para poderlo conectar a Internet con un cable estándar. Sin embargo, dado que no queremos limitar nuestra radio a estar cerca de un router, la conexión a internet será mediante Wifi. Concretamente con un adaptador USB 2.0 Ovislink EVO-W541USB que tenía por casa.

¿Y qué pinta el Arduino en esta radio? Pues debido a su facilidad para conectarlo a Pantallas LCD, botones y otras interfaces nos servirá de puente para conectar un display LCD que nos muestre la información de lo que esté sonando, las emisoras, etc. También nos servirá para controlar la radio, ya sea a través de botones o a través de un mando a distancia y un receptor de infrarrojos (lo he usado en un proyecto anterior y responde a la perfección). En cuanto a los displays, la mayoría de ellas son de caracteres, y utilizan en chip HD44780 para su control. Arduino tiene librerías que nos facilitan trabajar con este tipo de pantallas, por lo que no será difícil utilizarlas.

En mi casa tengo varias de estas pantallas de diferentes tamaños y colores. En cuanto a tamaños tengo unas de 16 caracteres y 2 líneas, y otras de 20 caracteres y 4 líneas. Aún no he decidido cuál de ellas voy a usar, aunque me inclino por la grande, ya que me permitiría incluir más información y algún icono adicional para indicar por ejemplo la cobertura del Wifi, el bitrate de la transmisión, etc.

Por último queda saber cómo se conectarán el Arduino y el RPi. En este caso la conexión la haremos emulando un puerto serie a través de USB. Haremos un programa en Python que se encargue de enviar los datos a representar en la pantalla desde el RPi al Arduino y que reciba de éste las pulsaciones de los botones o del mando a distancia y procese las órdenes.

sábado, 14 de abril de 2012

Ejemplo de messageBox en Swing

Con éste código se puede lanzar de manera sencilla un Message Box (Ventana emergente) en Swing. Este tipo de ventanas se utilizan mucho para informar al usuario de una aplicación de posibles errores o avisos importantes.

El código en cuestión es:

JOptionPane.showMessageDialog(mainWindow,
                              "File cannot be saved.",
                              "Save error",
                              JOptionPane.ERROR_MESSAGE);

Donde mainWindow es el contenedor Swing (JPanel, JFrame, JDialog, etc.) desde donde se lanza el MessageBox, de modo que éste aparecerá centrado respecto a dicho contenedor. Lo siguiente es el mensaje que queremos mostrar, seguido del título de la ventana y del tipo de ventana (en este caso he seleccionado JOptionPane.ERROR_MESSAGE, lo que adapta la ventana con un icono de error y un botón de Aceptar.

El resultado de dicho código sería:

Captura