Bluetooth Low Energy: Control de gestos

Introducción

En este tutorial vamos a ver un ejemplo de uso de de la tecnología Bluetooth Low Energy utilizando las placas Arduino MKR WiFi 1010 y Arduino Nano 33 BLE Sense junto con la librería ArduinoBLE.

 

Este ejemplo se basa en los sketchs “Central →  LedControl” y “Peripherical → LED” que vienen de ejemplo en la librería ArduinoBLE.



El Bluetooth en el Arduino Nano 33 BLE Sense es gestionado por el módulo NINA B306 que tiene la calificación de Bluetooth 5.0.

Ver Data Sheet NINA B306

En el caso del Arduino MKR WiFi 1010 el Bluetooth es gestionado por el módulo NINA -W102 que tiene la calificación de  Bluetooth 4.2.

Ver Data Sheet NINA-W10

En los siguientes enlaces se explican a los conceptos básicos de la tecnología Bluetooth Low Energy  que nos ayudará a entender su funcionamiento:

https://www.arduino.cc/en/Reference/ArduinoBLE

https://learn.adafruit.com/introduction-to-bluetooth-low-energy/introduction

Circuito

Componentes:

    • Dispositivo central:  Arduino Nano 33 BLE Sense. 
    • Dispositivo periférico: Arduino MKR WiFi 1010 + Arduino MKR RGB Shield.

Funcionamiento:

    • El dispositivo central se conectará al dispositivo periférico buscando la característica del servicio especificado. 
    • Una vez establecida la conexión si el sensor de gestos del Arduino Nano 33 BLE Sense (ADPS-9960) detecta cualquiera de los siguientes movimientos: UP, DOWN, LEFT y RIGHT el dispositivo central escribirá el valor correspondiente (asociado a estos movimientos) en la característica del servicio del dispositivo periférico haciendo que se muestre en la matriz de LEDs el texto correspondiente con un color determinado.

Programación

Skecth a cargar en el dispositivo central Arduino Nano 33 BLE Sense:

#include <ArduinoBLE.h>
#include <Arduino_APDS9960.h>

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";
  
int gesture = -1; 
int oldGestureValue = -1;   

void setup() {
  
  Serial.begin(9600);
  while (!Serial);

  if (!APDS.begin()) {
    Serial.println("Error initializing APDS9960 sensor!");
  }

   APDS.setGestureSensitivity(80); // [1..100]
  
  // begin ble initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");
    while (1);
  }

  Serial.println("BLE Central - gesture control");

}

void loop() {
  
     connectToPeripheral();
}


void connectToPeripheral(){

  BLEDevice peripheral;

  do
  {
     // start scanning for peripherals
    BLE.scanForUuid(deviceServiceUuid);
    peripheral = BLE.available();
    
  } while (!peripheral);

  
  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found  ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();
  
    // stop scanning
    BLE.stopScan();
  
    controlPeripheral(peripheral);
   
  }
  
}

void controlPeripheral(BLEDevice peripheral) {

  
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }

  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }

  BLECharacteristic gestureCharacteristic = peripheral.characteristic(deviceServiceCharacteristicUuid);
    
  if (!gestureCharacteristic) {
    Serial.println("Peripheral does not have gesture characteristic!");
    peripheral.disconnect();
    return;
  } else if (!gestureCharacteristic.canWrite()) {
    Serial.println("Peripheral does not have a writable gesture characteristic!");
    peripheral.disconnect();
    return;
  }

  
  while (peripheral.connected()) {

    gesture = gestureDetectection();

    if (oldGestureValue != gesture) {
      
      // gesture value changed
      oldGestureValue = gesture;
          
      Serial.print("writing value: ");
      Serial.println(gesture);
      gestureCharacteristic.writeValue((byte)gesture);
      Serial.println("done!");

    }
  
  }

  Serial.println("Peripheral disconnected!");

}
  
int gestureDetectection(){

  if (APDS.gestureAvailable()) {
    
    // a gesture was detected
    gesture = APDS.readGesture();

    switch (gesture) {
      case GESTURE_UP:
        Serial.println("Detected UP gesture");
        break;
      case GESTURE_DOWN:
        Serial.println("Detected DOWN gesture");
        break;
      case GESTURE_LEFT:
        Serial.println("Detected LEFT gesture");
        break;
      case GESTURE_RIGHT:
        Serial.println("Detected RIGHT gesture");
        break;
      default:
        Serial.println("NO gesture detected!");
        break;
      }
    
    }

    return gesture;
    
}

Skecth a cargar en el dispositivo periférico Arduino MKR WiFi 1010:

#include <ArduinoBLE.h>
#include <Arduino_MKRRGB.h>

enum {
  GESTURE_NONE = -1,
  GESTURE_UP = 0,
  GESTURE_DOWN = 1,
  GESTURE_LEFT = 2,
  GESTURE_RIGHT = 3
};

const char* deviceServiceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214";
const char* deviceServiceCharacteristicUuid = "19b10001-e8f2-537e-4f6c-d104768a1214";

int gesture = -1;

// BLE gesture Service
BLEService gestureService(deviceServiceUuid); 

// BLE gesture Switch Characteristic 
BLEByteCharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite);


void setup() {
  
  //Serial.begin(9600);
  //while (!Serial);

  // initialize the display
  MATRIX.begin();
  // set the brightness, supported values are 0 - 255
  MATRIX.brightness(120);
  // configure the text scroll speed
  MATRIX.textScrollSpeed(50);
  MATRIX.clear();
  MATRIX.endDraw();

  
  // begin ble initialization
  if (!BLE.begin()) {
    //Serial.println("starting BLE failed!");
    while (1);
  }

  // set advertised local name and service UUID:
  BLE.setLocalName("Gesture peripheral");
  BLE.setAdvertisedService(gestureService);

  // add the characteristic to the service
  gestureService.addCharacteristic(gestureCharacteristic);

  // add service
  BLE.addService(gestureService);

  // set the initial value for the characeristic:
  gestureCharacteristic.writeValue(-1);

  // start advertising
  BLE.advertise();

  //Serial.println("BLE gesture Peripheral");
}

void loop() {
  
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.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());

    // while the central is still connected to peripheral:
    while (central.connected()) {
      
      // if the remote device wrote to the characteristic,
      if (gestureCharacteristic.written()) {
         gesture = gestureCharacteristic.value();
         writeGesture(gesture);
       }
      
    }

    // when the central disconnects, print it out:
    //Serial.print(F("Disconnected from central: "));
    //Serial.println(central.address());
  }
}

void writeGesture(int gesture)
{

  int R = 0;
  int G = 0;
  int B = 0;
  String text = "";
  
   switch (gesture) {
    
      case GESTURE_UP:
        text =" UP";
        R=0;
        G=255;
        B=0;
        break;
      case GESTURE_DOWN:
        text ="DOWN";
        R=255;
        G=0;
        B=0;
        break;
      case GESTURE_LEFT:
        text ="LEFT";
        R=0;
        G=0;
        B=255;
        break;
      case GESTURE_RIGHT:
        text ="RIGHT";
        R=207;
        G=9;
        B=227;
        break;
      default:
        text ="";
        R=0;
        G=0;
        B=0;
        break;
        
    }
    
    MATRIX.clear();
    MATRIX.endDraw();
    MATRIX.beginText(0, 0, R, G, B); // X, Y, then R, G, B
    MATRIX.print(text);
    MATRIX.endText(SCROLL_LEFT);
      
}