Así que has hecho destellar algunos LEDs con Arduino y quizás hasta has dibujado bellas imágenes con Processing, pero ¿cuál es el siguiente paso a seguir? A este punto quizás te estés preguntando ¿existirá alguna forma de que Arduino y Processing se comuniquen? bueno, adivina que, si existe y en este tutorial te explicaremos cómo hacerlo.

En este tutorial aprenderás:

  • Como enviar datos desde Arduino a Processing mediante un puerto serial.
  • Como recibir datos de Arduino en Processing.
  • Como enviar datos desde Processing a Arduino.
  • Como recibir datos de Processing desde Arduino.
  • Como escribir un “handshake” entre Arduino y Processing mediante una puerta serial para control de flujo.

Antes de que comencemos hay un par de cosas con las que deberías estar familiarizado para poder aprovechar al máximo este tutorial:

  • Que es Arduino
  • Como usar una protoboard
  • Trabajando con la librería wire
  • Que es la comunicación serial

Conocimientos básicos de Processing pueden ser útiles pero no son estrictamente necesarios.

Desde Arduino

Te mostraremos los pasos básicos acerca de cómo hacer que un Arduino envíe información básica a través de un puerto serial.

  • Primero. Si aún no lo has hecho, descarga e instala el software de Arduino para tu sistema operativo. Puedes seguir el siguiente tutorial de instalación de Arduino en Windows.
  • También necesitaras un microcontrolador compatible con Arduino y una forma apropiada de conectarlo a tu computador (cable USB).

Hasta este punto deberías tener tu software de Arduino instalado, una placa Arduino de cualquier tipo y un cable USB. Ahora a programar:

  • Abre el software de Arduino. Deberías ver algo como esto.
proce1

Ese gran espacio blanco es donde vamos a escribir nuestro código. Haz clic en el área blanca y tipea lo siguiente (o copia y pega si ya tienes practica en esto):

void setup()
{
//esto inicia una comunicación serial a una tasa de 9600 baudios
Serial.begin(9600);
}

Esto se llama el método setup y es donde ponemos las opciones de nuestro programa. Aquí, lo estamos usando para iniciar una comunicación serial entre el Arduino y nuestro computador a una tasa de bits de 9600 que es la velocidad a la que enviaremos los datos a nuestro computador. Esta tasa de bits debe ser la misma que debes configurar en tu computador, ya que si son diferentes no podrán entenderse entre ellos.

Después de nuestro método setup() necesitamos un método llamado loop(), que se va a repetir todo el tiempo mientras nuestro programa se ejecute. Para nuestro primer ejemplo enviaremos el texto “hola mundo” a través del puerto serial una y otra vez. Para esto, escribe lo que esta abajo en tu sketch de Arduino debajo de lo que escribimos anteriormente:

void loop(){
//envía “hola mundo” por la puerta serial
Serial.println("hola mundo");
//espera 100 milisegundos para que no nos vuelva loco la repetición  
delay(100);}

Eso es todo lo que necesitamos desde el lado de Arduino para este ejemplo, lo que estamos haciendo aquí es abrir una comunicación serial en Arduino y diciéndole que envíe datos cada 100 milisegundos. Tu sketch de Arduino debería verse en este momento más o menos así:

proce2

Todo lo que te queda por hacer es conectar tu Arduino y elegir el tipo de tarjeta (opción herramientas  -> tipo de tarjeta), puerta serial (opción herramientas -> puerto serial) y apretar el botón subir para cargar el código en tu Arduino.

Ahora estamos listos para ver si podemos detectar el “hola mundo” que mostraremos desde Processing.

Desde Processing

Nuestra tarea ahora es encontrar una forma de escuchar lo que el sketch de Arduino está enviando. Por suerte Processing viene con una librería Serial diseñada justamente para eso. Si aún no tienes el software Processing, descarga la última versión desde Processing.org. Una vez que esté instalado ábrelo y deberías ver algo como esto:

proce3

¿Se parece mucho a Arduino no? Esto es porque el software de Arduino estaba originalmente basado en Processing.

Una vez que tengamos un sketch abierto, el primer paso es importar la librería serial. Ve a sketch -> importar librería -> Serial como se muestra a continuación:

proce4

Deberías ver en pantalla una línea similar a import processing.serial.*; al principio de tu sketch.

¡Magia! bajo esta declaración deberemos agregar un par de variables globales, todo lo que esto significa es que estas variables pueden ser usadas en cualquier parte de nuestro sketch.

