16 diciembre 2012

Conectando la Raspberry PI al Arduino vía Serial

De bachiller, hace ya algunos años por cierto, estudié una opción técnica en electrónica. Esto fué así porque en algún momento de mi vida quise ser ingeniero electrónico (o algo que se le asemejara). Lástimosamente, esa rama de la ingeniería no tiene mucha demanda en mi país y la verdad al descubrir la computación me di cuenta que era algo en lo que no era nada malo, me gustaba bastante y actualmente es lo que me da de comer.

Sin embargo, el pasar de los años no ha logrado hacer que pierda el cariño por la electrónica y esa magia especial que tiene el "inventar" o "armar" dispositivos que simplemente hagan cosas interesantes por muy pequeñas que sean. Actualmente, resulta muchísimo más facil el armado de prototipos para todos aquellos cuyo hobby o profesión sea la electrónica.

En esta entrada vamos a conocer al Rasberry PI, luego al Arduino y vamos a conectarlos vía puerto serial. Al final, podrán usar esta configuración para conectar sus Arduinos (o cualquier dispositivo que se comunique via Serie) al Rasperry PI y solo su imaginación será el límite para los proyectos que podrán inventar.



Conociendo a la Raspberry PI


A principios de este año, gracias a la gente de SVCommunity leí la noticia de que ya se encontraba disponible el "computador" de $25 y pronto saldría a la venta.

Para los que no conocen la "RaspPI" o "RPi", como le dicen de cariño, es una pequeña computadora completamente funcional del tamaño de una tarjeta de crédito, la cual podemos utilizar conectandole un teclado, un mouse y una TV.

Las RaspPIs son fabricadas por una "ONG" británica y su objetivo es promover un poco la informática a travez de una pequeña computadora, baráta y fácil de usar.

Muy fuera del contexto original, miles de personas alrededor del mundo han adquirido su RasPI para un sin fin de tareas, desde centros de entretenimiento hasta el control de robots.

En mi caso adquirí la mía, parte motivado por la curiosidad y parte para ver que inventaba.

 
Fotografía de una Raspberry PI


Hablando de Arduinos


Por otra parte tenemos a los Arduinos, estos dispositivos son pequeñas tabletas para el montaje de prototipos electrónicos que incluyen un pequeño microprocesador que puede programarse muy fácilmente.

Realmente desde hace muchos años que se pueden hacer cosas como las que se hacen actualmente con los Arduinos. Sin embargo, la ventaja de estas pequeñas tabletitas es que ya incluyen todo lo necesario para comenzar proyectos. Por una parte, no es necesario armar circuitería extra, solo se conectan a una fuente de poder y están funcionando. El otro punto a favor es incluyen un pequeño software que hace programar los Arduinos una "delicia". Simplemente uno escribe su programa y le da click al botón enviar al dispositivo.

Fotografía de un Arduino Mega

Si usted alguna vez intento programar un PIC: Créame, se lo garantizo, con los arduinos se sentirá en la gloria.

¿Pero el Rasberry PI es una computadora completa? ¿Para que me debería interesar conectarle un arduino?


Realmente, a mi manera de pensar el RasPI y el Arduino son dos mundos diferentes. Primero, si bien la Raspberry tiene un conjunto de pines para usos de proposito general (GPIO), estos no necesariamente son solo de conectar y ponerse a inventar, muchas veces hay que armar algo de circuitería extra y como dicen en la propia página de las Rasberrys: "La intención de esto es que la gente que realmente está seriamente interesada en hacer interfaces utilice una tableta externa con buffers, conversión de niveles y entradas análogas/digitales, en vez de soldar directamente en la tableta principal" (Fuente: elinux.org).

Los Arduinos por otra parte son un poco mas "rudos" ya que están diseñados justamente para trabajar directamente con circuitos. Esto nos da un poco más de "confianza" a la hora de crear hardware. Y justamente como recomiendan en elinux, nuestra idea es que el Arduino sea la "tableta externa" que interactua directamente con el hardware.

