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!

[code]
#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);

//}

}[/code]

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.
}