Writing Gyroscope Values to BLE Characteristic

Hello,

I am attempting to create a program that writes values (-180.00 to 180.00) from a gyroscope to a BLE characteristic. I believe I am unable to directly write these sensor values to the characteristic because of a memory constraint in designing services. My code (attached) will write values between 0 and 99 to my peripheral characteristic, however nothing more.

I would appreciate any help/recommendations as to how I can modify my code so that values between -180 and 180 are properly written as a BLE characteristic. I suspect I am going over the 512 byte limit described by the Arduino BLE reference, however I don't know why that is and how to fix it. I appreciate your patience in helping me learn how to solve this issue. I am not a professional programmer. Thank you.

/*
  BLE_Peripheral.ino
*/

#include <ArduinoBLE.h>
#include <Wire.h>
#include <MPU6050_light.h>

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

int gesture = -1;

BLEService gestureService(deviceServiceUuid); 
BLEByteCharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite);

MPU6050 mpu(Wire);
unsigned long timer = 0;

void setup() {
  Serial.begin(9600);  
  
  pinMode(LED_BUILTIN, OUTPUT);

  if (!BLE.begin()) {
    Serial.println("- Starting Bluetooth® Low Energy module failed!");
    while (1);
  }

  BLE.setLocalName("Arduino Nano 33 BLE (Peripheral)");
  BLE.setAdvertisedService(gestureService);
  gestureService.addCharacteristic(gestureCharacteristic);
  BLE.addService(gestureService);
  gestureCharacteristic.writeValue(-1);
  BLE.advertise();

  Wire.begin();
  mpu.begin();       
  mpu.calcGyroOffsets();                          // This does the calibration of the gyroscope  

  Serial.println("Nano 33 BLE (Peripheral Device)");
  Serial.println(" ");
}

void loop() {
  BLEDevice central = BLE.central();
  Serial.println("- Discovering central device...");
  delay(500);

  if (central) {
    Serial.println("* Connected to central device!");
    Serial.print("* Device MAC address: ");
    Serial.println(central.address());
    Serial.println(" ");

    while (central.connected()) {
      mpu.update();  
      if((millis()-timer)>10)                         // print data every 10ms
      {                                                                 
        float test = mpu.getAngleX();
        
        timer = millis();

        gestureCharacteristic.writeValue(39);
        
        Serial.println(gestureCharacteristic.value());
      }
    }
    
    Serial.println("* Disconnected to central device!");
  }
}

Hi,

Figured it out. I changed BLEByte to BLEFloat. Everything works smoothly now.

I recommend against using float types for your characteristics. BLE characteristics are an interface and should be designed to be as interoperable as possible.
There are multiple standards for floating point data (e.g., IEEE 754, IEEE 11073) and converting them is a pain.

The Bluetooth SiG has shown how to get around this issue by specifying a integer or unsigned integer data type with a fixed exponent. Check out how they defined the Environmental Sensor Service with temperature, humidity and pressure.

Have a look at the following examples I wrote a while ago. Reply #2.
https://forum.arduino.cc/t/bluetooth-communications/902610/2

So, store the value -18000 for -180.00. This can be done with a 16-bit integer.

Thank you Klaus_K. Do you think that might be the reason why my Central device only returns the value "1"?

Below is my central device code:

/*
  BLE_Central_Device.ino
*/

#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);

if (!BLE.begin()) {
    Serial.println("* Starting Bluetooth® Low Energy module failed!");
    while (1);
  }
  
  BLE.setLocalName("Nano 33 BLE (Central)"); 
  BLE.advertise();

  Serial.println("Arduino Nano 33 BLE Sense (Central Device)");
  Serial.println(" ");
}

void loop() {
  connectToPeripheral();
}

