Arduino Nano 33 IoT BLE pausing the system for 1.6 sec

Hello, I'm making a flight controller. I'm intending to use the NINA W102 radio, and trying out the BLE library right now. However the library would pause the system when connecting, also the transmission is taking too long. Imagine an multi-rotor helicopter stops correcting itself for 1.6 sec and the control cycle is 25 Hz after connected.
What can I do? Which direction should I go? Using WiFi? Write my own library from scratch? Is there a better library that suits my requirement? Or do I give up using the NINA module?

log bellow, loop time includes IMU update, writes IMU readings to characteristic:

BLE Central
Loop time: 412 us
Loop time: 406 us
Found 7c:9e:bd:3b:3f:ce 'VC-04' 19b10000-e8f2-537e-4f6c-d104768a1214
Loop time: 406 us
Connecting ...
Connected
Loop time: 198111 us
Discovering attributes ...
Attributes discovered
Loop time: 1699745 us
XL : 348 1156 8692
GY : -272 431 -159

Loop time: 406 us
XL : 73 921 7758
GY : -658 245 -9

Loop time: 131119 us
XL : 31 429 8568
GY : -776 310 74

Loop time: 407 us
XL : -78 -660 7884
GY : -1382 -277 -279

Hi @CCCanyon,

Can you post your code? Click on this icon </> above to get code tags and paste your code. It should look like this.

// your example code

If you use any libraries, please post a link from GitHub or let us know which library you picked from the library manager. Often the name of header files is the same for different libraries.

Most of the BLE code is part of the NINA firmware. Just changing the library will not make a lot of difference. On the other hand, that should allow you to run your code with little interference from the BLE code.

BLE is not designed for long range and high bandwidth. Is this an indoor UAV?

There are consumer drones that use WiFi. I suspect they add some special sauce to get the distance.

I have not investigated this a lot and just fly a DJI drone. I was under the impression that there are open-source flight controller hardware and software available. Are you building something from scratch?

1 Like

Thanks for replying.

For the speed, only 12 bytes at 10Hz is needed.
ArduinoBLE is the official one for arduino.

I've built my own flight controller and remote from the very scratch before, with old nano, MPU IMU, nrf24l01. It uses my own libraries made from reading data sheets myself. This time I wish to use the onboard nina of the new nano.
I've also tried putting imu update in timer interrupt routine (TC5 400Hz), it freezes.

I just looked into wifi, scanning (delays in code removed) takes 6 seconds :<
I thought NINA has it's own MCU and Nano can do other things while NINA is transmitting data or attempting connection, but it doesn't look like it with the official libraries.

/*
#002 2021/07/31 implementation of IMU, notes in C:\Users\Vacuo\Documents\Aircraft\VC-04 tandem\notes.xlsx
     ---------- inline function does not work, it produces undefined reference error
#003 2021/08/02 BLE struggle, the characteristic is wierd
     ---------- successfully tranferring the data, but the conversion is bugged
#004 2021/08/02 conversion fixed in v003, optimized the classes
     ---------- located issue: 182 peripheral.connect() 198 peripheral.discoverAttributes() are painfully slow

*/
#define VERSION "VC-04-A_v004"
#define SerialDebug // double slash to disable

#include "Types.h"
#include "LSM6DS3.h"
#include "Dstr.h"
#include <ArduinoBLE.h>
#include "uuid.h"

LSM6DS3 imu;

// Time Section ==========================================================================================

unsigned long then = 0;
unsigned long ds = 0;
#define tikLength 125000
unsigned long tikBottle = 0;
bool tikBell = 0;
int loopCount = 0;

// BLE Section ===========================================================================================

Dstr BLE_data(12);
BLEDevice peripheral;
BLECharacteristic BLE_sensor_char;
int BLE_routine_stat = 0;

// === SETUP =============================================================================================

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  
  //initialize imu ------------------------------------------------------------------------
  imu.init();
  
  // crash prevention ctrl-shift-M open serial monitor to continue ------------------------
  then = micros();
  bool flip = 0;
  while (!Serial and imu.A.A16.z<12288)
  {
    timeUpdate();
    
    imu.update();
    
    if(tikBell){ flip = !flip; }
    digitalWrite(LED_BUILTIN, flip);
  }
  digitalWrite(LED_BUILTIN, 0);
  
  // show version -------------------------------------------------------------------------
  Serial.print("version: "); Serial.println(VERSION);
  
  // BLE ----------------------------------------------------------------------------------
  BLE.begin();
  Serial.println("BLE Central");
  
  then = micros();
}

// === LOOP ==============================================================================================

