Simple Gyro Data from NANO 33 BLE Sense Rev 2 to computer via Bluetooth

Hi All,
I'm trying to get data from a NANO 33 BLE Sense Rev 2 to a computer via Bluetooth. I'm just wondering if anyone has seen a modified BLE or Simple Gyro sketch that can do this. The simple GYRO sketch works fine via USB, I just need to get the same data to the computer without a cable.

I will keep searching the topic board but thought I should start a new thread and post my tests here in case anyone can help or is interested.

I am using this sketch so far:

#include <ArduinoBLE.h>
/*
  Arduino BMI270 - Simple Gyroscope

  This example reads the gyroscope values from the BMI270
  sensor and continuously prints them to the Serial Monitor
  or Serial Plotter.

  The circuit:
  - Arduino Nano 33 BLE Sense Rev2

  created 10 Jul 2019
  by Riccardo Rizzo

  This example code is in the public domain.
*/

#include "Arduino_BMI270_BMM150.h"

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }
  Serial.print("Gyroscope sample rate = ");
  Serial.print(IMU.gyroscopeSampleRate());
  Serial.println(" Hz");
  Serial.println();
  Serial.println("Gyroscope in degrees/second");
  Serial.println("X\tY\tZ");
}

void loop() {
  float x, y, z;

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(x, y, z);

    Serial.print(x);
    Serial.print('\t');
    Serial.print(y);
    Serial.print('\t');
    Serial.println(z);
  }
}

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

I would advise that you start with the Arduino BLE library Battery Monitor example sketch which writes a simple integer value and see if you can the data to your computer. What app on the computer will read the data?

Hi, thanks for this I will look into it- i'm using touch designer

I managed to get two NANO sense rev2 - communicating using these sketches, with data printing on the Serial Port of the central device - which is great!

[Bluetooth communications]

I just need to separate the data being sent or received. I'm wondering if the sensor data is automatically generated somewhere on the board and then sent or whether this needs to be specified in the code? In Klaus_K code the data on the serial monitor of the CENTRAL device seems to be indicating that 4 sensors are generating data -

To clarify - do you know if the sensors are constantly active or do they become activated with code individually?

cheers
Miguel

Good progress.

The link you posted is only for a peripheral sending a struct.

I'm wondering if the sensor data is automatically generated somewhere on the board and then sent or whether this needs to be specified in the code?

The sensors are activated to run with these checks in setup().

if ( !HTS.begin() )
if ( !BARO.begin() )

The date they generate is then read in a timed loop in the function sensorTask().

sensorData.temperature = HTS.readTemperature();
sensorData.humidity = HTS.readHumidity();
sensorData.pressure = BARO.readPressure() * 1000; // kPa -> Pa

Then this date is then written to the characteristics for the central to read in the bleTask( ) function with .writeValue( ) statements.

if ( sensorData.updated )
  {
    // BLE defines Temperature UUID 2A6E Type sint16 ( see XML links )
    // Unit is in degrees Celsius with a resolution of 0.01 degrees Celsius
    int16_t temperature = round( sensorData.temperature * 100.0 );
    temperatureCharacteristic.writeValue( temperature );

    // BLE defines Humidity UUID 2A6F Type uint16
    // Unit is in percent with a resolution of 0.01 percent
    uint16_t humidity = round( sensorData.humidity * 100.0 );
    humidityCharacteristic.writeValue( humidity );

    // BLE defines Pressure UUID 2A6D Type uint32
    // Unit is in Pascal with a resolution of 0.1 Pa
    uint32_t pressure = round( sensorData.pressure * 10.0 );
    pressureCharacteristic.writeValue( pressure );

    sensorData.updated = false;
  }

To summarize the answer. Yes, the sensor data is automatically generated on the board once the sensors are started with .begin( ) statements, but then the code needs to read the data and transfer it to the ble characteristic values with .writeValue( ) statements where they can be read by the Central reading the characteristic values.

1 Like

Hi cattledog, I found your reply to kaiak from 2023 and have updated the peripheral to:

//PERIPHERAL TESTING 1
#include <ArduinoBLE.h>
#include <Arduino_LSM6DS3.h>
// Set the same service UUID as in the Peripheral Device
const char* deviceServiceUuid = "12345678-1234-5678-1234-56789abcdef0";
const char* AccXCharUuid = "12345678-1234-5678-1234-56789abcdef1";
const char* AccYCharUuid = "12345678-1234-5678-1234-56789abcdef2";
const char* AccZCharUuid = "12345678-1234-5678-1234-56789abcdef3";
const char* GyroXCharUuid = "12345678-1234-5678-1234-56789abcdef4";
const char* GyroYCharUuid = "12345678-1234-5678-1234-56789abcdef5";
const char* GyroZCharUuid = "12345678-1234-5678-1234-56789abcdef6";


