Archivo de la categoría: Programación

Programar el chip wifi ESP8266 como si fuera un microcontrolador (2/2)

En el anterior artículo explicaba cómo generar el toolchain para poder compilar programas y subirlos a nuestro módulo ESP8266. En este artículo explicaré cómo hacer un programa en C. Para ello me voy a poner un reto: un firmware que cuando pulse un botón o la tecla p, haga una llamada a una página web que muestre la acción realizada. Con este ejemplo vamos a trabajar con el gpio, puerto serie, wifi, temporizadores y eventos. No hay mucha documentación sobre cómo programar el chip esp8266 más allá de los ejemplos de código, foros y páginas web con artículos dedicados al chip y de la SDK de Espressif que en el momento de escribir este artículo es la 1.0.1.

Empezaré por mostrar un vídeo de lo que he hecho para tener claro desde el principio lo que explicaré aquí.

Lo que veis en el vídeo es que primero programo el esp8266 con el firmware de este artículo. Luego abro una terminal al puerto serie del ESP8266. Pulso 3 veces el botón físico y otras 3 veces la tecla p en la terminal para que se envíe por el puerto serie. Estas acciones provocan en el esp8266 la llamada a una página web que lo registra, mientras en otra página web se visualiza casi en tiempo real lo que he hecho. Cuando compiléis vosotros el ejemplo podéis usar la misma página para hacer vuestras pruebas.

Este es el esquema del circuito para el botón (he obviado las conexiones al puerto serie para simplificarlo):

placa

Vamos a ver cómo lo hecho. Lo primero es crear una carpeta llamada proyectos-esp8266 en nuestra carpeta personal, entra dentro de esta y crear otra llamada reto. Dentro de esta copiaremos el fichero Makefile que modificamos en el anterior artículo. Después crearemos una carpeta llamada user y dentro de esta compiaremos los ficheros uart.h y uart_register.h del ejemplo de IoT que trae la SDK:

Dentro de la carpeta user crearemos dos ficheros.

user_config.h

user_main.c

Lo primero que salta a la vista es que no existe una función main eso es porque este chip se programa con una función de inicialización y el resto con eventos/interrupciones.

La función de inicialización es user_init (al final del código), como decía esta función es llamada cuando el módulo se enciende y se encarga de inicializar todo en el esp8266. El modificador de función ICACHE_FLASH_ATTR significa que la función se guarde en la flash en vez de en la RAM y que cuando se vaya a usar sea cacheada en esta última, ahorrando así espacio para poder tener más datos en la memoria. Dentro de esta función hay que destacar:

  • system_init_done_cb: Esta función tiene un parámetro que es la función callback que será llamada cuando termine la inicialización.
  • system_os_task: Esta función define la ejecución, como tarea, de la función callback pasada como primer parámetro. Podemos tener hasta 4 tareas (cada una con una prioridad distinta). Más adelante hablaré de ello.

La función inicializado es llamada cuando ha terminado la inicialización como comentába antes. Dentro de esta función hay que destacar:

  • os_printf: Es como el printf de toda la vida, pero su salida es enviada al puerto serie 0 (el esp8266 tiene un puerto serie con tx y rx y otro con tx sólo para hacer debug).

La función inicializa_uart configura el puerto serie. Dentro de esta función hay que destacar:

  • ETS_UART_INTR_ATTACH: Esta función configura a qué función callback se llamará cuando se reciba un caracter por el puerto serie. El segundo parámetro es una estructura que existe por defecto con información del puerto serie y el buffer de recepción, pero yo no lo usaré.
  • PIN_PULLUP_DIS: Desactiva la configuración de pull-up del pin indicado (La lista de pines está en el fichero eagle_soc.h de la sdk), en este caso del pin TX.
  • PIN_FUNC_SELECT: Configura el pin indicado para comportarse de una manera determinada, en este caso para funcionar como TX del puerto serie.
  • uart_div_modify: Configura la velocidad del puerto serie
  • WRITE_PERI_REG(UART_CONF0(0), (STICK_PARITY_DIS)|(ONE_STOP_BIT << UART_STOP_BIT_NUM_S)| (EIGHT_BITS << UART_BIT_NUM_S)): Configura la comunicación como 8 bits, sin paridad y un bit de stop.
  • SET_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST) y CLEAR_PERI_REG_MASK(UART_CONF0(0), UART_RXFIFO_RST|UART_TXFIFO_RST): Limpia la FIFO de TX y RX.
  • WRITE_PERI_REG(UART_CONF1(0), (UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S): Configura el disparador FIFO de RX.
  • WRITE_PERI_REG(UART_INT_CLR(0), 0xffff): Borrar el flag de todas las interrupciones del puerto serie.
  • SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA): Configura la interrupción de recepción del pin RX.
  • ETS_UART_INTR_ENABLE: Activa las interrupciones del puerto serie.

La función inicializa_gpio configura el pin GPIO 2 (el único disponible en el ESP-01, pero en otros módulos hay más pines gpio usables). Dentro de esta función hay que destacar:

  • ETS_GPIO_INTR_DISABLE: Desactiva la interrupción de los pines GPIO.
  • ETS_GPIO_INTR_ATTACH: Esta función configura a que función callback se llamará cuando haya una interrpción en el pin gpio indicado.
  • PIN_PULLUP_EN: Activa la configuración de pull-up del pin indicado.
  • gpio_output_set: Configura el pin gpio 2 como entrada.
  • GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(2)): Borrar el flag de la interrupcion del pin gpio 2.
  • gpio_pin_intr_state_set: Indica que en el pin gpio 2 sólo debe activarse la interrupción cuando detecta un flanco de bajada (conecta con masa/GND).
  • ETS_GPIO_INTR_ENABLE: Activa las interrupciones gpio.

