Archivo de la categoría: Microcontroladores

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.

Elecrab: una startup española

eleCrab

Hay gente que, a pesar de la situación actual, son valientes y se atreven a lanzan startups que marquen una diferencia. En el artículo de hoy voy a comentar el caso de Elecrab. Una empresa muy pequeña cuyo fundador, Jorge M., tiene como objetivo crear algo parecido a Pololu, Sparkfun o Adafruit desde cero.

Jorge, Ingeniero Industrial, tiene una dilatada experiencia en el mundo del hardware abierto, no en vano es uno de los creadores de la placa VinciDuino, escritor de blog del cire y jmnlab,

En su primera incursión en el desarrollo de productos de hardware libre ha creado 4 placas para que, quien quiera adentrarse en el mundo de la electrónica, pueda empezar a experimentar por un precio irrisorio.

Estas placas que a continuación detallaré, están a la venta en tindie, un portal donde la gente que quiera vender sus creaciones lo puede hacer sin tener que crear desde cero un tienda online y donde los compradores pueden buscar productos novedosos de forma sencilla y centralizada.

IMG_20150222_230541

De izquierda a derecha tenemos:

attiny

Una placa con un microcontrolador ATtiny841, cuya principal carácterística es que tiene dos puertos serie por hardware.

 

 

 

ecswicthecSwitch: placa con botón pulsador, y cuya electrónica está diseñada para evitar los famosos rebotes cuando es pulsado.

 

 

 

ecledsecLeds: placa con 4 diodos led.

 

 

 

 

ecpowerecPower: placa para alimentar una protoboard y que puede enchufarse a un puerto micro usb (como los cargadores de los móviles) y que se puede seleccionar si la salida es de 5V. o de 3,3V gracias a un regulador de tensión.

 

 

Estas placas tiene un nivel muy avanzado en cuanto a su producción, ya que por un lado es una empresa china la que fabrica las placas en lotes, y por otro los componentes son soldados usando técnicas empresariales como plantillas (stencils) y soldadura por horno. El acabado es totalmente profesional.

1502222322131455598

Tener un hardware así para iniciarse en la electrónica está bien, pero si no sabemos por donde empezar a utilizarlo de poco nos servirá, por ello en la misma página de Elecrab tenemos unos detallados tutoriales donde se explica desde un principio cómo sacarle provecho a estas placas. Y si nos interesa cómo han sido diseñadas y los motivos por los cuales se han tomado algunas decisiones, puedes verlo más detenidamente en la sección de productos.

Si tienes curiosidad por la electrónica pero no te atreves a adentrarte por su complejidad o tus conocimientos son bajos, esta es una excelente oportunidad de hacerte con hardware libre, barato y completamente funcional para que te sirva como punto de partida en el apasionante mundo de la electrónica.

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.

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

Programar un microcontrolador AVR remotamente mediante bluetooth

Los que llevamos un tiempo en esto de la robótica para concursos nos vamos dando cuenta que se pierde mucho tiempo en muchas cosas para hacer las pruebas a nuestros robots y dejarlos configurados correctamente. Una de las cosas que lleva más tiempo es reprogramar el robot cada vez que queremos cambiar algo en el firmware que no funciona: tienes que ir a por el robot, cogerlo, pararlo, llevarlo hasta el ordenador, quitarle la batería, ponerle el cable ICSP, seleccionar el fichero .hex, programarlo, ponerle la batería de nuevo, llevarlo a la pista, dejarlo en ella y activarlo.

Con este artículo nos vamos a ahorrar todos los pasos mencionados simplemente programando el firmware del robot mediante bluetooth gracias a un bootloader.

Aunque este artículo esté enfocado a la baby orangutan (atmel328P) y el módulo bluetooth CSR, podría funcionar con otros microcontroladores AVR (incluido Arduino) y otros módulos bluetooth.

Como comentaba antes, la posibilidad de programar el firmware de nuestro microcontrolador AVR mediante bluetooth se basa en un bootloader. Los bootloader permiten reprogramar el microcontrolador sin necesidad de tener que usar siempre un programador ICSP. En realidad no es más que un programa que se carga en la zona alta de la memoria y que cambiando los fuse bits del microcontrolador hacemos que sea el primero que se ejecute. Esta gran ventaja nos permite que el bootloader esté comprobando durante unos segundos si se envía información desde el puerto serie del microcontrolador, si es así, reprograma el microcontolador (excepto la zona de memoria del bootloader) con el código enviado y lo ejecuta, si no es así, entonces pasado un tiempo ejecuta el código que hubiese anteriormente. Como el puerto serie ya ha sido configurado por el bootloader, en nuestro programa ya podremos usar las rutinas de envío y recepción por el puerto serie sin la necesidad de tenerlo que configurar de nuevo.

