About the reading frequency and sampling frequency

Hi,

Currently I am using MinIMU-9 (pololu.com/catalog/product/1264) to do the “shoe mounted inertial navigation system for pedestrian” project. I need to read the acc, gyro and magnetic values from the MinIMU-9 at a very high frequency. I set the gyro, acc and mag with following setting:

a. gyro: normal power mode, data rate 800Hz, 110 cut-off, dynamic range 2000 dps
b. acc: normal power mode, data rate 1000Hz, 780 cut-off, the dynamic range ± 8g
c. mag: data rate 220Hz, range 1.3 gauss

I use the Arduino board to read the senor through I2C interface, and use the provided library code downloaded from the Pololu website. But I got two issues:

  1. for each loop, I read the three sensors, and print out the values to the serial port without any delay. But I found that each loop took around 5ms, in which the library “read()” function took around 3+ ms. This causes the highest frequency of the output is less than 200Hz, but I need higher frequency, e.g. 300Hz or 400Hz. How can I achieve that?

  2. The second issue is about time synchronization. In each loop, besides the sensor data, I also record the current timestamp using “micros()” and print it to the serial port. However, since the “gyro.read()” and “compass.read()” functions take more than 3ms, I am not sure whether the timestamp I recorded is close enough to the true reading time. Since my project is very sensitive to the timestamp, I dont know whether there is a better way to do the time syncrhonization.

The code is listed below. Please help to ask my questions. I really appreciate it! Thanks!

#include <Wire.h>
#include <L3G.h>
#include <LSM303.h>

LSM303 compass;
L3G gyro;

unsigned long counter;
unsigned long time;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  if (!gyro.init())
  {
    Serial.println("Failed to autodetect gyro type!");
    while (1);
  }

  gyro.enableDefault();
  compass.init();
  compass.enableDefault();

  ///////////////////////////////////////////Gyro setting///////////////////////////////////////////
  //set gyro range to 2000dps
  gyro.writeReg(L3G_CTRL_REG4, 0x20);
  
  //set gyro in normal power mode, with 100Hz rate, 12.5 cut-off
  //gyro.writeReg(L3G_CTRL_REG1, 0x0F);
  
  //set gyro in normal power mode, with 400Hz rate, 50 cut-off
  //gyro.writeReg(L3G_CTRL_REG1, 0xAF);
  
  //set gyro in normal power mode, with 800Hz rate, 110 cut-off
  gyro.writeReg(L3G_CTRL_REG1, 0xFF);

  ///////////////////////////////////////////ACC setting///////////////////////////////////////////
  //set acc sensor range to +-8g
  compass.writeAccReg(LSM303_CTRL_REG4_A, 0x30);
  //set acc in normal power mode, with 100Hz rate, 74 cut-off
  //compass.writeAccReg(LSM303_CTRL_REG1_A, 0x2F);
  
  //set acc in normal power mode, with 400Hz rate, 292 cut-off
  //compass.writeAccReg(LSM303_CTRL_REG1_A, 0x37);
  
  //set acc in normal power mode, with 1000Hz rate, 780 cut-off
  compass.writeAccReg(LSM303_CTRL_REG1_A, 0x3F);
  
  ///////////////////////////////////////////Mag setting///////////////////////////////////////////
  //set mag rate 220Hz
  compass.writeMagReg(LSM303_CRA_REG_M, 0x1C);
  //set mag range 1.3 gauss, x/y 1100 LSB/Gauss, Z 980 LSB/Gauss
  compass.writeMagReg(LSM303_CRB_REG_M, 0x20);
  //set mag in continuous-conversion mode
  compass.writeMagReg(LSM303_MR_REG_M, 0x00);

  Serial.print("Gyro mode (L3G_CTRL_REG1): ");
  Serial.println(gyro.readReg(L3G_CTRL_REG1));
  Serial.print("Gyro Scaling status (L3G_CTRL_REG4): ");
  Serial.println(gyro.readReg(L3G_CTRL_REG4));

  Serial.print("Acc mode (LSM303_CTRL_REG1_A): ");
  Serial.println(compass.readAccReg(LSM303_CTRL_REG1_A));
  Serial.print("Acc Scaling status (LSM303_CTRL_REG4_A): ");
  Serial.println(compass.readAccReg(LSM303_CTRL_REG4_A));

  Serial.print("Mag mode (LSM303_MR_REG_M): ");
  Serial.println(compass.readMagReg(LSM303_MR_REG_M));
  Serial.print("Mag Scaling status(A) (LSM303_CRA_REG_M): ");
  Serial.println(compass.readMagReg(LSM303_CRA_REG_M));
  Serial.print("Mag Scaling status(B) (LSM303_CRB_REG_M): ");
  Serial.println(compass.readMagReg(LSM303_CRB_REG_M));

  counter = 0;
  time = 0;
 }

void loop() {
  //if (micros() - time > 20000 )
  //{
    time = micros();
    gyro.read();
    compass.read();
    
    counter = counter+1;
  
    Serial.print((int)gyro.g.x);
    Serial.print(" ");
    Serial.print((int)gyro.g.y);
    Serial.print(" ");
    Serial.print((int)gyro.g.z);
    Serial.print(" ");
  
    Serial.print((int)compass.a.x);
    Serial.print(" ");
    Serial.print((int)compass.a.y);
    Serial.print(" ");
    Serial.print((int)compass.a.z);
    Serial.print(" ");
  
    Serial.print((int)compass.m.x);
    Serial.print(" ");
    Serial.print((int)compass.m.y );
    Serial.print(" ");
    Serial.print((int)compass.m.z);
    Serial.print(" ");
  
    Serial.print(time);
    Serial.print(" ");
    Serial.println(counter);
  //}
  
}

Since you have the magnetometer data rate set at 220 Hz, it doesn’t make much sense to collect data faster than that.

It does not matter if there is a delay between reading the time, and reading the various sensors. If you do just those steps at a constant rate, you can measure how much time each sensor reading takes and correct the time for the measured delays between readings.

It is not a good idea to have serial.print in the fast measurement loop, as printing takes a variable amount of time depending on how many characters are transmitted. The sensor readings can be stored in arrays, dumping the array values later.

Thank you for your reply. I still have two questions based on your answer.

  1. Just ignore the magnetometer (since in my c# code, I use the magnetic value in a low frequency). If I want 300Hz or 400Hz samples from the acc and gyro, what should I do (each loop at least taks 5 milliseconds)?

  2. For the serial.print, you said I can store the readings to an array and then dump it lately. How can I do this? I need to send the data to the serial port. All the readings are float type. Do you mean I should convert the float to strings, and then concatenate all these small strings to a big string, and then print to the serial port?

[quote=“Jim Remington”]Since you have the magnetometer data rate set at 220 Hz, it doesn’t make much sense to collect data faster than that.

It does not matter if there is a delay between reading the time, and reading the various sensors. If you do just those steps at a constant rate, you can measure how much time each sensor reading takes and correct the time for the measured delays between readings.

It is not a good idea to have serial.print in the fast measurement loop, as printing takes a variable amount of time depending on how many characters are transmitted. The sensor readings can be stored in arrays, dumping the array values later.[/quote]

Save the binary values in an array, and print the array values later

for (i=0; i<array_size; i++) {
gyro.read();
gx[i]=gyro.g.x;
gy[i]=gyro.g.y;
//etc.
}

//later...

for(i=0; i<array_size; i++) {
Serial.print(gx[i]);
//etc.
}