jueves, 5 de diciembre de 2013

Ejemplo Bluetooth más completo

Bueno después de casi un año sin mucho tiempo, ahora que ando un poco más libre me ha dado tiempo de hacer un ejemplo de comunicación Android-Arduino basado en el primero, pero añadiéndole cosas bastante interesantes, que son las que habéis ido preguntando en los comentarios. Ya siento no haber podido contestar a los comentarios, pero he andado muy liado. Los que habíais preguntado me imagino ya que lo habéis conseguido solucionar, pero para personas que tengan las mismas dudas puede ayudar.
Después de este royo comencemos.


El montaje con el Arduino es exactamente el mismo que en el ejemplo anterior. Cuatro diodos conectados cada uno con una resistencia y a las salidas 13 12 11 10 digitales y el bluetooth conectado también a la placa. Solo he hecho un pequeño cambio en la conexión del bluetooth y es que en vez de conectarlo a la alimentación, lo he conectado a la salida 7. Esto es únicamente para poder reiniciarlo pulsando en el botón de reset, ya que si tienes el bluetooth conectado con tu móvil y en AppInventor haces modificaciones en la parte gráfica, este se queda bloqueado.



El programa para Android lo he hecho con la nueva versión del AppInventor (enlace). La verdad es que no sabía nada de que había una nueva versión y al usarla me ha resultado bastante agradable.
Lo primero de todo entramos en AppInventor y creamos un nuevo proyecto (por ahora creo que los proyectos antiguos no te valen para el nuevo AppInventor).
Es prácticamente igual que la primera aplicación solo que añadimos un botón para desconectar, un Layout horizontal, para organizar los botones ,un Notifier para mostrar alguna notificación y un ListPicker que ahora explicare su propósito. Este ListPicker lo tengo como no visible ya que accederemos a él a través de otra acción.

Ahora pasamos a la parte de programación por bloques.
Lo primero de todo es el botón conectar. Como alguno me preguntó sobre como saber la MAC de nuestro bluetooth, lo que voy a hacer es que al pulsar en conectar, nos muestre todos los dispositivos sincronizados con nuestro móvil.

Con esto solo hacemos que al hacer click en el botón conectar, compruebe si está conectado a algún dispositivo. Si está conectado, muestra una notificación, si no está conectado, establece como elementos de la ListPicker todos los dispositivos que han sido sincronizados con nuestro móvil Android, y nos abre la lista. En la lista nos deberían aparecer las MAC de cada dispositivo seguida de su nombre. A mí me aparecen solo dos dispositivos, ya que con el móvil que hago las pruebas (LG Optimus 2X), solo tengo sincronizados dos dispositivos, otro móvil, y el bluetooth del Arduino.
El siguiente evento que tenemos que gestionar es que pasa cuando pulsamos en uno de nuestro dispositivos:
Estos bloques lo que hacen es que después de pulsar en un elemento de la lista, coja el elemento seleccionado y se conecte a esa MAC. En realidad el texto que le pasamos es la MAC un espacio y el nombre, pero AppInventor directamente coge solo los primeros 17 caracteres, por lo que no hace falta recortar el String.
Aquí podíamos añadir alguna notificación del tipo "Conectado"o "No conectado". Yo no e añadido nada ya que cuando estemos conectados al bluetooth de nuestro Arduino lo vamos a saber ya que dejará de parpadear el led y se quedará fijo.

El otro botón que tenemos que configurar es el de desconectar. Lo único que hace es desconectar el bluetooth al pulsar.

Bueno hasta aquí tenemos una primera parte completada. Ahora voy a poneros el código que he puesto en el Arduino, así podéis ir probando poco a poco lo que vayáis haciendo con AppInventor sin tener que ir actualizando el programa del Arduino. Quiero comentar que el bluetooth lo he conectado en el Serial3 para evitar problemas a la hora de actualizar el programa.
Antes de nada una breve explicación del funcionamiento. Este programa va a estar todo el rato si le llega algún dato desde el bluetooth (como el otro ejemplo), pero en vez de directamente usar ese dato, va ir metiendo todos los datos en una cadena hasta que le llegue el carácter '#' (podéis elegir otro). Una vez que tiene el comando completo, ejecuta diferentes acciones.
Otra de las cosas que me preguntasteis en el anterior ejemplo de bluetooth era como enviar mensajes del Arduino al móvil, pues bien, vamos a enviar un mensaje de comprobación para que cuando se establezca la conexión, el Arduino le diga al móvil el estado real de los diodos (encendido o apagado), ya que en el anterior ejemplo, si hacíamos en la aplicación de Android cuando el bluetooth no estaba conectado, se producía una descoordinación (los diodos que habíamos cambiado en nuestra aplicación no se había cambiado en el Arduino, y al volver a conectar la información no era la correcta).

