Archivo de la etiqueta: processing

Android + Processing + Bluetooth

A finales de 2009 los creadores de Processing anunciaron que iban a dar soporte a la plataforma de Android. La verdad es que fue una noticia muy buena, ya que el famoso entorno de creación de gráficos animados iba a poder ejecutar sketchs dentro de móviles que tuviesen a Android como sistema operativo. Pero no se han quedado ahí y además admite la posibilidad de usar las características embebidas en los dispositivos móviles como el GPS, la brújula electrónica, enviar y recibir sms, etc y por supuesto bluetooth.

Lo que explicaré en este artículo son los pasos que he seguido para crear una conexión desde mi teléfono Android con un dispositivo bluetooth y poder enviarle información a la par que recibirla dibujando los resultados de una forma gráfica con Processing para Android.

Ya en su momento me dediqué a programar en symbian algo parecido:

Sin embargo finalmente lo deseché porque la plataforma de symbian tiene ya poco futuro y porque las APIS eran confusas, mal explicadas y no se puede acceder a todos los elementos de hardware con ellas.

Por otra parte no hay que compararlo con Amarino, ya que Amarino es una aplicación ya hecha para Android con una interfaz definida y está pensado para usarse con Arduino, sin embargo aquí vamos a programar nuestra propia aplicación con su propia interfaz para cualquier dispositivo que tenga un controlador bluetooth.

Dicho esto lo primero es necesario instalar todo el entorno de desarrollo, aquí viene bien explicado en castellano por lo que no considero necesario añadir más.

Antes de empezar, sería interesante que echarais un vistazo a dos páginas para entender mejor lo que viene a continuación. Por una parte la API de Android para bluetooth para comprender qué posibilidades nos ofrece. Por otra parte unos conceptos y un ejemplo de cómo usar Android y gestionar el hardware con Processing. A los que hayáis programado en Processing puede resultar extraño que además de poder usar las funciones básicas del entorno, se puedan incluir librerias y código de Java y la API Android. Esto es debido a que tanto Android como Processing tienen una fuerte vinculación con el lenguaje de programación Java y su unión ha creado una suerte de mescolanza que reúne lo mejor de ambos mundos.

El objetivo es que podamos crear una interfaz completa para que nos muestre los dispositivos bluetooth que hay alrededor, a continuación podamos elegir uno de ellos y finalmente conectarnos a este para enviar y recibir datos. En este caso en concreto voy a conectar mi móvil HTC Wildfire S con una placa Arduino a través de un módulo bluetooth. La placa Arduino enviará a mi móvil cada segundo un valor comprendido entre 0 y 39 y este lo mostrará en su pantalla. En el móvil habrá dibujado un botón que cuando se pulse enviará un 0 a la placa Arduino para encender o apagar el led del pin 13.

Este es el código fuente del sketch para la placa Arduino:

Ahora la parte de Android y Processing. A partir de aquí iré explicando los conceptos a medida que publico el código fuente para comentar los aspectos que considero que son más relevantes y finalmente pondré el código fuente integro.

Para poder programar el bluetooth de nuestro dispositivo basado en Android junto con Processing empezaremos por crear un sketch, daremos los permisos BLUETOOTH y BLUETOOTH_ADMIN en el menú Android/Sketch Permissions e importaremos las clases necesarias para que todo funcione:

Hay algunas librerías que, como veremos más adelante, podemos prescindir de ellas dependiendo de lo que queremos hacer y lo bien o mal que nos funcione.

A continuación vamos a añadir los métodos típicos de un sketch de Processing: setup y draw:

En el método setup forzamos a que la resolución de la pantalla sea de 320 píxeles de ancho x 480 píxeles de alto (HVGA), ya que es una configuración muy extendida dentro del mundo de los móviles. Establecemos que la frecuencia de refresco sea de 25 fps. Creamos dos tipos de fuentes con las que dibujar después los textos que queramos.

En el método draw vamos a simular varias ventanas dependiendo del estado en el que se encuentre nuestra aplicación en cada momento. Así nada más empezar se muestra la ventana de búsqueda de dispositivos, a continuación se ofrece al usuario que seleccione uno de los dispositivos mostrados:

Después se intenta conectar con el dispositivo elegido y finalmente si tiene éxito se muestra la ventana con los datos enviados por Arduino y con el botón que mencionaba antes:

Si algo falla se muestra el error en una ventana:

