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.
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.
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); }