En muchos tutoriales anteriores hemos explicado el formato para enviar datos de nuestra aplicación con App Inventor a nuestros robots con Arduino. Pero ahora nos toca hacer lo contrario. Enviar datos de nuestro robot a nuestra aplicación móvil.

Este caso es muy útil cuando tenemos un robot con el que no hay contacto visual, por ejemplo detectando obstáculos con un sensor ultrasonido y esa información nos sería útil para saber si debemos elegir un camino u otro para avanzar por un laberinto por ejemplo. No haría falta saber la ubicación de nuestro robot dentro del laberinto pero la información que nos llegaría al móvil sería suficiente para saber por dónde habría que avanzar.

Para ello, vamos a crear una aplicación móvil en la que dispondremos de un modelo de comunicación Bluetooth como ya explicamos en otros post anteriores o podéis acceder a más información desde el siguiente enlace.

En otros tutoriales ya hemos hecho comunicaciones similares con un objetivo práctico para aprender más las opciones de nuestras comunicaciones.

Pero a todo esto, enviar un dato del sensor de mi placa Arduino a mi aplicación Bluetooth, quizás no sea tan evidente. Desde un principio ya sabíamos que cada dispositivo dispone de dos pines; que en una comunicación entre dos módulos Bluetooth tendremos un total de 4 pines; dos en el móvil y dos en el robot. Cada pareja tiene un pin de transmisión y otro pin de recepción. Pero hasta ahora solo hemos usado el de transmisión de datos de nuestro móvil al pin de recepción de nuestra placa.

Ahora vamos a utilizar el pin de transmisión de nuestra placa para leer en recepción con nuestra aplicación móvil.

Para este apartado hemos de comprender quién maneja los eventos . Antes, el que ejecutaba la comunicación era el usuario al presionar un botón de forma manual. Ahora el encargado de ejecutar la acción es el robot, por lo que vamos a introducir un modelo de programación por eventos.

  • Arduino Event Model
  • App Inventor Listener
  • ASCII character data

Arduino Event Model

El modelo de definición de eventos trata en aplicar un cambio, solamente en el momento que ocurre un cambio en la información a procesar. Como nuestro robot funciona en bucle, repitiendo una y otra vez el contenido de su programa, es una mala práctica mandar señales por Bluetooth indefinidamente sin tener en cuenta que estaríamos saturando el programa. En tal caso, ralentizaríamos nuestro robot en cada iteración y el efecto final es visible con un bajo rendimiento y con muchos fallos. Más a tener en cuenta si estamos realizando múltiples acciones al mismo tiempo.

Nuestro objetivo es mandar una comunicación solamente en el único momento en el que se captura un cambio o un evento en el sensor definido.

El primer condicional es el conocido filtro para leer datos Bluetooth a la placa. En este caso mandamos un número para mover un servomotor.

El que nos interesa es el modelo programado más abajo. Éste es un  bloque de definición de eventos que se ejecuta solamente cuando la lectura del sensor digital cambia.

Realmente este bloque está realizando el siguiente código.

if(digitalRead(10) != estado_anterior){
  	estado_anterior = digitalRead(10);
  	  if (estado_anterior == true) {
      comm.println("ON");
    } else {
      comm.println("OFF");
    }

  }

Si lo estudiamos detenidamente, estamos utilizando una variable denominada “estado anterior” que memoriza el valor que tenía el sensor en la iteración anterior. Si en la iteración presente el sensor cambia de estado, entonces capturaremos con el condicional ese evento, definiendo que el valor presente es distinto al valor anterior, realizamos la acción a realizar debida al evento y actualizaremos esa variable de memoria para igualarla al estado actual del sensor. De esta manera, en la siguiente iteración si el sensor no ha cambiado de valor, los dos estados serán iguales y no se desarrollará ninguna acción, ya que no se ha capturado ningún evento.
Este modelo de eventos se explica en el siguiente enlace.



#include <SoftwareSerial.h>
#include <Servo.h>

String BT_data;
boolean estado_anterior;

SoftwareSerial comm(2,3);
Servo motor;

void setup() {
  Serial.begin(9600);
  comm.begin(9600);
  pinMode(10, INPUT);

  BT_data = (String)("");
  estado_anterior = (boolean)(false);
  motor.attach(5);

}

void loop() {
  if (comm.available()) {
    BT_data = (comm.readString());
    Serial.println(BT_data);
    motor.write((BT_data.toInt()));
  }
  if(digitalRead(10) != estado_anterior){
  	estado_anterior = digitalRead(10);
  	  if (estado_anterior == true) {
      comm.println("ON");
    } else {
      comm.println("OFF");
    }

  }
}


App inventor Listener

Un Listener vamos a definirlo como un escuchador. Este es el bloque del programa que está atento a cualquier cambio y en el momento que se reconoce este cambio se ejecuta una acción ante un evento definido.

En el caso de nuestra placa Arduino, el mero hecho de funcionar en un bucle nos proporciona la esencia de capturar en cada una de sus iteraciones si se captura un evento o no.

Pero ahora hemos de disponer de este modelo en App Inventor. Y para esto, necesitaremos una ejecución en bucle. Para ello, utilizaremos un reloj, que nos permite declarar un intervalo de tiempo en el que se va a repetir el Listener.

El Listener está definido a atender la llamada cada 2 segundos. Este valor es bastante elevado para una comunicación Bluetooth, así que lo reduciremos para repetirse en un valor menor. 300 milisegundos es un valor recomendado.

En este sentido temporal hay que pensar en dos aspectos. Por un lado el intervalo de tiempo de repetición debe ser suficientemente pequeño para que dé la sensación de responder de forma inmediata. Si dejamos mucho tiempo entre lectura y lectura; como en el ejemplo 2 segundos; en ese tiempo pueden suceder tantos cambios de lectura sin que nuestra aplicación los recopile.

Sin embargo, si el intervalo de tiempo es muy pequeño, saturaremos la aplicación con tantas llamadas, que podemos obstruir el comportamiento fluido de nuestra aplicación. Así que hay que pensar en un punto medio.

Para hacer algunas pruebas de test, podemos montar un Slider con el que modifiquemos el valor de este intervalo de tiempo y así poder elegir el más apropiado. Pondremos como valor máximo 2000 milisegundos.

 

ASCII Characters \r\n

El texto enviado de un Bluetooth al otro pueden contener algunos caracteres invisibles y esto nos puede perjudicar si no los tenemos en cuenta para filtrar la información que llega de un receptor.

En este caso hemos de tener muchísimo cuidado, sobre todo a la hora de enviar datos con salto de linea. Aunque nosotros no lo veamos, cuando enviamos un dato, podemos elegir dos opciones, print o println.

En el caso de utilizar la primera, no tendremos problema a la hora de capturar la información, ya que se envía el dato sin caracteres adicionales.

En el segundo caso, enviaremos estos datos invisibles que se corresponden con el salto de linea. Y el salto de linea introduce al final de nuestros datos los siguientes caracteres. \r\n

Ahora que sabemos envíar datos de nuestra placa a nuestra aplicación y viceversa, podemos empezar a pensar qué opciones se nos ocurren para crear un proyecto chulo.