Añade este par de líneas bajo la declaración import.

Serial myPort;  //Crea un objeto de clase serial
String val;     //Datos recibidos por el Puerto serial

Para poder escuchar una comunicación serial debemos crear un objeto serial al que llamaremos myPort (tú puedes ponerle el nombre que quieras), esto nos dejara escuchar en un puerto serial de nuestro computador cualquier dato de entrada. También vamos a necesitar una variable donde recibir los datos que lleguen. En este caso, ya que estamos enviando una string de texto (hola mundo) desde Arduino, necesitaremos recibir ese string en Processing. Tal como Arduino tiene setup() y loop(), Processing tiene setup() y draw() (en vez de loop).

Para nuestro método setup() en Processing vamos a buscar el puerto serial al que está conectado nuestro Arduino y configurar nuestro objeto Serial para escuchar en ese puerto.

// Yo sé que el primer Puerto serial en mi Mac
// Es Serial.list()[0].
// En máquinas Windows generalmente es COM1.
// Abre cualquiera sea el Puerto que estés utilizando.
String portName = Serial.list()[0]; 
//cambiar 0, 1 o el que sea al número de puerto que estés usando
myPort =newSerial(this, portName, 9600);

En nuestro loop draw(), vamos a escuchar algo y cuando recibamos ese dato lo vamos a vaciar a la variable val y luego mostrarlo por consola (esa área negra en la parte baja de tu sketch).

voiddraw() {  
if ( myPort.available() >0){  //If data is available,  
  val = myPort.readStringUntil('\n');  //Lo guarda en val  
  } 
println(val); //Lo muestra por consola
}

Listo, si presionas el botón ”run” (y tu Arduino está conectado y tiene cargado el código que vimos anteriormente) deberías ver una pequeña ventana aparecer después de unos segundos y deberías ver en ella la frase “hola mundo” muchas veces como indica la siguiente imagen.

proce5

Excelente, con eso hemos logrado enviar datos desde Arduino a Processing. El siguiente paso es ver cómo hacer lo contrario, enviar datos desde Processing hasta Arduino.

Desde Processing

Comencemos desde el lado de Processing. Comienza de forma similar importando la librería serial y declarando una variable global serial para que utilice nuestro puerto. También vamos a utilizar el comando size, que nos abrirá una pequeña ventana donde podremos hacer clic para activar nuestro sketch y así poder enviar datos al puerto serial de Arduino. Nuestro código debería verse más o menos así:

import processing.serial.*; 
Serial myPort;  // Create object from Serial class 
void setup() {  
  size(200,200); //make our canvas 200 x 200 pixels big  
  String portName = Serial.list()[0]; //change the 0 to a 1 or 2 etc. to match your port  
  myPort =newSerial(this, portName, 9600);
}

En nuestro loop draw(), enviamos lo que sea que queramos usando el método write de la librería de procesamiento serial. Para este sketch enviaremos un 1 cada vez que hagamos clic en la ventana de procesamiento y lo enviaremos por consola. Solo para confirmar que en efecto estamos enviando algo a la puerta serial enviaremos 0 si es que no estamos clickeando nada.

void draw() {
if (mousePressed == true){  //if we clicked in the window
  myPort.write('1');         //send a 1
  println("1");  
  } 
else {                       //otherwise
  myPort.write('0');         //send a 0
  }  
}

Tu código debería verse más o menos así hasta este punto.

proce6

Si ejecutas este código, deberías ver un montón de números 1 aparecer en el área de consola mientras estás haciendo clic en la ventana.

A continuación veremos cómo ubicar estos números 1 desde el lado de Arduino.

Desde Arduino

En esta parte del tutorial buscaremos los números 1 que provienen desde Processing y si es que los vemos encenderemos el LED conectado al pin 13 de nuestro Arduino (en algunos Arduino como el Uno, el pin 13 es el LED integrado así que no necesitas un LED externo para ver que esto funciona).

Al principio de nuestro sketch necesitaremos dos variables globales, una para para vaciar los datos que vienen desde Processing y otra para decirle a Arduino en que pin está conectado nuestro LED.

char val; //Data received from the serial port
int LedPin = 13; //Set the pin to digital I/O 13

Luego, en nuestro método setup() conectaremos nuestro pin 13 como salida ya que estamos energizando un LED e iniciaremos la comunicación serial a 9600 baudios.

