adafruit / Adafruit_LSM6DS

Arduino library for LSM6DS
Other
47 stars 39 forks source link

LSM6DSO32 getEvent seems to be slow #22

Open simon88 opened 3 years ago

simon88 commented 3 years ago

Hi all, I'am working with an LSM6DSO32 and one SAMD21E18A. I've a personal board, so I use your library. But it's seem to be slow, I have a delay of 3ms for calling getEvent. I set my captor (accel and gyro) at 208Hz with LSM6DS_RATE_208_HZ mask in my setup function. After that I have a loop and I call getEvent when new data are availables like this

if(dso32.accelerationAvailable() == 1 && dso32.gyroscopeAvailable() == 1){
      SerialUSB.println(millis()));
      dso32.getEvent(&accel_dso, &gyro_dso, &temp_dso); //here I have 3ms
      SerialUSB.println(millis()));
     ..... other lines  ......
}

3ms seems to be long no? If I increase my data rate at 400Hz I can't getEvent beceause I have a minimum of 3ms in my loop just to read the register. So the maximum frequency of my loop is 333Hz....

anders-bogild commented 2 years ago

Having the same issue with a lsm6ds33 connected via i2c to an Adafruit Feather nRF52840 board maxing out at 208Hz rate.

A contributing factor to slowness is that Adafruit_LSM6DS::_read(), which is called by Adafruit_LSM6DS::getEvent(), will try to determine current range of acc and gyr each time it is called (!).

https://github.com/adafruit/Adafruit_LSM6DS/blob/1ea3bd2c77be022ea5c847029471f7bf57635ee6/Adafruit_LSM6DS.cpp#L450-L502

This is clearly not necessary and should be done only once efter e.g. reset(), and if the ranges are changed with Adafruit_LSM6DS::setAccellRange() or Adafruit_LSM6DS::setGyroRange().

simon88 commented 2 years ago

Yes you've right @anders-bogild this os clearly not necessary

ladyada commented 2 years ago

a tested PR to add caching would be awesome!

eringerli commented 2 years ago

In #31, I addressed this problem by buffering the ranges. This is a substantial performance gain, especially when reading the IMU with fast sample rates.

eringerli commented 2 years ago

@simon88: try connecting the IMU per SPI and with a data ready-line on an interrupt. I could max an ISM330 out with 6.66kHz sample rate on an ESP32 feather. The bigger problem was to send this collected data over WIFI, as it generates about 300kB/s when using a timestamp and 6 float, not calculating the other protocol overhead :wink:

steffensol commented 2 years ago

Should this new PR change affect LSM6DSOX getEvent in the same way? I'm running an LSM6DSOX over i2c with a feather m0, and am being capped at around 313Hz - and was starting to get a bit confused as to why this was running so slow.

The code I am running is basically;


#include <Adafruit_LSM6DSOX.h>
Adafruit_LSM6DSOX sox;

File logfile;

int iterator = 1;
unsigned long timebefore;
unsigned long timeafter;
unsigned long duration;
unsigned long timeAtEvent;
volatile unsigned long timeAtReset = 0;
float freq;

void loop() {
  sensors_event_t accel;
  sensors_event_t gyro;
  sensors_event_t temp;

  noInterrupts();
  timebefore = micros() - timeAtReset;
  sox.getEvent(&accel, &gyro, &temp);
  timeAtEvent = micros() - timeAtReset;
  logfile.print(timeAtEvent); logfile.print(","); logfile.print(accel.acceleration.x); logfile.print(","); logfile.print(accel.acceleration.y); logfile.print(","); logfile.println(accel.acceleration.z);
  timeafter = micros() - timeAtReset;
  duration = timeafter-timebefore;
  interrupts();

  freq = 1000000/(duration);
    if (iterator % 1001 == 0) {
    logfile.flush();
    Serial.println("Wrote to file");
    Serial.print("Time spent reading last sensor value(microseconds): ");
    Serial.println(duration);
    Serial.print("Frequency: ");
    Serial.println(freq);
    Serial.print("Last reset at time: ");
    Serial.println(timeAtReset);
    iterator = 1;
    } else { iterator++; }
eringerli commented 2 years ago

It should get you an improvement, as it removes two additional reads of registers. If you want to test it, wait until @ladyada releases a new version or clone the repo locally to get the new code.

If you really want to read out the sensor fast, you have to connect it by SPI and with an interrupt on the DRDY-line to keep the latency low. I²C is maxed out at 400kHz, with SPI you can rise the datarate to 10MHz, which is 25x faster. In my first attempt I also connected the sensors by I²C, but I couldn't get much higher overall than about 50Hz with three different sensors on the same bus (ADS1115, ISM330 and LIS3MDL) and with many collisions and overruns, which negatively impacted latency and jitter. But that was before I removed the register reads for the range in both drivers (ISM330/LSM6DSOX and LIS3MDL), so YMMV.