There seems to be a problem with using BLE.

Hello, I’ve tried learning specific motions using the ‘arduino nano 33 ble’ board’s IMU and Tensorflow. And I tried to count when I did that motion. Now I’m going to use BLE to print out the count to the app.
However, when the upload is performed, the Bluetooth connection is not connected and the output is not available on the serial monitor. I think there’s a problem with setting the UUID. How can we solve this problem? I need a lot of help.

#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h> 
  
#include <TensorFlowLite.h>
#include <tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h>
#include <tensorflow/lite/experimental/micro/micro_error_reporter.h>
#include <tensorflow/lite/experimental/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>

#include "model.h" //tensorflow data


BLEService yscheulService("180F");
BLEFloatCharacteristic yscheulLevelChar("2A19", BLERead | BLEWrite);

long previousMillis = 0;

const float accelerationThreshold = 2.5; // threshold of significant in G's
const int numSamples = 119;

int samplesRead = numSamples;

// global variables used for TensorFlow Lite (Micro)
tflite::MicroErrorReporter tflErrorReporter;

// pull in all the TFLM ops, you can remove this line and
// only pull in the TFLM ops you need, if would like to reduce
// the compiled size of the sketch.
tflite::ops::micro::AllOpsResolver tflOpsResolver;

const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tflInterpreter = nullptr;
TfLiteTensor* tflInputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;

// Create a static memory buffer for TFLM, the size may need to
// be adjusted based on the model you are using
constexpr int tensorArenaSize = 8 * 1024;
byte tensorArena[tensorArenaSize];

// array to map gesture index to a name
const char* GESTURES[] = {"flex"};

#define NUM_GESTURES (sizeof(GESTURES) / sizeof(GESTURES[0]))

int a=0; // count 

void setup() {

 Serial.begin(9600);
  if (!IMU.begin()) { 
    Serial.println("LSM9DS1 failed!");
    while (1);
  }

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

  // set advertised local name and service UUID:
  BLE.setAdvertisedService(yscheulService); // add the service UUID
  yscheulService.addCharacteristic(yscheulLevelChar);
  BLE.addService(yscheulService);
  // start advertising
  BLE.setLocalName("yschul");
  // set the initial value for the characeristic:
  yscheulLevelChar.writeValue(0);
  // start advertising
  BLE.advertise(); 
  Serial.println("BLE LED Peripheral");
  
  // print out the samples rates of the IMUs
  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");
  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println(" Hz");
  Serial.println();

  // get the TFL representation of the model byte array
  tflModel = tflite::GetModel(model);
  if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
    Serial.println("Model schema mismatch!");
    while (1);
  }
  // Create an interpreter to run the model
  tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
  
  // Allocate memory for the model's input and output tensors
  tflInterpreter->AllocateTensors();
  
  // Get pointers for the model's input and output tensors
  tflInputTensor = tflInterpreter->input(0);
  tflOutputTensor = tflInterpreter->output(0);
}

//String Level_String;
float aX, aY, aZ, gX, gY, gZ;

void updateyscheulLevel() {
  if (IMU.accelerationAvailable()) 
  {
    //Level_String=String(a);
    //Level_String=String(aX,2)+","+String(aY,2)+","+String(aZ,2);
   // Serial.println(a);
    yscheulLevelChar.writeValue(a); // count value -> Bluetooth
  }
 }

void loop() {
  // wait for significant motion
  while (samplesRead == numSamples) {
    if (IMU.accelerationAvailable()) {
      // read the acceleration data
      IMU.readAcceleration(aX, aY, aZ);

      // sum up the absolutes
      float aSum = fabs(aX) + fabs(aY) + fabs(aZ);

      // check if it's above the threshold
      if (aSum >= accelerationThreshold) {
        // reset the sample read count
        samplesRead = 0;
        break;
      }
    }
  }
  // check if the all the required samples have been read since
  // the last time the significant motion was detected
  while (samplesRead < numSamples) {
    // check if new acceleration AND gyroscope data is available
    if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
      // read the acceleration and gyroscope data
      IMU.readAcceleration(aX, aY, aZ);
      IMU.readGyroscope(gX, gY, gZ);

      // normalize the IMU data between 0 to 1 and store in the model's
      // input tensor
      tflInputTensor->data.f[samplesRead * 6 + 0] = (aX + 4.0) / 8.0;
      tflInputTensor->data.f[samplesRead * 6 + 1] = (aY + 4.0) / 8.0;
      tflInputTensor->data.f[samplesRead * 6 + 2] = (aZ + 4.0) / 8.0;
      tflInputTensor->data.f[samplesRead * 6 + 3] = (gX + 2000.0) / 4000.0;
      tflInputTensor->data.f[samplesRead * 6 + 4] = (gY + 2000.0) / 4000.0;
      tflInputTensor->data.f[samplesRead * 6 + 5] = (gZ + 2000.0) / 4000.0;

      samplesRead++;

      if (samplesRead == numSamples) {
        // Run inferencing
        TfLiteStatus invokeStatus = tflInterpreter->Invoke();
        if (invokeStatus != kTfLiteOk) {
          Serial.println("Invoke failed!");
          while (1);
          return;
        }

        // Loop through the output tensor values from the model
        Serial.print(GESTURES[0]); // GESTURES[0] = flex
        Serial.print(": ");
        Serial.println(tflOutputTensor->data.f[0], 6);       
        Serial.println(); 
      }
    }
  }
