25 de junio de 2014

Cómo programar a tu Arduino

En esta entrada explicaremos cómo se programa un Arduino usando el lenguaje de programación Python.

Arte conceptual de Toby Shelton para la película
Cómo entrenar a tu dragón de DreamWorks Animation.

Opciones para programar al Arduino

Partimos primero del supuesto de que tenemos una computadora anfitriona (con Windows, Linux o MacOS) conectada a un Arduino a través de un cable USB tipo A-B (como el que usamos comúnmente para conectar una computadora a una impresora), tal como se muestra en la siguiente figura:


Arduino conectado a la computadora 
anfitriona a través del cable USB.

A partir de esta configuración, hay dos lugares en donde un programa puede ser ejecutado:
  1. Directamente en el Arduino.
  2. En la computadora anfitriona. 
En la opción 1, la computadora anfitriona sirve para desarrollar el programa y compilarlo para producir un archivo ejecutable que se descarga posteriormente al Arduino a través de la conexión USB. Dicho archivo no debe sobrepasar el espacio de la memoria flash del microcontrolador (32 Kbytes en el caso del Arduino Uno).

En la opción 2, por otro lado, se instala en el Arduino un firmware que permite que un programa corriendo en la computadora anfitriona controle las acciones del Arduino a través del intercambio de datos vía la conexión USB. El firmware que usualmente se utiliza con este fin se llama Firmata.

Para la opción 1 comúnmente se utiliza el lenguaje de programación C++ junto con el ambiente de desarrollo integrado (IDE) de Arduino. Una ventaja de este esquema es que, una vez cargado el programa en el Arduino, es posible retirar la computadora anfitriona por completo. Dado que la conexión USB sirve también como fuente de alimentación, es necesario suplir al Arduino de una fuente alterna. Por ejemplo, es posible conectar al Arduino a una pila de nueve voltios.

Arduino con pila de 9V como fuente de alimentación
y sin conexión a la computadora anfitriona.

En cuanto a la opción 2, ésta tiene la desventaja fundamental de que nunca podemos retirar la computadora anfitriona; sin embargo, tiene dos ventajas significativas:
  • Ya que nuestros programas corren en la computadora anfitriona y no directamente en el Arduino, no estamos restringidos a tener que usar C++. Podemos usar cualquier lenguaje de programación en la que exista una interfaz con Firmata: Processing, Pascal, Perl, C#, PHP, Java, JavaScript, Clojure, Ruby y por su puesto Python, por mencionar algunos.
  • El código de nuestros programas no está limitado al tamaño de la memoria flash del microcontrolador, sino al tamaño de la memoria de la computadora anfitriona (kilobytes vs. gigabytes).
Dado que deseamos programar el Arduino usando Python, estamos obligados a utilizar la opción 2.

Instalación del software

Hay que seguir estos tres pasos:
  1. Descargar e instalar el software de Arduino, según el sistema operativo de la computadora anfitriona, tal como se describe en la página Comienza a usar Arduino. Al momento de configurar el IDE, hay que anotar el puerto serie (serial port) al que se conecta el Arduino, ya que más adelante haremos referencia a éste. Según el sistema operativo, el puerto serie puede ser algo así como COM3 (Windows), /dev/ttyACM0 (Linux) o /dev/tty.usbserial (MacOS).
  2. Descargar Firmata en el Arduino. En el IDE de Arduino seleccionar File del menú principal. De ahí seleccionar: Examples/Firmata/StandardFirmata.



    Posteriormente, presionar Ctrl-U para compilar y copiar el código de Firmata al Arduino. Después de un momento debe aparecer el texto “Done uploading” en la barra de mensajes del IDE.
  3. Descargar e instalar la biblioteca pyFirmata en la computadora anfitriona. Esta biblioteca permite que un programa de Python, corriendo en una computadora anfitriona, se comunique vía USB con un Arduino corriendo Firmata. Desde una terminal (posiblemente con privilegios de administrador), teclear:
    pip install pyfirmata
    Si el sistema de administración de paquetes de Python pip no está instalado, referirse a la siguiente liga: http://pip.readthedocs.org/en/latest/installing.html. En algunos sistemas en necesario usar el comando pip3 en lugar de pip para instalar bibliotecas de Python 3.

