arduino-libraries / ArduinoBLE

ArduinoBLE library for Arduino
GNU Lesser General Public License v2.1
319 stars 207 forks source link

Weak signal doesn't trigger disconnect() and hangs in multiple places #45

Open fgaetani opened 4 years ago

fgaetani commented 4 years ago

I noticed several problems when disconnecting on Arduino Nano 33 BLE board. Code execution remained locked in the writeValue() function, specifically in the HCIClass::sendAclPkt() function of the HCI.cpp file. The code remained locked in the while loop, because the device is disconnected. This is the original code:

while (_pendingPkt> = _maxPkt) {
    poll (); 
}

I solved this way:

int k = 0;
while (_pendingPkt> = _maxPkt) {
    k ++;
    if (k> _maxPkt) break;
    poll ();
}

Everything seems to work well, when it freezes in the cycle if the counter k exceeds _maxPkt exits the cycle. Is this the right way to correct? Has anyone found similar problems?

alexisicte commented 4 years ago

Hi @fgaetani, Can you name a few ways of disconnecting rduino Nano 33 BLE board? Are you using your device as peripheral or central?

Check this issue: https://github.com/arduino-libraries/ArduinoBLE/issues/33

I will update mine logs after your change.

fgaetani commented 4 years ago

Hi @alexisicte, thank you! I had already read that issue, but it is not clear how and if it was solved by pull request # 44. I confirm that the Arduino Nano BLE is configured as peripheral and that often it happens that central.connected() or BLE.central() still returns true when I move away from the device and the connection lost, but I solved this issue by examining the RSSI value, and disconnecting the central when RSSI value is less than a threshold. Can the problem encountered be due to the same reason?

alexisicte commented 4 years ago

According to my tests, #44 didn't solve the issue and i posted the results. I confirm that "central.connected() or BLE.central() still returns true when I move away from the device and the connection lost". Many thanks for the RSSI value hint! I am not sure if both problems have the same reason.. Despite that when using your logic i have different output. I'll post my findings

morettigiorgio commented 4 years ago

I agree with @alexisicte , me too #44 didn't solve the issue #33 and this. I checked that the changes mentioned by @sandeepmistry were in my ArduinoBLE library. I tested the above modify too (https://github.com/arduino-libraries/ArduinoBLE/issues/45#issue-540365091) but without having solved. I also noticed that if i forced a BLE.disconnect() (during the connection lost), central.connected() and BLE.central() returned the correct false, but my Arduino peripheral (Arduino Nano 33 BLE and Arduino Nano 33 BLE Sense) is no more discoverable, not even with another BLE.advertise() cmd. It's very strange... I have to restart, therefore, for my case, RSSI idea isn't a good solution

JoeyTolentino commented 4 years ago

Hello Everyone!

I've been following these particular threads (33, 44, and 45) for a few days now, and thought that maybe I could share my experience, to maybe help fix this issue. My programming is not very strong, however, maybe my observation of the behaviour of the hardware will help.

I've created a little sketch that will read values from the Nano 33 BLE's IMU and advertise them as a peripheral. I also display the values to a little OLED. When I connect to the Nano 33 BLE, I display a value on the OLED which indicates connectivity. So long as I'm within range, I can connect and disconnect all I wish, the values from the IMU continue to display, and the connection indicator on the display will go on and off as I request...what's interesting is that when I walk away, and I lose connectivity, the little display still indicates that "something is connected" and the IMU data is still updating as it should; however, I'm unable to see the device to reconnect to it when I'm near by. I'm not using anything fancy, other than LightBlue, and nRF Connect.

I think it is congruent with everyone else's experience. I've tried adding the recommended code by @fgaetani and I did not realize a behaviour change by the hardware.

The only way to reconnect would be to press the reset button, or cut power. Of which, when I do, I can connect again without issue...that is until I lose connectivity when walking away.

I'm not sure how else I can contribute, but I'm willing to try. C/C++ is not my strong suite, but I can assist with testing.

If there is code you wish for me to test, please let me know, I'll do what I can.

Thank you,

Joey