El código ha quedado un poco largo pero es por los comentarios, si los quitas queda bastante corto.


//dato va a ser el entero donde almacenaremos los datos que iremos 
//recibiendo desde el bluetooth
int dato;



//i lo vamos a usar para crear un vector de caracteres a partir de los
//datos recibidos
int i=0;

//Le indicamos cada diodo en la patilla a la que la vamos a conectar.
int ledAzul=13;
int ledRojo=12;
int ledNaranja=11;
int ledVerde=10;

//Inicializamos todos los diodos como apagados
boolean estadoAzul=false;
boolean estadoRojo=false;
boolean estadoVerde=false;
boolean estadoNaranja=false;

//Esta variable la vamos a usar para saber si hemos empezado a recibir
//datos, pero todavía no nos ha llegado el comando entero (no nos ha
//llegado la #)
boolean mensajePendiente=false;

//Aquí iremos almacenando cada uno de los caracteres hasta que nos
//llegue '#', he definido tamaño 6, si os hace falta más grande o
//pequeño, definidlo a vuestro gusto
char mensaje[6];

//Aquí almacenaremos el comando una vez que haya llegado completo
String comando;

void setup(){
  //Iniciamos el puerto Serial3, si no tenéis Arduino Mega usad Serial,
  // pero tendréis que tener cuidado a la hora de transferir los 
  //programas al Arduino
  Serial3.begin(9600);

  //Inicializamos los puertos de los diodos como salidas
  pinMode(ledAzul,OUTPUT);
  pinMode(ledRojo,OUTPUT);
  pinMode(ledVerde,OUTPUT);
  pinMode(ledNaranja,OUTPUT);

  //Esto es para lo que he comentado de reiniciar el bluetooth cuando
  //se queda colgado. 
  pinMode(7,OUTPUT);
  digitalWrite(7,LOW);
  digitalWrite(7,HIGH);
}

void loop(){
  //Actualizamos continuamente el estado de cada diodo.
  digitalWrite(ledVerde,estadoVerde);
  digitalWrite(ledAzul,estadoAzul);
  digitalWrite(ledRojo,estadoRojo);
  digitalWrite(ledNaranja,estadoNaranja);

  //Leemos un dato
  dato=Serial3.read();

  //Comprobamos si nos llega un dato, ya que si leemos el puerto
  //Serie, y no tenemos hemos recibido dato nos aparece '-1'
  if(dato>0){
    //Si hay dato lo almacenamos en la posición que le corresponda e
    //incrementamos una posición, ya que tenemos que el mensaje nos va
    //a llegar por partes, primero nos llegara una letra, después un
    //rato sin recibir nada (-1) luego otra letra...
    mensaje[i]=(char)dato;
    i++; 

    //Si estamos dentro de esta condición, significa que hemos empezado
    //recibir un mensaje
    mensajePendiente=true;

    //Comprobamos si nuestro dato es el último de nuestro código ya
    //que el 35 es el código ASCII de '#'. También se podría haber hecho
    //con Serial3.available(), pero me pareció más sencillo así
    if(dato==35){
      //Si es así, metemos en comando, todo el texto que haya en
      //mensaje[] hasta la '#'
      comando=(String)mensaje;
      comando=comando.substring(0,comando.indexOf('#'));

      //Reiniciamos el contador de la posición del mensaje y ya hemos
      //terminado de recibir nuestro mensaje
      i=0;
      mensajePendiente=false;

      //Realizamos las acciones dependiendo de nuestro comando
      //Las cuatro primera son las mismas que en el otro ejemplo.
      //Estas códigos los he elegido yo y tienen que ser los mismos
      //que se pongas después en el AppInventor
      if(comando=="1"){
         estadoVerde=!estadoVerde;
      }else if(comando=="2"){
         estadoNaranja=!estadoNaranja;
      }else if(comando=="3"){
         estadoRojo=!estadoRojo;
      }else if(comando=="4"){
         estadoAzul=!estadoAzul;
      }else if(comando=="check"){
         //Esta es la parte nueva y es lo que voy a utilizar para 
         //comprobar el estado de cada diodo. Se podía haber puesto de
         //una forma mucho más compacta pero teniendo en cuenta que 
         //AppInventor para alguna cosas es algo limitado, me pareció 
         //la forma más cómoda de enviar el código.
         //Lo único que hace es enviar el estado de cada diodo como un                    
         //mensaje separado.
         Serial3.write(estadoVerde);
         Serial3.write(estadoNaranja);
         Serial3.write(estadoRojo);
         Serial3.write(estadoAzul);
      }
    }
  }
}