Resumen del API de pyFirmata

NOTA: Todo el código presentado aquí fue probado con Python 3.4.

Para comenzar a usar pyFirmata debemos importar el paquete correspondiente al inicio de nuestro programa:
import pyfirmata
Podemos determinar qué versión de pyFirmata estamos usando:
print('pyFirmata version:', pyfirmata.__version__)
A continuación creamos un objeto que representa nuestra placa (board) de Arduino. Para ello necesitamos indicar como cadena de caracteres el puerto serie que anotamos durante la configuración del IDE ('/dev/ttyACM0' en mi caso, ya que estoy usando Linux):
placa = pyfirmata.Arduino('/dev/ttyACM0')
Con el objeto referido por la variable placa podemos determinar la versión de Firmata que está usando nuestro Arduino. El método get_firmata_version() devuelve una tupla con dos valores: la versión mayor y la versión menor. Podemos utilizar una asignación paralela para extraer los valores de la tupla en dos variables:
v_mayor, v_menor = placa.get_firmata_version()
print('Firmata version mayor:', v_mayor)
print('Firmata version menor:', v_menor)
Al correr estas instrucciones, la salida en mi sistema me indica que la versión mayor es 2 y la versión menor es 3, por lo que el número completo de versión es 2.3.

El método get_pin() sirve para activar un pin en el Arduino, configurándolo según la cadena que se le envía como argumento. Dicha cadena está compuesta de a o d (para indicar que el pin es analógico o digital), el número de pin, y el modo (i para entrada, o para salida, p para PWM). Estos tres elementos se separan entre sí usando un carácter de dos punto (:). Por ejemplo d:12:o indica que el pin 12 es una salida digital. Este es un ejemplo de cómo se utiliza el método:
salida = placa.get_pin('d:12:o')
El siguiente ejemplo activa el pin 8 del Arduino como una entrada digital.
entrada = placa.get_pin('d:8:i')
Después del código de arriba, es necesario invocar el método enable_reporting() sobre el objeto que representa el pin de entrada para poder leer las señales recibidas:
entrada.enable_reporting()
Si se utilizan uno o más pines de entrada es necesario crear un thread iterador, de lo contrario la placa puede seguir enviando datos por la conexión serial hasta producir un desbordamiento. Para crear dicho thread usamos la siguiente instrucción:
pyfirmata.util.Iterator(placa).start()
Para escribir a un pin de salida digital, usamos el método write() enviando como argumento False (0V) o True (5V), según la cantidad de voltaje que deseemos producir como salida. Ejemplo:
salida.write(True)
En lugar de False y True se puede usar 0 y 1, respectivamente.

Usamos el método read() para leer de un pin de entrada digital. Este método devuelve 0 si el voltaje de entrada es menor a 2.5V, o 1 si es mayor a 2.5V. Por ejemplo:
x = entrada.read()
Posteriormente, podemos usar la variable x en una instrucción condicional (if) para determinar qué valor efectivamente se leyó.

Para pausar nuestro programa por una cierta cantidad de tiempo se recomienda usar el método pass_time() sobre el objeto que representa nuestra placa de Arduino. Se le envía como argumento el número de segundos que deseamos que dure la pausa. La siguiente porción de código detiene el programa en curso durante medio segundo:
placa.pass_time(0.5)
Por último, para terminar nuestro programa de manera limpia, se debe invocar el método exit() así:
placa.exit()

Un ejemplo completo

Realicemos ahora un pequeño proyecto que nos permita integrar todo lo que describimos en la sección anterior. Vamos a usar un botón para controlar el prendido y apagado de un LED.

Además del Arduino Uno conectado vía USB a la computadora anfitriona, vamos a requerir el siguiente hardware:
  • Un protoboard.
  • Un botón o pulsador (push button).
  • Un LED (diodo emisor de luz).
  • Una resistencia de 330Ω (bandas naranja, naranja, café).
  • Una resistencia de 10KΩ (bandas café, negro, naranja).
  • Cinco cables conectores.