Otra de las razones por las que prefiero interactuar directamente con sensores, voltajes, etc. en Arduino es por su facilidad de programación. Si bien la RasPI es una computadora completa el programar a "bajo nivel" se vuelve más complicado. Es decir si bien tenemos una distribución GNU/Linux completa y fácil de usar, perdemos la simpleza de programar un Arduino.

Por último, el Arduino viene preparado de fábrica para interactuar con el hardware, varias líneas digitales de entrada y salida, convertidores análogo-digital, modulación del ancho del pulso (PWM), etc, etc. Son parte de las cosas que lo hacen ideal para trabajar a muy "bajo nivel".

Combinando lo mejor de ambos mundos


Para evitar una pelea de opiniones les quiero dar una mejor sugerencia: ¿Por qué no combinamos lo mejor de ambos mundos? ¿Qué tal si utilizamos el Arduino para cosas de bajo nivel como medir voltajes, detectar pulsadores, hacer girar motores, cambiar intensidad de leds, etc, etc, etc. y en cambio utilizamos la RasPI para cosas de muy alto nivel, como por ejemplo manejar la IA de un robót, enviar datos vía internet, control remoto, etc., etc.?

Mi propuesta es simple: dejemos que Arduino haga lo que hace mejor interactuar con los sensores y actuadores simples y que la RasPI se encargue de cosas mas complejas, como dar una interfaz de usuario bonita para controlar uno o varios arduinos.

La pregunta obvia que surge es la siguiente: ¿Cómo hacemos que se comuniquen?

El puerto GPIO de la Raspberry PI


Las Raspberry incluyen una serie de pines de propósito general que pueden ser utilizados como entradas o salidas digitales entre los cuales se incluye un pequeño puerto "serial". Este puerto puede ser utilizado para enviar o recibir datos desde y hacia otros dispositivos. De fábrica viene configurado como un puerto de "consola" para monitorear el funcionamiento del RasPI.

Antes de intentar comunicar algo por el puerto tenemos que cambiar un par de líneas de configuración.

  1.  Primero en la RasPI tenemos que modificar el archivo /boot/cmdline.txt y eliminar la parte que dice:
    console=ttyAMA0,115200 kgdboc=ttyAMA0,115200
    
  2. Lo siguiente que hay que hacer es comentar la siguiente línea en el archivo /etc/inittab:
    #Spawn a getty on Raspberry Pi serial line
    #T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 
Una vez realizadas estas modificaciones reiniciamos nuestra RasPI. Estas modificaciones evitarán que el Kernel envíe mensajes a la línea serial.

Preparando el Arduino


Con el arduino es un poco más fácil, para este caso ya viene configurado un puerto serial de fábrica al cual nos comunicamos con el código que pego a continuación:
void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.write("Hola Raspi!\n");
  Serial.write("Soy un Arduino Mega\n");
  delay(1000);
}
Una vez estemos listos, conectamos nuestro Arduino y hacemos clic al botón cargar.

Igualando los voltajes.


El pequeño gran problema de las RasPIs es que el puerto GPIO utiliza un voltaje de 3.3 y no tiene ningún tipo de protección contra sobre-voltajes. Si utilizaramos directamente los voltajes del Arduino de 5V corremos el riesgo de dañar permanentemente el puerto y en consecuencia terminar con nuestra RasPI achicharrada.

Para evitar sorpresas desagradables, podemos utilizar un par de transistores y unas cuantas resistencias para "igualar" los niveles de voltaje y no tener circuitos achicharrados ni de un lado ni del otro, para ello pueden utilizar el siguiente circuito que coloco a continuación:



En este caso he utilizado los famosos 2N2222, son unos transistores baratos que se pueden encontrar en El Salvador y las nunca bien ponderadas resistencias de 1K que son igual de baratas y fácil de conseguir.