// Counts if accuracy is 0.7 or higher
 if(tflOutputTensor->data.f[0] >= 0.7)
        {
          a=a+1; 
          Serial.println(a);
        }
  
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();
  // if a central is connected to peripheral:
  if (central) 
  {
    while (central.connected()) 
    {
       long currentMillis = millis();
       if (currentMillis - previousMillis >= 50) 
       {
        previousMillis = currentMillis;
        updateyscheulLevel();
      }
    } 
  }
}

YAY! First post and proper use of code tags! Karma++

I have not used BLE so I cannot comment directly on what might cause problems.
I DO believe that troubleshooting problems should be done in as much isolation as possible.
Take out all the code and all the libraries that are not directly used in the BLE connection and communication.
Send a simple set of data.
Often this can be done using tutorials in the libraries for the hardware you chose.
Are there example sketches in ArduinoBLE.h

vinceherman:
Are there example sketches in ArduinoBLE.h

Yes:

@yscheol has also requested assistance with this on GitHub:

Have you tried JUST the BLE connectivity?
Take out ALL the code for the sensor.
JUST test the BLE.
Are you able to use the BLE examples to test and resolve the BLE problem you asked about in the original post?

vinceherman:
Have you tried JUST the BLE connectivity?
Take out ALL the code for the sensor.
JUST test the BLE.
Are you able to use the BLE examples to test and resolve the BLE problem you asked about in the original post?

Before doing this, I succeeded in printing the IMU value as BLE.
And I used this BLE code for the tensor flow code above.
However, if you insert any BLE code, all functions will not work. And as a result of removing the BLE part little by little, it doesn't work with just the UUID of BLE.
This is the UUID I use. Is there a problem with this?

BLEService gyroService("c34935d5-792e-42fc-9945-44d76c582acf");

BLEStringCharacteristic LevelChar("c34935d5-792e-42fc-9945-44d76c582acf", BLERead | BLENotify,100);

I had the exact same problem.

The problem always occurs when the tenserflow invoke() is called, but i’m not sure why. Also make sure that you are not blocking the loop function because otherwise the bluetooth will not work.

Replace the following lines:

BLEService yscheulService(“180F”);
BLEFloatCharacteristic yscheulLevelChar(“2A19”, BLERead | BLEWrite);

with:

BLEByteCharacteristic* yscheulLevelChar = nullptr;
BLEService* yscheulService = nullptr;

void setup(){
 yscheulService = new BLEService("180F");
 yscheulLevelChar = new BLEByteCharacteristic("2A19", BLERead | BLEWrite);
...
}

The full code becomes:

#include <ArduinoBLE.h>

#include <Arduino_LSM9DS1.h>
 
#include <TensorFlowLite.h>
#include <tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h>
#include <tensorflow/lite/experimental/micro/micro_error_reporter.h>
#include <tensorflow/lite/experimental/micro/micro_interpreter.h>
#include <tensorflow/lite/schema/schema_generated.h>
#include <tensorflow/lite/version.h>

#include "model.h" //tensorflow data

BLEByteCharacteristic* yscheulLevelChar = nullptr;
BLEService* yscheulService = nullptr;

long previousMillis = 0;

const float accelerationThreshold = 2.5; // threshold of significant in G's
const int numSamples = 119;

int samplesRead = numSamples;

// global variables used for TensorFlow Lite (Micro)
tflite::MicroErrorReporter tflErrorReporter;

// pull in all the TFLM ops, you can remove this line and
// only pull in the TFLM ops you need, if would like to reduce
// the compiled size of the sketch.
tflite::ops::micro::AllOpsResolver tflOpsResolver;

const tflite::Model* tflModel = nullptr;
tflite::MicroInterpreter* tflInterpreter = nullptr;
TfLiteTensor* tflInputTensor = nullptr;
TfLiteTensor* tflOutputTensor = nullptr;