La siguiente figura, elaborada con Fritzing, muestra la manera de conectar todos los componentes:

Vista de protoboard Fritzing para
el LED controlado por un botón.

Usando un par de cables, conectamos un pin de tierra (GND) y un de pin de 5V del Arduino a los buses respectivos de alimentación negativa (línea azul) y positiva (línea roja) del protoboard.

El ánodo del LED (la patita larga) se conecta al pin 12 del Arduino, mientras que el cátodo (la patita corta) se conecta a la resistencia de 330Ω. El otro extremo de esta resistencia se conecta a tierra (bus negativo).

El push button se coloca de tal forma que un par de patitas quede a la izquierda y el otro par a la derecha del canal central del protoboard. Conectamos una de las patitas inferiores del botón al bus positivo. Una de las patitas superiores del botón se conecta a una resistencia de 10KΩ, mientras el otro extremo de la resistencia se conecta a tierra (bus negativo). La patita superior que queda del botón se conecta al pin 8 del Arduino. Dada esta disposición, se dice que la resistencia es de tipo pull-down. En términos prácticos esto significa que el valor que va leer el pin 8 por omisión (cuando el botón no está presionado) es 0V, y 5V cuando el botón está presionado.

Físicamente las conexiones de nuestros componentes electrónicos se ven como se muestra en la siguiente foto:

Vista física del LED controlado
por un botón.

El programa completo en Python 3.4 se muestra a continuación:
# Archivo: led_boton.py

import pyfirmata

placa = pyfirmata.Arduino('/dev/ttyACM0')

print('Firmata version: %d.%d' % placa.get_firmata_version())
print('pyFirmata version:', pyfirmata.__version__)

pyfirmata.util.Iterator(placa).start()

entrada = placa.get_pin('d:8:i')
entrada.enable_reporting()
salida = placa.get_pin('d:12:o')

try:
    encendido = False
    while True:
        if entrada.read():
            encendido = not encendido
            salida.write(encendido)
            placa.pass_time(0.2)

finally:
    salida.write(False)
    placa.exit()
Para correr el programa, requerimos ejecutar el siguiente comando desde una terminal en el mismo directorio donde radica el archivo led_boton.py:
python3 led_boton.py
Cuando corremos el programa, el LED se prende cuando presionamos el botón y se apaga cuando lo volvemos a presionar, y así indefinidamente hasta que presionemos Ctrl-C para terminar el programa.

Más información

18 de junio de 2014

Arduino

El Arduino es una plataforma de hardware libre. Consiste de un microcontrolador y un ambiente de programación que permite la creación de sistemas que interactúan con el mundo físico a través de sensores y otros componentes electrónicos. A este tipo de tecnología, que también incluye a la Raspberry Pi, se le conoce usualmente como computación física.


El proyecto Arduino comenzó en el año 2005. Su objetivo era proveer de dispositivos económicos y fáciles de usar a los estudiantes del Instituto Ivrea de Diseño Interactivo (IDII), en Ivrea, Italia. Massimo Banzi, uno de los principales fundadores del proyecto, daba clases en IDII.

Massimo Banzi

Se puede utilizar al Arduino para elaborar una infinidad de cosas, por ejemplo: redes de sensores, alarmas, sistemas de comunicaciones, robots sencillos, proyectos de arte digital, etc. En general se puede usar un Arduino para construir casi cualquier tipo de objeto interactivo, limitado solo por nuestra imaginación.

El hardware del Arduino consiste de una tarjeta de circuito impreso o PCB (printed circuit board) en la que reside el microcontrolador junto con otros conectores y elementos electrónicos que permiten al usuario acoplar componentes de entrada y salida.

El Arduino Uno

Un microcontrolador es una pequeña computadora contenida en solo circuito integrado. Está conformado por un procesador, memoria y periféricos programables de entrada y salida.

Existen varios modelos del Arduino. El más conocido es el Arduino Uno, que cuenta con un microcontrolador ATmega328 de Atmel. Dicho microcontrolador tiene las siguientes características:
  • Procesador RISC de 8 bits AVR.
  • Una velocidad de reloj de 16 MHz.
  • 32 registros de propósito general.
  • 2 Kbytes de memoria RAM para almacenar datos volátiles.
  • 1 Kbyte de memoria EEPROM para almacenar datos no volátiles
  • 32 Kbytes de memoria flash (memoria no volátil) para almacenar el código del programa.

