Solved! - BLE Sketch will write the same sensor value over and over

Hey guys, i tried to write a ble sketch which writes encoded imu data into a characteristic. My debugging included writing buf[] with simulated values(to have a ground-truth) to the characteristic which worked. And later using an app to read the bytearray and decode it within an online tool. Those values looked realistic. So i thought my script worked fine. After building a receiving tool i noticed that my arduino script will only write one singular value for each instance of an imu(acc x,y,z, gyro x,y,z...) and never update it. Those values seem to be realistic and are non zero.

I need someone with a second perspective i feel. Thanks for any hint you can give me :slight_smile:

#include <imu_struct.pb.h>
#include <pb_common.h>
#include <pb.h>
#include <pb_encode.h>

#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>

uint8_t sample_freq =  100; //hz

uint8_t buf[45] = {0};
BLEService imuService("49cc6a9e-0fa3-493b-b290-e1ac59909dec");

// Bluetooth® Low Energy Battery Level Characteristic
BLECharacteristic imuChar("ad0e768f-d4ae-4aa5-97bb-98300a987864", BLERead | BLENotify ,sizeof(buf), true); // remote clients will be able to get notifications if this characteristic changes


long previousMillis = 0;
ImuData data = {};

void setup() {
 Serial.begin(115200);
 for (int i=0;i<5;i++){Serial.print(buf[i]);Serial.print(" ");}
   pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
     // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }
  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
  

  /* Set a local name for the Bluetooth® Low Energy device
     This name will appear in advertising packets
     and can be used by remote devices to identify this Bluetooth® Low Energy device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("imu_1");
  BLE.setDeviceName("imu_1");
  

  BLE.setAdvertisedService(imuService); // add the service UUID
  imuService.addCharacteristic(imuChar); // add the battery level characteristic
  
  BLE.addService(imuService); // Add the battery service
  imuChar.writeValue(buf,sizeof(buf) ); // set initial value for this characteristic
 

  /* Start advertising Bluetooth® Low Energy.  It will start continuously transmitting Bluetooth® Low Energy
     advertising packets and will be visible to remote Bluetooth® Low Energy central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth® device active, waiting for connections...");
  
}
void loop() {   
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(data.aX, data.aY, data.aZ);
  }

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(data.gX, data.gY, data.gZ);
  }

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(data.mX, data.mY, data.mZ);
}
   
  pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf));
  
  bool status = pb_encode(&stream, ImuData_fields, &data);
   if (!status)
  {
      Serial.println("Failed to encode");
      return;
  }
 
 
    // wait for a Bluetooth® Low Energy central
  BLEDevice central = BLE.central();

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


    // while the central is connected:
    while (central.connected()) {

      
      long currentMillis = millis();
      // wait regarding user defined frequency value:
      int sampleDelayPeriod = calcSampleRate();
      //Serial.println(sampleDelayPeriod);
      if (currentMillis - previousMillis >= sampleDelayPeriod ) {
        previousMillis = currentMillis;
        updateImu();
      }
    }
    // when the central disconnects, turn off the LED:
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }    
}

void updateImu() {
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(data.aX, data.aY, data.aZ);
  }

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(data.gX, data.gY, data.gZ);
  }

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(data.mX, data.mY, data.mZ);
  }
      imuChar.writeValue(buf, sizeof(buf));  // and update the characteristic


//    for(uint32_t i = 0; i< 45; i++){
//      Serial.print(buf[i],HEX);
//      Serial.println();
//    }
//    Serial.println("________");
  }
#include <imu_struct.pb.h>
#include <pb_common.h>
#include <pb.h>
#include <pb_encode.h>

I am unfamiliar with your architecture. Here's a more commonly used way to send the imu stuct data separated into three characteristics.

https://forum.arduino.cc/t/what-is-the-most-efficient-way-to-send-accelerometer-data-over-ble-to-a-raspberry-pi/926450/13

Hey cattledog, i am using protobuf. Its an encoding protocol by google which is pretty efficient. I use it because i have an easy standardized way to package.
Anyway the problem with my code was that i was encoding data before the if connected loop so it would never be updated but once in the beginning.

Btw. Can't i close this ticket?

the problem with my code was that i was encoding data before the if connected loop so it would never be updated

Yes, I now see the location of the encoding outside of the while() loop.

Go to your topic, select More:Modify, and add Solved to the title.

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