fgaetani commented 4 years ago

The reported issue #45 is different, in my case the microcontroller lock in loop in that cycle and by modifying in that way I solved it. While the other issue that sometimes the device disconnects, but Arduino nano BLE doesn't detect this, it happens to me too, and it's a frustrating issue. I tried to reset the BLE connection through the methods disconnect(), connect(), etc., but the problem is not solved. The board remains apparently connected and is no longer visible from other devices. The only solution is to reset the microcontroller manually or through a watchdog, but this is a damage for my application. I believe I will try to program the Arduino Nano BLE board with Adafruit libraries and bootloaders to see if the issue is solved.

JoeyTolentino commented 4 years ago

Thank you for your insight @fgaetani. I tried the same methods as yourself and found that it would remain in the central.connected() state. The only way that I could give the Arduino a chance was to be proactive about disconnection.

    if (central.connected()) {
      // Check for reasonable RSSI signal strength.
      if (central.rssi() >= RSSI_REASONABLE_SIGNAL) {
        // update BLE Characteristics      
      } else {
        // Until the defect is fixed, we force disconnection
        // of the central device.
        if (!central.disconnect()) {
          central.disconnect();          
        }                
      }    
    }

This way, when either of the devices come back in range, they can proactively reconnect.

I hope a solution can be found soon, it would be nice to be able to trust the .connected() method.

JoeyTolentino commented 4 years ago

Hello Everyone!

I had a chance to play with the Watchdog function of the nRF52840 microcontroller. The Watchdog code is only included when compiled and loaded onto a BLE or BLE Sense.

I'm still hoping that there will be a fix...so that the BLE and BLE Sense will function much like the 33 IoT when the connection is lost. I can confirm that the following code works "well"—I have it running on three boards. The 33 IoT does not reboot; whereas the BLE and BLE Sense do, when the connection is lost.

It's ugly...but it works. In my case, I'm only transmitting the values from the sensors, so nothing to critical is lost when the Watchdog reboots the board.

I hope this helps!

Joey

void setup() {
#if defined(ARDUINO_ARDUINO_NANO33BLE)
  // This segment of code only exists when compiled and loaded onto an
  // Arduino Nano 33 BLE and BLE Sense

  //Configure WDT.
  NRF_WDT->CONFIG         = 0x01;             // Configure WDT to run when CPU is asleep
  NRF_WDT->CRV            = 2 * 32768;        // Set timeout for 2 seconds
  NRF_WDT->RREN           = 0x01;             // Enable the RR[0] reload register
  NRF_WDT->TASKS_START    = 1;                // Start WDT
#endif
  // Execute initialization methods...
}

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

  if (central) {
    if (central.connected()) {
#if defined(ARDUINO_ARDUINO_NANO33BLE)
      // This segment of code only exists when compiled and loaded onto an
      // Arduino Nano 33 BLE and BLE Sense

      // Check for reasonable RSSI signal strength.
      if (central.rssi() > RSSI_REASONABLE_SIGNAL) {
        // So long as we have connection, reset the timer.
        NRF_WDT->RR[0] = WDT_RR_RR_Reload;
      }
#endif
      // Do the stuff you want to do while connected...
    }
  }

#if defined(ARDUINO_ARDUINO_NANO33BLE)
  // This segment of code only exists when compiled and loaded onto an
  // Arduino Nano 33 BLE and BLE Sense
  if (!central) {
    NRF_WDT->RR[0] = WDT_RR_RR_Reload;
  }
#endif
}
fgaetani commented 4 years ago

Hi @JoeyTolentino , I had already indicated that with the watchdog the problem is solved, but unfortunately in my application this is problematic. We hope for a solution as soon as possible. We await news from @facchinm

facchinm commented 4 years ago

@fgaetani I'm not 100% sure why that line is there in the first place. Can you provide a minimum working example of your application and how to trigger the issue exactly?

JoeyTolentino commented 4 years ago

Hi @fgaetani!

Thank you, I was intrigued by your Watchdog solution, so I had to look into how to implement it. I thought to share my solution to hopefully have some feedback. or maybe someone's insight on how to do it better.