Microcontrolador ATmega328 de Atmel.

El número de bits, la velocidad y la memoria disponible de este microcontrolador parecen ser los de una configuración de alguna micro-computadora de inicios de los años ochenta. Sin embargo, no hay que perder de vista que los microcontroladores se utilizan principalmente en sistemas embebidos, por ejemplo dentro de electrodomésticos, automóviles, aparatos médicos y juguetes. Típicamente, estos sistemas no necesitan la velocidad ni la cantidad de memoria de una computadora convencional contemporánea.

El AVR es un procesador con arquitectura Harvard. Esto quiere decir que los dispositivos de almacenamiento para instrucciones y datos están físicamente separados. Esto contrasta con la arquitectura de von Neumann, en donde se utiliza el mismo hardware de memoria principal para almacenar datos e instrucciones. El término “arquitectura Harvard” proviene de la computadora Harvard Mark I, que almacenaba las instrucciones en cintas perforadas y los datos en interruptores.

El Arduino Uno tiene un costo aproximado de treinta dólares. Cuenta con 16 pines de entrada/salida digital y 6 pines de entrada analógica. De los pines digitales, 6 se pueden usar también como salidas de modulación por ancho de pulsos (PWM por sus siglas en inglés), que de forma práctica son como si fueran salidas analógicas.

El puerto USB del Arduino sirve como fuente de alimentación y también permite establecer comunicación serial con una computadora anfitriona. Es precisamente por este medio que podemos programar al Arduino; éste será el tema central de una entrada futura del blog de EduPython.

Para concluir, recomiendo a las personas interesadas ver el video Arduino the Documentary (2011) (incluye subtítulos en español). Este documental presenta en media hora un contexto más amplio de qué es y de dónde viene el Arduino, así como la manera en que surge el movimiento de hardware de open-source y las implicaciones que tiene todo esto en la educación. En palabras de Juan Carlos de Mena, maestro de educación media superior en Madrid, España:
Los alumnos aprenden que hay otro lado aparte del lado del consumidor, que hay formas de conocer los cacharros por dentro y tener el control sobre ellos. El Arduino es muy divertido y sirve para enseñar electrónica. Sirve para enseñar a pensar. Sirve para enseñar a tener proyectos a medio plazo y trabajar en equipo, para participar en una comunidad y documentarse. 

Más información

  • El sitio oficial de Arduino: http://www.arduino.cc/es/
  • ¿Dónde puedo adquirir un Arduino? Eso depende del lugar donde te encuentres. En México se puede adquirir a través de distribuidores autorizados tales como ElectronicaEstudio.com, o en algunos comercios de electrónica de la calle de República del Salvador en el Centro de la Ciudad de México, solo por mencionar algunos lugares. Adafruit.com y Amazon.com atienden pedidos internacionales, pero siempre hay que considerar los costos de envío, impuestos y restricciones aduanales de cada país. Otra opción para países de América Latina son los sitios de venta entre particulares, por ejemplo MercadoLibre.com.

5 de junio de 2014

Contador binario

En esta entrada del blog de EduPython elaboraremos un nuevo proyecto para la Raspberry Pi (RPi). En esta ocasión vamos a hacer un contador binario. Utilizaremos cuatro LEDs para representar cuatro bits que nos permitirán contar del 0000 al 1111 en binario (0 al 15 en decimal). Tendremos también un botón, y cada vez que lo presionemos se incrementará en uno el contador.

La siguiente tabla muestra los valores que pueden tener los cuatro bits junto con su valor correspondiente en decimal:

Valores decimales y
sus equivalentes en binario.

Comencemos por escribir una función en Python que dado un entero n del 0 al 15, devuelva una lista con cuatro enteros que correspondan a los cuatro bits de la representación binaria de n:
def binario(n):
    resultado = []
    for i in range(4):
        resultado.append(n & 1)
        n >>= 1
    return resultado