void loop()
{
  
  timeUpdate();
  
  imu.update();

  loopCount++;
  
  if(tikBell)
  {
    Serial.print("Loop time: "); Serial.print(ds); Serial.println(" us");
    loopCount=0;
    switch(BLE_routine_stat)
    {
      // start scan
      case 0:
        BLE.scanForUuid(service_uuid); BLE_routine_stat = 1;
        break;
      // scanning
      case 1:
        BLE_routine_stat = BLE_scanning()?2:0;
        ; break;
      // checking
      case 2:
        BLE_routine_stat = BLE_checkCharacteristic()?3:1;
        ; break;
      // discover
      case 3:
        BLE_routine_stat = BLE_discoverAttributes()?4:1;
        ; break;
      // update value
      case 4:
        if(peripheral.connected())
        {
          BLE_data.setCursor(0);
          BLE_data << imu.A;
          BLE_data << imu.G;
          //BLE_charWriteDstr(BLE_sensor_char, BLE_data);
          Serial.print("XL  : "); imu.A.prt();
          Serial.print("GY  : "); imu.G.prt();
          Serial.println("======================");
        }
        else
        {
          Serial.println("Peripheral disconnected");
          BLE_routine_stat = 0;
        }
        ; break;
    }
    BLE_charWriteDstr(BLE_sensor_char, BLE_data);
    /*
    Serial.print("XL : "); imu.A.prt();
    Serial.print("GY : "); imu.G.prt();
    Serial.println("======================");
    */
  }
}



// === FUNCTIONS =========================================================================================

void timeUpdate()
{
  ds = micros() - then;
  then += ds;
  
  tikBell = 0;
  tikBottle += ds;
  if(tikBottle > tikLength){ tikBell = 1; tikBottle = 0; }
}

inline void BLE_charWriteDstr(BLECharacteristic& c, Dstr& s)
{
  c.writeValue(s.data, s.len);
}

inline void BLE_charReadDstr(BLECharacteristic& c, Dstr& s)
{
  c.readValue(s.data, s.len);
}

bool BLE_scanning()
{
  peripheral = BLE.available();
  if (peripheral)
  {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address()); Serial.print(" '");
    Serial.print(peripheral.localName()); Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid()); Serial.println();

    if (peripheral.localName() != service_local_name){ return 0; }

    // stop scanning
    BLE.stopScan();
    
    return 1;
  }
  return 0;
}

bool BLE_checkCharacteristic()
{
  // connect to the peripheral
  Serial.println("Connecting ...");

  if (peripheral.connect())
  {
    Serial.println("Connected");
    return 1;
  }
  else
  {
    Serial.println("Failed to connect!");
    return 0;
  }
}

bool BLE_discoverAttributes()
{
  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if(peripheral.discoverAttributes())
  {
    Serial.println("Attributes discovered");
  }
  else
  {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return 0;
  }

  // retrieve the LED characteristic
  BLE_sensor_char = peripheral.characteristic(sensor_char_uuid);

  if(!BLE_sensor_char)
  {
    Serial.println("Peripheral does not have BLE_sensor_char!");
    peripheral.disconnect();
    return 0;
  }
  else if(!BLE_sensor_char.canWrite())
  {
    Serial.println("Peripheral does not have a writable BLE_sensor_char!");
    peripheral.disconnect();
    return 0;
  }
  return 1;
}

There nothing that sticks out with your code. You seem to know what you are doing.

As a guess, discovering the attributes of a peripheral is a time-consuming process.

  • It would be an interesting experiment to see whether there are differences between the Arduino Nano 33 IoT (slower processor, external interface but part of the stack runs external) and Nano 33 BLE (faster processor but needs to handle the entire stack, direct access radio).
  • Also how does the time change with the number of characteristics and descriptors.

I have both devices and the RP2040 Connect. But I cannot run this right now.

Despite that, I think it would be reasonable to assume that the BLE connection needs to be established before the control loop for the helicopter is started. Do you get any delays after the discovery phase?

Another option would be to run the control code in interrupt.

Or. I am not sure how the Arduino Nano 33 IoT framework looks like below the Arduino stuff. Maybe they run FreeRTOS or something (the Arduino Nano 33 BLE uses mbedOS, the Nano 33 IoT uses something else). That might give you another option to elevate your codes priority.

As you can see in the log of the first post, it takes up to more than 130ms per cycle when transferring data, that's not acceptable

And in my first reply I've noted timer interrupt would freeze the system if BLE is active.

I'd not assume the connection would always be fine in flight. So I'll be investigating the source to divide the time-consuming processes up into the switch section.

Thanks for the help!

I did a test and found there are slight variations between the different Arduinos but overall, the timing is in the same order of magnitude. I just measured the calls themselves using micros().

  • peripheral.connect() ~ 300 ms average
  • peripheral.discoverAttributes() ~ 560ms

So, there is not much you can do at the application layer to shorten the time.

1 Like