El objetivo de este artículo no es explicar cómo hacer un bootloader, sino utilizarlo directamente. Por eso voy a usar uno ya hecho: KAVR. Este bootloader espera por el puerto serie que se le envíe el fichero .hex del código a programar, por lo que podríamos usar cualquier programa como Minicom (linux), Hyperterminal (windows xp) o, como en mi caso, Tera Term (windows 7).

Antes de usarlo hay que retocar los fuentes, por lo que debemos bajarnos el código fuente, descomprimirlo, entrar en el directorio bootloaderskavr-0.2_328P-14s y editar el fichero Makefile. Dentro de este hay 3 valores que cambiar dependiendo de nuestro sistema:

  • F_CPU: La velocidad de nuestro microncontrolador en hertzios, en el caso de la Baby Orangutan es 20000000.
  • BAUD: La velocidad del puerto serie en bps, en mi caso el bluetooth está configurado a 115200.
  • TIMEOUT: El tiempo que esperará el bootloader a posibles datos en el puerto serie antes de ejecutar el firmware anterior, en mi caso le he puesto 5000 (5 segundos).

Dentro de la misma carpeta tenemos que editar el fichero kavr.c y añadir a la lista de cabeceras la siguiente:

y justo antes de la línea

añadir las siguientes dos líneas que desactivan el watchdog (que explicaré más adelante) en el bootloader:

Después hay que recompilarlo para que nos genere el fichero kavr.hex Para ello usaremos el toolchain de AVR, que en mi caso está en directorio C:Program Files (x86)AtmelAVR ToolsAVR Toolchainbin:

A continuación debéis activar en el microcontrolador los fuse bits BOOTSZ y BOOTRST para indicarle que va a tener un bootloader, el BOOTSZ debe ser de 512 palabras para que quepa el KAVR:

Finalmente enviamos el fichero kavr.hex mediante ICSP al microcontrolador, esta será la última vez que tengáis que hacerlo 😉 .

Ya tenemos nuestro bootloader activo. Ahora hay que hacer nuestro programa, compilarlo y enviárselo mediante bluetooth a nuestro microcontrolador. Para ello previamente deberemos haber vinculado nuestro dispositivo bluetooth a nuestro PC. Después abriremos el puerto serie que se ha creado en la vinculación con los siguientes parámetros 115200,8N1,XON/XOFF:

Debido a la alta velocidad de transmisión he necesitado poner un retardo en el envío de cada línea de 1 ms, pero este ha sido mi caso y no se si os pasará igual si usáis otro módulo bluetooth (si ponéis todo el conjunto a una velocidad menor, por ejemplo 19200, no será necesario ese retardo en el envío con el módulo CSR). Lo del control de errores XON/XOFF lo implementa el bootloader, permite que el microcontrolador le diga al software de control de puerto serie que pare el flujo de datos mientras escribe en la memoria flash, así no se pierdan bytes por el camino al no poder procesarlos a tiempo.

Una vez abierto el canal de comunicación el bootloader nos enviará el texto KAVR indicando que está esperando a que le enviemos un fichero .hex:

Si no le enviamos el fichero en 5 segundos lanzará el programa que esté en la posición cero de la memoria flash, pero si no existiese tal programa, volvería el bootloader a ejecutarse. El fichero debe enviarse como fichero de texto, en Tera Term se hace en el menú FileSend File…

Si la programación ha ido mal, el bootloader enviará el símbolo ?. Si ha ido bien enviará el carácter S e inmediatamente se ejecutará el código.

Ahora sólo queda conseguir que cuando queramos programar otro firmware no tengamos la necesidad de acercarnos al robot y pulsar el botón de reset para que se resetee el microcontrolador y arranque el bootloader de nuevo. Por desgracia en los AVR no hay posibilidad de resetear mediante software, sin embargo hay un truco para lograrlo: El watchdog es un temporizador que si llega al final de su cuenta resetea el micro, por lo tanto para que no ocurra esto se debe poner a 0 el contador cada poco tiempo. El truco consiste en que cuando el microcontrolador reciba una orden a través del puerto serie, este lance un bucle infinito que no actualice el contador del watchdog, provocando su reseteo y en consecuencia ejecutando el bootloader.

A continuación pongo un ejemplo de código muy sencillo: Lo que hace el programa es activar la interrupción de recepción de carácteres. Después apaga y enciende un led en el pin PD7 cada 500 ms. indefinidatmente, pero cuando recibe una R por el puerto serie, cambia el valor de una variable a 1. Dentro del bucle principal se comprueba si esa variable está a 1, y si es así, envía OK por el puerto serie, activa el watchdog y se mete en un bucle infinito para provocar el reseteo.