La función inicializa_wifi configura la conexión a la wifi. Dentro de esta función hay que destacar:

  • wifi_set_opmode: Configura el módulo como estación cliente.
  • wifi_station_set_auto_connect: Indica que cuando se encienda el módulo se conecte automáticamente a la wifi establecida.
  • wifi_station_set_reconnect_policy: Indica que si se pierde la conexión con el punto de acceso, la vuelva a restablecer.
  • os_memcpy(&configuracion.ssid, ssid, 32) y os_memcpy(&configuracion.password, password, 64): Copia el nombre de la red wifi y la contraseña a la estructura del tipo station_config. Sirve para copiar datos de una posición de memoria a otra, sería equiparable al memcpy del C.
  • configuracion.bssid_set = 0: Para que conecte a cualquier wifi que tenga el nombre proporcionado anteriormente. Si hay varias wifis con el mismo nombre (SSID) puedes indicar a qué punto de acceso quieres acceder poniendo aquí su BSSID (su dirección MAC).
  • wifi_station_set_config: Inicializa la wifi con los valores proporcionados en la estructura del tipo station_config.
  • wifi_set_event_handler_cb: Esta función configura a que función callback se llamará cuando haya cambios en la wifi (conexión, desconexión, ip recibida…).

La función callback interrupcion_wifi es llamada por el chip cuando un evento en la wifi es generado. Quizá el más importante es cuando recibimos una IP de nuestro router. En el ejemplo pongo una variable a TRUE para indicar que tiene libertad para procesar las pulsaciones del teclado o del botón.

La función callback interrupcion_gpio es llamada por el chip cuando se ha detectado un evento en los pines GPIO. Dentro de esta función hay que destacar:

  • GPIO_REG_READ(GPIO_STATUS_ADDRESS): Devuelve el estado de los pones gpio y cual ha sido el que ha causado el evento.
  • os_timer_disarm: desactiva un temporizador si este estuviese activo.
  • os_timer_setfn: configura un temporizador indicando a qué función callback llamará cuando expire. Se le puede pasar un parámetro (en este caso NULL).
  • os_timer_arm: Activa el temporizador indicando cuanto tiempo dura en milisegundos y si debe o no repetirse. La idea de usarlo es para evitar los rebotes físicos cuando el botón es pulsado.
  • system_os_post: Indica al chip que, cuando pueda, ejecute la tarea de prioridad 0 que predefinimos en la función user_init con los parámetros 0,0.

La función callback boton_pulsado establece una variable a FALSE para indicar que el tiempo dado para mitigar los rebotes físicos del botón ya ha pasado y de nuevo permite reconocer la pulsación de éste.

