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