Internamente en la computadora, los números están almacenados en binario, así que podemos inspeccionar los bits individuales de n para crear la lista con los valores que necesitamos. Los operadores & y >>= del código de arriba sirven para tal efecto en dos pasos dentro del ciclo for, el cual se repite un total de cuatro veces (una vez por cada bit que nos interesa):
  • La expresión n & 1 realiza un and (conjunción) a nivel de bits entre n y 1, efectivamente obteniendo el cero o el uno contenido en el bit 0 (el bit que está más a la derecha) de la representación binaria de n, y almacenando ese valor al final de la lista resultado usando el método append()
  • La expresión n >>= 1 desplaza todos los bits de n una posición hacia la derecha. Es decir el bit 1 original se convierte en el nuevo bit 0, el bit 2 original se convierte en el nuevo bit 1, y así sucesivamente. El bit 0 original se pierde en este proceso, pero no importa, ya que fue inspeccionado y almacenado en el paso anterior.
Como ejemplo, si invocamos la función binario() con argumento 1, ésta nos devuelve la lista [1, 0, 0, 0]. La lista resultante pudiera dar la impresión de estar invertida. Sin embargo, por simplicidad nos conviene que el bit 0 se encuentre en la primera posición de la lista, el bit 1 en la segunda, y así sucesivamente.

Vale la pena notar que la función binario() solo considera los cuatro bits menos significativos (los bits que están más a la derecha) de su entrada n. Esto significa, en términos prácticos, que la función devuelve una lista con la representación en binario de n módulo 16. Lo anterior es útil para saber interpretar el resultado para los casos en los que n esté fuera del rango del 0 al 15.

El hardware

Además de la RPi, para este proyecto requerimos los siguientes componentes:
  • Un protoboard.
  • Un botón o pulsador (push button).
  • Cuatro LEDs (diodos emisores de luz).
  • Cuatro resistencias de 330Ω (bandas naranja, naranja, café).
  • Siete cables conectores.
La siguiente figura, elaborada con Fritzing, muestra la manera de conectar los componentes:

Vista de protoboard Fritzing para el contador binario.

Usando un cable conectamos un pin de tierra (GND) de la RPi a uno de los buses para alimentación negativa (línea azul) del protoboard. El botón se coloca de tal forma que un par de patitas quede a la izquierda y el otro par a la derecha del canal central del protoboard. Conectamos una de las patitas superiores del botón a tierra (bus negativo), y una de las patitas inferiores la conectamos al pin 22 de la RPi. Colocamos los cuatro LEDs en el protoboard, en donde el cátodo (patita corta) y el ánodo (patita larga) de cada LED debe estar en su propia pista. Conectamos el cátodo de cada uno de los LEDs a una resistencia de 330Ω. El otro extremo de cada resistencia lo conectamos a tierra (bus negativo). Ahora conectamos el ánodo de cada LED a uno de los pines de la RPi:
  • Pin 18 para el LED correspondiente al bit 0 (LED inferior de la figura).
  • Pin 23 para el LED correspondiente al bit 1.
  • Pin 24 para el LED correspondiente al bit 2.
  • Pin 25 para el LED correspondiente al bit 3 (LED superior de la figura).
Con nuestros componentes ya en su lugar, estamos listos para escribir lo que falta de nuestro programa.

El software

Para controlar los LEDs, requerimos básicamente hacer lo mismo que hicimos en la entrada del LED parpadeante. Dado que son cuatro LEDs a controlar en lugar de uno, usamos una lista con los respectivos números de pin de salida. El siguiente código se encarga de establecer a los pines 18, 23, 24 y 25 de la RPi como pines de salida y además se asegura de que inicialmente se encuentren apagados:
PIN_LEDS = [18, 23, 24, 25]
for i in PIN_LEDS:
    GPIO.setup(i, GPIO.OUT, initial=GPIO.LOW)
En la RPi usaremos el pin 22 para inspeccionar el estado de nuestro botón. Esto quiere decir que tenemos que configurar dicho pin como un pin de entrada para poder leer una señal LOW (0 voltios) o HIGH (3.3 voltios), según el estado del botón.