Conexiones Físicas


Por suerte en mi casa tengo un par de computadoras sin uso y pude extraer los cables de los USB que van conectados a la motherboard. La ventaja de estos cables es que vienen marcados y son de diferentes colores así que colocarlos no es complicado y se hace todo muy fácil de recordar.

Utilizo una Breadboard para realizar la conexión de los cables y la circuitería de para equilibrar los niveles, en la siguiente imágen pueden ver las líneas que vienen de la breadboard al puerto serial del Arduino Mega:

Nota muy importante: Para evitar el riesgo de "voltajes flotantes" y/o descargas estáticas, antes de realizar cualquier conexión verifiquen que tanto la RasPI como el Arduino se encuentre apagados, luego conecten las líneas de negativo o tierra. Después de haber realizado este procedimiento procedan a conectar el resto de líneas de positivos y señales.

En la siguiente foto pueden ver el circuito. Pido disculpas por ser tan poco estético pero ya era algo tarde en la noche y tenía sueño, así que lo hice un poco a la carrera.

+Modificado: Como el circuito anterior me daba pena. Decidí ponerlo mas bonito. Esta vez utilizo el mismo cable USB para conectarme al arduino. Notaran que estoy usando Verde para TX y Blanco/Verde para RX. La línea naranja es 3.3V del RasPI y la línea Café es GND del RasPI.
(Ignoren las líneas Roja y Negra del conector de arriba, estas las uso para detectar un switch y una línea de datos de un display que tengo en la otra mitad de la breadboard.)

Por último realizamos las conexiones correspondientes del lado de la Rasperrry, esta parte es más fácil ya que los cables están marcados y ayudan mucho.

Pueden notar como utilizo el voltaje de 3.3V de la Raspberry para alimentar el transistor. De esta manera me aseguro que los voltajes nunca superaran el rango de trabajo de la RasPI.

Armando todo debería quedar más o menos de la siguiente manera, de nuevo disculpen un poco el caos pero esque me he mudado a trabajar a la cocina.

+Modificado: Luego de ordenar todo me quedó un poco más bonito, les dejo la foto, ahora tengo más cables ya que estoy utilizando un display de 7 segmentos para mostrar datos, algunos interruptores para jugar con las interrupciones y utilizo todos los cables de los conectores USB para interconectar los serial entre el arduino y la RasPI.

Probando todo


Una vez tenemos todo listo y conectado llega la hora de la verdad. Lo primero que tenemos que hacer es encender nuestra RasPI y abrir una consola. (Ojo, yo me conectó vía red a mi RasPI vía SSH.)

Dentro de la consola vamos a ejecutar el siguiente comando:
$ stty -F /dev/ttyAMA0 9600

El comando anterior se encarga de establecer la velocidad del puerto serial de la RasPI a 9600bps, algunas personas han reportado problemas de comunicación con arduinos a velocidads mayores, así que nos iremos seguros con algo que sabemos que funciona y luego pueden intentar conectarse a mayores velocidades.

Para leer los datos de la consola ejecutamos el siguiente comando:
$ cat /dev/ttyAMA0

Deberá de mostrarse una pantalla como la siguiente:

Por último encendemos nuestro Arduino y crucamos los dedos. Si todo funciona según lo esperado deberán de obtener algo como se muestra en la siguiente imágen:
Les dejo una pequeña foto del "caos" de mi escritorio de trabajo, en este caso al Arduino lo alimento desde la compu, pero pueden utilizar una fuente aparte. La RasPI es alimentada con un cargador de Nokia.


Conclusiones

Espero este post les haya sido de utilidad para conocer estas maravillosas herramientas para el armado de prototipos. Hace algunos años nisiquiera soñabamos con que podríamos programar microcontroladores en minutos ni que tendríamos una computadora completa para hacer prototipos a un costo de $35.

