Characteristic.valueUpdated() don't work on NANO 33 SENSE


Hello guys, i am using two NANO 33 SENSE to communicate each other with BLE, followed by the tutorial https://docs.arduino.cc/tutorials/nano-33-ble-sense/ble-device-to-device it is easy to have the gesture monitored, I then have the peripheral device get an analog signal from an IR sensor, and I add an IR characteristic under the gesture service.

I use bleCharacteristic.writeValue() to update IR sensor value on peripheral device and bleCharacteristic.valueUpdated() on cnetral device. I can see from peripheral device serial print that the data is always updating, but on cnetral device the bleCharacteristic.valueUpdated() just doesn't work.

Can anyone see what's going on here? THX.

/*
  BLE_Peripheral.ino

  This program uses the ArduinoBLE library to set-up an Arduino Nano 33 BLE
  as a peripheral device and specifies a service and a characteristic. Depending
  of the value of the specified characteristic, an on-board LED gets on.

  The circuit:
  - Arduino Nano 33 BLE.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#include <Servo.h>
#include <SharpIR.h>

// Define IR model and input pin:
#define IRPin A0
#define model 1080   // not use, use SharpIR myIRSensor(SharpIR::GP2Y0A21YK0F, IRPin); instead

Servo myservo;

// Create a new instance of the SharpIR class:
SharpIR myIRSensor(SharpIR::GP2Y0A21YK0F, IRPin);


const char* deviceServiceUuid_1 = "ecef0000-8671-4730-a18d-dc6262f78a27";
const char* deviceServiceCharacteristicUuid_1 = "ecef0001-8671-4730-a18d-dc6262f78a27";
const char* deviceServiceCharacteristicUuid_2 = "ecef0002-8671-4730-a18d-dc6262f78a27";
BLEService gestureService(deviceServiceUuid_1);
BLEByteCharacteristic gestureCharacteristic(deviceServiceCharacteristicUuid_1, BLERead | BLEWrite);
BLEUnsignedCharCharacteristic IR_distance_Characteristic(deviceServiceCharacteristicUuid_2, BLERead | BLENotify | BLEBroadcast);

int gesture = -1;
int old_IR_Distance = 10;  // last distance reading from analog input
long previousMillis = 0;  // last time the distance was checked, in ms

int servo_position_1 = 96;
int servo_position_2 = 136;
int i = 1;

enum {
  GESTURE_NONE  = -1,
  GESTURE_UP    = 0,
  GESTURE_DOWN  = 1,
  GESTURE_LEFT  = 2,
  GESTURE_RIGHT = 3
};




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

  // Use D12 pin of [NANO 33 SENSE BLE] as servo drive pin;
  myservo.attach(D12);
  for (i = 90; i < 180; i++) {
    myservo.write(i);
    delay(100);
  }

  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);

  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
  digitalWrite(LED_BUILTIN, LOW);


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

  BLE.setLocalName("Range Detect on Arduino Nano 33 BLE (Peripheral)");
  BLE.setAdvertisedService(gestureService);
  gestureService.addCharacteristic(gestureCharacteristic);
  gestureService.addCharacteristic(IR_distance_Characteristic);
  BLE.addService(gestureService);
  gestureCharacteristic.writeValue(-1);   // set initial value for this characteristic
  IR_distance_Characteristic.writeValue(old_IR_Distance);   // set initial value for this characteristic

  // start advertising
  BLE.advertise();

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

void loop() {
  // wait for a Bluetooth® Low Energy central
  BLEDevice central = BLE.central();
  Serial.println("- Discovering central device...");
  delay(500);

  // if a central is connected to the peripheral:
  if (central) {
    Serial.println("* Connected to central device!");
    Serial.print("* Device MAC address: ");
    Serial.println(central.address());
    Serial.println(" ");

    while (central.connected()) {
      if (gestureCharacteristic.written()) {
        gesture = gestureCharacteristic.value();
        writeGesture(gesture);
      }

      long currentMillis = millis();
      // if 200ms have passed, check the distance:
      if (currentMillis - previousMillis >= 1000) {
        previousMillis = currentMillis;
        updateDistance();
      }

    }

    Serial.print("* Disconnected to central device: ");
    Serial.println(central.address());
  }
}

void writeGesture(int gesture) {
  Serial.println("- Characteristic <gesture_type> has changed!");

  switch (gesture) {
    case GESTURE_UP:
      Serial.println("* Actual value: UP (red LED on)");
      Serial.println(" ");
      digitalWrite(LEDR, LOW);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
      digitalWrite(LED_BUILTIN, LOW);
      myservo.write(servo_position_1);
      break;
    case GESTURE_DOWN:
      Serial.println("* Actual value: DOWN (green LED on)");
      Serial.println(" ");
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, LOW);
      digitalWrite(LEDB, HIGH);
      digitalWrite(LED_BUILTIN, LOW);
      myservo.write(servo_position_1);
      break;
    case GESTURE_LEFT:
      Serial.println("* Actual value: LEFT (blue LED on)");
      Serial.println(" ");
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, LOW);
      digitalWrite(LED_BUILTIN, LOW);
      myservo.write(servo_position_2);
      break;
    case GESTURE_RIGHT:
      Serial.println("* Actual value: RIGHT (built-in LED on)");
      Serial.println(" ");
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
      digitalWrite(LED_BUILTIN, HIGH);
      myservo.write(servo_position_2);
      break;
    default:
      digitalWrite(LEDR, HIGH);
      digitalWrite(LEDG, HIGH);
      digitalWrite(LEDB, HIGH);
      digitalWrite(LED_BUILTIN, LOW);
      myservo.write(servo_position_1);
      break;
  }
}


void updateDistance() {
  /* Read the current range distance on the A0 analog input pin.
     This is used here to simulate the charge level of a battery.
  */
  int range = myIRSensor.getDistance();

  if (range != old_IR_Distance) {      // if the distance has changed
    Serial.print("Distance is now: "); // print it
    Serial.println(range);
    IR_distance_Characteristic.writeValue(range);  // and update the battery level characteristic
    IR_distance_Characteristic.broadcast();
    old_IR_Distance = range;           // save the level for next comparison
  }
}
/*
  BLE_Central_Device.ino

  This program uses the ArduinoBLE library to set-up an Arduino Nano 33 BLE Sense
  as a central device and looks for a specified service and characteristic in a
  peripheral device. If the specified service and characteristic is found in a
  peripheral device, the last detected value of the on-board gesture sensor of
  the Nano 33 BLE Sense, the APDS9960, is written in the specified characteristic.

  The circuit:
  - Arduino Nano 33 BLE Sense.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#include <Arduino_APDS9960.h>

const char* deviceServiceUuid_1 = "ecef0000-8671-4730-a18d-dc6262f78a27";
const char* deviceServiceCharacteristicUuid_1 = "ecef0001-8671-4730-a18d-dc6262f78a27";
const char* deviceServiceCharacteristicUuid_2 = "ecef0002-8671-4730-a18d-dc6262f78a27";

int gesture = -1;
int oldGestureValue = -1;
const uint8_t* IR_distance;

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

  if (!APDS.begin()) {
    Serial.println("* Error initializing APDS9960 sensor!");
  }

  APDS.setGestureSensitivity(80);

  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(" ");
  BLE.scan();
}

void loop() {
  connectToPeripheral();
}

void connectToPeripheral() {
  BLEDevice peripheral;

  Serial.println("- Discovering peripheral device...");

  do
  {
    BLE.scanForUuid(deviceServiceUuid_1);
   
    peripheral = BLE.available();
  } while (!peripheral);

  if (peripheral) {
    Serial.println("* Peripheral device found!");
    Serial.print("* Device MAC address: ");
    Serial.println(peripheral.address());
    Serial.print("* Has local name? ");
    Serial.println(peripheral.hasLocalName());
    Serial.print("* Device name: ");
    Serial.println(peripheral.localName());
    Serial.print("* Advertised service UUID: ");
    Serial.println(peripheral.advertisedServiceUuid());
    Serial.println(" ");

    //if (peripheral.localName() == "Range Detect on Arduino Nano 33 BLE (Peripheral)") {
    if (peripheral.advertisedServiceUuid() == deviceServiceUuid_1) {
      // stop scanning
      BLE.stopScan();

      controlPeripheral(peripheral);
    }
  }
}

void controlPeripheral(BLEDevice peripheral) {
  // connect to the 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;
  }
  // discover peripheral attributes
  Serial.println("- Discovering peripheral device attributes...");
  if (peripheral.discoverService(deviceServiceUuid_1)) {
    Serial.println("* Peripheral device attributes discovered!");
    Serial.println(" ");
  } else {
    Serial.println("* Peripheral device attributes discovery failed!");
    Serial.println(" ");
    peripheral.disconnect();

    while (1);
    return;
  }

  // retrieve the characteristics
  BLECharacteristic gestureCharacteristic = peripheral.characteristic(deviceServiceCharacteristicUuid_1);
  BLECharacteristic IR_distance_Characteristic = peripheral.characteristic(deviceServiceCharacteristicUuid_2);


  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;
  }
  
  if (!IR_distance_Characteristic) {
    Serial.println("* Peripheral device does not have IR_distance_type characteristic!");
    peripheral.disconnect();
    return;
  }
  else if (!IR_distance_Characteristic.canSubscribe()) {
    Serial.println("* IR_distance_Characteristic is not subscribable!");
    peripheral.disconnect();
    return;
    }
    else if (!IR_distance_Characteristic.subscribe()) {
    Serial.println("subscription failed!");
    peripheral.disconnect();
    return;
    }
  else {
    Serial.println("Subscribed");
    Serial.println("Press the right and left buttons on your SensorTag.");
  }

  while (peripheral.connected()) {
    gesture = gestureDetectection();

    if (oldGestureValue != gesture) {
      oldGestureValue = gesture;
      Serial.print("* Writing value to gesture_type characteristic: ");
      Serial.println(gesture);
      gestureCharacteristic.writeValue((byte)gesture);
      Serial.println("* Writing value to gesture_type characteristic done!");
      Serial.println(" ");
    }

    
    if (IR_distance_Characteristic.valueUpdated()) {
    byte IR_distance = 0;
    IR_distance_Characteristic.readValue(IR_distance);
      Serial.print("incoming data is : ");
      Serial.println(IR_distance);
      }
  }

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

int gestureDetectection() {
  if (APDS.gestureAvailable()) {
    gesture = APDS.readGesture();

    switch (gesture) {
      case GESTURE_UP:
        Serial.println(" - UP gesture detected");
        break;
      case GESTURE_DOWN:
        Serial.println(" - DOWN gesture detected");
        break;
      case GESTURE_LEFT:
        Serial.println(" - LEFT gesture detected");
        break;
      case GESTURE_RIGHT:
        Serial.println(" - RIGHT gesture detected");
        break;
      default:
        Serial.println(" - No gesture detected");
        break;
    }
  }
  return gesture;
}

Welcome to the forum.

You asked in the wrong section of the forum. This will reduce your chance of getting answers. Most users only check sections they are interested in. I asked the moderators to move your post to Arduino Nano BLE or Sense.

Regarding your question.
Currently your central sketch does not subscribe to the characteristic. That means the central will not be informed about updates.
Also in the peripheral sketch the gestureCharacteristic has notification disabled.

Can you please make sure you remove the > in your code? Otherwise we need to clean it before we can test your code.

Hi, KK, I'm not familiar with the forum yet, thanks for the heads-up.

Actually I just figured out the bug, it's a typo of miss use the gestureCharacteristic in the .canSubscribe() and .subscribe() for IR_distance_Characteristic, both sketches work fine after correction.

The code is a simple modification from IDE examples , I shall try to set more services later.

Thanks again for the reminding, forum is supposed to be used to solve more serious problems, hope I didn't take up too much of your time.

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