arduino / ArduinoCore-arc32

GNU Lesser General Public License v2.1
328 stars 284 forks source link

Arduino101 'freezes' when shacking it #357

Closed nicolocarpignoli closed 7 years ago

nicolocarpignoli commented 7 years ago

Hi, i'm seeing a randomly strange behaviour of the Arduino101. If I don't move the board everything works fine, but when I start shacking and moving constantly the board it randomly gets stucked. This means that you can not see anymore the BLE Arduino device when scanning, and the only way to work again with it it's to restart the board. When facing this issue, the power on the arduino is still ok. Again I repeat, it seems something related with shacking the board for a while.

I put here my code hoping that you can help me understand the possible reasons for that (maybe some problem about performance or the way I handle interrupts).


#include "CurieIMU.h"
#include "CurieBLE.h"
#include <stdio.h>      /* puts, printf */

bool motion;
int aix, aiy, aiz;    // raw accelerometer values
int gix, giy, giz;    // raw gyro values

BLEPeripheral blePeripheral;
BLEService sensorService("19B10010-E8F2-537E-4F6C-D104768A1214");
BLEUnsignedLongCharacteristic stepCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead);  // stepcount
BLEFloatCharacteristic axCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in x in g
BLEFloatCharacteristic ayCharacteristic("19B10013-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in y in g
BLEFloatCharacteristic azCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in z in g
BLEFloatCharacteristic gxCharacteristic("19B10015-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in x in deg/s
BLEFloatCharacteristic gyCharacteristic("19B10016-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in y in deg/s
BLEFloatCharacteristic gzCharacteristic("19B10017-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in z in deg/s
BLEIntCharacteristic shockCharacteristic("19B10018-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);  // true if shock sensed
BLEIntCharacteristic modeCharacteristic("19B10019-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // sensing mode
BLEIntCharacteristic srangeCharacteristic("19B10020-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // shock range
BLEIntCharacteristic arangeCharacteristic("19B10021-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // acc. range
BLEIntCharacteristic grangeCharacteristic("19B100122-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); // gyro range
BLEIntCharacteristic calibCharacteristic("19B100123-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // 1 if calibration is on, otherwise 0

void printSerial() {
    // print for debug
}

void initPeriph() {
    // initialization of BLE sensor device
    blePeripheral.begin();
}

void setup()
{
    // Serial.begin(9600);
    //while (!Serial);    // wait for the serial port to open
    // Serial.println("Initializing IMU device...");
    CurieIMU.begin();
    // configure Bluetooth
    blePeripheral.setLocalName("MOOVBIT");
    blePeripheral.setAdvertisedServiceUuid(sensorService.uuid());
    blePeripheral.addAttribute(sensorService);
    blePeripheral.addAttribute(stepCharacteristic);
    blePeripheral.addAttribute(axCharacteristic);
    blePeripheral.addAttribute(ayCharacteristic);
    blePeripheral.addAttribute(azCharacteristic);
    blePeripheral.addAttribute(gxCharacteristic);
    blePeripheral.addAttribute(gyCharacteristic);
    blePeripheral.addAttribute(gzCharacteristic);
    blePeripheral.addAttribute(shockCharacteristic);
    blePeripheral.addAttribute(modeCharacteristic);
    blePeripheral.addAttribute(arangeCharacteristic);
    blePeripheral.addAttribute(srangeCharacteristic);
    blePeripheral.addAttribute(grangeCharacteristic);
    blePeripheral.addAttribute(calibCharacteristic);
    // set initial characteristics values
    stepCharacteristic.setValue(0);
    shockCharacteristic.setValue(0);
    modeCharacteristic.setValue(0);
    arangeCharacteristic.setValue(4);
    srangeCharacteristic.setValue(4);
    grangeCharacteristic.setValue(250);
    calibCharacteristic.setValue(1);
    initPeriph();
    //Serial.println("Bluetooth device active, waiting for connections...");

    if (calibCharacteristic.value() == 1) {
        //Serial.println("About to calibrate. Make sure your board is stable and upright");
        delay(5000);
        CurieIMU.autoCalibrateGyroOffset();
        CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
        CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
        CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
    }
    else {
        //Serial.println("No calibration");
    }
    // Configure sensors 
    CurieIMU.setAccelerometerRange(arangeCharacteristic.value());
    CurieIMU.setGyroRange(grangeCharacteristic.value());
    CurieIMU.setStepDetectionMode(CURIE_IMU_STEP_MODE_SENSITIVE);
    CurieIMU.setStepCountEnabled(true);
    /*CurieIMU.setDetectionThreshold(CURIE_IMU_TAP, 750);       // (750mg)
    CurieIMU.setDetectionThreshold(CURIE_IMU_DOUBLE_TAP, 750);    // (750mg)
    CurieIMU.interrupts(CURIE_IMU_TAP);
    CurieIMU.interrupts(CURIE_IMU_DOUBLE_TAP);*/
    CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, srangeCharacteristic.value() * 500); // 1g = 1000 mg
    CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 50); // 50ms or 75ms
    CurieIMU.interrupts(CURIE_IMU_SHOCK);
    CurieIMU.interrupts(CURIE_IMU_MOTION);
    CurieIMU.attachInterrupt(eventCallback);
    //Serial.println("Sensor ready");
    motion = false;

}

void loop()
{

    /* NOT IMPLEMENTED WRITE CHARS SO COMMENTED THIS SECTION
    if (arangeCharacteristic.written()) CurieIMU.setAccelerometerRange(arangeCharacteristic.value());
    if (grangeCharacteristic.written()) CurieIMU.setGyroRange(grangeCharacteristic.value());
    if (srangeCharacteristic.written()) {
    CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, srangeCharacteristic.value() * 1000);
    }
    if (modeCharacteristic.written()) {
    // change sensing mode
    }*/

    if (motion) {
        if (!axCharacteristic.setValue(convertRawAcceleration(aix)) || !ayCharacteristic.setValue(convertRawAcceleration(aiy)) ||
            !azCharacteristic.setValue(convertRawAcceleration(aiz)) || !gxCharacteristic.setValue(convertRawGyro(gix)) ||
            !gyCharacteristic.setValue(convertRawGyro(giy)) || !gzCharacteristic.setValue(convertRawGyro(giz))) {
            //Serial.println("Erorr BLE");
        }
        stepCharacteristic.setValue(CurieIMU.getStepCount());
        motion = false;
    }
    delay(2000);
    shockCharacteristic.setValue(0);
}

void eventCallback() {
    if (CurieIMU.getInterruptStatus(CURIE_IMU_SHOCK)) {
        if (shockCharacteristic.value() == 0) {
            //Serial.println("Shock sensed");
            shockCharacteristic.setValue(1);
        }
        //CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz);
        //motion = true;
    }
    else if (CurieIMU.getInterruptStatus(CURIE_IMU_MOTION)) {
        CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz);
        motion = true;
    }
}

// converted values based on accelerometer range
float convertRawAcceleration(int aRaw) {
    float a = (aRaw * float(arangeCharacteristic.value()) / 32768.0); // output values from -16.0 to +16.0
    return a;
}

// converted values based on gyro range
float convertRawGyro(int gRaw) {
    float g = (gRaw * float(grangeCharacteristic.value()) / 32768.0); // output values from -2000.0 to +2000.0
    return g;
}
noelpaz commented 7 years ago

First of all, you have a lot of characteristics for this service and usually performance gets affected when you have that much. I did not check thoroughly but make sure you are using all of them further down the code. Will your central app be querying/subscribing to all those characteristics?

SidLeung commented 7 years ago

Hello, There...

The sketch provided exercises a large amount of code (libraries) and several h/w features. It would be helpful to nail down the suspicious area to locate the source of the problem - the divide and conquer strategy. There are several areas that can be singled out to verify its operation.

  1. Verify if the IMU interrupt mechanism is good. Comment out the BLE related code. Use the USB serial interface to dump out the IMU data instead of the BLE. Perform the same shaking test to see if the system can hold up.

  2. Verify if the BLE interface section. First, comment out the eventHandler/interrupt driven code. Then, in the loop(), perform a, CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz). And set each characteristic to see if the system can hold up. Use a Central to check on the values. The IMU is capable of generating data at 100 Hz. With each piece of IMU data as an individual characteristic, it is certain that the Central will not be able to pull out IMU data at 100 Hz.

nicolocarpignoli commented 7 years ago

The IMU interrupt mechanism is good, I've done that try. The only way that I could got this thing work with my shacking test is with the following code:


#include "CurieIMU.h"
#include "CurieBLE.h"
#include <stdio.h>      /* puts, printf */

int aix, aiy, aiz;    // raw accelerometer values
int gix, giy, giz;    // raw gyro values
bool flag = false;

BLEPeripheral blePeripheral;
BLEService sensorService("19B10010-E8F2-537E-4F6C-D104768A1214");
BLEUnsignedLongCharacteristic stepCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead);  // stepcount
BLEFloatCharacteristic axCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in x in g
BLEFloatCharacteristic ayCharacteristic("19B10013-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in y in g
BLEFloatCharacteristic azCharacteristic("19B10014-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // acc.in z in g
BLEFloatCharacteristic gxCharacteristic("19B10015-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in x in deg/s
BLEFloatCharacteristic gyCharacteristic("19B10016-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in y in deg/s
BLEFloatCharacteristic gzCharacteristic("19B10017-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // rot.in z in deg/s
BLEIntCharacteristic shockCharacteristic("19B10018-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);  // true if shock sensed
BLEIntCharacteristic modeCharacteristic("19B10019-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // sensing mode
BLEIntCharacteristic srangeCharacteristic("19B10020-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // shock range
BLEIntCharacteristic arangeCharacteristic("19B10021-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // acc. range
BLEIntCharacteristic grangeCharacteristic("9B100122-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); // gyro range
BLEIntCharacteristic calibCharacteristic("9B100123-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);  // 1 if calibration is on, otherwise 0

void setup()
{
   //Serial.begin(9600);
   //while (!Serial);    // wait for the serial port to open
  // Serial.println("Initializing IMU device...");
  CurieIMU.begin();
  // configure Bluetooth
  blePeripheral.setLocalName("MOOVBIT");
  blePeripheral.setAdvertisedServiceUuid(sensorService.uuid());
  blePeripheral.addAttribute(sensorService);
  blePeripheral.addAttribute(stepCharacteristic);
  blePeripheral.addAttribute(axCharacteristic);
  blePeripheral.addAttribute(ayCharacteristic);
  blePeripheral.addAttribute(azCharacteristic);
  blePeripheral.addAttribute(gxCharacteristic);
  blePeripheral.addAttribute(gyCharacteristic);
  blePeripheral.addAttribute(gzCharacteristic);
  blePeripheral.addAttribute(shockCharacteristic);
  /*blePeripheral.addAttribute(modeCharacteristic);
  blePeripheral.addAttribute(arangeCharacteristic);
  blePeripheral.addAttribute(srangeCharacteristic);
  blePeripheral.addAttribute(grangeCharacteristic);
  blePeripheral.addAttribute(calibCharacteristic);*/
  // set initial characteristics values
  stepCharacteristic.setValue(0);
  shockCharacteristic.setValue(0);
  modeCharacteristic.setValue(0);
  arangeCharacteristic.setValue(4);
  srangeCharacteristic.setValue(4);
  grangeCharacteristic.setValue(250);
  calibCharacteristic.setValue(1);
  blePeripheral.begin();

  // Configure sensors 
  CurieIMU.setAccelerometerRange(arangeCharacteristic.value());
  CurieIMU.setGyroRange(grangeCharacteristic.value());
  CurieIMU.setStepDetectionMode(CURIE_IMU_STEP_MODE_SENSITIVE);
  CurieIMU.setStepCountEnabled(true);
  /*CurieIMU.setDetectionThreshold(CURIE_IMU_TAP, 750);       // (750mg)
  CurieIMU.setDetectionThreshold(CURIE_IMU_DOUBLE_TAP, 750);    // (750mg)
  CurieIMU.interrupts(CURIE_IMU_TAP);
  CurieIMU.interrupts(CURIE_IMU_DOUBLE_TAP);*/
  CurieIMU.setDetectionThreshold(CURIE_IMU_SHOCK, srangeCharacteristic.value() * 500); // 1g = 1000 mg
  CurieIMU.setDetectionDuration(CURIE_IMU_SHOCK, 50); // 50ms or 75ms
  CurieIMU.interrupts(CURIE_IMU_SHOCK);
  //CurieIMU.interrupts(CURIE_IMU_MOTION);
  CurieIMU.attachInterrupt(eventCallback);

}

void loop()
{
  if(!flag){
    CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz);
    flag = true;  
  }else{
    if(!axCharacteristic.setValue(convertRawAcceleration(aix))
     || !ayCharacteristic.setValue(convertRawAcceleration(aiy))
     || !azCharacteristic.setValue(convertRawAcceleration(aiz))
     || !gxCharacteristic.setValue(convertRawGyro(gix))
     || !gyCharacteristic.setValue(convertRawGyro(giy))
     || !gzCharacteristic.setValue(convertRawGyro(giz))){
      // do nothing
    }
    stepCharacteristic.setValue(CurieIMU.getStepCount());
    shockCharacteristic.setValue(0);
    flag = false;
  }
  delay(1000);

}

void eventCallback() {
  if (CurieIMU.getInterruptStatus(CURIE_IMU_SHOCK)) {
    shockCharacteristic.setValue(1);
  }

}

// converted values based on accelerometer range
float convertRawAcceleration(int aRaw) {
  float a = (aRaw * float(arangeCharacteristic.value()) / 32768.0); // output values from -16.0 to +16.0
  return a;
}

// converted values based on gyro range
float convertRawGyro(int gRaw) {
  float g = (gRaw * float(grangeCharacteristic.value()) / 32768.0); // output values from -2000.0 to +2000.0
  return g;
}
eriknyquist commented 7 years ago

@nicolocarpignoli, can you do us a favour and tell us what you changed to make it work? instead of posting the whole sketch for us to figure out....

nicolocarpignoli commented 7 years ago

this precise part:

void loop()
{
  if(!flag){
    CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz);
    flag = true;  
  }else{
    if(!axCharacteristic.setValue(convertRawAcceleration(aix))
     || !ayCharacteristic.setValue(convertRawAcceleration(aiy))
     || !azCharacteristic.setValue(convertRawAcceleration(aiz))
     || !gxCharacteristic.setValue(convertRawGyro(gix))
     || !gyCharacteristic.setValue(convertRawGyro(giy))
     || !gzCharacteristic.setValue(convertRawGyro(giz))){
      // do nothing
    }
    stepCharacteristic.setValue(CurieIMU.getStepCount());
    shockCharacteristic.setValue(0);
    flag = false;
  }
  delay(1000);

reading in the first step of the loop cycle and writing characteristics in the following step made the trick

kitsunami commented 7 years ago

Thanks @nicolocarpignoli !