Un sketch de Proccesing para Arduino se trata como una Activity, por eso se puede inicializar todo en el evento OnStart cuando es llamado al arrancar la aplicación (OnCreate no es llamado).

En el evento OnStart primero debemos llamar al método onStart de la clase padre para inicializar correctamente. Después recuperamos el adaptador bluetooth del móvil y comprobamos si está activo. Si está activo empezamos a mostrar la lista de dispositivos. Si no lo está, lanzamos una petición para activarlo. En esta petición Android nos mostrará un mensaje similar a este en el móvil para activar el bluetooth:

Pulsemos la opción que pulsemos, se llamará al evento onActivityResult:

Si hemos pulsado Si entonces empezaremos a mostrar la lista de dispositivos, si hemos pulsado No iremos directamente a la pantalla de error.

Cuando se abandona la aplicación se llama al evento onStop (onDestroy no es llamado)  y aquí se pueden liberar los recursos que hayamos utilizado antes de terminar definitivamente.

En el evento OnStop vamos a hacer dos cosas, aunque una de ellas está comentada por una razón que explicaré más adelante. Lo que se ve es que se cierra un socket que no es otra cosa que la conexión que hayamos establecido con nuestro dispositivo para poder liberar los recursos asociados a este. Finalmente se llama al método onStop de la clase padre para cerrar correctamente la aplicación.

El método empieza sirve para rellenar la lista de dispositivos bluetooth que más tarde mostraremos al usuario.

Inicializamos un array que rellenaremos de objetos BluetoothDevice. Aquí comento una problemática que me he encontrado: Puedes incluir los dispositivos que hay alrededor del móvil o bien incluir los que previamente se hayan emparejado. La parte que está comentada (y por tanto la del método onStop que desregistra el Receiver) se usa para lanzar un proceso de búsqueda de dispositivos bluetooth que estén cerca de nuestro móvil: se registra el empiece, cada dispositivo que se encuentre y el final de la búsqueda. Para manejar estos eventos se usa una clase del tipo BroadcastReceiver ya inicializada:

Cuando se empieza la búsqueda se encuentra en el estado 0 para mostrar la lista de dispositivos a medida que van apareciendo. Por cada dispositivo bluetooth que se encuentre se añade al array de dispositivos bluetooth, Cuando termina la búsqueda se pasa al estado 1 para que el usuario seleccione el dispositivo al que quiere conectarse.

El hacerlo de esta forma provoca que más adelante cuando se conecte al dispositivo bluetooth se tenga que mostrar una ventana preguntando por un código de emparejamiento para vincular el móvil con este.El problema es que esa ventana no se visualiza cuando están los gráficos mostrándose y el proceso de conexión dará finalmente un error. Por eso la otra alternativa que he encontrado es emparejar el dispositivo bluetooth a mano con el móvil y rellenar la lista de dispositivos con los que ya están vinculados en el móvil, así no pedirá el código de emparejamiento y se conectará con el dispositivo bluetooth directamente.

En varias ocasiones hay que capturar donde pulsa el dedo del usuario para saber qué acción quiere realizar. Esto se consigue con el evento mouseReleased:

Depende del estado en el que encontremos hará una acción diferente. Cuando estamos en el estado 0 y si se usara la búsqueda de dispositivos bluetooth (pero no es así por los motivos que he comentado) al pulsar en la pantalla cancelaría la búsqueda y lanzaría un ACTION_DISCOVERY_FINISHED al BroadCastReceiver visto anteriormente. Si estamos en el estado 1 se buscaría qué dispositivo bluetooth de la lista ha pulsado el usuario para conectarse a el. Si estamos en el estado 3 se comprueba si se ha pulsado el botón que envía un byte al dispositivo bluetooth.

El método que comprueba que elección ha hecho el usuario en el estado 1 es compruebaEleccion:

Con una sencilla fórmula matemática se puede sacar el dispositivo bluetooth que el usuario ha elegido en base a en qué parte de la pantalla ha pulsado. Después se pasa al estado 2 (Conexión al dispositivo bluetooth).

La lista de dispostivos bluetooth se hace con el método listaDispositivos:

Se recorre el array de dispositivos bluetooth mostrando su nombre y su dirección MAC. Es usada tanto en el estado 0 (listado de dispositivos bluetooth a medida que van apareciendo en la búsqueda) como en el estado 1 (selección del dispositivo bluetooth al que conectarse).

La conexión con el dispositivo bluetooth se hace con el método conectaDispositivo:

Aquí ocurre un caso especial. Para conectar con el dispositivo bluetooth se debe crear un socket con el dispositivo y después hacer la conexión propiamente dicha con el método connect. Sin embargo dependiendo de con qué dispositivo se conecte puede dar problemas el método que se use para obtener ese socket. La versión normal es la que está en el metodo y se supone que es la estándar, pero a mi me dio problemas al conectar al blueooth de un PC y tuve que usar las dos líneas que aparecen comentadas . Sin embargo con el módulo bluetooth de Sure la línea que aparece actualmente ha funcionado sin problemas. Como estamos creando una conexión SPP (como si fuese un puerto serie virtual) a través del protocolo RFCOMM, debemos obtener el socket que conecta con el servicio 00001101-0000-1000-8000-00805F9B34FB, que es el identificador único de servicio para SPP en el estandar Bluetooth. El método connect es bloqueante por lo que dejará la aplicación paralizada hasta que se conecte realmente o surja un error. Google dice que se debe usar un thread para separar el hilo de ejecución principal con el de la conexión, pero creo que está solución es más sencilla. Una vez se ha conectado se pueden recuperar el stream de entrada y el de salida para recibir y enviar datos respectivamente con el dispositivo bluetooth. A continuación se pasa al estado 3 (Visualización de datos e interacción con el botón). Si hubiese algún error se pasaría al estado 4 mostrando qué lo ha provocado.

El método que muestra los datos enviados desde el dispositivo bluetooth es muestraDatos:

Simplemente comprueba si se ha recibido algún byte y lo muestra. También muestra el botón ficticio que puede pulsar el usuario.

El método que se ejecuta cuando el usuario pulsa el botón es compruebaBoton:

Si se comprueba que el usuario ha pulsado en el área del botón se envía un byte con valor 0 al dispositivo bluetooth, que actualmente lo que hace es encender o apagar el led de la placa Arduino. Si hubiese algún error se pasaría al estado 4 mostrando qué lo ha provocado.

Finalmente el método que muestra los errores es muestraError:

Simplemente muestra el texto del error de forma apaisada para mostrar cadenas largas.

Dejo el código fuente entero:

Clase BarraInfo para Processing

He creado una clase llamada BarraInfo para que podais añadir a vuestros proyectos de Processing. La clase sirve para crear barras de información, como las que habeis visto en la telemetría para mostrar el PWM de los motores o el nivel de la batería.

La ventaja de usar esta clase (y cualquier otra) es que os evitais tener que crear el código de cero porque ya está hecho, podeis usarla en todos los proyectos de Processing que hagais, podeis tener varias barras de información en la pantalla y se puede configurar a medida.

A continuación os pongo el código fuente de la clase:

Para usarla os voy a poner un ejemplo de cómo mostrar el PWM asignado a un motor.

Lo primero es copiar el código fuente que he puesto más arriba en vuestro proyecto, preferentemente al final.

Lo segundo es crear una variable global del tipo BarraInfo.

Lo tercero es instanciar la clase para crear un objeto en el método setup de vuestro sketch.

Después, y dentro del mismo método setup inicializamos las variables de la clase. Dado que las variables de las clases de Processing son públicas y no se admiten variables de tipo privado, he preferido acceder a ellas directamente sin métodos get/set:

Establecemos el valor de inicio y final que podrá tener la barra, en el PWM es de 0 a 255, en una batería Lipo sería de 0 a 8,4.

Establecemos el color de las lineas (que comprende las muescas y el texto asociado a ellas) y el color de la barra.

Establecemos la posición x e y de nuestra ventana donde se mostrará la barra de información.

Establecemos la anchura de las muescas y de la barra (cada una) y la altura del conjunto.

Establecemos cada cuantos píxeles se dibuja una muesca y cada cuantos píxeles se muestra un número de referencia.

Establecemos la fuente que previamente habremos creado en el menú Tools/Create Font… de Processing y la desplazamos en su eje x e y para que encaje bien en las muescas.

Establecemos el número mínimo de enteros que apareceran (rellenando con ceros por la izquierda si no llega) y el número de decimales (-1 si no queremos que salgan) de los números de referencia.

Finalmente en el método draw se debe establecer el valor que debe tener la barra y pintarlo. He puesto un random para que pueda apreciar el movimiento.

Así es como quedaría el código fuente:

Y así el resultado:

Processing y el puerto serie

