Tag Archives: BLE

Comandos por BLE – (Parte 2 de 2) – El Transmisor (TX)

22 Jul , 2017,
Jose Nunez
, , , , , ,
No Comments

Como lo prometido es deuda, acá está la 2da entrega referente a controlar cosas con telefonos celulares mediante Bluetooth Low Energy (BLE) usando IONIC 3.

En esta segunda parte, implementaremos una App (Android y IOS) usando IONIC 3 que le envía comandos al micro-controlador mediante el sistema BLE del teléfono.

Para ver la Parte 1 haz clic acá

(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.

Programando el App

En resumen:

  1. IONIC 3 es un sistema para crear aplicaciones móviles usando tecnologías híbridas (cordova, angularjs 4, typescript, html, css, etc.)
  2. Necesitaremos configurar IONIC3 en nuestro computador; esto incluye NodeJS, NVM, NPM y IONIC.
  3. También necesitaremos un muy buen editor de código para TypeScript. Puedo recomendarles Visual Studio Code o Atom.
  4. Descargamos el código del app de ejemplo de mi repositorio de Github y lo abrimos con el IDE de ARDUINO.git clone https://github.com/janunezc/robotics.gitEl código se ubica en ~/robotics/intel_curie/ble_command_app/
  5. En el celular podemos utilizar el sistema Ionic View (descargado del App Store o Google Play) y previsualizar el app 03B50F88Las siguientes imágenes muestran la operación del app

 

Seguidamente mostramos las partes más importantes del código original del programa con los comentarios detallados sobre su funcionamiento. Es realmente sencillo; podemos resumirlo en:

  1. El tab “SCAN” implementa un proceso básico de búsqueda de dispositivos Bluetooth. No vamos a detallar mucho en este tutorial sobre ese tab.
  2. El tab “LED” implementa la búsqueda de un dispositivo específico y una vez que lo encuentra permite interactuar con el LED para encenderlo y apagarlo.
    1. Los componentes (tabs) de la aplicación IONIC3 se dividen en 3 elementos principales: una vista o view (led.html), un controlador (led.ts) y un modelo que corresponde a los datos que va a manejar la aplicación y que se ubican en el objeto this y sus propiedades públicas.
    2. El archivo led.html es realmente simple. Aparte de los párrafos de texto expicativo y títulos, posee un botón que tiene algunas características importantes de AngularJS como lo son el atributo [disabled] ligado a una variable del modelo denominada “ejecutandoComando”. Cuando la variable tiene un valor verdadero (true) el atributo disabled se activa y el botón se deshabilita. A su vez tiene una directiva (click) que ejecuta la función “Command()” del controlador.
    3. Una parte importante del archivo led.html es el último párrafo en la línea 11. Este utiliza una directiva *ngFor para iterar sobre la variable “messages” y mostrar cada mensaje como un párrafo ( <p> ) individual. Esto nos permite mostrar mensajes de aclaración conforme se ejecutan los procesos en el controlador.
  3. Exploremos ahora el archivo led.ts. Se trata de un script escrito en TypeScript. Un pseudo-lenguaje basado en JavaScript que permite una orientación a objetos más elaborada.
    1. Lo primero que se realiza en led.ts es importar las librerías necesarias. Dos de las más notorias serán BLE y ApplicationRef. La primera permite comunicación BLE, y la segunda permite manipular el framework de Angular para refrescar la pantalla cuando sea necesario.
    2. La siguiente parte super importante es el constructor, el cual implementa una serie de inyecciones de dependencia que vale la pena mencionar.
    3. Nótese la forma en que se inyectan en el constructor tanto la librería BLE como la librería de Angular ApplicationRef. En el constructor también se inicializan variables importantes tales como el ID de servicio y el ID de Característica que se van a manipular.
    4. Las funciones más interesantes en este archivo son:
      1. findDevice() que busca un dispositivo particular y una vez que lo encuentra cambia el modo de comandos para encender o apagar un LED. Para esto usa la funcion de BLE nativo denominada ble.scan()
      2. txData() que utiliza ble.connect y ble.write para conectarse al dispositivo y hacerle llegar un mensaje.
      3. SetMessage() tambien merece ser mecionado como la forma que tenemos de agregar mensajes de control que nos permitan entender cómo se está ejectuando el programa.

Espero que este artículo les sea de utilidad junto con el anterior para aprender a enviar comandos a un dispositivo BLE basado en Intel Curie, mediante el teléfono celular.

Los dejo con estos enlaces de utilidad:

  1. Aprender TypeScript: https://www.typescriptlang.org/docs/home.html
  2. Aprender Ionic 3: https://ionicframework.com/
  3. Aprender Angular 4: https://www.youtube.com/watch?v=kFTmoLm9Jwg

Que estén bien!


led.html

<ion-header>
   <ion-navbar>
   <ion-title>LED</ion-title>
   <p>Acá podemos operar el LED que está implementado en TinyTILE</p>
   <button ion-button [disabled]="ejecutandoComando" (click)="Command()">{{ComandoTXT}}</button>
</ion-navbar>
</ion-header>
<ion-content padding>
   <p>Histórico de Ejecución: ({{myCount}} | {{test}})</p>
   <hr />
   <p *ngFor="let message of messages">{{message}}</p>
</ion-content>

led.ts

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { BLE } from '@ionic-native/ble';
import { ApplicationRef } from '@angular/core';

@Component({
  selector: 'page-led',
  templateUrl: 'led.html'
})

export class LEDPage {

  public messages = []; //Histórico de ejecución
  public ejecutandoComando = false;
  public BLE;
  public ComandoTXT = "";
  public Value = "";
  public TargetDevice;
  private appRef;

  /**
   * CONSTANTES que serán usadas a lo largo del controlador
   */
  public constants  = {
      DEVICE_NAME: "COMANDO LED",
      CMD_FIND_DEVICE:"FIND DEVICE",
      CMD_STOP_SCAN:"Escaneando... (Clic para parar)",
      CMD_TOGGLE_LED:"CAMBIAR LED",
      ON:"ON",
      OFF:"OFF"
    };

  /**
   * Constructor para el controlador. Todo comienza acá...
   */
  constructor(public navCtrl: NavController, private ble: BLE /*Librería BLE nativa*/, private applicationRef : ApplicationRef /*Librería ApplicationRef de Angular*/ ) {
    this.appRef = applicationRef; //Referencia a la aplicación ANGULAR
    this.SetMessage("Constructor: Iniciado!");
    this.BLE = ble; //Acceso a la librería BLE Nativa
    this.ComandoTXT = this.constants.CMD_FIND_DEVICE;
    this.Value = "ON"; //VALOR PARA ENVIAR
    this.TargetDevice = {}; //Dispositivo al cual conectarse. Inicialmente vacío... se llenará cuando se encuentre el dispositivo en el escaneo.
    this['service_id'] = "db938b80-f010-44b6-8aa9-1835adf9419a"; //Identificador del servicio BLE a conectarse
    this['characteristic_id'] = "9906064e-9bbe-4eba-b415-bbd223f7d3d9"; //Identificador de la característica BLE a conectarse
    this.SetMessage("Constructor: Finalizado!");
  }

  /**
   * This is triggered when the button is clicked.
   */
  public Command(){
    this.ejecutandoComando = true;
    this.SetMessage("Command() - Comando recibido!");
    this.SetMessage(this["ComandoTXT"]);
    this.SetMessage("Interpretando comando...");

    if(this['ComandoTXT']===this.constants.CMD_FIND_DEVICE) {
      this.SetMessage("Ejecutando Comando: FIND DEVICE");
      this['ComandoTXT'] = this.constants.CMD_STOP_SCAN;
      this.findDevice();

    } else if (this['ComandoTXT']===this.constants.CMD_STOP_SCAN) {
      this.SetMessage("Ejecutando Comando: STOP SCAN");
      clearInterval(this['intervalHandle']);
      this['ComandoTXT'] = this.constants.CMD_FIND_DEVICE;
      this.ejecutandoComando = false;

    } else if(this['ComandoTXT']=== this.constants.CMD_TOGGLE_LED){
      this.SetMessage("Ejecutando Comando: TOGGLE LED: " + this.Value);
      this.SetMessage("Acá es donde enviamos un valor al dispositivo BLE");
      this.txData();
    }
  }

  /**
   * This searches for DEVICE in the AIR using SCAN technique.
   */
  private findDevice(){
      this.SetMessage("FindDevice() - INICIO!");
      let  ble = this.BLE;

      this.SetMessage("FindDevice() - ENABLE!");
      ble.enable();

      this.SetMessage("FindDevice() - SET INTERVAL!");
      this['intervalHandle'] = setInterval(() => { // PROGRAMAR UN TIMER DE 2.1 SEGUNDOS
        this.SetMessage("INTERVAL: INICIO! LLAMANDO A BLE SCAN...");
        ble.scan([], 2 /*seconds (0) */).subscribe( data => { //REALIZAR SCAN BLE POR 2 SEGUNDOS
          this.SetMessage("BLE SCAN CALLBACK: " + data['id'] + ' | ' + data['name'] + ' | ' + data['rssi']);
          if(data['name']==this.constants.DEVICE_NAME){
            this.SetMessage(this.constants.DEVICE_NAME + " HA SIDO ENCONTRADO!!");
            clearInterval(this["intervalHandle"]);
            this.TargetDevice = data;
            this["ComandoTXT"] = this.constants.CMD_TOGGLE_LED;
            this.ejecutandoComando = false;
          }
          this.appRef.tick();
        });
      },2100);//FIN DE LA DEFINICIÓN DEL TIMER
      this.ejecutandoComando = false;
    }

  /**
   * Transmitir datos al dispositivo BLE
   */
  private txData(){
    this.SetMessage("txData(): INICIO! Llamando a BLE CONNECT...");

    let id = this.TargetDevice.id;
    this.SetMessage("ID DE DISPOSITIVO: " + id);

    this.ble.connect(id).subscribe(datos=>{
      this.SetMessage("BLE CONNECT CALLBACK: INICIO!. Llamando a BLE WRITE..." + this.Value);

      this.ble.write(this.TargetDevice.id, this['service_id'],this['characteristic_id'], this.StringToBytes(this.Value) ).then(()=>{
        this.SetMessage("BLE WRITE CALLBACK: INICIO! Cambiando valor... " + this.Value);
        if(this.Value==this.constants.ON){
          this.Value = this.constants.OFF;
        } else {
          this.Value = this.constants.ON;
        }
        this.SetMessage("Nuevo valor... " + this.Value);

        this.SetMessage("Llamando a BLE DISCONNECT...");
        this.ble.disconnect(id);
        this.ejecutandoComando = false;
        this.appRef.tick();
      },(error)=>{
        this.SetMessage("BLE Write ERROR!");
        this.SetMessage(error);
        this.SetMessage("Llamando a BLE DISCONNECT...");
        this.ble.disconnect(id);
        this.ejecutandoComando = false;
        this.appRef.tick();
      });
    },error=>{
      this.SetMessage("BLE Connect ERROR!");
      this.SetMessage(error.message);
      this.ejecutandoComando = false;
      this.appRef.tick();
    });
  }

  /**
   * Agrega mensajes de ejecución al histórico
   */
  public SetMessage(message){
    var count = this['messages'].length;
    message = count + ':' + message;
    this['messages'].unshift(message);

    /*
      ESTA LINEA ES IMPORTANTE PARA REFRESCAR LA PANTALLA CUANDO SE GENERAN EVENTOS
      FUERA DEL CONTROL DE ANGULAR. POR EJEMPLO CUANDO SE LLAMA A UN CALLBACK EN
      UN PROCESO DE BLE SCAN.
    */
    this.appRef.tick();
  }

  // ASCII only. Convierte el valor a escribir a un arreglo de BYTES
  public StringToBytes(string) {
     let array = new Uint8Array(string.length);
     for (let i = 0, l = string.length; i < l; i++) {
         array[i] = string.charCodeAt(i);
      }
      return array.buffer;
  }

  // ASCII only
  public BytesToString(buffer) {
      return String.fromCharCode.apply(null, new Uint8Array(buffer));
  }
}

Fundamentos y Experimentación con Bluetooth Low Energy

1 Jul , 2017,
Rebeca Rodriguez Tencio
, , , , ,
No Comments

Resumen: En esta publicación, Rebeca Rodiguez nos da una importante lección sobre la importancia de profundizar un poco en los fundamentos de las tecnologías que usamos, y a su vez nos propone un experimento muy interesante para aplicar estos conocimientos en una aplicación que permite controlar una luz (LED) de manera remota desde un teléfono celular.

(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.

¿Conocen lo que es el Bluetooth de Baja Energía?

Saber de una tecnología va más allá de solo leer artículos informativos acerca de ella, antes de empezar a experimentar con BLE pensé que se me facilitaría desarrollar con está herramienta, no obstante descubrí que los conocimientos con los que contaba eran mínimos, y necesitaba aprender más para poder trabajar en uno de los proyectos actuales del Centro de Innovación, por lo que con el apoyo de Jose Núñez, uno de los ingenieros y colaboradores del centro, empecé la aventura de investigar y experimentar el mundo del Bluetooth de Baja Energía.

En muchos casos es muy fácil poder hacer aplicaciones funcionales e interesantes porque ya alguien más se tomó la molestia de hacer frameworks, librerías y tutoriales que nos facilitan la complejidad que conlleva realizar algo desde cero; probablemente si te gusta el mundo maker o estudias algo relacionado a la tecnología te has encontrado con proyectos que incluyan bluetooth como parte de las aplicaciones, sin embargo ¿te has preguntado la historia o cómo funciona toda la comunicación que hay detrás de esa tecnología o solamente has seguido los pasos de un tutorial e instalado las librerías respectivas copiando y pegando código y nos conformamos con que funcione a la primera?

PD: no importa si agarramos código de internet o nos basamos en algo ya existente para realizar un proyecto o aprender, existe mucha información y hay que sacarle el mayor provecho, pero es importante entender cómo funciona lo que estamos programando, la historia que hay detrás de  la comunicación entre los dispositivos y los términos empleados.

Resultado de imagen para BLUETOOTH low energy

El BLE es la versión ligera y mejorada del Bluetooth 4.0 clásico, está diseñado para abordar las necesidades de eficiencia energética y la simplicidad en el diseño de los productos, convirtiendose en una solución inalámbrica ULP (Ultra Low Power, Ultra Bajo Consumo); esta tecnología opera en la banda mundial de 2.4GHz, cuenta con una banda de bits de capa física de 1Mbps en un rango de 15metros.

El Bluetooth de Baja Energía fue desarrollado por Nordic Semiconductor, fue uno de los primeros miembros de “Wibree Alliance” la organización que inicio el desarrollo estándar de la ULP (Ultra Low Power), sin embargo después fue adoptado por el SIG (Special Interest Group, Grupo con Especial Interés), que fue conformado por cinco compañías (Ericsson, Nokia, Toshiba, IBM e INTEL). Nordic ha jugado un papel importante en el desarrollo de BLE, y continua desempeñando un papel clave a través del trabajo realizado como miembro asociado de Bluetooth SIG.

Lo interesante al usar BLE es que ha sido implementado en la gran mayoría de plataformas móviles modernas, sea iOS, Android, móviles con Windows, entre otros.

Hay conceptos indispensables con los que se van a encontrar siempre que empiecen a investigar acerca del BLE, por lo que conocer el significado o familiarizarse con los términos es importante.

Comenzamos hablando de perfiles y protocolos: el primer concepto es la subcategoría GAP (Generic Access Profile, Perfil de Acceso Genérico). El GAP es el encargado de permitir que el dispositivo sea público al exterior y por lo tanto define la forma de interacción entre los dispositivos. El GAP tiene dos roles importantes de conexión:  (1) los dispositivos centrales – de ahí el término BLE Central – (que corresponde a los móviles, tablet o dispositivos con capacidad de procesamiento mayor que inician la conexión con los periféricos) y (2) los periféricos (dispositivos pequeños de baja potencia y consumo) a los que se pueden conectar los dispositivos centrales.

Una vez que se establece la conexión entre los dispositivos centrales y los dispositivos periféricos entra al juego el GATT (Generic Attribute Profile, Perfil Genérico de Atributos) permitiendo la comunicación en ambas direcciones, a través del protocolo ATT que se usa para almacenar los servicios, los datos y las características propias de cada dispositivo utilizado; es importante destacar que un periférico BLE solo puede ser conectado a un dispositivo central a la vez, ya que tan pronto como el periférico es conectado al dispositivo central dejara de ser visible para otros dispositivos, sin embargo un dispositivo central (celulares, tablets…) si puede ser conectado a varios periféricos.

Al igual que en el GAP, el GATT también tiene roles de interacción que es importante conocer, como por ejemplo: el servidor que contiene las características de la búsqueda ATT asi como las definiciones del servicio y las características, el otro concepto es el cliente GATT que es el encargado de enviar las solicitudes. Todas las transacciones de comunicación entre los dispositivos son iniciadas por el GATT cliente (central) que recibe la respuesta del dispositivo esclavo, el GATT servidor (periférico).

Existen muchas aplicaciones para poder escanear periféricos BLE desde un dispositivo móvil, sin embargo hay una de ellas que me gustó mucho al momento de utilizarla. Se trata de nRF Connect for Mobile (Que antes se llamaba nRF Master Control Panel) es un app muy útil para experimentar y entender los conceptos de comunicación BLE.

Hay un ejemplo que encontré y quiero compartir porque está interesante ya que permite controlar un LED desde el celular, es decir podemos controlar un TinyTILE de Intel o una placa de Arduino 101 a través de un dispositivo central.

NOTA: Antes de iniciar el ejercicio es importante repasar qué es Intel Curie, esto para tener más claro el funcionamiento de los dispositvos perifericos utilizados, pueden guiarse con el siguiente enlace: https://costaricamakers.com/?s=curie

EJERCICIO PROPUESTO

Materiales:

  • 1LED
  • 1 Protoboard
  • Cable para prototipar
  • 1 tiny tile o placa arduino 101
  • 1 resistencia de 220Ω
  • Instalar el app de nRF Master Control Panel

Pasos a seguir:


PASO 1: Prototipar según la imagen del diagrama, que se obtuvo de: https://cdn.sparkfun.com/assets/learn_tutorials/4/9/2/Exp_1_Blink_bb.png

 

 

 

 

 

 

 


PASO 2: Conectar el periférico utilizado (Arduino 101 o TinyTILE), abrir el Arduino IDE y cargarle el código de ejemplo:

#include 
BLEPeripheral blePeripheral;
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED servicio app

//BLE caracteristicas asigandas
BLEUnsignedCharCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = 13; // pin asignado al LED

void setup() {
    pinMode(ledPin, OUTPUT);

    blePeripheral.setLocalName("TINYTILE BLE"); //Nombre que se le asigna al periferico para ser encontrado
    blePeripheral.setAdvertisedServiceUuid(ledService.uuid());

    blePeripheral.addAttribute(ledService); //caracteristicas del servicio
    blePeripheral.addAttribute(switchCharacteristic);

    switchCharacteristic.setValue(0);

    blePeripheral.begin();
}

void loop() {
    // Escucha los perifericos BLE para conectarse:
    BLECentral central = blePeripheral.central();

    // Si el central es conectado al periferico:
    if (central) {
        // Mientras la central siga conectada al periferico:
        while (central.connected()) {
            // Si el dispositivo remoto escribió a la característica,
            // usar un valor para encender el LED
            if (switchCharacteristic.written()) {
                // Cualquier valor a diferencia de 0 encendera el LED
                if (switchCharacteristic.value()) {
                    digitalWrite(ledPin, HIGH);
                }
                else {
                    digitalWrite(ledPin, LOW);
                }
            }
        }
    }
}

PASO 3: Abrir el app y hacer escaner de los dispositivos periféricos, conectar en este caso con el “TINYTILE BLE” como se muestra en la siguiente imagen. Una vez que se selecciona la opción de “CONNECT”, hay que hacer click en “Unknown Service” van aparecer unas flechas, haga click en la  flecha que tiene direción hacia abajo.

 


PASO 4: Se abrirá una pantalla o cuadro de dialogo, donde debemos seleccionar la opción de “UNIT 8” e introducir un número distinto de 0 para encencer el LED y haga click en enviar o “SEND”.

¡El LED debe encenderse! para volver apagarlo, debe abrir el mismo cuadro de diálogo e ingresar el número 0 y hacer nuevamente click en enviar y el LED debe apagarse.

Gracias por leer este artículo. Nos será de mucho valor que nos digas en comentarios si te fue de utilidad, si trataste de hacer el experimento y si realizaste cambios al mismo.

Arduino 101 – Tutorial

2 Abr , 2016,
Jose Nunez
, , , , , , ,
No Comments

Bienvenido al tutorial introductorio de la placa Arduino 101; sin duda una tarjeta especial para aprender y para prototipar usando conceptos de movimiento (aceleración, rotación) y sistemas de comunicación de red de área personal (PAN) para el desarrollo de ideas de tecnología vestible.

Al momento de escribir este tutorial, el Arduino 101 tenia un costo de $30, mientras que el Arduino UNO convencional un costo de $25.


(!) Antes de seguir estas instrucciones asegúrese de entender las Condiciones de Uso de nuestro sitio.


Contenido:

  1. ¿Qué es el Arduino 101 y qué es Intel Curie?
  2. Ejercicios:
    1. Acelerómetro y Giroscopio
    2. Acelerómetro y BLE: Contador de Pasos
    3. Bluetooth Low Energy (BLE): Monitor de Batería
    4. RTC / EEPROM
  3. ¿Dónde encontrar más información?

¿Qué es un Arduino 101 y qué es un Intel Curie?

El Arduino 101 es una de las más recientes creaciones de la familia de placas Arduino. Es una placa para prototipado y aprendizaje que implementa el nuevo chip SoC (Sistema en un solo chip) de Intel denominado Intel Curie(r)

¿Intel Curie?

Se trata del sistema en un solo chip más reciente de Intel, orientado al “mercado maker” que tiene como objetivo traer mayores capacidades computacionales y de sensado y comunicación al mundo maker y el mercado de la computación vestible y embebida.

Dentro de las especificaciones y funcionalidades de Intel Curie encontramos:

  • Voltaje de operación de 3.3V
  • Memoria Flash (no volatil) de 384Kb
  • Memoria SRAM (volatil) de 80Kb
  • Sistema on-chip QUARK-SE
  • Capacidad de comunicación Bluetooth Low Energy (BLE)
  • Combo integrado de sensores: acelerómetro + giroscópio 6 ejes.

Al implementar Intel Curie, el Arduino 101 presenta las siguientes ventajas comparativas con respecto del Arduino UNO

  • 196 Kb de memoria no volatil (flash). 6 veces más memoria que el Arduino UNO que trae 32Kb.
  • 24 Kb de memoria volatil (SRAM). 12 veces más memoria que el Arduino UNO que trae 2Kb.
  • 32MHz de velocidad de reloj; lo que representa el doble de los 16MHz del Arduino UNO
  • Alimentación (barril) de 7-12V
  • Sistema Operativo de Tiempo Real (RTOS) instalado en el Curie
  • Reloj de tiempo real (RTC)
  • Corriente por pin: 20mA
  • Sensores de Movimiento de 6 ejes: Acelerómetro (x,y,z) y giroscopio (roll, jaw, pitch)

La siguiente imagen ilustra los 6 ejes de movimiento sensables:

ejes_acc_gyro

Figura 1 – Ejes detectables de movimiento.


EJERCICIOS

En estos cuatro ejercicios exploraremos las diferentes funciones del Arduino 101, en lo referente a sensores de movimiento, comunicación Bluetooth BLE y uso de la memoria no volatil del sistema.

Para todos los ejercicios utilizaremos este programa base:

/*
 Copyright (c) 2015 Intel Corporation. All rights reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

 Modified by Jose Nunez @ intel corporation on April 2 2016

 https://www.arduino.cc/en/Tutorial/Genuino101CurieBLEHeartRateMonitor
 
*/

/*
 This sketch example demonstrates how the BMI160 on the
 Intel(R) Curie(TM) module can be used to read accelerometer data
*/

#include "CurieIMU.h"
#include <CurieBLE.h>

int EXERCISE = 1;


/****************** BLE HEARTRATE GLOBALS **************************/
BLEPeripheral blePeripheral; // BLE Peripheral Device (the board you're programming)
BLEService heartRateService("180D"); // BLE Heart Rate Service

// BLE Heart Rate Measurement Characteristic"
BLECharacteristic heartRateChar("2A37", // standard 16-bit characteristic UUID
 BLERead | BLENotify, 2); // remote clients will be able to get notifications if this characteristic changes
 // the characteristic is 2 bytes long as the first field needs to be "Flags" as per BLE specifications
 // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml

int oldHeartRate = 0; // last heart rate reading from analog input
long previousMillis = 0; // last time the heart rate was checked, in ms
/****************** END OF BLE HEARTRATE GLOBALS **************************/

void setup() {
 delay(3000);
 Serial.begin(9600); // initialize Serial communication
 pinMode(13, OUTPUT); // initialize the LED on pin 13 to indicate when a central is connected
 while (!Serial); // wait for the serial port to open
 Serial.println("SETUP...");
 // initialize device
 Serial.println("Initializing IMU device...");
 CurieIMU.begin();

 // Set the accelerometer range to 2G
 CurieIMU.setAccelerometerRange(2);

/****************** BLE HEARTRATE SETUP **************************/
 /* Set a local name for the BLE device
 This name will appear in advertising packets
 and can be used by remote devices to identify this BLE device
 The name can be changed but maybe be truncated based on space left in advertisement packet */
 blePeripheral.setLocalName("HeartRateSketch");
 blePeripheral.setAdvertisedServiceUuid(heartRateService.uuid()); // add the service UUID
 blePeripheral.addAttribute(heartRateService); // Add the BLE Heart Rate service
 blePeripheral.addAttribute(heartRateChar); // add the Heart Rate Measurement characteristic

 /* Now activate the BLE device. It will start continuously transmitting BLE
 advertising packets and will be visible to remote BLE central devices
 until it receives a new connection */
 blePeripheral.begin();
 Serial.println("Bluetooth device active, waiting for connections...");
/****************** END OF BLE HEARTRATE SETUP **************************/

 Serial.println("SETUP COMPLETE");
 
}

void loop() {
 switch(EXERCISE){
 case 1: 
 readAndReportAccelerometer();
 break;
 case 2:
 readAndReportGyroscope();
 break;
 case 3:
 monitorHeartRate();
 break;
 }
}

float pax, pay, paz, dax, dayy, daz;
void readAndReportAccelerometer(){
 int axRaw, ayRaw, azRaw; // raw accelerometer values
 float ax, ay, az;

 // read raw accelerometer measurements from device
 CurieIMU.readAccelerometer(axRaw, ayRaw, azRaw);

 // convert the raw accelerometer data to G's
 ax = convertRawAcceleration(axRaw);
 ay = convertRawAcceleration(ayRaw);
 az = convertRawAcceleration(azRaw);

 dax = abs(ax-pax);
 dayy = abs(ay-pay);
 daz = abs(az-paz);
 
 if(dax>0.02 || dayy>0.02 || daz>0.02){

 // display tab-separated accelerometer x/y/z values
 Serial.print("a:\t");
 Serial.print(ax);
 Serial.print("\t");
 Serial.print(ay);
 Serial.print("\t");
 Serial.print(az);
 Serial.println();

 pax = ax;
 pay = ay;
 paz = az;
 } 
}

float prev_gx, prev_gy, prev_gz, diff_gx, diff_gy, diff_gz;
float relevancyTrigger = 0.3;
void readAndReportGyroscope() {
 int gxRaw, gyRaw, gzRaw; // raw gyro values
 float gx, gy, gz;

 // read raw gyro measurements from device
 CurieIMU.readGyro(gxRaw, gyRaw, gzRaw);

 // convert the raw gyro data to degrees/second
 gx = convertRawGyro(gxRaw);
 gy = convertRawGyro(gyRaw);
 gz = convertRawGyro(gzRaw);

 diff_gx = abs(prev_gx-gx);
 diff_gy = abs(prev_gy-gy);
 diff_gz = abs(prev_gz-gz);

 if(diff_gx>relevancyTrigger || diff_gy>relevancyTrigger || diff_gz>relevancyTrigger){

 // display tab-separated gyro x/y/z values
 Serial.print("g: \t");
 Serial.print(gx);
 Serial.print("\t");
 Serial.print(gy);
 Serial.print("\t");
 Serial.print(gz);
 Serial.println( "");

 prev_gx = gx;
 prev_gy = gy;
 prev_gz = gz;
 }

}

void monitorHeartRate(){
 // listen for BLE peripherals to connect:
 BLECentral central = blePeripheral.central();

 // if a central is connected to peripheral:
 if (central) {
 Serial.print("Connected to central: ");
 // print the central's MAC address:
 Serial.println(central.address());
 // turn on the LED to indicate the connection:
 digitalWrite(13, HIGH);

 // check the heart rate measurement every 200ms
 // as long as the central is still connected:
 while (central.connected()) {
 long currentMillis = millis();
 // if 200ms have passed, check the heart rate measurement:
 if (currentMillis - previousMillis >= 200) {
 previousMillis = currentMillis;
 updateHeartRate();
 }
 }
 // when the central disconnects, turn off the LED:
 digitalWrite(13, LOW);
 Serial.print("Disconnected from central: ");
 Serial.println(central.address());
 }
}

void updateHeartRate() {
 /* Read the current voltage level on the A0 analog input pin.
 This is used here to simulate the heart rate's measurement.
 */
 int heartRateMeasurement = analogRead(A0);
 int heartRate = map(heartRateMeasurement, 0, 1023, 0, 100);
 if (heartRate != oldHeartRate) { // if the heart rate has changed
 Serial.print("Heart Rate is now: "); // print it
 Serial.println(heartRate);
 const unsigned char heartRateCharArray[2] = { 0, (char)heartRate };
 heartRateChar.setValue(heartRateCharArray, 2); // and update the heart rate measurement characteristic
 oldHeartRate = heartRate; // save the level for next comparison
 }
}

float convertRawAcceleration(int aRaw) {
 // since we are using 2G range
 // -2g maps to a raw value of -32768
 // +2g maps to a raw value of 32767
 
 float a = (aRaw * 2.0) / 32768.0;

 return a;
}

float convertRawGyro(int gRaw) {
 // since we are using 250 degrees/seconds range
 // -250 maps to a raw value of -32768
 // +250 maps to a raw value of 32767
 
 float g = (gRaw * 250.0) / 32768.0;

 return g;
}

 

EJERCICIOS #1 y 2 – ACELERÓMETRO Y GIROSCOPIO

En este ejercicio realizaremos lecturas del acelerómetro y del giroscopio y mostraremos el resultado en el monitor serial.

A su vez, implementamos una lógica de detección de cambios relevantes que nos permitirá observar con mayor claridad los cambios ocurridos en las medidas de los sensores.

PASO 1 – Cargue el programa del tutorial en su Arduino 101

PASO 2 – Utilizando la Figura 1 como guía, verifique en el Monitor Serial del IDE ARDUINO si los ejes mencionados son correctos para el acelerómetro (x,y,z)

PASO 3 – Modifique el programa, comentando la línea 32 para darle el valor de 2 a la variable EXERCISE.

ex02

PASO 4 – Cargue el programa modificado al Arduino 101 y verifique  los ejes de giro tal y como se ilustran en la Figura 1

PASO 5 – Preste atención a las líneas de la 110 a la 114; esta es la lógica de detección de cambios relevantes. Trate de explicarla.

110-114

PASO 6 – Ahora preste atención a las líneas de la 145 a la 149, es una implementación más limpia / autoexplicable de la lógica de detección de cambios relevantes. Trate de explicarla.

145-149

PASO 7 – Reto: Modifique la lógica de detección de  cambios relevantes para que detecte cualquier cambio.


EJERCICIO #3 – SIMULACION DE BLE HEARTBEAT SERVICE

En este ejercicio vamos a utilizar la comunicación Bluetooth/BLE para simular un mecanismo de detección de ritmo cardiaco y graficarlo en el celular.

Para esto necesitaremos un celular con capacidad BLE. En este descargaremos una aplicación llamada “nRF Toolbox” la cual hace una implementación de varios esquemas de servicio BLE. Utilizaremos entonces el servicio “HRM” (Heart Rate Monitor) para graficar datos provenientes del Arduino 101.

PASO 1 – Instale nRF Toolbox en su celular

PASO 2 – Re-configure el sketch base de este tutorial para ejecutar el ejercicio 3. En la línea 32 modifique la variable EXERCISE para que tenga un valor de 3.

arduino101_ex3

 

PASO 3 – Descargue el programa hacia la placa Arduino 101

PASO 4 – Abra el Monitor Serial (SHIFT + CTRL + M)

PASO 5 – En su celular, abra la aplicación “nRF Toolbox” y abra el servicio HRM. Allí pulse el botón “Connect” y elija “HeartRateSketch”

4 screens

PASO 6 – Observe cómo se grafican los datos

PASO 7 – Explicación

Esta simulación toma el valor de uno de los puertos analógicos del Arduino 101 (A0) y envia los datos a través de un servicio BLE estandard de tipo “Heart Rate Service”. Si se deja el pin A0 de la placa sin conexion, este tendrá valores “aleatorios” que serán graficados igual.

 


Recursos Adicionales

https://www.arduino.cc/en/Guide/Arduino101

http://www.intel.com/content/www/us/en/wearables/wearable-soc.html