// Create a static memory buffer for TFLM, the size may need to
// be adjusted based on the model you are using
constexpr int tensorArenaSize = 8 * 1024;
byte tensorArena[tensorArenaSize];

// array to map gesture index to a name
const char* GESTURES[] = {"flex"};

#define NUM_GESTURES (sizeof(GESTURES) / sizeof(GESTURES[0]))

int a=0; // count

void setup() {

 yscheulService = new BLEService("180F");
 yscheulLevelChar = new BLEByteCharacteristic("2A19", BLERead | BLEWrite);

 Serial.begin(9600);
  if (!IMU.begin()) {
    Serial.println("LSM9DS1 failed!");
    while (1);
  }

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

  // set advertised local name and service UUID:
  BLE.setAdvertisedService(*yscheulService); // add the service UUID
  yscheulService->addCharacteristic(*yscheulLevelChar);
  BLE.addService(*yscheulService);
  // start advertising
  BLE.setLocalName("yschul");
  // set the initial value for the characeristic:
  yscheulLevelChar->writeValue(0);
  // start advertising
  BLE.advertise();
  Serial.println("BLE LED Peripheral");
 
  // print out the samples rates of the IMUs
  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU.accelerationSampleRate());
  Serial.println(" Hz");
  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println(" Hz");
  Serial.println();

  // get the TFL representation of the model byte array
  tflModel = tflite::GetModel(model);
  if (tflModel->version() != TFLITE_SCHEMA_VERSION) {
    Serial.println("Model schema mismatch!");
    while (1);
  }
  // Create an interpreter to run the model
  tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
 
  // Allocate memory for the model's input and output tensors
  tflInterpreter->AllocateTensors();
 
  // Get pointers for the model's input and output tensors
  tflInputTensor = tflInterpreter->input(0);
  tflOutputTensor = tflInterpreter->output(0);
}

//String Level_String;
float aX, aY, aZ, gX, gY, gZ;

boolean active = false;

void loop() {

  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();
  // if a central is connected to peripheral:
  if (central)
  {
    Serial.println("Bluetooth connected");
    while (central.connected())
    {
      // bluetooth device is connected
      
      // wait for significant motion
      if(active == false && samplesRead == numSamples) {
        if (IMU.accelerationAvailable()) {
          // read the acceleration data
          IMU.readAcceleration(aX, aY, aZ);
    
          // sum up the absolutes
          float aSum = fabs(aX) + fabs(aY) + fabs(aZ);
    
          // check if it's above the threshold
          if (aSum >= accelerationThreshold) {
            // reset the sample read count
            samplesRead = 0;
            active = true;
          }
        }
      }
      
      // check if the all the required samples have been read since
      // the last time the significant motion was detected
      if (active == true && samplesRead < numSamples) {
        // check if new acceleration AND gyroscope data is available
        if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
          // read the acceleration and gyroscope data
          IMU.readAcceleration(aX, aY, aZ);
          IMU.readGyroscope(gX, gY, gZ);
    
          // normalize the IMU data between 0 to 1 and store in the model's
          // input tensor
          tflInputTensor->data.f[samplesRead * 6 + 0] = (aX + 4.0) / 8.0;
          tflInputTensor->data.f[samplesRead * 6 + 1] = (aY + 4.0) / 8.0;
          tflInputTensor->data.f[samplesRead * 6 + 2] = (aZ + 4.0) / 8.0;
          tflInputTensor->data.f[samplesRead * 6 + 3] = (gX + 2000.0) / 4000.0;
          tflInputTensor->data.f[samplesRead * 6 + 4] = (gY + 2000.0) / 4000.0;
          tflInputTensor->data.f[samplesRead * 6 + 5] = (gZ + 2000.0) / 4000.0;
    
          samplesRead++;
    
          if (samplesRead == numSamples) {
            active = false;
            // Run inferencing
            TfLiteStatus invokeStatus = tflInterpreter->Invoke();
            if (invokeStatus != kTfLiteOk) {
              Serial.println("Invoke failed!");
              while (1);
              return;
            }

            // Counts if accuracy is 0.7 or higher
           if(tflOutputTensor->data.f[0] >= 0.7){
             // do something
             Serial.println("So far so good");
             if(central.connected()){
               // write to bluetooth
               yscheulLevelChar->writeValue(1);
             }
           }
          
    
            // Loop through the output tensor values from the model
            Serial.print(GESTURES[0]); // GESTURES[0] = flex
            Serial.print(": ");
            Serial.println(tflOutputTensor->data.f[0], 6);       
            Serial.println();
          }
        }
      }     
    }
    Serial.println("Bluetooth disconnected");
  }
}