void connectToPeripheral(){
  BLEDevice peripheral;
  
  Serial.println("- Discovering peripheral device...");

  do
  {
    Serial.println("I don't see anything yet brother.");
    BLE.scanForUuid(deviceServiceUuid);
    peripheral = BLE.available();
  } while (!peripheral);
  
  if (peripheral) {
    Serial.println("* Peripheral device found!");
    Serial.print("* Device MAC address: ");
    Serial.println(peripheral.address());
    Serial.print("* Device name: ");
    Serial.println(peripheral.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(peripheral.advertisedServiceUuid());
    Serial.println(" ");
    BLE.stopScan();
    controlPeripheral(peripheral);
  }
}

void controlPeripheral(BLEDevice peripheral) {
  Serial.println("- Connecting to peripheral device...");

  if (peripheral.connect()) {
    Serial.println("* Connected to peripheral device!");
    Serial.println(" ");
  } else {
    Serial.println("* Connection to peripheral device failed!");
    Serial.println(" ");
    return;
  }

  Serial.println("- Discovering peripheral device attributes...");
  if (peripheral.discoverAttributes()) {
    Serial.println("* Peripheral device attributes discovered!");
    Serial.println(" ");
  } else {
    Serial.println("* Peripheral device attributes discovery failed!");
    Serial.println(" ");
    peripheral.disconnect();
    return;
  }

  BLECharacteristic gestureCharacteristic = peripheral.characteristic(deviceServiceCharacteristicUuid);
    
  if (!gestureCharacteristic) {
    Serial.println("* Peripheral device does not have gesture_type characteristic!");
    peripheral.disconnect();
    return;
  } else if (!gestureCharacteristic.canWrite()) {
    Serial.println("* Peripheral does not have a writable gesture_type characteristic!");
    peripheral.disconnect();
    return;
  }
  
  while (peripheral.connected()) {
    
    Serial.println(gestureCharacteristic.read());
    if (5==5) {  

      Serial.println(" ");
    }
  
  }
  Serial.println("- Peripheral device disconnected!");
}

To clarify, when I ask the peripheral device to print its characteristic value it returns the correct gyroscopic float value. But, when I ask the central device to read the peripheral characteristic it only prints the value "1".

Any suggestions on how to resolve this?

Yes, you need to use the read function with the buffer and length parameter and then convert the bytes a float. Have a look at the library documentation and source:

https://www.arduino.cc/reference/en/libraries/arduinoble/blecharacteristic.readvalue/

https://github.com/arduino-libraries/ArduinoBLE/blob/master/src/BLECharacteristic.h

There are two issues:

  • There is no read function for float types.
  • Your central does not know what data is in the characteristic.

When you use a integer data type you can just use the read function and pass it a variable of the right type. See line 64-69 in the source file above and the example in the library doc (uses byte). Change the type of the value variable to what you have in the peripheral characteristic.

I recommend to use the uint8_t, int16_t, ..., uint32_t type notation. That will make it absolutely clear how many bytes/bits you expect in the characteristic when you or someone reads your code. This is especially important here because the code is about number of bytes being exchanged between to devices. See my example code.

Thank you Klaus for your response. I am now storing the gyroscope values directly as a byte to make things more simple. In doing so, I still get the serial output "1" from my central device. Can you elaborate further on what remains the issue in my central code? Thank you for your patience while I learn. Modified central and peripheral code included below:

Central code:

/*
  BLE_Central_Device.ino
*/

#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);

if (!BLE.begin()) {
    Serial.println("* Starting Bluetooth® Low Energy module failed!");
    while (1);
  }
  
  BLE.setLocalName("Nano 33 BLE (Central)"); 
  BLE.advertise();

  Serial.println("Arduino Nano 33 BLE Sense (Central Device)");
  Serial.println(" ");
}

void loop() {
  connectToPeripheral();
}

void connectToPeripheral(){
  BLEDevice peripheral;
  
  Serial.println("- Discovering peripheral device...");

  do
  {
    Serial.println("I don't see anything yet brother.");
    BLE.scanForUuid(deviceServiceUuid);
    peripheral = BLE.available();
  } while (!peripheral);
  
  if (peripheral) {
    Serial.println("* Peripheral device found!");
    Serial.print("* Device MAC address: ");
    Serial.println(peripheral.address());
    Serial.print("* Device name: ");
    Serial.println(peripheral.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(peripheral.advertisedServiceUuid());
    Serial.println(" ");
    BLE.stopScan();
    controlPeripheral(peripheral);
  }
}

void controlPeripheral(BLEDevice peripheral) {
  Serial.println("- Connecting to peripheral device...");

  if (peripheral.connect()) {
    Serial.println("* Connected to peripheral device!");
    Serial.println(" ");
  } else {
    Serial.println("* Connection to peripheral device failed!");
    Serial.println(" ");
    return;
  }

  Serial.println("- Discovering peripheral device attributes...");
  if (peripheral.discoverAttributes()) {
    Serial.println("* Peripheral device attributes discovered!");
    Serial.println(" ");
  } else {
    Serial.println("* Peripheral device attributes discovery failed!");
    Serial.println(" ");
    peripheral.disconnect();
    return;
  }

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

    uint32_t  my_int;
    Serial.println(gestureCharacteristic.readValue(my_int));
  
  }
  Serial.println("- Peripheral device disconnected!");
}

Peripheral code:

/*
  BLE_Peripheral.ino
*/

#include <ArduinoBLE.h>
#include <Wire.h>
#include <MPU6050_light.h>

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

int gesture = -1;

BLEService gestureService(deviceServiceUuid); 
BLEByteCharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid, BLERead | BLEWrite);

MPU6050 mpu(Wire);
unsigned long timer = 0;

void setup() {
  Serial.begin(9600);  
  
  pinMode(LED_BUILTIN, OUTPUT);

  if (!BLE.begin()) {
    Serial.println("- Starting Bluetooth® Low Energy module failed!");
    while (1);
  }

  BLE.setLocalName("Arduino Nano 33 BLE (Peripheral)");
  BLE.setAdvertisedService(gestureService);
  gestureService.addCharacteristic(gestureCharacteristic);
  BLE.addService(gestureService);
  gestureCharacteristic.writeValue(-1);
  BLE.advertise();

  Wire.begin();
  mpu.begin();       
  mpu.calcGyroOffsets();                          // This does the calibration of the gyroscope  

  Serial.println("Nano 33 BLE (Peripheral Device)");
  Serial.println(" ");
}

void loop() {
  BLEDevice central = BLE.central();
  Serial.println("- Discovering central device...");
  delay(500);

  if (central) {
    Serial.println("* Connected to central device!");
    Serial.print("* Device MAC address: ");
    Serial.println(central.address());
    Serial.println(" ");

    while (central.connected()) {
      mpu.update();  
      if((millis()-timer)>10)                         // print data every 10ms
      {                                                                 
        byte test = (mpu.getAngleX());
        
        timer = millis();

        gestureCharacteristic.writeValue(test);
        
        Serial.println(gestureCharacteristic.value());
      }
    }
    
    Serial.println("* Disconnected to central device!");
  }
}

have you found a solution because i have the same probleme

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.