Con esto tenemos toda la programación necesaria en nuestra placa Arduino para poder probar nuestro progreso.
Ahora, el resto de código de nuestro programa en AppInventor.
Lo primero que tenemos que hacer es crear una variable para decidir cuando queremos que los botones envíen información al Arduino y añadir que se desactive (que se ponga en false) cuando pulsemos en el botón Desconectar.



Con esto establecemos las acciones al pulsar cada botón, teniendo en cuenta la condición que le hemos impuesto. La acción es que envíe un comando (que ya hemos configurado en el programa de Arduino) si está activa la condición de "botonesActivos".


Lo que nos falta es crear una función que se ejecute cuando nos conectemos (pulsemos en uno de los dispositivos que nos aparece en el ListPicker) para actualizar el estado de nuestro "Diodos" en el móvil. Para ello creamos una función personalizada (Procedure) y decimos que se ejecute después de conectar.
(Solo hemos añadido la parte de la función "actualizarDiodos" a la acción de cuando pulsamos en el ListPicker)
Y por último la función que actualiza el estado de los diodos.
Esta función lo único que hace es envía el comando de comprobación, y recibe y compara con 1 el estado(0 ó 1) de cada uno de los diodos y dependiendo de esto los marca o los desmarca. Además activamos de nuevo los "botenesActivos", con esto nos evitamos que cuando cambiemos el estado (durante la comprobación) de los Checkbox, se envíe al Arduino, que lo que haría sería cambiar su estado real, por lo que volverían a no coincidir.

Hay que tener en cuenta que todo lo que envíes por el puerto serie, en la dirección que sea, si no lo lees al momento, se queda pendiente. Esto puede provocar problemas de descoordinación (que recibamos mensajes con retraso).

Con esto espero haber resuelto las dudas que hayan surgido o puedan surgir. Esto es solo un programa de base con poco aplicación en sí, pero con pequeñas variaciones se puede adaptar a multitud de necesidades.

Por último dar las gracias por leer el "tochazo" que he escrito que no tiene pinta de ser muy entretenido y pedir disculpas a aquellas personas que me habían preguntado dudas y no había tenido tiempo de contestar.

Cualquier duda, error o simplemente un comentario de agradecimiento o crítica será bien recibido.

Ambos archivos los puedes descargar desde aquí.

Nos vemos pronto (espero)



7 comentarios:

  1. Oye y como hago para enviar texto por bluetooth?
    digamos que escribo un mensaje largo y lo quiero enviarpor bluetooth
    como seria o que bloques ocupo'
    saludos?

    ResponderEliminar
    Respuestas
    1. En los bloques de los check box aparecen esos bloques claramente.

      call BluetoothClient1. Send Text
      text -> "Aqui lo que quieras enviar"

      Un saludo.

      Eliminar
  2. que tal amigo cheveres tus tutoriales.....talvez sabes como le puedo hacer lo mismo que se hace con el monitor serial del arduino ,pero yo quiero que esos datos se puedan ver en mi celular,,,,ejemplo quiero visualizar la variación de temperatura

    ResponderEliminar
  3. que buen ejemplo. me esta ayudando mucho
    pero tengo un porblema. no se conecta a BT la app. me dice un error de
    need bluetooth_admin
    permission : neither user 10110
    ...
    deduzco que no tiene permiso de utilizar el BT. pero no se como dárselo

    ResponderEliminar
  4. Hola.
    Alguien que tenga los programas?

    ResponderEliminar