float x,y,z,gx,gy,gz;
double accelX=0;
double accelY=1;
double accelZ=0;
double gyroX=0;
double gyroY=0;
double gyroZ=0;


BLEService IMUService(deviceServiceUuid);
BLEDoubleCharacteristic AccXChar(AccXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccYChar(AccYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccZChar(AccZCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroXChar(GyroXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroYChar(GyroYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroZChar(GyroZCharUuid, BLERead | BLENotify);


void setup() {
  Serial.begin(9600);
  while (!Serial);


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


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


  BLE.setLocalName("IMU Peripheral");
  BLE.setAdvertisedService(IMUService);
  IMUService.addCharacteristic(AccXChar);
  IMUService.addCharacteristic(AccYChar);
  IMUService.addCharacteristic(AccZChar);
  IMUService.addCharacteristic(GyroXChar);
  IMUService.addCharacteristic(GyroYChar);
  IMUService.addCharacteristic(GyroZChar);
  BLE.addService(IMUService);
  BLE.advertise();


  Serial.println("IMU Peripheral (Sending Data)");
}


void loop() {
  BLEDevice central = BLE.central();


  if (central) {
    if (central.connected()) {
      Serial.println("Connected to central device");
      Serial.print("Device MAC address: ");
      Serial.println(central.address());
    } else {
      Serial.println("Disconnected from central device");
    }
  }


  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);
    accelX = x;
    accelY = y;
    accelZ = z;
    Serial.print("Acceleration - x: ");
    Serial.print(x);
    Serial.print(", y: ");
    Serial.print(y);
    Serial.print(", z: ");
    Serial.println(z);
  }


  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gx, gy, gz);
    gyroX = gx;
    gyroY = gy;
    gyroZ = gz;
    Serial.print("Gyroscope - gx: ");
    Serial.print(gx);
    Serial.print(", gy: ");
    Serial.print(gy);
    Serial.print(", gz: ");
    Serial.println(gz);
  }


  AccXChar.writeValue(accelX);
  AccYChar.writeValue(accelY);
  AccZChar.writeValue(accelZ);
  GyroXChar.writeValue(gyroX);
  GyroYChar.writeValue(gyroY);
  GyroZChar.writeValue(gyroZ);


  delay(3000);
}

And the Central to :

//CENTRAL TESTING 1
#include <ArduinoBLE.h>


const char* deviceServiceUuid = "12345678-1234-5678-1234-56789abcdef0";
const char* AccXCharUuid = "12345678-1234-5678-1234-56789abcdef1";
const char* AccYCharUuid = "12345678-1234-5678-1234-56789abcdef2";
const char* AccZCharUuid = "12345678-1234-5678-1234-56789abcdef3";
const char* GyroXCharUuid = "12345678-1234-5678-1234-56789abcdef4";
const char* GyroYCharUuid = "12345678-1234-5678-1234-56789abcdef5";
const char* GyroZCharUuid = "12345678-1234-5678-1234-56789abcdef6";


BLEDoubleCharacteristic AccXChar(AccXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccYChar(AccYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccZChar(AccZCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroXChar(GyroXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroYChar(GyroYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroZChar(GyroZCharUuid, BLERead | BLENotify);


void setup() {
  Serial.begin(9600);
  while (!Serial);


  BLE.begin();
} // setup


void loop() {
  BLE.scanForUuid(deviceServiceUuid);
  BLEDevice peripheral = BLE.available();


  if (peripheral) {
    Serial.println("Peripheral Device Found");
    Serial.print("Device Name: ");
    Serial.println(peripheral.localName());
    Serial.print("Device MAC Address: ");
    Serial.println(peripheral.address());
    BLE.stopScan();
    Serial.println("- Connecting to peripheral device...");


    if (peripheral.connect()) {
      Serial.println("Connected to Peripheral Device");
      Serial.println(" ");


      if (peripheral.discoverAttributes()) {
        Serial.println("Attributes Discovered");


        BLECharacteristic  accXChar = peripheral.characteristic(AccXCharUuid);
        BLECharacteristic  accYChar = peripheral.characteristic(AccYCharUuid);
        BLECharacteristic  accZChar = peripheral.characteristic(AccZCharUuid);
        BLECharacteristic  gyroXChar = peripheral.characteristic(GyroXCharUuid);
        BLECharacteristic  gyroYChar = peripheral.characteristic(GyroYCharUuid);
        BLECharacteristic  gyroZChar = peripheral.characteristic(GyroZCharUuid);


        while (peripheral.connected()){
        if (accXChar) {
          const uint8_t* bytes = accXChar.value();
          double accXValue;
          accXChar.readValue(&accXValue, sizeof(accXValue));
          //memcpy(&accXValue, bytes, sizeof(accXValue));
          Serial.print("Acceleration X: ");
          Serial.println(accXValue);
        }


        if (accYChar) {
          const uint8_t* bytes = accYChar.value();
          double accYValue;
          accYChar.readValue(&accYValue, sizeof(accYValue));
          //memcpy(&accYValue, bytes, sizeof(accYValue));
          Serial.print("Acceleration Y: ");
          Serial.println(accYValue);
        }


        if (accZChar) {
          const uint8_t* bytes = accZChar.value();
          double accZValue;
           accZChar.readValue(&accZValue, sizeof(accZValue));
         // memcpy(&accZValue, bytes, sizeof(accZValue));
          Serial.print("Acceleration Z: ");
          Serial.println(accZValue);
        }


        if (gyroXChar) {
          const uint8_t* bytes = gyroXChar.value();
          double gyroXValue;
           gyroXChar.readValue(&gyroXValue, sizeof(gyroXValue));
          //memcpy(&gyroXValue, bytes, sizeof(gyroXValue));
          Serial.print("Gyroscope X: ");
          Serial.println(gyroXValue);
        }


        if (gyroYChar) {
          const uint8_t* bytes = gyroYChar.value();
          double gyroYValue;
          gyroYChar.readValue(&gyroYValue, sizeof(gyroYValue));
          //memcpy(&gyroYValue, bytes, sizeof(gyroYValue));
          Serial.print("Gyroscope Y: ");
          Serial.println(gyroYValue);
        }


        if (gyroZChar) {
          const uint8_t* bytes = gyroZChar.value();
          double gyroZValue;
          gyroZChar.readValue(&gyroZValue, sizeof(gyroZValue));
          //memcpy(&gyroZValue, bytes, sizeof(gyroZValue));
          Serial.print("Gyroscope Z: ");
          Serial.println(gyroZValue);
          }
          delay(1000);
        }
      }
    } else {
      Serial.println("* Connection to peripheral device failed!");
      Serial.println(" ");
    }
  }
  delay(500);
}

I am getting no data on the serial monitor for the Central device and when I connect the Peripheral to USB I get a "Failed to Initialise IMU" message. I am using the Nano 33 Sense Rev 2. Not sure if the delay value affects the central's ability to read the advertised values. I have the peripheral running off a 9V battery - for mobility.

You have made really good progress.

when I connect the Peripheral to USB I get a "Failed to Initialise IMU" message.

Clearly this is your first issue to resolve. You can not expect the central to read data which is not there. :wink:

#include <Arduino_LSM6DS3.h>

I'm not certain this is correct for the BLE Sense Rev2 IMU.

EDIT:
I think you were using the correct library in your first posting

#include "Arduino_BMI270_BMM150.h"

See this link, and try using the library examples to see if you can get the data you want from the Nano 33 Ble Sense Rev2. Unfortunately, I do not have a board to help you work through this, as I only have a Nano 33 BLE which has a different imu.

https://docs.arduino.cc/tutorials/nano-33-ble-sense-rev2/imu-accelerometer/

Great! thanks that worked for the Peripheral - now getting a constant read of Gyro and Accelerometer values.

However, the data is not being read by the central device. I am using a 9V battery on the Peripheral - this worked well with the Bluetooth communications examples mentioned earlier - so there is proof of concept.

I'm wondering if it may be something in the Central sketch that is not reading Just a few questions: (do I include the "Arduino_BMI270_BMM150.h" library on the Central as well?)- or is the peripheral not advertising for some reason?

No need for the imu library in the central.

However, the data is not being read by the central device.

Is the central device connecting?
What is the central device?

I would suggest that you use Light Blue or nrfConnect on a phone to check the peripheral sketch.

I have tried to find the Peripheral on LightBlue - iOS - but no luck seeing it there. I should be seeing the name "IMU Service" I think?

I tried restarting the Arduino Cloud and finally got a "Connecting" message in the Serial Monitor - but then it changes to a yellow "Serial Monitor Unavailable" message - some progress at least - Here are the updated sketches Im using:
for the PERIPHERAL

//PERIPHERAL TESTING 1
#include <ArduinoBLE.h>
//#include <Arduino_LSM6DS3.h>
#include <Arduino_BMI270_BMM150.h>
// Set the same service UUID as in the Peripheral Device
const char* deviceServiceUuid = "b83b6b32-0d38-45da-9a65-73eecc736b17";
const char* AccXCharUuid = "22128dec-f7bc-4c21-a329-c13449221777";
const char* AccYCharUuid = "677314b1-6d7d-4b38-8e37-0a3d24538c01";
const char* AccZCharUuid = "648ae827-f439-4038-a8ed-88e67b2cbb33";
const char* GyroXCharUuid = "07c120ff-3915-410b-9c45-c84533e674df";
const char* GyroYCharUuid = "17a45678-jj34-5678-1234-56789ab34ef5";
const char* GyroZCharUuid = "9f345678-dd34-5678-1234-56789a67def6";


float x,y,z,gx,gy,gz;
double accelX=0;
double accelY=1;
double accelZ=0;
double gyroX=0;
double gyroY=0;
double gyroZ=0;


BLEService IMUService(deviceServiceUuid);
BLEDoubleCharacteristic AccXChar(AccXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccYChar(AccYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccZChar(AccZCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroXChar(GyroXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroYChar(GyroYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroZChar(GyroZCharUuid, BLERead | BLENotify);


void setup() {
  Serial.begin(9600);
  while (!Serial);


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


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


  BLE.setLocalName("IMU Peripheral");
  BLE.setAdvertisedService(IMUService);
  IMUService.addCharacteristic(AccXChar);
  IMUService.addCharacteristic(AccYChar);
  IMUService.addCharacteristic(AccZChar);
  IMUService.addCharacteristic(GyroXChar);
  IMUService.addCharacteristic(GyroYChar);
  IMUService.addCharacteristic(GyroZChar);
  BLE.addService(IMUService);
  BLE.advertise();


  Serial.println("IMU Peripheral (Sending Data)");
}


void loop() {
  BLEDevice central = BLE.central();


  if (central) {
    if (central.connected()) {
      Serial.println("Connected to central device");
      Serial.print("Device MAC address: ");
      Serial.println(central.address());
    } else {
      Serial.println("Disconnected from central device");
    }
  }


  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);
    accelX = x;
    accelY = y;
    accelZ = z;
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(", y: ");
    Serial.print(y);
    Serial.print(", z: ");
    Serial.println(z);
  }


  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gx, gy, gz);
    gyroX = gx;
    gyroY = gy;
    gyroZ = gz;
    Serial.print("gx: ");
    Serial.print(gx);
    Serial.print(", gy: ");
    Serial.print(gy);
    Serial.print(", gz: ");
    Serial.println(gz);
  }


  AccXChar.writeValue(accelX);
  AccYChar.writeValue(accelY);
  AccZChar.writeValue(accelZ);
  GyroXChar.writeValue(gyroX);
  GyroYChar.writeValue(gyroY);
  GyroZChar.writeValue(gyroZ);


  delay(1000);
}

the CENTRAL

//CENTRAL TESTING 1
#include <ArduinoBLE.h>


const char* deviceServiceUuid = "b83b6b32-0d38-45da-9a65-73eecc736b17";
const char* AccXCharUuid = "22128dec-f7bc-4c21-a329-c13449221777";
const char* AccYCharUuid = "677314b1-6d7d-4b38-8e37-0a3d24538c01";
const char* AccZCharUuid = "648ae827-f439-4038-a8ed-88e67b2cbb33";
const char* GyroXCharUuid = "07c120ff-3915-410b-9c45-c84533e674df";
const char* GyroYCharUuid = "17a45678-jj34-5678-1234-56789ab34ef5";
const char* GyroZCharUuid = "9f345678-dd34-5678-1234-56789a67def6";


BLEDoubleCharacteristic AccXChar(AccXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccYChar(AccYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic AccZChar(AccZCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroXChar(GyroXCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroYChar(GyroYCharUuid, BLERead | BLENotify);
BLEDoubleCharacteristic GyroZChar(GyroZCharUuid, BLERead | BLENotify);


void setup() {
  Serial.begin(9600);
  while (!Serial);

  BLE.begin();
  BLE.scanForUuid(deviceServiceUuid);
  
} // setup


void loop() {
 BLEDevice peripheral = BLE.available();

  if (peripheral) {
    Serial.println("Peripheral Device Found");
    Serial.print("Device Name: ");
    Serial.println(peripheral.localName());
    Serial.print("Device MAC Address: ");
    Serial.println(peripheral.address());
    BLE.stopScan();
    Serial.println("- Connecting to peripheral device...");


    if (peripheral.connect()) {
      Serial.println("Connected to Peripheral Device");
      Serial.println(" ");


      if (peripheral.discoverAttributes()) {
        Serial.println("Attributes Discovered");


        BLECharacteristic  accXChar = peripheral.characteristic(AccXCharUuid);
        BLECharacteristic  accYChar = peripheral.characteristic(AccYCharUuid);
        BLECharacteristic  accZChar = peripheral.characteristic(AccZCharUuid);
        BLECharacteristic  gyroXChar = peripheral.characteristic(GyroXCharUuid);
        BLECharacteristic  gyroYChar = peripheral.characteristic(GyroYCharUuid);
        BLECharacteristic  gyroZChar = peripheral.characteristic(GyroZCharUuid);


        while (peripheral.connected()){
        if (accXChar) {
          const uint8_t* bytes = accXChar.value();
          double accXValue;
          accXChar.readValue(&accXValue, sizeof(accXValue));
          //memcpy(&accXValue, bytes, sizeof(accXValue));
          Serial.print("X: ");
          Serial.println(accXValue);
        }


        if (accYChar) {
          const uint8_t* bytes = accYChar.value();
          double accYValue;
          accYChar.readValue(&accYValue, sizeof(accYValue));
          //memcpy(&accYValue, bytes, sizeof(accYValue));
          Serial.print("Y: ");
          Serial.println(accYValue);
        }


        if (accZChar) {
          const uint8_t* bytes = accZChar.value();
          double accZValue;
           accZChar.readValue(&accZValue, sizeof(accZValue));
         // memcpy(&accZValue, bytes, sizeof(accZValue));
          Serial.print("Z: ");
          Serial.println(accZValue);
        }


        if (gyroXChar) {
          const uint8_t* bytes = gyroXChar.value();
          double gyroXValue;
           gyroXChar.readValue(&gyroXValue, sizeof(gyroXValue));
          //memcpy(&gyroXValue, bytes, sizeof(gyroXValue));
          Serial.print("gX: ");
          Serial.println(gyroXValue);
        }


        if (gyroYChar) {
          const uint8_t* bytes = gyroYChar.value();
          double gyroYValue;
          gyroYChar.readValue(&gyroYValue, sizeof(gyroYValue));
          //memcpy(&gyroYValue, bytes, sizeof(gyroYValue));
          Serial.print("gY: ");
          Serial.println(gyroYValue);
        }


        if (gyroZChar) {
          const uint8_t* bytes = gyroZChar.value();
          double gyroZValue;
          gyroZChar.readValue(&gyroZValue, sizeof(gyroZValue));
          //memcpy(&gyroZValue, bytes, sizeof(gyroZValue));
          Serial.print("gZ: ");
          Serial.println(gyroZValue);
          }
          delay(1000);
        }
      }
    } else {
      Serial.println("* Connection to peripheral device failed!");
      Serial.println(" ");
    }
  }
  delay(1000);
}

I just thought I would also post the two sketches that are definitely working. I'm using them as a guide as I work through the meaning of each section. The second set seem to have elements that are missing from the thirst two. I am wondering if this might be a clue. For example, I haven't been able to find documentation on BLEDoubleCharacteristic?

Working sketches:
PERIPHERAL

/*
  This example creates a BLE peripheral with a service containing a characeristic with multiple values combined.
  The yellow LED shows the BLE module is initialized.
  The green LED shows RSSI of zero. The more it blinks the worse the connection.

  The circuit:
  - Arduino Nano 33 BLE Sense board.

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

//----------------------------------------------------------------------------------------------------------------------
// BLE UUIDs
//----------------------------------------------------------------------------------------------------------------------

#define BLE_UUID_SENSOR_DATA_SERVICE              "2BEEF31A-B10D-271C-C9EA-35D865C1F48A"
#define BLE_UUID_MULTI_SENSOR_DATA                "4664E7A1-5A13-BFFF-4636-7D0A4B16496C"

#define NUMBER_OF_SENSORS 4

union multi_sensor_data
{
  struct __attribute__( ( packed ) )
  {
    float values[NUMBER_OF_SENSORS];
  };
  uint8_t bytes[ NUMBER_OF_SENSORS * sizeof( float ) ];
};

union multi_sensor_data multiSensorData;


//----------------------------------------------------------------------------------------------------------------------
// BLE
//----------------------------------------------------------------------------------------------------------------------

BLEService sensorDataService( BLE_UUID_SENSOR_DATA_SERVICE );
BLECharacteristic multiSensorDataCharacteristic( BLE_UUID_MULTI_SENSOR_DATA, BLERead | BLENotify, sizeof multiSensorData.bytes );


const int BLE_LED_PIN = LED_BUILTIN;
const int RSSI_LED_PIN = LED_PWR;


void setup()
{
  Serial.begin( 9600 );
  //while ( !Serial );

  pinMode( BLE_LED_PIN, OUTPUT );
  pinMode( RSSI_LED_PIN, OUTPUT );

  if ( setupBleMode() )
  {
    digitalWrite( BLE_LED_PIN, HIGH );
  }

  for ( int i = 0; i < NUMBER_OF_SENSORS; i++ )
  {
    multiSensorData.values[i] = i;
  }
}


void loop()
{
  #define UPDATE_INTERVALL 50
  static long previousMillis = 0;

  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();

  if ( central )
  {
    Serial.print( "Connected to central: " );
    Serial.println( central.address() );

    while ( central.connected() )
    {
      unsigned long currentMillis = millis();
      if ( currentMillis - previousMillis > UPDATE_INTERVALL )
      {
        previousMillis = currentMillis;

        Serial.print( "Central RSSI: " );
        Serial.println( central.rssi() );

        if ( central.rssi() != 0 )
        {
          digitalWrite( RSSI_LED_PIN, LOW );

          for ( int i = 0; i < NUMBER_OF_SENSORS; i++ )
          {
            multiSensorData.values[i] = multiSensorData.values[i] + 0.1;
          }

          multiSensorDataCharacteristic.writeValue( multiSensorData.bytes, sizeof multiSensorData.bytes );
        }
        else
        {
          digitalWrite( RSSI_LED_PIN, HIGH );
        }
      }
    }

    Serial.print( F( "Disconnected from central: " ) );
    Serial.println( central.address() );
  }
}



bool setupBleMode()
{
  if ( !BLE.begin() )
  {
    return false;
  }

  // set advertised local name and service UUID:
  BLE.setDeviceName( "Arduino Nano 33 BLE" );
  BLE.setLocalName( "Arduino Nano 33 BLE" );
  BLE.setAdvertisedService( sensorDataService );

  // BLE add characteristics
  sensorDataService.addCharacteristic( multiSensorDataCharacteristic );

  // add service
  BLE.addService( sensorDataService );

  // set the initial value for the characeristic:
  multiSensorDataCharacteristic.writeValue( multiSensorData.bytes, sizeof multiSensorData.bytes );

  // start advertising
  BLE.advertise();

  return true;
}

CENTRAL

/*
  This example creates a BLE central that scans for a peripheral with a service containing a multi value characteristic. WORKS GREAT!!

  The circuit:
  - Arduino Nano 33 BLE or Arduino Nano 33 IoT board.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

//----------------------------------------------------------------------------------------------------------------------
// BLE UUIDs
//----------------------------------------------------------------------------------------------------------------------

#define BLE_UUID_SENSOR_DATA_SERVICE              "2BEEF31A-B10D-271C-C9EA-35D865C1F48A"
#define BLE_UUID_MULTI_SENSOR_DATA                "4664E7A1-5A13-BFFF-4636-7D0A4B16496C"

#define NUMBER_OF_SENSORS 4

union multi_sensor_data
{
  struct __attribute__( ( packed ) )
  {
    float values[NUMBER_OF_SENSORS];
  };
  uint8_t bytes[ NUMBER_OF_SENSORS * sizeof( float ) ];
};

union multi_sensor_data multiSensorData;


void setup()
{
  Serial.begin( 9600 );
  while ( !Serial );

  BLE.begin();

  BLE.scanForUuid( BLE_UUID_SENSOR_DATA_SERVICE );
}


void loop()
{
#define UPDATE_INTERVALL 10
  static long previousMillis = 0;

  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > UPDATE_INTERVALL )
  {
    previousMillis = currentMillis;

    BLEDevice peripheral = BLE.available();

    if ( peripheral )
    {
      if ( peripheral.localName() != "Arduino Nano 33 BLE" )
      {
        return;
      }

      BLE.stopScan();

      explorePeripheral( peripheral );

      BLE.scanForUuid( BLE_UUID_SENSOR_DATA_SERVICE );
    }
  }
}


bool explorePeripheral( BLEDevice peripheral )
{
  if ( !peripheral.connect() )
  {
    return false;
  }
  Serial.println( "BLE connected" );

  if ( !peripheral.discoverAttributes() )
  {
    peripheral.disconnect();
    return false;
  }
  Serial.println( "BLE attributes discovered" );

  BLECharacteristic multiSensorDataCharacteristic = peripheral.characteristic( BLE_UUID_MULTI_SENSOR_DATA );
  if ( !multiSensorDataCharacteristic )
  {
    peripheral.disconnect();
    return false;
  }
  Serial.println( "BLE characteristic found" );

  if ( !multiSensorDataCharacteristic.canSubscribe() )
  {
    peripheral.disconnect();
    return false;
  }
  Serial.println( "BLE characteristic can subscribe" );

  if ( !multiSensorDataCharacteristic.subscribe() )
  {
    peripheral.disconnect();
    return false;
  }
  Serial.println( "BLE characteristic subscribed" );

  while ( 1 ) // need to add logic to leave
  {
#define BLE_POLL_INTERVALL 5
    static long previousMillis = 0;
    unsigned long currentMillis = millis();
    if ( currentMillis - previousMillis > BLE_POLL_INTERVALL )
    {
      BLE.poll();

      if ( multiSensorDataCharacteristic.valueUpdated() )
      {
        Serial.println( "BLE new data" );

        multiSensorDataCharacteristic.readValue( multiSensorData.bytes, sizeof multiSensorData.bytes );
        for ( int i = 0; i < NUMBER_OF_SENSORS; i++ )
        {
          Serial.print( "Sensor (" );
          Serial.print( i );
          Serial.print( "): " );
          Serial.println( multiSensorData.values[i] );
        }
      }
    }
  }

  peripheral.disconnect();
  return true;
}

I don't know if you will see the name or just the service uuid
"b83b6b32-0d38-45da-9a65-73eecc736b17"

Not seeing the peripheral and the characteristics in a standard phone app is not a good sign.

In my experience the peripheral is easier to code. Verifying with a phone app is the first thing. One thing that you might try for debugging is to change the characteristic values to text. It's easier to see the values in a phone app as they don't show floats in any other way than the 4 byte values.

I really don't understand your environment. What is the reference to the cloud.

I'm not remembering where you said the central is running. Is it on a second Nano 33 or is it on a PC?

I am uploading the sketch from the Arduino Cloud and opening the Serial Monitor from there (with the second - CENTRAL - NANO 33 Sense Rev 2 connected via USB), but also have been checking on IDE on a Mac - both haven't shown data in the Serial Monitor yet.

When you say "characteristic values to text" do you mean here:

  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(x, y, z);
    accelX = x;
    accelY = y;
    accelZ = z;
    Serial.print("x: ");
    Serial.print(x);
    Serial.print(", y: ");
    Serial.print(y);
    Serial.print(", z: ");
    Serial.println(z);
  }


  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gx, gy, gz);
    gyroX = gx;
    gyroY = gy;
    gyroZ = gz;
    Serial.print("gx: ");
    Serial.print(gx);
    Serial.print(", gy: ");
    Serial.print(gy);
    Serial.print(", gz: ");
    Serial.println(gz);
  }

OK. Using two Nano 33's is good, and I am setting up to test you codes.

I have modified your peripheral sketch to used the imu in my Nano33 which
#include <Arduino_LSM9DS1.h>

The serial output from the sketch looks good, and I can see the connected to central device message,

08:42:11.855 -> Connected to central device
08:42:11.855 -> Device MAC address: 78:30:76:ad:b1:74
08:42:11.855 -> Acceleration - x: 0.04, y: 0.05, z: 0.98
08:42:11.855 -> Gyroscope - gx: 1.46, gy: -1.59, gz: 1.28

I have tried to find the Peripheral on LightBlue - iOS - but no luck seeing it there. I should be seeing the name "IMU Service" I think?

I think there is something very wrong with your iOS test tools, When I use LightBlue on an Android phone, I can connect to the peripheral sketch posted in and see the advertised name IMU peripheral, the Service uuid, and the 6 characteristics. I can subscribe to the characteristics and see them change.

I'll be working on the central to read the characteristics, but your first order of business is to get a phone app working as central with the peripheral. You can try nrfConnect as well as LightBlue. I can connect to the peripheral with both apps and see all chacteristics.

When I use the central sketch that you posted in Post #7 along with the central. It appears to work correctly on a Nano 33.

I get this serial output, and the data matches what is sent by the peripheral.
The attribute discovery after connection takes some time.

09:59:19.190 -> Peripheral Device Found
09:59:19.190 -> Device Name: IMU Peripheral
09:59:19.190 -> Device MAC Address: 2a:c1:f3:8f:19:fb
09:59:19.190 -> - Connecting to peripheral device...
09:59:19.269 -> Connected to Peripheral Device
09:59:19.269 ->  
10:00:52.491 -> Attributes Discovered
10:00:55.508 -> Acceleration X: 0.04
10:00:58.481 -> Acceleration Y: -0.02
10:01:01.505 -> Acceleration Z: 0.98
10:01:04.519 -> Gyroscope X: 1.22
10:01:07.579 -> Gyroscope Y: -1.28
10:01:10.576 -> Gyroscope Z: 1.28
10:01:13.620 -> Acceleration X: 0.04
10:01:16.637 -> Acceleration Y: -0.02
10:01:19.640 -> Acceleration Z: 0.99

I do not understand the issues you are having in your environment.
I am using IDE 1.8.19 on a Win10 PC. Two Nano 33 Ble devices. I open two instances of the ide so I can see both monitors at the same time. The connection by the central and the finding of the attributes takes some time.

There are some things I don't understand about the timing and why the central only sees one new value each three seconds.

But your first order of business is getting the two Nano connected and exchanging data.

I had a brainwave and connected the peripheral to one computer via USB and opened the Serial Monitor and have a constant stream of accelerometer and gyro data.

IMU Peripheral (Sending Data)
x: 0.28, y: -0.15, z: 1.10
gx: -51.33, gy: -68.66, gz: -34.85
x: 0.67, y: -0.14, z: 0.68
gx: -105.41, gy: 106.57, gz: 49.50
x: 0.90, y: 0.12, z: 0.24
gx: 51.03, gy: -19.35, gz: -24.41
x: 0.48, y: -0.07, z: 0.96
gx: -55.66, gy: -11.96, gz: -10.50
x: 0.09, y: -0.72, z: 0.87

I then connected the other NANO to another computer and - got this in the Serial Monitor for the Peripheral:

x: -0.20, y: 0.01, z: 0.98
gx: -0.24, gy: 0.06, gz: 0.12
Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: -0.20, y: 0.01, z: 0.98
gx: -0.24, gy: 0.00, gz: 0.06
Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: -0.20, y: 0.02, z: 0.98
gx: -0.24, gy: 0.06, gz: 0.00
Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: -0.20, y: 0.02, z: 0.98
gx: -0.24, gy: 0.00, gz: 0.00
Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: -0.20, y: 0.02, z: 0.98
gx: -0.24, gy: 0.00, gz: 0.00

I then tried opening the Serial Monitor on the CENTRAL NANO (via USB on the second computer) and am not seeing any data in the Serial Monitor being received - but they are clearly connected!

There is something wrong with the print command on the Central Maybe?

After I disconnect the CENTRAL from computer 2 - I get this on the Peripheral:

Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: 0.01, y: -0.01, z: 1.00
gx: -0.31, gy: 0.06, gz: 0.00
Connected to central device
Device MAC address: 30:bb:ac:35:a5:2b
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: 0.06, gz: 0.00
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: 0.06, gz: 0.00
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: -0.06, gz: 0.06
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: 0.00, gz: 0.00
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: 0.06, gz: 0.06
x: 0.01, y: -0.01, z: 1.00
gx: -0.24, gy: 0.06, gz: 0.00
x: -0.00, y: -0.25, z: 0.97

The good news is that the CENTRAL did receive data from the Peripheral - with the peripheral plugged in to the second computer- meaning it was drawing power from the computer - I then tried it using a 9V battery and no data.

This means that there is communication! Will keep testing...

All tests since have failed - will update after more tests in coming days.

I then tried opening the Serial Monitor on the CENTRAL NANO (via USB on the second computer) and am not seeing any data in the Serial Monitor being received - but they are clearly connected!

There is something wrong with the print command on the Central Maybe?

When I tested your sketches the print out from the central was fine, so I do not believe that there is an issue with the print commands. The connection and then discovery did take some time, as you can see from the timing of the print statements in the data I posted.

The good news is that the CENTRAL did receive data from the Peripheral - with the peripheral plugged in to the second computer- meaning it was drawing power from the computer - I then tried it using a 9V battery and no data.

Does this mean that you saw data on a print out from the central when connected to a PC?

Both sketches contain a line while(!Serial)
This means that a monitor needs to be open and connected to the serial port. If you are using this sketch in the cloud and not on a pc, I have no idea if the Nano33 knows it is connected to a monitor and breaks from the blocking statement. If you are using a battery and not connection to Serial, the code will not go past the while(!Serial) statement.

Try and take that line out of the code and see if the central and peripheral work as planned.

Removed the while (!Serial); on the Peripheral and Central and:

Z: 0.25
gX: 25.45
gZ: -0.06
X: 0.00
Y: -0.96
Z: -0.19
gX: -0.06
gZ: 0.00
X: 0.00
Y: -0.96
Z: -0.19
gX: -0.18
gZ: 0.06
X: 0.00
Y: -0.96
Z: -0.19
gX: -0.18
gZ: 0.12
X: 0.00

You're a genius Thanks!!!