Yes! Fingers crossed for a solution.

:)

Joey

fgaetani commented 4 years ago

Hi @facchinm , I did not understand which line you are referring to. The problem occurs during connection and disconnection procedure. I managed to emphasize the problem by making many repeated connections and disconnections though smartphone. This bug seems to be related to the problem in which the device is unable to detect the disconnection from the central, reported by other user in this issue, in #33 and #44.

facchinm commented 4 years ago

Ok, but do you have a sketch and a precise procedure I can try? Otherwise all debugging is useless

Hoffa25 commented 4 years ago

@facchinm @fgaetani

I have the same problems... I connect to the Arduino Nano BLE with an iOS app. When the app and the nano disconnects the app immediately tries to reconnect (according to https://stackoverflow.com/questions/26878173/ios-how-to-reconnect-to-ble-device-in-background).

To reproduce the error:

  1. You probably need an app that tries to auto reconnect when disconnected. If you dont know how to get one I can share my iOS app.
  2. Install arduino code below.
  3. Connect them and follow the output in serial monitor.
  4. Move the phone to a spot were the connection is really weak and it continuously jumps between connected and disconnected (9-10 meters and/or some object in front).
  5. Most of the time the error will occur within 5 minutes. To make it come quicker you can force disconnects by putting objects around the arduino (your hands, another smartphone, tablet, whatever blocks the signal well). When disconnected keep covering the arduino for 10-30s and then remove. Repeat until error occurs.

You will see the error in the serial monitor. See below how it looks like for me. As you see the loop() stops looping. Also a really weird thing starts: every 30 s from then on the eventhandlers get triggered with disconnected and connected. Even if I have removed my app!? I have also read in a post that its a bug that the rssi value sometimes is 0. As you see I get that regularly with a weak connection.

When this error has occured the only solution is to restart the arduino:/

My arduino code:

#include <ArduinoBLE.h>
unsigned long prevNow = 0;

BLEService testService("d3ed5e96-392c-4316-a4a6-eb92a7010c1f");

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

  BLE.setLocalName("Test");
  BLE.setAdvertisedService(testService);
  BLE.addService(testService);
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);
  BLE.advertise();
  Serial.println(("Bluetooth device active, waiting for connections..."));
}