En la siguiente imagen podemos ver cómo arranca el bootloader con el texto KAVR, como no hay nada que programar no sale nada más y arranca el programa principal, pero al cabo de poco se le ha enviado al programa una R y este ha respondido con un OK, a continuación el microcontrolador se ha reseteado arrancando de nuevo el bootloader y mostrando otra vez KAVR, se le ha enviado un fichero .hex y el bootloader ha respondido con una S indicando que todo ha ido bien y procediendo a ejecutar el programa principal:

Y aquí una demostración en vídeo:

Leer múltiples sensores de infrarrojos con un sólo pin analógico / Read several infrared sensors with an unique analogic pin

Cuando queremos crear un robot que distinga el blanco del negro de una superficie tenemos que leer la posición en la que se encuentra con varios sensores infrarrojos.

To make a robot that distinguishes a black area between a white one, we need to know the position of the robot by reading the information of several infrared sensors.

Muchas veces los microcontroladores que usamos para estos robots tienen un número muy ajustado de pines de entrada y salida, y si tenemos que usar uno de estos por cada sensor infrarrojo que utilicemos vamos a tener problemas para añadirle funcionalidades a nuestro robot: Comunicaciones serie, acelerómetros, giroscopios, i2c, sensores de distancia, bumpers, botones, motores, leds, etc.

Many times the microcontrollers used for these robots have a very limited number of in/out pins, so if we have to use one of those for each infrared sensor, we will find problems to add functionalities to our robot as Serial Communications, accelerometers, gyroscopes, i2c, distance sensors, bumpers, buttons, motors, LEDs, etc..

En los robots rastreadores se usan dos sensores infrarrojos como mínimo, en los de sumo se usan 4, en los velocistas suelen ser 6 sensores o más. Todo esto provoca que tengamos que «desaprovechar» pines de nuestro micro para leer los sensores. Sin embargo hay una forma de leer varios sensores de infrarrojos usando sólo un pin analógico del microcontrolador.

Tracker robots at least use two infrared sensors; sumo robot 4 and line follower robot tend to have 6 or more sensors. All this causes the «waste» of the pins of our micro to read sensors. However, there is a way of reading several infrared sensors using only one analog pin microcontroller.

La idea proviene de este artículo, donde se explica cómo se puede leer un teclado matricial de 4 filas x 3 columnas con un sólo pin analógico de un microcontrolador PIC.  El objetivo es usar varias resistencias para que, dependiendo de la tecla que se pulse, el pin del micro reciba una tensión distinta y poder discernir cuál es la que se ha pulsado. Aquí tendremos un inversor Schmitt trigger en cuyas salidas pondremos resistencias en serie de distintos valores unidas a un punto en común. Desde ese punto se medirá el valor de la tensión, que será distinto dependiendo del sensor activo, pudiendo conocer así la posición del robot.

The idea comes from this article, which explains how to read a keypad matrix of 4 rows x 3 columns with only one analog pin of the PIC microcontroller. The objective is to use several resistors for, depending on which key is pressed, the micro pin receives a different voltage discerning this way which key has been pressed. At this point, we will have a Schmitt trigger inverter whose output have resistors connected in series of different values attached to a common point. From this point the voltage value is measured, which will be different depending on the active sensor, being able to know the position of the robot.

Primera ventaja: Tener varios sensores CNY70 o un array QTR-8A ya no es un problema porque podemos leer todos los valores  con un sólo pin de nuestro microcontrolador y dejar el resto para otras tareas.

First advantage: Having multiple CNY70 sensors or a QTR-8A array is no longer a problem because we can read the values with a single pin of our microcontroller and leave the rest for other tasks.

Segunda ventaja: Por cada sensor que se leía con un pin analógico se provocaba una pausa, ya que la lectura de un ADC tarda un tiempo en hacerse, multiplicado por el número de sensores. Con esta solución sólo se hace una lectura.

Second advantage: Each sensor read with an analog pin causes a pause, since the reading of an ADC takes a while to execute, and this pause must be multiplied by the number of sensors. Using this solution takes only one reading.

Tercera ventaja: Como vamos a usar un inversor schmitt trigger y este sólo nos da una señal alta (5 v.) o baja (0 v.) en sus salidas, con las resistencias siempre vamos a obtener los mismos resultados de tensión aunque cambiemos de entorno (pistas de competición o caseras con distinta iluminación), por tanto no hay que calibrar.