void setup() {
  pinMode(LedPin, OUTPUT); //Set pin as OUTPUT
  Serial.begin(9600); //Start serial communication at 9600 bps
}

Finalmente, en el método loop() leeremos los datos seriales de entrada y si vemos un número 1 pondremos el LED como HIGH y si no (por ejemplo si vemos un 0) apagaremos el LED. En el final del loop pondremos un pequeño retraso para ayudar a que Arduino lleve bien el tiempo con el enlace serial.

void loop() {
if (Serial.available()) { //If data is available to read,
  val = Serial.read(); //read it and store it in val
  }
if (val == '1') { //If 1 was received
  digitalWrite(ledPin, HIGH); // turn the LED on
  } 
else {
  digitalWrite(ledPin, LOW); // otherwise turn it off
  }
delay(10); // Wait 10 milliseconds for next reading
}

Así debería verse tu código al terminar.

proce7

Listo, ahora sube el código a tu Arduino y corre el código anteriormente escrito en Processing. Deberías poder encender el pin 13 de tu Arduino al hacer clic en la ventana de Processing.

Handshake (parte 1)

Hasta ahora hemos aprendido que Arduino y Processing pueden conversar mediante comunicación serial cuando uno está hablando y el otro escuchando. Entonces, ¿podemos hacer un enlace que permita el flujo de datos en ambas direcciones de modo que Arduino y Processing puedan enviar y recibir datos? ¡Claro que sí! A esto se le llama apretón de manos o “Handshake” Serial ya que ambos lados deben ponerse de acuerdo en que momento enviar y recibir datos.

En esta página y la siguiente vamos a combinar nuestros dos ejemplos previos, de tal forma que Processing pueda recibir un “hola mundo” de Arduino y pueda enviar un numero 1 de vuelta para encender un LED en Arduino.

Comencemos desde el lado de Arduino. Para que esto pueda funcionar correctamente, ambos lados deben saber qué es lo que deben decir y que es lo que el otro lado espera escuchar. También buscamos minimizar el tráfico de datos en el puerto serial y así tener repuestas más oportunas.

Al igual que en nuestro ejemplo de lectura Serial, necesitaremos una variable tanto para los datos de entrada como para el pin LED que buscamos encender:

char val; // Data recibida desde el Puerto serial
int LedPin = 13; // asocia el LED al pin digital 13
boolean LEDState = LOW; //enciende el LED

Ya que buscamos ser eficientes, vamos a cambiar nuestro código para que solo escuche números 1 y que cada vez que los reconozca, encenderá o apagara el LED. Para hacer esto agregaremos una variable Boolean (verdadero o falso) para el estado HIGH o LOW de nuestro LED. Esto significa que no tenemos que enviar constantemente 1 o 0 desde Processing, lo que libera un poco la carga de nuestra puerta serial.

Nuestro método setup() se ve casi igual con la excepción de una función establishcontact() que veremos más tarde, por ahora solo la tipiamos.

void setup(){
  pinMode(LedPin, OUTPUT); // configure el pin como salida
  //inicializa la comunicación serial a 9600 baudios
  Serial.begin(9600);
  establishContact();  // envía un byte para establecer contacto hasta que el receptor responda
}

En nuestra función loop lo único que hicimos fue combinar y reducir el código de nuestros dos sketch anteriores, además hemos cambiado nuestro código LED para activarse en base a nuestro valor boolean. El signo ”!” significa que cada vez que veamos un numero 1 configuraremos el boolean como el contrario de lo que anteriormente señalaba (de esta forma LOW se transforma en HIGH y viceversa). También pondremos nuestro “hola mundo” en una declaración else para que solo se envíe cuando no se esté recibiendo un “1”

void loop(){
If (Serial.available() > 0) {  //si los datos están disponibles para leer,
  val = Serial.read(); / /leerlos y guardarlos en val
  if(val == '1'){ //si recibimos un 1
    LEDState = !LEDState; //cambiar el LEDState
    digitalWrite(LedPin, LEDState);
    }
  delay(100);
  }
else {
  Serial.println("hola mundo"); //de otra forma enviar un hola mundo
  delay(50);
  }
}

Ahora llegamos a la función establishcontact() que pusimos en nuestra función setup (). Esta función lo único que hace es enviar un string (el mismo que necesitamos buscar en Processing) para ver si escucha algo de vuelta, lo que le indica a Processing que está listo para recibir datos. Es como decir “Marco” una y otra vez hasta escuchar de vuelta “polo” de alguna parte.