Lástimosamente aquí en el país nadie importa este tipo de hardware pero pueden comprarlo vía por Internet y los costos no son demasiado altos. Para el Raspberry les recomiendo enviarlo hasta un casillero ya que el courier local DHL cobra un recargo bastante alto por el manejo del envío (casi $40 solo de manejo del paquete). De igual manera para los Arduinos pueden encontrar en eBay y si tienen servicio de casillero los costos de envío son risibles ($15 de arduino + $9 de envio con impuestos).

Sería interesante que algun grupo local o colegio técnico, o universidad se animara a importar Arduinos y RasPIs con fines didácticos. El costo es sumamente bajo y estoy seguro que "en volúmen" sería una inversión muy bien aprovechada. El precio es tán bajo que cuestan menos que muchos libros de texto y abren un sin fín de oportunidades para proyectos electrónicos.

En una próxima entrada veremos como capturar interrupciones, enviarlas a travez de serial y transmitir datos desde la RasPI hasta el Arduino, una vez realizada la interconexión esto último se vuelve más un problema de "software" que de hardware, pero espero les sea también de utilidad.

Solo para animarlos un poco les dejo una fotografía del circuito en breadboard que estaremos usando la próxima entrega para hacer algunos inventos:


No habiendo nada mas que comentar por hoy solo me queda decirles ¡Hasta la próxima!

Fuentes y Recursos (La mayoría en inglés)

27 comentarios:

Maurcio Rodriguez dijo...
Este comentario ha sido eliminado por el autor.
Maurcio Rodriguez dijo...

hola que ondas pues tengo una consulta ... yo tengo un proyecto con un lector de barras y lo que quiero es que cuando haga una lectura el escaner el dato que lee lo mande por UART.... como puedo leer ese dato del USB en el raspberry pi?

Unknown dijo...

hola,
Que programa me recomiendas para una conexion serial bilateral entre Raspberry y Arduino?
Esta copnexion serial es capaz de alimentar al Arduino o necesitamos fuente externa? en ese caso no es mejor una conexion serial por USB usando Minicom?
Un saludo y gran blog.

Mario Gómez dijo...

¡Hola Mauricio!

Primero necesitas un circuito capaz de "igualar" los niveles de voltaje entre UART y la Raspberry Pi. Si es un puerto serial estándar podrías intentar con el integrado MAX3232 que convierte los niveles de voltaje del puerto serial a 3.3V que puede utilizarse fácilmente con la Raspberry Pi.

Para leer datos del puerto puedes tomar como ejemplo el código que publiqué en la entrada Seguro programable con Arduino y Raspberry Pi (Parte 2) para monitorear los datos que vienen del puerto serial.

Una vez leas los datos solo es de que modifiques tu programa para que haga lo que necesites.

¡Saludos!
Mario

Maurcio Rodriguez dijo...

Hola Mario !!!!

Si el circuito MAX 232 lo tengo, ya puedo igualar el voltaje....lo que no puedo es leer ni capturar es el dato que manda el lector de barra USB manda al raspberry.
no encuentro el archivo donde guarda el dato ya probe con :
lsusb y da que el lector esta en :
/dev/bus/usb/006 con un archivo que se llama 005 de tipo caracter especial, el cual no puedo leer, quisiera saber si tu sabes donde puedo encontrar ese archivo. de antemano gracias Mario...

Mario Gómez dijo...

!Hola Mauricio!

¿Qué marca y modelo de lector de código de barras estás usando? Dejame buscar algo de info tal vez encuentro algo que te pueda ayudar.

¡Saludos!
Mario.

Mario Gómez dijo...

¡Hola Unknown!

En lo personal yo solo utilizaría los pines del Raspberry Pi para enviar y recibir datos, no para alimentar un circuito, a menos que sea algo muy pero muy sencillo como un LED.

¿Por qué? Las corrientes que proveen los puertos GPIO son muy pequeñas por lo que si piensas alimentar un circuito externo debes estar seguro de que la carga que colocaras sobre el puerto no sea demasiado grande para evitar dañar la Raspberry Pi.