Third advantage: As it is use a Schmitt trigger inverter which only gives a high level (5 V) or low one (0 V) in their outputs, the resistors are always going to get the same voltage if you change the environment (race tracks with different lighting or home), so there is no need to calibrate.

Cuarta ventaja: Con las resistencias correctas sólo es necesario tener un ADC de 8 bits (0-255) para medir el voltaje (en tramos de 0,02 V. aproximadamente) con una referencia de 5 V.

Fourth advantage: With the proper resistors it is only necessary an ADC of 8 bits (0-255) to measure the voltage (0.02 V steps approximately) with a 5 V reference.

Voy a poner como ejemplo 8 sensores infrarrojos que leen una hoja que tiene fondo blanco (devuelven valor cercano a 0) y la línea de color negro (devuelven un voltaje mayor). Como inversor schmitt trigger podemos usar un 40106 o un 74HCT14 que tienen 6 entradas/salidas. Como se necesitan 2 entradas más para alcanzar las 8 hay que poner otro chip inversor (recomiendo distribuirlos en 4 + 4 en vez de 6 + 2). También necesitaremos 8 diodos y 9 resistencias.

Let me give an example of 8 infrared sensors that distinguish a white background (return value close to 0) and the black line on it (that return a higher voltage). As the Schmitt trigger inverter it can be used a 40106 or 74HCT14 which has 6 inputs / outputs. Since it takes 2 more entries to reach the 8 sensor, another chip inverter is necessary (I recommend distribute 4 + 4 instead of 6 + 2). We also need 8 diodes and 9 resistors.


La salida de cada CNY70 o de cada elemento del array QTR-8A va dirigido a una de las entradas de uno de los inversores.

The output of each CNY70 or each element of the QTR-8A array is routed to one input of one of the inverters.

La salida correspondiente de ese inversor va a un diodo enfrentado. Esto es necesario ya que al juntar al final todas las salidas evitamos que si una salida esta a 5 v. y otra a 0 v. se derive la corriente entre ellas.

The corresponding output of each inverter is routed to a faced diode. This is necessary since it prevents the pass of current among outputs in different states (one output in 5V and another at 0V).

Después del diodo viene la resistencia, que dependiendo del valor que tenga hará que la tensión caiga más o menos. El valor de la resistencia debe ser único con respecto al de las otras para que la caida de tensión sea diferente.

After the diode, it is placed the resistor, which depending on its value, the voltage will decrease more or less. Each resistor value must be unique in the set so the final voltage was different.

Finalmente se unen todas las salidas en otra resistencia para crear lo que se denomina un divisor de tensión. En ese punto se debe poner la línea que une al pin analógico del microcontrolador para que este pueda medir el voltaje total y diferenciar qué sensor o sensores están activos. Esta resistencia final que une al resto va a alimentación (Vcc). Esta configuración esta diseñada para poder leer el fondo blanco con una línea negra siempre y cuando los sensores nos den un valor cercano a 0 para cuando leen el fondo blanco y un valor mucho mayor para cuando leen la línea negra. Si se necesita cambiar este comportamiento, se puede conectar la resistencia final a masa e invertir los diodos.

Finally, all outputs are joined together in another resistor to create what is called a voltage divider. In that point you may put the line connected to the microcontroller’s analog pin so the total voltage can be measured and distinguish which sensor or sensors are active. This final resistor that joins the other ones must be connected to Vcc. This configuration is designed to read a black line on the white background as long as the sensors give us a value close to 0 when reading the white background and a much greater value when reading the black line. If you need to change this behavior, you can connect the ending resistor to ground and reverse the diodes.

Ahora que ya recibimos distintas tensiones en el pin analógico de nuestro microcontrolador dependiendo de los sensores que estén activos o no, debemos plantearnos cuántas medidas posibles podemos tener. Como he puesto un ejemplo de un velocista podemos tener los siguientes casos:

  • Todos los sensores leen el fondo blanco.
  • Un sensor lee la línea negra y el resto el fondo blanco.
  • Dos sensores leen la línea negra y el resto el fondo blanco.

Now that we got different voltages in the analog pin of our microcontroller depending on the sensors that are active or not, we must consider how many possible measures can we have. As continuing with the example of the line follower, we have the following cases:

  • All sensors read white background.
  • One sensor reads the black line and the rest, white background.
  • Two sensors read the black line and the rest, white background.

Así pues según la combinatoria, debemos multiplicar el número de sensores por 2. En total tenemos 16 medidas posibles (y diferentes) para todos los estados que pueden tener nuestros sensores. Pongo un esquema con los distintos estados, el voltaje resultante según una simulación y su valor de ADC de 8 bits:

Using Combinatory, we must multiply the number of sensors by 2. In total there are 16 possible (and different) measures for all states which can have in our sensors. I put a scheme with the states, the resulting voltage according to a simulation and its value in 8-bit ADC:

Aquí dejo un vídeo de una simulación en proteus sobre la activación de varios sensores (verlo en HD y a pantalla completa):

Here I show a video of a simulation in proteus on the activation of multiple sensors (see this in HD and full screen):

Para uno de sumo ya no valdría el cálculo anterior ya que habría 7 combinaciones posibles con sus 4 sensores y el fondo es negro con una línea blanca:

For a sumo robot the previous situation is no longer valid as it would be 7 combinations with 4 sensors and the background is black with a white line:

Ahora sólo quedaría medir una primera vez los distintos valores de los sensores y luego programar en nuestro microcontrolador una tabla con esos valores que nos servirá para siempre. Por supuesto como los valores de las resistencias tienen un margen de error y la caída de tensión de los diodos no suele ser siempre el mismo, sólo podremos hablar de valores orientativos y únicamente podemos sacar los valores correctos midiéndolos directamente con un polímetro o que el microcontrolador nos lo diga a través del puerto serie. Yo he probado con valores consecutivos de resistencias comerciales y me ha funcionado bien.

Last action to take is to measure the different sensor values and then program a table in our microcontroller with those values that will be correct for us forever. Of course, the values of the resistors have a margin of error and the voltage drop across the diodes is not usually the same: we are talking only about approximate values and we can only get the correct values by measuring directly with a multimeter or with the microcontroller and sending it trough the serial port. I’ve tried commercial consecutive values of resistors and it has worked well.

Finalmente comentar que si nuestro micro no tiene pin analógico pero si tres pines digitales libres podemos usar un ADC0831.

Finally, I would like to remark that if our micro does not have an analog pin but three digital pins, we can use an ADC0831.

Gracias a Maiki por la traducción / Thanks to Maiki for translation

Calcular la resistencia para un transistor accionado por un microcontrolador

Muchas veces he querido usar un transistor NPN para actuar como interruptor y poder des/activar otras partes del circuito que con las patas de un microcontrolador no se puede hacer directamente (un relé, una bombilla de 12 voltios, otro circuito, etc).

Un transistor puede ser activado (saturación) o desactivado (corte) desde un microcontrolador, pero es necesario poner una resistencia entre la pata del micro y la base del transistor. En este artículo explicaré como se puede calcular de una forma sencilla.

Dependiendo de la carga que queramos manejar debemos seleccionar un transistor NPN u otro. No es lo mismo usar un BC107 que permite tensiones de hasta 45 V. y corrientes de hasta 100 mA. que un 2N3055 que permite tensiones de hasta 60 V. y corrientes de hasta 15 A. Aquí podemos ver unos cuantos para ver cuál se adapta mejor a nuestras necesidades. Por eso debemos saber qué corriente pasa por el punto donde queremos poner el transistor para que actúe como interruptor.

Una vez que hemos seleccionado el transistor , debemos calcular qué resistencia debemos poner entre la patilla del microcontrolador que elijamos y la patilla base del transistor. Para eso primero debemos saber qué hFe (ganancia de corriente) mínima tiene nuestro transistor y nada mejor que consultar el datasheet para saber ese dato.

Después con la siguiente fórmula ya podemos calcular qué resistencia necesitamos:

  • Voltaje: Es la tensión que proporciona la pata del microcontrolador, normalmente 5 o 3,3 V. Se resta 0,7 V. porque es la caída de tensión típica entre la base y el emisor de un transistor, aunque lo puedes mirar en el datasheet del transistor como Vbe.
  • Corriente: Es la corriente que consume el circuito que queremos encender o apagar.
  • hFe: Es la ganancia de corriente (current gain) que tiene el transistor (si hay varios valores elegir el más pequeño).

El resultado es el valor en ohmnios de la resistencia que necesitamos poner.

Así por ejemplo vamos a calcular la resistencia que usaremos para manejar un circuito que consume 500 mA. funcionando a 12 V. y gestionado por un microcontrolador PIC cuya patilla da una tensión de 5 voltios.  Lo primero es buscar un transistor que se adapte a nuestras necesidades, mirando la lista anterior el 2N3053 nos viene bien ya que permite tensiones de hasta 40V. y corrientes de hasta 700 mA. Podemos ver que su hFe es de 50, por tanto la fórmula aplicada sería:

Una resistencia de 430 ohm. no es una resistencia común, por lo que buscaremos el valor más aproximado de las resistencias comerciales, que en este caso podríamos elegir entre una de 390 ohm. o una de 470 ohm.

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):