La función callback caracter_recibido es llamada por el chip cuando se ha detectado un evento en el puerto serie. Dentro de esta función hay que destacar:

  • READ_PERI_REG(UART_INT_ST(UART0): Lee cual ha sido el motivo de la interrupción.
  • WRITE_PERI_REG(UART_INT_CLR(UART0): UART_RXFIFO_FULL_INT_CLR): Borra el bit de la interrupción correspondiente a carácter recibido.
  • READ_PERI_REG(UART_STATUS(UART0)): Lee el estado del puerto serie.
  • READ_PERI_REG(UART_FIFO(UART0)): Lee el caracter propiamente dicho. El chip ya tiene un buffer donde se pueden almacenar los carácteres recibidos, yo no lo he usado pero puede ser interesante.

La función callback conecta es llamada por el chip como una tarea. Inicia el proceso de envío de datos. Dentro de esta función hay que destacar:

  • os_zalloc: Sirve para reservar memoria, sería equiparable al malloc del C.
  • espconn_gethostbyname: Esta función hace una consulta dns para obtener la ip de un host dado y llamará a una función callback. Usa una estructura del tipo espconn donde se rellenarán todos los datos referentes a la conexión TCP

La función callback encontrado es llamada cuando se ha resuelto un nombre de host. Dentro de esta función hay que destacar:

  • espconn_port: Crea un puerto local para poder enganchar el socket con el puerto remoto 80 (http).
  • espconn_regist_connectcb: Esta función indica al chip que cuando se establece una conexión TCP, debe llamar a la función callback definida.
  • espconn_regist_disconcb: Esta función indica al chip que cuando hay una desconexión, debe llamar a la función callback definida.
  • espconn_regist_recvcb: Esta función indica al chip que cuando se reciben datos desde una conexión TCP, debe llamar a la función callback definida.

La función callback conectado es llamada por el chip cuando se establece una conexión TCP. Dentro de esta función hay que destacar:

  • os_sprintf: Sirve para rellenar un buffer con datos formateados, sería equiparable al sprintf del C.
  • espconn_sent: Envía los datos indicados a través del socket TCP.
  • os_strlen: Devuelve la longitud de una cadena, sería equiparable al strlen del C.

La función callback recibido es llamada por el chip cuando se reciben datos de una conexión TCP. En el ejemplo sólo los muestro directamente. Dentro de esta función hay que destacar:

  • os_free: Sirve para liberar memoria, sería equiparable al free del C.

La función callback desconectado es llamada por el chip cuando se desconecta la conexión TCP. En el ejemplo libero los buffers de memoria reservados previamente.

Quiero comentar es que no soy un experto en el esp8266, por lo que si que me preguntáis algo puede que no lo sepa responder, por ello os recomiendo ir a la página www.esp8266.com donde hay mucha gente que trabaja con el esp8266 y os podrán resolver vuestras dudas mejor que yo. Todo lo que he juntado aquí ha sido fruto de búsquedas por internet, mil y una pruebas con código fuente, etc. Sin embargo lo que aquí he explicado, aún siendo de las partes más importantes de la programación de un ESP8266, no cubre todo lo que se puede hacer con este chip, por lo que una vez te encuentres cómodo con lo aquí expuesto, te animo a que busques por tu cuenta más funcionalidades.

Programar el chip wifi ESP8266 como si fuera un microcontrolador (1/2)

IMG_20150504_230102

En esta tanda de dos artículos explicaré cómo olvidarse de los comandos AT del módulo ESP8266 ESP-01 (aunque lo escrito vale para toda la familia ESP) y poder programarlo como un chip independiente: conectando la wifi, manejando el puerto serie, usando los pines GPIO, etc. La gran ventaja es que tenemos un microprocesador más potente, más versátil, más rápido y además en muchos casos es más barato que si usáramos los microcontroladores PIC o AVR (como contrapartida tiene menos pines de E/S).

CONSTRUYENDO EL TOOLCHAIN

El primer paso que tenemos que hacer para programarlo es construir el toolchain para poder compilar los programas para este chip con el compilador cruzado. Para ello recomiendo tener un linux donde construirlo (ya sea físico o virtualizado), no recomiendo usar windows y cygwin. Yo estoy usando el ubuntu 14.04 LTS.

Lo primero es instalar las herramientas necesarias, para ello ejecutar:

Vamos a usar el toolchain de https://github.com/pfalcon/esp-open-sdk, con el que el proceso de creación es bastante sencillo (ejecútalo en la raíz de tu directorio personal):

Esto habrá creado una carpeta esp-open-sdk. Entra dentro de está y haz un make (con el parámetro STANDALONE=y) para crear todo el toolchain (puede tardar un rato dependiendo de tu ordenador):

Ahora vamos a poner en la variable de entorno PATH la ruta a los binarios, ya que el esptool no funciona si no se pone (cambia oscar por tu usuario):

COMPILANDO PROGRAMAS

Vamos a descargarnos unos ejemplos ya hechos:

Esto creará una carpeta llamada source-code-examples. Entra dentro de esta carpeta y edita el fichero example.Makefile.

Modifica las siguientes lineas (recuerda cambiar oscar por tu usuario):

POR

POR

POR

El campo ESPPORT debes cambiarlo si no coincide con la ruta al dispositivo asociado a tu dongle usb a serie.
Ahora entra dentro del direcotrio blinky, copia el fichero anteriormente editado como Makefile y haz un make para compilar el firmware:

Si todo ha ido bien habremos compilado el firmware para nuestro ESP8266:
shell1

PROGRAMANDO EL ESP8266

Para poder programar nuestro módulo ESP8266 necesitamos un dongle usb a serie (USB2TTL) como este:
IMG_20150501_165235
Después es necesario añadir al usuario que estemos utilizando (en el ejemplo, oscar) en el grupo dialout para poder acceder al dongle:

Ahora sólo queda subir el programa al módulo ESP8266, para ello debes cablear el módulo de la siguiente forma (estando éste sin alimentación):
conexiones
Las líneas rojas van a VCC (3,3V) y las negras a GND (masa). Ahora alimenta el módulo.

Si es la primera vez que vas a programar el módulo wifi, debes borrar las configuraciones por defecto, esto se consigue ejecutando el siguiente comando:

shell2
Las siguientes veces ya no será necesario repetir este paso. Si has hecho este paso vuelve a apagar y encender el módulo.

Finalmente para programar el firmware creado, ejecuta el comando:

shell3
Enhorabuena, acabas de programar por primera vez tu módulo ESP8266. Ahora desconecta el cable que va al pin de programacion (así el módulo no estará en modo de programación), conecta un led entre el GPIO 2 (el que no aparece conectado a ningún sitio en la fila de GND de la foto anterior de las conexiones) y masa. Así es como luce el «hola mundo» del chip ESP8266:

En el siguiente artículo explicaré cómo hacer tus propios programas en C para el esp8266.

Programando un Arduino remotamente con el módulo ESP8266

IMG_20141108_002938

Una de mis viejas aspiraciones cuando construyo robots es poder programarlos sin tener que recogerlos, enchufarles un cable usb o un programador ICSP y volverlos a dejar en su sitio.

En este artículo explicaré cómo con un Arduino UNO y un módulo ESP8266 (llamado WI07C) se puede programar un sketch de Arduino en la placa sin tener que estar cerca de esta, todo mediante wifi y sockets tcp/ip.

Descripción general

Como se puede ver en el vídeo tenemos un Arduino UNO conectado a un display HD44780 y a un módulo wifi ESP8266. Arduino envía cadenas hello world al servidor sockettest que está escuchando por el puerto 49000. Se modifica el código Arduino en el IDE poniendo hello folks, se compila y el fichero .hex generado (se puede ver donde está activandolo en Archivo/Preferencias/compilación) se copia a la carpeta del programa en python. Cuando Arduino recibe un comando reboot se conecta al servidor python por el puerto 50000 entrando en modo de datos, acto seguido se reinicia y empieza la programación remota de Arduino. El proceso se reliza dos veces en el vídeo.

Lo que se aprovecha es el método que tiene Arduino para programarse, ya que usando el puerto serie después de un reset se puede programar un Arduino si se sigue el protocolo STK500 implementado en el bootloader.

Esquema de conexiones

esquema

El Arduino y el display HD44780 se alimentan a 5 voltios, el módulo ESP8266 se alimenta a 3,3 voltios. Como el pin rx del módulo wifi sólo puede funcionar a 3,3V se usa un diodo zener de 3,3 voltios junto con una resistencia de 100 Ω.

En las placas Arduino, el pin de reset del microcontrolador está conectado a una resistencia y esta a su vez está conectada a VCC, con lo que para el microcontrolador el pin está a nivel alto. Cuando se pulsa el botón de reset lo que se hace es derivar la corriente hacia masa (ya que el bóton está conectado a esta) y el microcontrolador, al estar a nivel bajo el pin de reset, realiza un reseteo. Cuando el microcontrolador arranca, todos los pines están configurados como entradas (alta impedancia) y por eso no le afecta que el pin de reset esté conectado directamente al pin 12. Si se configura el pin 12 como salida y luego se conecta a masa (nivel bajo o LOW) se provoca el mismo efecto que si se pulsase el botón de reset, además, al existir la resistencia anteriormente mencionada, no hay que preocuparse de que se produzca un cortocircuito al unir VCC con masa (GND).

Sketch de Arduino

Lo que hace el skecth de Arduino es:

  • Inicializa el puerto serie a 115200 bps.
  • Elimina los caracteres que hubiera en el buffer de entrada del puerto serie.
  • Inicializa el módulo wifi en modo estación, lo resetea, se conecta al punto de acceso normal, configura las conexiones como simples en modo normal y se conecta al servidor normal por el puerto 49000. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.
  • Envia una cadena de texto y un número consecutivo tanto al servidor como al display. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.
  • Si entre el envío de las cadenas de texto se recibe una cadena reboot entonces resetea el módulo, se conecta al punto de acceso bootloader, configura las conexiones como simples en modo normal y se conecta al servidor de programación por el puerto 50000. Acto seguido envía una cadena hello y espera a recibir una cadena welcome, si ha sido así, entonces envía el nombre del fichero .hex con el que quiere ser programado el Arduino y espera a recibir una cadena ok, momento en el cual configura el pin 12 como salida y lo pone a nivel bajo, conectándolo a masa y provocando un reset en el Arduino. Si hubiese algún fallo en algún punto pararía la ejecución y lo indicaría en el display.

Aquí cabe destacar cómo funciona el sistema de reseteo: Justo después del reseteo, el pin de TX de Arduino está a nivel bajo durante un tiempo, lo que provoca que el módulo wifi vea eso como un byte 0, que enviará a través de la conexión TCP/IP. El servidor de programación aprovechará esta circunstancia para saber cuando ha empezado el reseteo e iniciar el protocolo STK500. El bootloader de Arduino entra en acción después del reseteo y espera a recibir ordenes del protocolo STK500, si las recibe actúa en consecuencia, si no, ejecuta el programa principal.

Servidor de programación

Lo que hace el servidor de programación es:

  • Crea un socket que escuche por el puerto 50000
  • Cuando un cliente de conecta espera a la cadena hello, si la recibe reponde con una cadena welcome.
  • Espera a que el cliente le envíe un nombre de fichero .hex. Trata de abrir el fichero en el mismo directorio y lo lee interpretando todas las líneas para guardar los datos del programa en memoria. Si todo va bien envía una cadena ok.
  • Espera a recibir el byte 0, y cuando lo recibe empieza el protocolo STK500 para comunicarse con el bootloader de Arduino y programarlo. Básicamente lo que hace es entrar en modo de programación, indicarle a que páginas quiere acceder y enviar los datos de cada página, así hasta que ha enviado todos los datos del programa, después sale del modo de programación cerrando la conexión

Aquí cabe destacar que cuando se cierra la conexión TCP/IP con el cliente (ya sea por un error o porque el proceso de programación ya ha terminado), el módulo ESP8266 sale del modo de datos automáticamente y no es necesario que el nuevo sketch tenga que enviarle la cadena de escape +++ para poder entrar otra vez en modo de comandos.

Conclusiones

Espero que esto os sirva para que en vuestros proyectos podais programar remotamente vuestros Arduinos a través de una red local o Internet.

Habría que tener en cuenta que el proceso de actualización puede quedarse a medias si la conexión a la red wifi es lenta y provocaría que el programa no se ejecutara correctamente. Así que que una mejora sería acoplar un chip aparte que reprogramase el Arduino por ICSP con un programa preestablecido en caso de que detectase que la programación no fue finalizada correctamente.

Comentar que la versión de firmware del módulo ESP8266 que he usado es la 0019000902 y el Arduino es un UNO. Ambos funcionan a 115200 bps, pero si quisierais utilizar otras velocidades (en otros Arduinos el bootloader configura el puerto serie a 19200 o 57600 bps) habría que cargar un firmware que lo permitiese, como por ejemplo la versión 0.922 de electrodragon y su comando AT+CIOBAUD.

Publicar mensajes en Twitter desde tu dispositivo

twitelec
Vivimos en una época donde las redes sociales cada vez están más presentes y donde los dispositivos cada vez aplican más el concepto de internet de las cosas. En algún momento surge la necesidad de que nuestras creaciones tengan capacidad para conectar a internet y puedan enviar información sobre su estado.

En este artículo explicaré cómo hacer que vuestros dispositivos, si tienen acceso a la red de redes, puedan enviar tweets de una forma sencilla.

Para enviar mensajes en Twitter desde una aplicación distinta a la de la web oficial hay que usar la API (en este momento la 1.1), pero previamente hay que autentificarse usando el protocolo OAuth, que sinceramente es un infierno de implementar en dispositivos.

Para simplificar las cosas hay una página que ofrece de manera sencilla la publicación de tweets: http://arduino-tweet.appspot.com/ . Originalmente está pensada para Arduino con el shield ethernet, pero se puede usar con cualquier dispositivo que tenga acceso a internet.

Para darse de alta es muy sencillo:

Con ese token ya puedes acceder a la web de arduino-tweet para publicar tweets desde tu dispositivo. Para ello debes usar el protocolo HTTP. Como cada dispositivo tiene una forma de crear un socket y conectarse, aquí sólo voy a explicar genéricamente cómo se hace:

  • Conectar a arduino-tweet.appspot.com por el puerto 80
  • Enviar la cadena:

X es el mensaje que quieres publicar en twitter (p.e: @webdelcire hola #saludos)
Y es el token que antes has copiado
Z (con su espacio después de «:») es el número de caracteres que componen la línea:

token=Y&status=X

Fijate que entre Content y token hay dos saltos de línea (formados por los códigos ASCII 13 y 10) y después hay otros dos saltos más, esto es así porque el protocolo HTTP obliga a ello.

Finalmente si la respuesta del servidor es

HTTP/1.0 200

o

HTTP/1.1 200

entonces es que ha ido todo bien y el mensaje ha sido publicado.

A continuación pongo un formulario donde puedes probar a publicar un mensaje en twitter con el token que te haya dado. Guárdalo como un fichero html y ábrelo con el navegador.

O si lo prefieres, desde linux puedes usar el comando wget para probarlo:

Ahora tu dispositivo ya es capaz de publicar mensajes y si además tiene su propia cuenta en twitter, animar a tus colegas a que sigan su estado a lo largo del tiempo.

En otro artículo explicaré cómo hacer que tu dispositivo reciba ordenes desde twitter a través de los mensajes.

Quitar el control parental de una XBOX 360 mediante fuerza bruta

logo

 

Ante todo no quiero que penséis que esto es ilegal, puesto que Microsoft en su soporte técnico ya ofrece la posibilidad de quitar el control parental de la XBOX 360 mediante una combinación de botones en el mando única para cada consola. Por supuesto no me hago responsable de los usos que le vayáis a dar puesto que el contenido sólo es divulgativo.

La XBOX 360 tiene control parental, que significa que los padres pueden bloquear mediante contraseña el acceso a determinados juegos, películas, etc. Esta contraseña es de 4 dígitos numéricos, por lo que hay 10000 posibles combinaciones de números (del 0000 al 9999). Normalmente los números se introducen mediante la pulsación de los botones del mando de la consola, pero existe la posibilidad de enchufar un teclado usb a la consola y pulsar las teclas correspondientes.

Con esta idea se me ocurrió como prueba de concepto crear un sistema que pudiese introducir las 10000 contraseñas una por una hasta que diese con la correcta (fuerza bruta), en vez de hacerlo a mano que sería más engorroso :-). Lo que tenía más a mano para emular un teclado usb es la placa Vinciduino, pero perfectamente se puede hacer con otra placa con un microcontrolador Atmega32U4 como Arduino Leonardo o la Teensy 2.0.

Para programar el microcontrolador usé el Atmel Studio 6.1 junto con la librería LUFA en su extensión para Atmel Studio. La librería LUFA contiene múltiples ejemplos de cómo sacar provecho a los microcontroladores AVR con USB embebido.

Yo usé el ejemplo Keyboard HID Device Demo (Class Driver APIs):

proyecto_ejemplo

 

Antes de nada hay que cambiar los valores por defecto que tiene el proyecto para adecuarlos a nuestra placa, en mi caso para Vinciduino:

-El tipo de microcontrolador (Vinciduno tiene un Atmega32U4)

microcontrolador

-La velocidad del microcontrolador y del USB en todas las configuraciones (Vinciduno corre a 16 Mhz.)

velocidad_cristal

-Después hay que activar el modo Release para cuando se cree el fichero .hex

release

-Finalmente sustituir el fichero Keyboard.c por este Keyboard

El programa funciona de la siguiente manera:

  1. Se espera 10 segundos hasta empezar a enviar la secuencia de números.
  2. Se emula la pulsación de cada una de las 4 cifras que contiene el número con un intervalo aleatorio entre 0,5 y 1,5 segundos (Esto es así para emular las pulsaciones que haría una persona en un teclado).
  3. Después se espera 1,5 segundos para que dé tiempo a que salga la pantalla de contraseña incorrecta. A continuación se emula la pulsación de la tecla ENTER.
  4. Se esperan otros 1,5 segundos para que dé tiempo a que salga la pantalla de introducción de la contraseña de nuevo.
  5. Se repite el proceso desde el paso 2 hasta que se llegue al número 10000.

Las esperas se realizan mediante el timer0 del microcontrolador. El envío de las pulsaciones del teclado se hacen desde la función de LUFA que genera el informe HID. Cada pulsación enciende el led de la Vinciduino durante 333 ms.

El tiempo máximo entre números es 6 segundos, por lo que en el peor de lo casos se tardaría 6 * 10000 = 60000 segundos (16,7 horas) en encontrar la contraseña correcta.

Como ejemplo pongo un vídeo que he grabado para demostrar el funcionamiento, lo mejor es verlo a 1080 y a pantalla completa. Primero se ve cómo pruebo el sistema en un ordenador donde se ven las pulsaciones en un editor de textos, comprobando así que funciona como si de un teclado se tratase. Después en la XBOX 360 elijo la opción Familia, momento en el que me pide la contraseña, y le enchufo la Vinciduino para que empiece a introducir los diferentes números. La contraseña en esta prueba es 0010 (empezando por el 0000). Cuando se llega a la contraseña correcta no existe una forma de saber si ha sido así, pero como se observa en el vídeo se queda en la opción de menú Activada sin que le afecten las pulsaciones, por lo que se podría dejar corriendo sin estar presente, sabiendo que cuando llegase al número 10000 dejaría de enviar pulsaciones.

Cuentavueltas y cronómetro para robots velocistas

Cuando has fabricado un robot velocista y has hecho una pista para probarlo siempre es necesario medir los tiempos que emplea en dar una vuelta a la pista. Así podrás comprobar en cuantas décimas de segundo has mejorado tu robot. Ya sea porque le has cambiado el código de control, has ajustado alguna constante o porque hayas modificado algo de la mecánica; esas décimas que ahorres en dar una vuelta son cruciales para mejorar su rendimiento de cara a las competiciones. Puedes medirlo a mano con un cronómetro, pero nunca tendrás la precisión suficiente y el margen de error cuando quieres medir las mejoras en décimas de segundo es grande. En este artículo voy a explicar cómo fabricar un medidor de vueltas o cuentavueltas sencillo.

IMGP2895

El cuentavueltas se compone de dos módulos. El módulo principal contiene los siguientes materiales:

  • Un microcontrolador PIC16F628A.
  • Un display HD44780.
  • Un módulo bluetooth HC06.
  • Un regulador de tensión 7805.
  • Un LDR.
  • Un botón.
  • Un diodo led.
  • Un buzzer.
  • Un cristal de cuarzo de 20Mhz.
  • Dos condensadores de 22pF.
  • Un condensador de 0,1uF.
  • Un condensador de 0,22uF.
  • Una resistencia variable de 10K Ω.
  • Una resistencia de 220 Ω.
  • Una batería Lipo de 7,4V o 5 pilas de 1,5V o una pila de 9V.

cronometro

El módulo secundario en un puntero laser de 0,5mW. Es importante que su potencia sea de 0,5mW (NO 5mW como muchos) ya que valores mayores son peligrosos para la vista si por algún casual el haz de láser hace contacto con la retina de tus ojos (directamente o por reflejo especular). Úsalo bajo tu responsabilidad y con las medidas de seguridad adecuadas.

La idea es sencilla: el láser está apuntando constantemente hacia el LDR a pie de pista. Cuando el robot velocista pasa por delante corta el haz de láser y se registra en el sistema una vuelta. El sistema puede estar monitorizado tanto desde el propio display del módulo principal como remotamente desde un ordenador a través de bluetooth.

El LDR tiene un caperuzón negro hecho con cartulina negra para que no le afecte la luz de ambiente. El conjunto está pegado a una base de cartón para apoyarlo en el suelo y evitar que se mueva.

IMGP2902

El puntero láser tiene otro caperuzón negro hecho con la misma cartulina, pero está completamente tapado excepto por un agujero donde saldrá un haz de laser muy pequeño, pudiendo así ser cortado más fácilmente por el robot cuando pase por delante. El conjunto está igualmente pegado a una base de cartón para apoyarlo en el suelo y evitar que se mueva.

IMGP2904

Al principio hay que apuntar el láser hacia el LDR moviendo el puntero. Cada vez que el haz de láser incida sobre el LDR el diodo led se encenderá y se oirá un pitido en el buzzer. Así sabremos que está apuntando correctamente.

IMGP2900

Se pulsa el botón, se apaga el led y a continuación muestra los datos de la última carrera que ha grabado en la eeprom del microcontrolador.

IMGP2901

De izquierda a derecha y de arriba a abajo:

  • Tiempo de la vuelta actual (a 0 por que ahora no está corriendo).
  • Tiempo de la última vuelta dada.
  • Número de vueltas hechas.
  • Tiempo total de la carrera.

Se vuelve a pulsar de nuevo el botón, se enciende el led y se ponen los contadores a 0, esperando a que el robot corte por primera vez el haz del láser para empezar la cuenta.

IMGP2905

Cuando el robot pasa a través del haz de láser, se apaga el led y empieza a contar automáticamente.

IMGP2903

Cada vez que el robot corta el haz de láser, suena un pitido, se pone a 0 el contador de la vuelta actual, se actualiza el valor de la vuelta anterior y se suma 1 al número de vueltas. Así hasta que se pulse el botón o se llegue a la vuelta 10, momento en el que el cronómetro se parará para poder visualizar los resultados y guardarlos en la eeprom del microcontrolador.

Si se quiere volver a medir sólo hay que pulsar el botón de nuevo, se enciende el led, se ponen los contadores a 0 y se espera a que el robot corte el haz de láser de nuevo.

Todos los datos son enviados por bluetooth a 115200 bps, por lo que se puede hacer un seguimiento desde un ordenador usando Processing sin tener que estar cerca del display o para visualizarlo en una pantalla panorámica en un evento con espectadores.

cuantavueltas

El sketch de processing: Cuentavueltas_Processing

El código fuente y el .hex del programa del microcontrolador PIC. Está hecho en PCW CCS: Cronometro_PIC

Mandar datos de nuestros dispositivos a Pachube

Para quien no lo conozca, Pachube es una web donde poder transmitir la información que generan nuestros dispositivos (lo que se conoce como Internet de las cosas). Todos alguna vez hemos creado/tenido un dispositivo que genera información que nos gustaría consultar: Un sensor de temperatura o de humedad, un contador de entradas a un recinto, cuantas veces se ha ejecutado un comando, etc. Cualquier cosa que queramos saber y se pueda medir es susceptible de usarse con Pachube. Eso si, nuestro dispositivo debe tener una conexión a Internet para poder subir los datos (Wifi, ethernet, GPRS u estar conectado a otro dispositivo que lo tenga como un PC). La ventaja es que mediante nuestro ordenador/móvil/tablet podremos consultar los datos que nuestro dispositivo envía en la web de Pachube de una forma gráfica. El servicio es gratuito, podemos hacer que nuestros feeds sean públicos o privados, podemos consultar el historial de datos y enviar alarmas y notificaciones a nuestros dispositivos. Tiene limitaciones como que no se puede hacer más de 100 peticiones por minuto, pero en la mayoría de los casos nos da de sobra.

Voy a explicar de una forma sencilla cómo enviar los datos, aunque si queréis profundizar tendréis que leer la documentación. Lo primero que hay que hacer es registrarse en su web. Es un proceso sencillo y rápido.

Lo segundo es crear una key en el menú My keys. Esta sirve para poder autentificarnos en las acciones que enviamos a Pachube. Además se les asignan permisos para que pueda ser usando en cualquier feed, en todos nuestros feeds (públicos o privados) o en unos determinados feed de nuestra elección. Además se les asigna los permisos de lectura de feeds, creación de feeds, actualización de feeds o borrado de feeds. Igualmente tiene restricciones avanzadas como caducidad de la key, sólo dejar a una IP o acceder desde una URL concreta para ejecutar el comando. La guardamos y ya nos aparecerá en el menú de My keys.

El siguiente paso es crear un feed en el menú Create a feed. Un feed no es nada más que un servicio donde se almacenarán los datos que envíe nuestro dispositivo y que puede ser consultado a posteriori. Puede ser creado directamente desde las web de Pachube o desde la API de Pachube. Para crearlo debemos rellenar datos sobre su nombre, la ubicación de nuestro dispositivo, si es privado (sólo lo podemos consultar nosotros) o público (cualquier puede consultarlo), etc. Finalmente tenemos que añadir tantos datastreams como distintos datos envía nuestro dispositivo: Si por ejemplo es un sensor de temperatura y de humedad tendremos que dar de alta dos datastreams. Los datastreams necesitan un identificador único en ese feed, un tag (nombre) que lo identifique, un nombre de la unidad en que se va a medir y el símbolo que se usa para esa unidad de medida. Lo guardamos y ya nos aparece en el menú de My feeds.

Ahora si accedemos al menu de My feeds podemos ver nuestro feed y si pulsamos sobre el podemos observar entre otras cosas qué número único le ha asignado Pachube en el campo Website.

Para meterle datos simplemente tenemos que rellenar los datapoints, que son los datos de nuestro sensor. Podemos hacerlo manualmente desde la misma página del feed, pero no tiene sentido ya que se supone que será nuestro dispositivo (u otro intermediario) conectado a internet el que los proporcione. Este debe tener la opción de comunicarse mediante peticiones HTTP a la web de Pachube. Yo lo voy a enseñar desde el nivel más bajo, pero si el dispositivo intermedio es un PC podéis usar curl mediante scipts o las librerías que vuestro dispositivo tenga para usar TCP/IP y HTTP. Voy a poner un ejemplo de una petición PUT para actualizar un feed que contiene como datastream el uso de una supuesta CPU de un servidor ubicado en la isla Perejil. Me conecto al puerto 80 del host api.pachube.com y le envío esto:

Después de lanzar esa petición, si todo ha ido bien, recibiremos esta respuesta del servidor de Pachube:

Que indica con el código 200 que todo ha ido bien y que se ha guardado el datapoint en nuestro datastream. En nuestra petición le hemos indicado la URL de nuestro feed con la extensión csv para indicar que los datos que queremos subir están en ese formato, pero también podemos subirlos en XML o JSON (ver aquí una guía rápida). También hemos de enviar la key que tiene permisos para escribir en nuestro feed. Finalmente enviamos los datapoints en formato <datastream>,<valor> (uno por línea).

Así si nos vamos a la URL de nuestro feed (en este caso https://pachube.com/feeds/48063) podremos ver toda la información del feed: nombre, localización, lectura de los datos en formato JSON, XML y CSV y finalmente un gráfico que podemos configurar a nuestro gusto para ver cómo han ido evolucionando los valores.

Crear un demonio en el linux embebido en placas

Ahora que están de moda las placas que contienen un linux embebido como las beagleboard, las raspberry pilas foneras, he creido interesante escribir un artículo en el cual se explica cómo ejecutar una tarea por tiempo indefinido desde que arranca la placa  y sin necesidad de acceder por shell a la misma.

Presupongo que tienes el compilador cruzado que genera ejecutables para la plataforma de la placa y que tienes acceso a ella mediante shell con el usuario root.

Nuestro objetivo es sencillo, crear lo que se denomina en entornos linux y unix un demonio (en windows es un servicio) lo más sencillo posible. Un demonio no es nada más que una aplicación que se ejecuta en segundo plano y no muestra directamente datos al usuario ni este puede interactuar con ella.

Como queremos que el ejemplo sea bastante sencillo nuestro demonio simplemente va a escribir en un fichero una cadena cada cierto tiempo. Vosotros podreis modificarlo para que haga lo que querais (leer y escribir datos en un puerto serie, analizar imágenes de una webcam, manejar GPIO, crear un servicio para internet, etc).

Scripts de demonios:

Normalmente cuando se arranca un sistema linux, después de cargar el kernel se ejecuta el proceso init, que es el proceso padre del que dependerán el resto de procesos que se ejecuten en el sistema. Este proceso lee el fichero /etc/inittab para saber entre otras cosas en qué nivel de arranque (runlevel de 1 a 5) debe iniciar el sistema.

Dependiendo de ese nivel de arranque se ejecutarán unos scripts ubicados en la carpeta correspondiente. Así por ejemplo si el nivel es 3, los scripts de la carpeta /etc/rc3.d que empiecen por S (Start) se ejecutarían al arrancar. Estos scripts tienen un número que indica en qué orden se ejecutan (se puede repetir el número).

Pero… un momento… ¡¡¡ Si estos ficheros son en realidad son enlaces simbólicos !!!.

Efectivamente, en realidad son accesos directos que apuntan al directorio /etc/init.d donde realmente están los scripts para los demonios. El proceso init lee de la carpeta /etc/rc3.d los enlaces que empiezan por S y ejecuta el script al que apunta con el parámetro start. Igualmente cuando se apaga o se reinicia el sistema el proceso init lee de la carpeta /etc/rc0.d o /etc/rc6.d  respectivamente los enlaces que empiezan por K y ejecuta el script al que apunta con el parámetro stop.

Los scripts que se encuentran en la carpeta /etc/init.d son en realidad scripts shell que dependiendo del parámetro que se le pase (start, stop, reload, etc) ejecuta el comando necesario para lo que se requiere. Ni que decir tiene que igualmente nosotros podemos ejecutar por nuestra cuenta el script con los parámetros mencionados para parar o arrancar el demonio desde una consola.

Por tanto vamos a crear un sencillo script que arranque o pare nuestro demonio. Lo crearemos dentro del directorio /etc/init.d y lo llamaremos nohacenada con el siguiente contenido:

Este ejemplo muestra un sencillo script donde se espera como parámetro una cadena start o stop. Si es start simplemente arranca la aplicación. Si es stop comprueba si existe el fichero /var/run/nohacenada.pid para saber si la aplicación está corriendo, después lee su contenido, que es el identificador del proceso, para posteriormente mandarle una señal kill y que este pueda cerrarse por si sóla limpiamente. Si no es ninguno de los dos parámetros anteriores es que el usuario intentó ejecutar el script por su cuenta sin poner start o stop como parámetro.

El script debe tener permisos 755  y pertenecer a root por lo que debemos dárselo de esta forma desde una consola shell con el usuario root:

Además hay que crear los enlaces simbólicos en el directorio correspondiente para que init sepa que tiene que arrancarlo (niveles 2, 3, 4 y 5) y pararlo (niveles 0, 1 y 6):

o si te lo permite el linux que tienes instalado, simplemente:

Con estos pasos ya hemos terminado nuestro script para que el proceso init pueda arrancar o parar nuestro demonio.

El demonio:

Para crear nuestro demonio usaremos el lenguaje C, que es el lenguaje estandar de linux. Nuestra aplicación se convertirá en demonio para quedar residente en el sistema permanentemente hasta que se termine mediante kill.

Programaremos nuestra aplicación para que informe de los errores en el log, genere un fichero pid, cree un hilo de ejecución que se convierta en demonio y escriba una cadena cada segundo mientras espera a que se termine la aplicación mediante una señal.

Dado que la aplicación no muestra datos al usuario este no sabe que está pasando por dentro, por eso habrá que informarle a través de los log. De esto se encargan las funciones openlog y syslog. Toda la información podrá ser consultada en el fichero /var/log/syslog.

Muchos demonios generan en el directorio /var/run un fichero con el nombre de la aplicación y extensión pid. Dentro guardan el PID o identificador de proceso en formato numérico. Con esto se obtienen dos ventajas: por un lado la misma aplicación sabe si ya hay una copia de ella misma ejecutandose para no duplicar procesos; por otro lado como guarda el pid dentro del fichero cualquier proceso puede leerlo para poder comunicarse con la aplicación (por ejemplo el comando kill que explicaré más adelante).

Para crear un demonio la aplicación principal crea un hilo de ejecución con fork y la aplicación principal se saldrá. Esto provoca que el hilo de ejecución se quede huerfano. Después se ejecuta umask para no heredar los permisos de los ficheros del proceso padre. A continuación se ejecuta setsid para que el proceso huerfano tenga su propio SID y sea un proceso independiente para el sistema operativo.  Por otro lado cambiaremos de directorio de ejecución para apuntar a la raiz con un chdir ya que es el único directorio seguro que existe en linux.  Finalmente cerraremos con un close la entrada estandar, la salida estandar y la salida de errores ya que no las necesitamos.

Con la función signal haremos que cuando el usuario (o init) nos envíe un comando kill (sin el -9) salgamos de la aplicación limpiamente. Esto es debido a que cuando se ejecuta kill <pid> lo que se está haciendo realmente es enviar una señal SIGTERM a la aplicación. La aplicación recupera la señal y ejecuta la función asociada mediante la función signal. En el ejemplo de más abajo veremos que se asocia a la función adios que simplemente cambia una variable para que se salga del bucle principal. Mientra se espera a recibir la señal, cada segundo se está escribiendo en el fichero /tmp/nohacenada.txt una cadena.

Al salir del bucle se escribirá en el fichero anterior otra cadena y cerramos ese fichero. Igualmente cerraremos el log y se borrará el fichero pid para que se pueda volver a ejecutar la aplicación nuevamente (en un arranque del sistema o nosotros mismos).

Dejo el código fuente de la aplicación llamado nohacenada.c para que os hagais una idea y poder hacer vuestros demonios basados en este:

Para compilarlo depende del toolchain para cada plataforma, pero sería algo parecido a esto:

Como seguramente hayais instalado un compilador cruzado en vuestro ordenador de sobremesa, habrá que subir el fichero ejecutable a la placa. Yo recomiendo que useis scp en linux o winscp en windows si la placa tiene acceso a la red ethernet o wifi ya que hace uso del demonio sshd (el que se usa para las sesiones de consola remotas por ssh).

Una vez subido el fichero a la placa debemos darle permisos de ejecución, asignarle como propietario al usuario root y moverlo a la ruta /usr/sbin a través de la consola shell con el usuario root de la siguiente manera:

Ahora podeis probar si funciona realmente simplemente ejecutando:

Podeis comprobar en la carpeta /tmp si hay un fichero llamado nohacenada.txt y consultarlo, también podeis mirar en la carpeta /var/run si existe un fichero llamado nohacenada.pid y visualizarlo. Si no veis nada podeis mirar el fichero /var/log/syslog para ver si hubiese algún error de la aplicación nohacenada.

Y para pararlo:

Con esto espero que le saqueis bastante provecho a vuestras placas con linux embebido ya que así conseguis que nada más encenderla se ejecute el programa sin tener que hacer vosotros nada por vuestra cuenta. Quizá en el futuro explique cómo programar módulos para el kernel y extender la funcionalidad de vuestra placa aún más lejos (drivers para hardware, sistemas de ficheros, llamadas al sistema, etc).

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:

Robot EVA

Tenía pendiente publicar el modo en el que había construido mi robot Eva. Este robot hizo el segundo mejor tiempo en la clasificación del cosmobot de 2011 y quedó entre los 8 primeros, desbancado por su hermano VELORP (otro de los robot Zero) en cuartos de final. Básicamente comparte muchas características del robot Zero ya que ha sido también probado en el medialab y se han sacado las mismas conclusiones, sin embargo la placa es distinta y la programación también.

Los componentes que tienen en común son:

Sin embargo las ruedas son las del miniz, ya que logran poner el chasis más pegado al suelo y derrapan menos.

La batería no es una Lipo 1S sino 2S (7,4 V.) enchufada directamente a la baby orangutan. Esta se encuentra entre los motores para dejar el centro de gravedad en medio y centrar más el peso en las ruedas.

Como no tiene conversor DC-DC que mantenga un voltaje continuo hacia los motores, he usado un divisor de tensión que mide el voltaje de la batería y así puede calcular el PWM que tengo que enviar a los motores según esté más o menos cargada la batería. Esto se consigue con la siguiente fórmula:

PWM * 7,4 / batería

  • PWM: Es el PWM que queremos enviar al motor.
  • 7,4: Es el voltaje normal que tiene una batería de Lipo 2S.
  • batería: Es el voltaje que tiene la batería en un momento dado.

Así si le meto 180 de PWM y tengo 8,4 voltios en la batería al final mando al motor 159 de PWM.
Si en el anterior caso en la batería tengo 7,4 voltios entonces da los 180 exactos de PWM.
Si la batería está a 7 voltios le metería al final 190 de PWM.

Como la tensión de la batería no es constante sino que tiene picos, es mejor tener 10 valores de tensión y luego calcular la media arimética para tener un valor más coherente.

El divisor de tensión también es útil para saber cuando la batería está cerca de agotarse y parar el robot, salvando así que las celdas pasen por debajo de los 3 voltios.

Este es el esquema de la placa:

A comentar:

  • Tiene un pin auxiliar por si fuese necesario usarlo para algo.
  • Tiene unos pines para añadirle un módulo bluetooth (se baja la tensión con un par de diodos para lograr 3,6 V.).
  • Usa un 7805 para alimentar los sensores y el bluetooth.

El código fuente que he desarrollado lo expongo a continuación. Este implementa el control Proporcional Derivativo y hace uso de las librerías que provee Pololu para poder manejarse con los sensores y con la baby orangutan.

velocistaB_2.h

velocistaB_2.c

Como habeis podido leer en el código fuente tiene un sistema de calibrado por el cual guarda en la EEPROM los valores minimos y máximos de los sensores la primera vez que se calibra y ya no es necesario hacerlo en futuras ocasiones a no ser que cambien las condiciones de iluminación.

La calibración consiste en dejar el robot en la pista, pulsar el botón y que de unas vueltas sobre sí mismo, lea los valores de blanco y negro y los guarde además en la EEPROM. Las siguientes veces que pulsemos el botón ya no se hará la calibración y empezará a correr el robot.

Para realizar la calibración la EEPROM debe estar vacía, y eso se consigue con el siguiente programa:

Y por último un video (gracias Puck2099) de cómo funcionó en la cosmobot (tuve que bajarle un poco el PWM porque al final derrapa un poco y cambia de sentido):