Processing es un software de programación de representaciónes gráficas y animaciones. Está basado en java y debido a ello es multiplataforma. Es software libre y tiene una comunidad muy extensa de desarrolladores y de usuarios.

El objetivo de este artículo es tratar de dar una idea de cómo hacer que Processing pueda interactuar con un puerto serie: cómo recibir y enviar datos, cómo mostrarlos en un gráfico y/o guardarlos en un fichero.

Como Processing puede usar librerías al estilo de java, hay una que necesitaremos para la programación del puerto serie, esta es processing.serial y se puede importar desde un sketch de la siguiente manera:

A continuación se debe crear una variable global del tipo Serial (o varias si vamos a tratar con más de un puerto serie).

Después hay que instanciarlo en el método Setup.

Lo que estamos haciendo es crear un objeto Serial. El constructor de la clase Serial tiene varias sobrecargas:

Serial(padre)
Serial(padre, velocidad)
Serial(padre, puerto)
Serial(padre, puerto, velocidad)
Serial(padre, puerto, velocidad, paridad, palabra, parada)

Los parámetros son:

padre: Se suele usar this siempre.
velocidad: La velocidad en b.p.s. a la que se quiere enviar y recibir datos: 9600 es la que toma por defecto si no se le indica otra cosa.
puerto: Nombre del puerto de comunicaciones. «COM1» es el que toma por defecto, pero puede ser otro de windows. En linux o mac suele ser /dev/tty*
paridad: ‘N’ para ninguna, ‘E’ para paridad par, ‘O’ para paridad impar. ‘N’ es la que se toma por defecto.
palabra: Número de bits que conforman una unidad de datos. 8 es el que se toma por defecto.
parada: Número de bits de parada (stop). Puede ser 1.0, 1.5, or 2.0, siempre en formato float. 1.0 es el que se toma por defecto.

Si no sabemos a priori qué puertos serie tenemos en nuestro ordenador, podemos imprimir un listado de los disponibles.

Como se trata simplemente de un array de cadenas, podemos acceder al valor de cualquier de ellas y pasárselo como argumento al constructor de Serial, tal y como he expuesto lineas atrás en la creación del objeto.

A partir de aquí, y si el puerto se ha podido abrir sin problemas, podemos enviar y recibir los datos.

Para enviar datos desde Processing al puerto serie hay que usar el método write del objeto que hayamos creado.

Se puede enviar tipos byte, char, int, array de bytes o cadenas.

Para recibir los datos tenemos dos posibilidades.

1) Comprobar dentro del método Draw si hay datos disponibles para su lectura, leerlos y procesarlos:

El método available nos devuelve el número de bytes que hay pendientes por leer en el buffer. El método read nos devuelve un valor de 0 a 255 del primer byte de la cola FIFO del buffer, o -1 si no hay dato disponible. Además de read hay otros métodos para recuperar los datos: readChar, readBytes, readBytesUntil, readString, readStringUntil.

2) Definir en el método Setup cuantos bytes queremos leer cada vez, esperar a que se active el evento serialEvent, y dentro de este leer los bytes.

En Setup:

En el cuerpo principal del sketch:

Esta técnica es mucho más optima que la primera. El rendimiento del método Draw para leer los datos del puerto serie y dibujarlos será menor que si el método Draw sólo se centra en leer las variables y dibujar en consecuencia, dejando al evento serialEvent que se encargue de poblar las variables con los datos recibidos por el puerto serie. Para que funcione esta técnica, se debe informar al objeto Serial de cuantos bytes se deben leer antes de que se dispare el evento serialEvent, esto se hace usando el método buffer indicando los bytes a leer. Dentro del evento serialEvent se deben leer tantos bytes como se especificaron con el método buffer. Si se está trabajando con más de un puerto serie se puede usar el único parámetro del evento serialEvent para distinguir desde qué puerto serie se han recibido los bytes.

Si se desea escribir los datos que se reciben a un fichero se debe crear una variable global del tipo PrintWriter.

Luego en el método Setup debemos crear el objeto PrintWriter indicando en qué fichero guardar los datos.

Finalmente, ya sea dentro del método Draw o del evento serialEvent (recomendado) se escriben los datos al fichero:

Es importante ejecutar el método flush para garantizar que se están guardando los datos y no se quedan en buffers intermedios, ya que cuando cerremos la ejecución de nuestro sketch todo lo que no haya sido físicamente escrito al disco se pierde.