De acuerdo a la manera en que conectamos nuestros componentes, el pin 22 recibe la señal de tierra (0 voltios) solo cuando se cierra el circuito (el botón se encuentra presionado). Pero, ¿qué pasa cuando no es así? En ese caso se dice que el pin está “flotando”, lo que puede producir resultados inesperados. Para evitar este problema podemos utilizar una resistencia pull-up, con lo que efectivamente proveemos de un valor por omisión al pin cuando el circuito no está cerrado (el botón no está presionado). Lo anterior se puede lograr vía hardware (colocando una resistencia de 10KΩ entre el pin de entrada y una alimentación de 3.3 voltios) o por software configurando el pin para que utilice la resistencia pull-up interna provista por la misma RPi. El siguiente código se encarga de este último caso:
PIN_BOTON = 22
GPIO.setup(PIN_BOTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
Con esta configuración podemos usar la función input() indicando el número de pin de entrada como argumento. En este contexto, la función devuelve LOW (0) para indicar que el botón está presionado, o HIGH (1) en caso contrario. Este comportamiento es inverso a lo que alguien podría inicialmente suponer.

El siguiente ciclo infinito verifica en cada iteración si el botón está siendo presionado en ese preciso instante. En caso afirmativo, incrementa el contador y usa su representación binaria para prender o apagar los LEDs correspondientes:
contador = 0

while True:
    if GPIO.input(PIN_BOTON) == GPIO.LOW:
        contador = (contador + 1) % 16
        for pin, bit in zip(PIN_LEDS, binario(contador)):
            GPIO.output(pin, bit)
        time.sleep(0.2)
Dentro del cuerpo del if la instrucción:
contador = (contador + 1) % 16
se utiliza para incrementar en uno a la variable contador. La operación de módulo (%) 16 sirve para reiniciar contador a cero una vez que haya llegado a su máximo valor (15). El siguiente código es equivalente, aunque menos compacto:
contador += 1
if contador == 16:
    contador = 0
La función zip() que se usa dentro de la instrucción for permite iterar simultáneamente sobre dos o más colecciones. Por ejemplo, si PIN_LEDS es [18, 23, 24, 25] y el resultado de binario(1) es [1, 0, 0, 0], entonces la función zip() hace que las variables pin y bit sean 18 y 1 en la primera iteración del for, 23 y 0 en la segunda, y así sucesivamente.

Al final del cuerpo del if usamos la función sleep() para hacer una breve pausa antes de intentar leer nuevamente el estado del botón. De no hacerlo podríamos incrementar más de una vez a contador debido al tiempo que transcurre entre que presionamos el botón y el momento en que lo soltamos.

El programa completo se muestra a continuación:
# Archivo: contador_binario.py

import RPi.GPIO as GPIO
import time

# Usar el esquema de numeracion de pines de Broadcom SoC.
GPIO.setmode(GPIO.BCM)

# Inicializar pines de salida.
PIN_LEDS = [18, 23, 24, 25]
for i in PIN_LEDS:
    GPIO.setup(i, GPIO.OUT, initial=GPIO.LOW)

# Inicializar pin de entrada.
PIN_BOTON = 22
GPIO.setup(PIN_BOTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def binario(n):
    """Devuelve como lista el valor binario de n.

    La lista resultante es de la forma:

       [bit0, bit1, bit2, bit3]

    Los bit4 en adelante son ignorados.
    """
    resultado = []
    for i in range(4):
        resultado.append(n & 1)
        n >>= 1
    return resultado

contador = 0
try:
    while True:
        if GPIO.input(PIN_BOTON) == GPIO.LOW:
            contador = (contador + 1) % 16
            for pin, bit in zip(PIN_LEDS, binario(contador)):
                GPIO.output(pin, bit)
            time.sleep(0.2)
finally:
    GPIO.cleanup()

Desde una terminal de la RPi, debemos ejecutar el siguiente comando para correr el programa:
sudo python contador_binario.py
La siguiente foto muestra cómo se ve nuestro proyecto después de correr el programa y presionar once veces el botón:

Contador binario mostrando
1011 binario (11 decimal).