void establishContact() {
  while (Serial.available() <= 0) {
  Serial.println("A");   // envía una A mayúscula
  delay(300);
  }
}

Tu código de Arduino debería verse más o menos así.

proce8

Eso es todo en el lado de Arduino ahora volvemos a Processing.

Handshake (Parte 2)

Desde el lado de Processing tenemos que hacer un par de cambios. Primero vamos a hacer uso de la función serialEvent() que llamaremos cada vez que veamos un carácter específico en el buffer serial, lo que actúa como nuestro delimitador. Esto básicamente le dice a Processing que ya hemos terminado con un pedazo de data, en nuestro caso “hola mundo”

El principio de nuestro sketch es el mismo a excepción de un boolean nuevo llamado firstContact, que nos permite saber cuándo hemos hecho una conexión con Arduino.

import processing.serial.*; //Importa la libreria serial
Serial myPort;  //El objeto Puerto serial
String val;
//Ya que estamos hacienda un handshake
//Necesitamos saber si hemos hecho contacto con el micro controlador
boolean firstContact = false;

Nuestra función setup() actúa de la misma forma que usamos para escribir en serial, a excepción de que agregamos la línea myPort.buferuntil (‘\n’); Esta línea nos deja guardar los datos de entrada en un buffer hasta que encontremos el carácter en específico que estamos buscando, en este caso un retorno de carrera (\n). Ya que lo que enviamos desde Arduino, sabemos que utilizamos la forma Serial.println, el “ln” al final significa que el string está terminado con un retorno de carrera así que sabemos que esa será la última cosa que vamos a ver

void setup() {
  size(200, 200); //hace que nuestro lienzo sea de 200 x 200 pixeles
  //Inicializa el Puerto serial y lo configure a 9600 baudios
  myPort = new Serial(this, Serial.list()[4], 9600);
  myPort.bufferUntil('\n');
}

Ya que estamos enviando datos continuamente, nuestra función serialEvent() ahora actúa como nuestro nuevo loop draw() así que este lo dejamos vacio:

void draw() {
  //podemos dejar esto vacío ya que toda nuestra programación ocurre en la función serialEvent
}

Ahora debemos programar la función serialEvent(). Cada vez que recibamos un retorno de carro esta función será llamada. Ahora necesitamos que esta función ejecute una serie de acciones:

  • Leer los datos que llegan.
  • Verifique la existencia de datos después de una lectura (por ejemplo que no sea vacío o null).
  • Reducir los espacios en blanco y otras cosas.
  • Si es la primera vez que recibimos un dato o carácter que buscamos, cambia nuestro boolean firstContact y deja saber a Arduino que estamos listos para recibir más datos.
  • Si no es la primera vez que ejecutamos esto, entonces debemos mostrar por consola los datos y enviar de vuelta cualquiera sea la cantidad de clics (en forma de números 1) que hagamos en la ventana.
  • Finalmente debemos decirle a nuestro Arduino que estamos listos para recibir más datos.

¡Estos son una gran cantidad de pasos! Por suerte Processing tiene funciones que hacen la mayoría de estas tareas y de una manera bastante fácil. Veamos cómo es que termina resultando todo esto.

void serialEvent( Serial myPort) { //Pone los datos en un string. El '\n' es nuestro delimitador que indica el fin de un paquete
val = myPort.readStringUntil('\n');
//se asegura que nuestros datos no son espacios en blanco
if (val != null) { //Remueve los espacios en blanco
  val = trim(val);
  println(val);
//Busca nuestro string A para iniciar el handshake. Si el carácter existe limpiar el buffer de datos y envia una solicitud de datos
if (firstContact == false) {
  if (val.equals("A")) {
  myPort.clear();
  firstContact = true;
  myPort.write("A");
  println("contact");
  }
}
else { //si la conexión ya se estableció entonces seguir recibiendo datos
  println(val);
  if (mousePressed == true){  //si hacemos clic en la ventana
    myPort.write('1');        //enviar un 1
    println("1");
    }
// Cuando termine de revisar los datos, solicita mas datos
  myPort.write("A");
  }
 }
}

Parece ser bastante código, pero si lo lees con cuidado (especialmente los comentarios) tiene bastante sentido. Cuando tengas este código terminado y cargado en tu tarjeta, prueba correr este sketch y deberías ver un hola mundo en tu consola y al hacer clic en la ventana de Processing deberías ver el LED, conectado al pin 13, encenderse y apagarse.