Mi recomendación personal es que utilices una fuente externa para alimentar tu Arduino y asi te evitas dolores de cabeza. Solo recuerda que los tierras tienen que estar conectados y pon mucha atención a los niveles de voltaje. Recordá que la Raspberry Pi trabaja con 3.3V y la mayoría de modelos de Arduino trabaja con niveles TTL de 5V.

¡Saludos!
Mario.

Maurcio Rodriguez dijo...

Hola Mario
ahora por la mañana solucione el problema del USB. pude guardar lo que queria del USB con este codigo:

cat stdin > doc.txt

la lectora la conecto al USB del raspberry y al final trabaja como que es un teclado .. ahora lo que guarde en doc.txt tengo que mandarlo al puerto serial ... seguiré leyendo tu blog esa parte es la que necesito ahora... gracias cualquier pregunta que tenga a futuro no dudo en llamarte muchas gracias

Joel Gornati dijo...

Hola, no me anda el comando este
$ tty -F /dev/ttyAMA0 9600
tty: invalid option -- 'F'
Try `tty --help' for more information.

estoy intentando comunicar con un pic

el programa que tiene es muy parecido al de arduino, el problema era que al ejecutar

cat /dev/ttyAMA0 el puerto serie leia algo pero eran todas AAAAxA y despues simbolos raros, y ahora no lee nada... que paso???????

Eduardo Gracia dijo...

Genial, precisamente acabo de adquirir una Rpi y un Arduino uno para empezar a jugar con ellos.

Por cierto, lo de que te has mudado a la cocina.... ¿Te has mudado tu o "te han mudado"?.

A mi también me han desterrado a la cocina con todos mis cacharros, creo que mi próximo destino será el garaje.

Mario Gómez dijo...

Joel, gracias por el comentario, es un error de teclado que cometí en el blog. El comando correcto es "stty" en este momento lo corrijo.

¡Saludos!
Mario

franck edwin dijo...

hola, esta genial el post, pero luego desde python como hago para almacenar en una variable el valor leido por el puerto serie?

franck edwin dijo...
Este comentario ha sido eliminado por el autor.
Maurcio Rodriguez dijo...

hola franck
pos yo estuve haciendo unas pruebas con el puerto serial, luego de hacer lo que Mario dice en el post sobre los archivos ocupe este comando >


import time
import serial
esa = serial.Serial(port='/dev/ttyAMA0', baudrate=38400, timeout=1)
centroamerica=esa.read(ser.inWaiting())

lo que este en el puerto ttyAMAO lo tendras en la variable que se llama centroamerica
y de ahi tu sabras lo que haras ... espero te sirva

franck edwin dijo...

Hola Mauricio, gracias por tu aporte, solo que cuando llego al (ser.inWaiting) ser no es una función definida, por tanto donde se defini esta función?

Gracias.

Mario Gómez dijo...

¡Hola Frank!

La funcion in.Waiting() espera a que existan datos en el puerto serial que puedan ser leidos por la función read().

Si te da el error de que la función no está definida, verifica que tengas una versión reciente de PySerial. En esta página podes encontrar las instrucciones de instalación:

http://pyserial.sourceforge.net/pyserial.html#installation

franck edwin dijo...

Hola Mario,

Muchas gracias por tu anotación y pues hasta aquí llegue, instale el pySerial de varias formas y nunca me reconoció la función in.Waiting()

Maurcio Rodriguez dijo...

Bueno Franck
y ya probaste con solo poner read()
..... sin ponerle in.Waiting() proba asi y mira que pasa ejemplo:

>>centroamerica=esa.read()

Esto te deberia de leer la primera letra y guardarla en centroamerica...

sino es eso te recomiendo que vayas a la carpeta ttyAMAO y abras con cat y mirar lo hay en esa carpeta, manda de nuevo algo y vuelve a leer , si tu problema sigue es porque posiblemente tienes mal configurado el puerto Serial.

esta pagina me ayudo mucho en eso
http://pyserial.sourceforge.net/shortintro.html

franck edwin dijo...

Hola Mauricio y Mario,

Gracias por tu aporte y te cuento que ya me lee los datos del puerto serie, he utilizado sencillamente la función readline(). a diferencia de usar read() es que me permite guardar un entero completo, es decir, si por el purto esto recibiendo un valor ej: 25874 con redline() me almacena el entero completo, ahora si utilizo read(), solo me almacena en la varialbe el primer digito 2, tengo que volver a leer el puerto para que me enseñe digito a digito.

Por tanto aquí es donde radica el problema.

Yo necesito estar leyendo constantemente un valor por el puerto serie, pero dentro de mi código tengo una función que me pide entrar un valor por teclado con raw_input() y este comando es bloqueante, es decir hasta que no entre un valor por el teclado no me muestra lo que estoy leyendo por el puerto serie.

Sabes si existe una función o hay alguna manera de estar mostrando la lectura del puerto serie hasta que me detecte que entre un valor por el teclado?

Gracias.

Mario Gómez dijo...

¡Hola Frank!

Lo que necesitas es leer el puerto serial en un hilo de ejecución secundario. Así el hilo estará leyendo constantemente el puerto serial sin que los datos que estás leyendo desde el teclado interrumpan la lectura.

Esto lo puedes hacer de manera muy sencilla en Python.

Revisa la entrada del Inclinometro Digital con Arduino y revisa la sección que dice "Monitoreando el puerto serial" el código es sumamente sencillo son 2 o tres líneas que se encargan de leer el valor del puerto y almacenarlo en una variable, esto se ejecuta en un hilo secundario por lo que tu aplicación puede seguir corriendo sin problema, para el caso del inclinometro el hilo principal es el que se encarga de dibujar la pantalla, mientras que el hilo secundario lee los datos de inclinación desde el Arduino.

franck edwin dijo...

Hola Mario,

Excelente tu información muchas gracias. con tu inforamción he logrado implemetar los dos hilos y ahora todo me va perfecto.

Un saludo y gracias tanto a tí como a Mauricio por el aporte, me ha sido de gran ayuda.

Carlos Hernandez dijo...

Hola,
para empezar woww muy buen blog, bueno ahora si jaja, tengo una duda en la que ojala me puedas ayudar, tengo undato numerico, supongamos un 59, este numero es una variable dentro de un script hecho en python y lo k kiero es mandar ese nuemro a otra raspi pero lo nesesito hacer por infrarrojo, k podria hacer, si me contestars a mi correo mejor, carlos_wolfi@hotmail.com
gracias

WA dijo...

Hey un gran trabajo. Muchas gracias por compartirlo. Excelente Mario todo un crack.

Someby Elseee dijo...

Hola mario, con respecto a lo de igualar voltajes, tengo un convertidor de sparkfun https://www.sparkfun.com/products/11978 no se si este me puede salvar de comprar los transistores y resistencia, y de ser asi me dices como implementarlo...

Meta dijo...

Interfaz Java y Arduino.

Tutorial diseño de interfaz con Java bajo NetBeans para controlar Arduino desde el puerto serie / USB, odrás encender y apagar un Led, recibir mensajes de textos o comandos desde Arduino.

Ver tutorial.
http://www.slideshare.net/Metaconta2/interfaz-java-y-arduino

Saludos.

Angel Cardenas dijo...

si deseo conectar la raspi para que mande un pulso de voltaje a uno de los pines digitales del arduino como lo programaria y me serviria el mismo arreglo de programacion que el tuyo y de conexiones con transistores

Fermín dijo...

Una pregunta. El conversor de niveles que has montado; las masas van conectadas al GND de la Raspi solamente?
Gracias por la aportación, muy interesante