Ultra low power gesture detection on Arduino Nano 33 BLE Sense board?

Hi guys,

I am trying to achieve an ultra low power gesture detection on the Arduino Nano 33 BLE Sense board but whatever I tried it is still above 5mA. I know that using these functions:

int main(void){

  init();
  initVariant();

  NRF_UART0->TASKS_STOPTX = 1;
  NRF_UART0->TASKS_STOPRX = 1;
  NRF_UART0->ENABLE = 0;
  *(volatile uint32_t *)0x40002FFC = 0;
  *(volatile uint32_t *)0x40002FFC; 
  *(volatile uint32_t *)0x40002FFC = 0;

  setup();
  for(;;){
    loop();
  }
  return 0;
}

void low_power()
{
  digitalWrite(LED_PWR, LOW);
  digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);
  digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
}

I can reduce it a lot, down to ~250 microAmpere but also cut of the power to IMU sensors required for making gestures. Is there any other way of achieving this low power consumption and using IMU at the same time? Something like IMU.end() when it is not needed while I am doing some other functions or defining this digitalWrite(PIN_ENABLE_SENSORS_3V3, HIGH/LOW) when it is needed? Any kind of help is welcome. Thanks! :smiley:

Well, how much time is needed for your IMU to stabilize after power on? Does that matter to your project?

I need to make a new gesture every 10 seconds. So basically after each gesture I would like to turn off everything related to IMU as I guess only in that case I can go around ~1mA or even lower. Otherwise, it will be more than 5mA, which is way too much for my project. So basically here I need to available every 10 seconds in order to make gesture for my tinyML model.

So you don't know how long the IMU need to stabilize. Probably should find out before proceeding.

I did not understand you before. I thought you asked me if there is some constraint regarding IMU stabilization after power off/on. That information I do not know but based on experiments and way I tried it never happened. And this is my idea:

void low_power()
{
  digitalWrite(LED_PWR, LOW);
  digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);
  digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
}
void collectData(){

  digitalWrite(PIN_ENABLE_SENSORS_3V3, HIGH);
  IMU.begin();

  while (samplesRead == numSamples) {
    if (IMU.accelerationAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);
      float aSum = fabs(aX) + fabs(aY) + fabs(aZ);
      if (aSum >= accelerationThreshold) {
        samplesRead = 0;
        break;
      }
    }
  }
  while (samplesRead < numSamples) {
    if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);
      IMU.readGyroscope(gX, gY, gZ);

      float minAccel = -2.0;
      float maxAccel = 2.0;
      float minGyro = -1000.0;
      float maxGyro = 1000.0;

      tflInputTensor->data.f[samplesRead * 6 + 0] = (2.0 * (aX - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 1] = (2.0 * (aY - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 2] = (2.0 * (aZ - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 3] = (2.0 * (gX - minGyro) / (maxGyro - minGyro)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 4] = (2.0 * (gY - minGyro) / (maxGyro - minGyro)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 5] = (2.0 * (gZ - minGyro) / (maxGyro - minGyro)) - 1.0;

      samplesRead++;
    }
  }

  digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);
  IMU.end();
}

So basically, enable power to 3V3 sensors and initialize IMU every time before collectData task starts and cut it off both after it is completed. Based on my experiments, it never happened as it is always off. Considering this, seems that putting this constantly off and on is not the solution (or I made mistake somewhere else). I am not sure if it is possible to control it via ADC or GPIO pins with some triggers (like switch that opens the circuit when it needed)? :smiley:

I solved the issue by adding this additional line:

digitalWrite(PIN_ENABLE_I2C_PULLUP, HIGH);

I defined it as LOW in the setup and did not change it, which affected IMU and did not allow it to use sensors for collecting gesture data. By adding this, the code works as expected, turning on IMU when needed and immediately after data is collected, ending the session.

Here is the scratch:

void collectData(){

  digitalWrite(PIN_ENABLE_SENSORS_3V3, HIGH);
  digitalWrite(PIN_ENABLE_I2C_PULLUP, HIGH);
  IMU.begin();

  while (samplesRead == numSamples) {
    if (IMU.accelerationAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);
      float aSum = fabs(aX) + fabs(aY) + fabs(aZ);
      if (aSum >= accelerationThreshold) {
        samplesRead = 0;
        break;
      }
    }
  }
  while (samplesRead < numSamples) {
    if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);
      IMU.readGyroscope(gX, gY, gZ);

      float minAccel = -2.0;
      float maxAccel = 2.0;
      float minGyro = -1000.0;
      float maxGyro = 1000.0;

      tflInputTensor->data.f[samplesRead * 6 + 0] = (2.0 * (aX - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 1] = (2.0 * (aY - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 2] = (2.0 * (aZ - minAccel) / (maxAccel - minAccel)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 3] = (2.0 * (gX - minGyro) / (maxGyro - minGyro)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 4] = (2.0 * (gY - minGyro) / (maxGyro - minGyro)) - 1.0;
      tflInputTensor->data.f[samplesRead * 6 + 5] = (2.0 * (gZ - minGyro) / (maxGyro - minGyro)) - 1.0;

      samplesRead++;
    }
  }

  digitalWrite(PIN_ENABLE_SENSORS_3V3, LOW);
  digitalWrite(PIN_ENABLE_I2C_PULLUP, LOW);
  IMU.end();

}

In this case, the power consumption during the sleep state is ~850microAmpere with Nano 33 BLE, and ~950microAmpere when Nano 33 BLE Sense is used.

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