void blePeripheralConnectHandler(BLEDevice central) {
  Serial.println("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  Serial.println("Disconnected event, central: ");
  Serial.println(central.address());
}

void loop() {
  BLE.poll();
  long now = millis();
  if (now - prevNow >= 1000) {
    prevNow = now;
    if (BLE.connected()) {
      int rssiValue = BLE.rssi();
      Serial.println(rssiValue);
      Serial.println("Connected to central");
    }
    else {
      Serial.println("Not connected to central");
    }
  }
}

Output from serial monitor:

13:15:17.206 -> Connected to central
13:15:18.199 -> -84
13:15:18.199 -> Connected to central
13:15:19.213 -> -85
13:15:19.213 -> Connected to central
13:15:20.197 -> 0
13:15:20.240 -> Connected to central
13:15:21.045 -> Disconnected event, central: 
13:15:21.045 -> 72:8d:da:0b:6d:ad
13:15:21.195 -> Not connected to central
13:15:22.198 -> Not connected to central
13:15:23.199 -> Not connected to central
13:15:24.230 -> Not connected to central
13:15:25.041 -> Connected event, central: 
13:15:25.041 -> 72:8d:da:0b:6d:ad
13:15:25.242 -> -85
13:15:25.242 -> Connected to central
13:15:26.217 -> 0
13:15:26.217 -> Connected to central
13:15:27.233 -> 0
13:15:27.233 -> Connected to central
13:15:28.222 -> -80
13:15:28.222 -> Connected to central
13:15:29.223 -> 0
13:15:29.223 -> Connected to central
13:15:30.240 -> 0
13:15:30.240 -> Connected to central
13:15:31.216 -> 0
13:15:31.216 -> Connected to central
13:15:31.851 -> Disconnected event, central: 
13:15:31.851 -> 72:8d:da:0b:6d:ad
13:15:32.217 -> Not connected to central
13:15:32.734 -> Connected event, central: 
13:15:32.734 -> 72:8d:da:0b:6d:ad
13:15:33.217 -> -85
13:15:33.217 -> Connected to central
13:15:34.212 -> 0
13:15:34.212 -> Connected to central
13:15:34.993 -> Disconnected event, central: 
13:15:34.993 -> 72:8d:da:0b:6d:ad
13:15:35.033 -> Connected event, central: 
13:15:35.033 -> 72:8d:da:0b:6d:ad
13:15:35.216 -> -85
13:15:35.216 -> Connected to central
13:15:36.207 -> -83
13:15:36.207 -> Connected to central <---------------------------------- No longer looping
13:15:53.353 -> Disconnected event, central: 
13:15:53.353 -> 72:8d:da:0b:6d:ad
13:15:53.803 -> Connected event, central: 
13:15:53.803 -> 72:8d:da:0b:6d:ad
13:16:00.711 -> Disconnected event, central:  <----------- 30 s interval disconnect/connect begins
13:16:00.711 -> 72:8d:da:0b:6d:ad
13:16:00.926 -> Connected event, central: 
13:16:00.926 -> 72:8d:da:0b:6d:ad 
13:16:32.304 -> Disconnected event, central: 
13:16:32.304 -> 72:8d:da:0b:6d:ad
13:16:32.304 -> Connected event, central: 
13:16:32.304 -> 72:8d:da:0b:6d:ad
13:17:02.828 -> Disconnected event, central: 
13:17:02.828 -> 72:8d:da:0b:6d:ad
AndreasLamparter commented 4 years ago

Hi,

what is a reasonable value for "RSSI_REASONABLE_SIGNAL" ? The max distance of my android phone and Arduino Nano BLE is not more then 1 meter.

With rssi you can only get out of range disconnects?

Best regards Andreas

JoeyTolentino commented 4 years ago

Hi @AndreasLamparter,

When I shared the little snippet of code, I figured that individuals could fill in their own signal strength, which would work best with their applications. For example, I used:

#define RSSI_REASONABLE_SIGNAL -113 // A reasonable RSSI signal strength

It was reasonable for me when I wanted the Arduino BLE and BLE Sense to drop connection proactively. Doing it this way, gave the Arduino a shot a staying alive vs locking up.

For your particular app, perhaps you would consider using a stronger signal, so something like -65 to -75...but feel free to play around to where you feel comfortable that your app is responding and not dropping proactively, "just because." Sometimes my app would drop because another Bluetooth device came close and disrupted it...

I've implemented a Watchdog, so that in case the BLE or BLE Sense hangs, it gets itself out of trouble. I've also since moved to the IoT because it doesn't seem to suffer form the same issues.

I hope this helps,

Joey

polldo commented 4 years ago

Hi @Hoffa25 , Using your sketch (https://github.com/arduino-libraries/ArduinoBLE/issues/45#issuecomment-622368639) I was not able to observe the reported error. I have used the following Setup: Arduino Core: Arduino-nRF582x version 1.1.5 and Arduino-mbed versione 1.2.0 ArduinoBLE: version 1.1.2-8-g3b228dc BLE Peripheral: nano 33 ble BLE Central: Android smartphone connected through 'nRF Connect' app by Nordic. (Auto-connection: on)

Even after several disconnection events caused by the weakness of the bluetooth signal, the nano33ble continues to loop and both the connection and disconnection events are correctly triggered. However, the strange behavior is that when the connection is weak the returned RSSI value appears to be 0. Would you mind testing your sketch with the same library and core version? Thanks

ChrisKretschmer commented 3 years ago

Is there still no solid solution in sight? It's a bit sad, if the BLE part in Arduino Nano BLE Sense doesn't work properly...

GeoAlta-admin commented 1 month ago

2024 and still no solution so would it be fair to say that the hardware is defective in design? With that, why is this device being sold anymore as it clearly does not live up to its advertised capability.