4

I want to calculate the displacement of the Arduino 101 board compared to the starting point (only in the x direction so far).

In below data I'm swinging the board multiple times in circles around my laptop and then putting it back at the origin a few seconds later.

Regardless if 1ms-100ms between the loops, the numbers show no sign of the board returning to the origin. I've calibrated the accelerometer x-axis as closely as possible.

Results from swinging

Am I doing something wrong in deriving the acceleration/velocity/distance, or is this the level of compounding error to expect?

If so, can combining gyro data correct acceleration (thought it mainly worked the other way around)?

I have a GPS meant for correcting position but was hoping any drift wouldn't be this quick.

EDIT: I was incorrect re. use of gyro data; the attitude of the board, which was not consistent in my swings, will effect the acceleration output. Gyro data can be used to calculate and "cancel out" this gravitational impact, and get a more accurate (linear) acceleration (http://www.cl.cam.ac.uk/research/dtg/www/files/publications/public/abr28/ojw28_thesis.pdf). Will report back in a few days.

Code:

#include "CurieIMU.h"

float gravity = 9.80665; // to convert G forces (1 m/s2 = 0.101972 g; 1 g = 9.80665 m/s2) 
long t1; // create object for first time reference, set time just before the loop later on

// Variables that are dependent on value from last loop
float vx, vy, vz;
float imu_x, imu_y, imu_z;

void setup() {
  Serial.begin(9600); 
  while (!Serial);  // wait for serial to open

  Serial.println("Initializing IMU device...");
  CurieIMU.begin(); // start accelerometer / gyro
  CurieIMU.setAccelerometerRange(2);  // accelerometer range to 2G - might need to be greater later on (18 m/s2 highest possible now)

  /* 

  // Auto-calibration to ensure accelerometer doesn't drift
  CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0); // 89.69999 creates both positive and negative spikes
  delay(1000);
  CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
  delay(1000);
  CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
  delay(1000);

  */

  // Hardcoded accelerometer offsets after testing
  CurieIMU.setAccelerometerOffset(X_AXIS,89);

  // Fetch the offsets from the IMU
  float x_offset = CurieIMU.getAccelerometerOffset(X_AXIS);
  float y_offset = CurieIMU.getAccelerometerOffset(Y_AXIS); 
  float z_offset = CurieIMU.getAccelerometerOffset(Z_AXIS); 

  Serial.println("Current x_offset, y offset, z offset");
  Serial.print(x_offset, 6); 
  Serial.print("\t");
  Serial.print(y_offset, 6);
  Serial.print("\t");
  Serial.println(z_offset, 6);
  delay(5000);

  t1 = millis(); // set the first time reference

  Serial.println("ax_g (g), ax (m/s2), t1 (ms), t2 (ms), td (ms), tds (s), vx (m/s), imu_posx (m)");

}

void loop() {

  // Fetch G forces
  float ax_g, ay_g, az_g;   //scaled accelerometer values
  CurieIMU.readAccelerometerScaled(ax_g, ay_g, az_g); // read accelerometer measurements from device, scaled to the configured range

  // Convert G force to m/s2
  float ax = ax_g / gravity;
  float ay = ay_g / gravity;
  float az = az_g / gravity;

  // Calculate time since last loop
  long t2 = millis();
  float td = t2 - t1; // time delta in ms
  float tds = td / 1000; // delta in seconds for easier logic

  // Calculate current velocity: velocity (m/s) = velocity (m/s) + acceleration (m/s2) * deltaTime (s)
  vx = vx + ax * tds;
  vy = vy + ay * tds;
  vz = vz + az * tds;

  // Calculate position: position (m) = position (m) + velocity (m/s) * deltaTime (s)
  imu_x = imu_x + vx * tds;
  imu_y = imu_y + vy * tds;
  imu_z = imu_z + vz * tds;

  // Print the values
  Serial.print(ax_g, 6);
  Serial.print("\t");
  Serial.print(ax, 6);
  Serial.print("\t");
  Serial.print(t1);
  Serial.print("\t");
  Serial.print(t2);
  Serial.print("\t");
  Serial.print(td, 6);
  Serial.print("\t");
  Serial.print(tds, 6);
  Serial.print("\t");
  Serial.print(vx, 6);
  Serial.print("\t");
  Serial.println(imu_x, 6);

  // Reset start values for next loop
  t1 = millis();

  delay(1);

}
  • I don't think millis is going to be accurate enough, try micros instead and grab it only once per loop. – ratchet freak Sep 6 '17 at 18:23
  • This is dead reckoning and is very difficult. When (few) cars do this (after loosing their GPS signal) they usually count the number of wheel rotations and turning direction. Just consider if you stopped moving your Arduino. Then your acceleration would go to zero but your integral calculation of velocity may not due to noise or round off error. If this happens, the integral of your velocity (position) would continue to change. – st2000 Sep 7 '17 at 2:14
  • @ratchetfreak thanks, will try in combination with the edited conclusion above – Henrik Bohman Sep 7 '17 at 10:12
  • Do you have to use 9600 baud? That's quite slow, and is probably introducing 70ms of that 100ms delay. Why not use 115200? Also, did you try using doubles instead of floats - although I guess this would only help with minor drifts. – Kingsley Oct 31 '17 at 21:20
1

The Arduino 101 contains the Intel® Curie™ Module, this module contains an Inertial Measurements Unit or IMU for short among other sensors and peripherals Intel® Curie™ Module Block Diagram

The IMU of this module is Bosch BMI160 which is a low cost MEMS IMU, this IMUs typically suffer from systematic errors and random/stochastic errors, the following diagram summarize them: enter image description here

If we take the bias error as an example of those errors, an uncompensated accelerometer bias introduces an error proportional to time (t) in the velocity and proportional to t^2 in the position. For example, consider a case where accelerometer bias is 10 m/s^2. If this bias offset is not removed from the measurements, it can generate a 500 m error in position after 10 seconds and 12.5 km error after 50 seconds. Let us back to our IMU, if we read the data sheet the Zero-g error "or bias" is 40mg for the 8g sensing accelerometer and Ta = 25 Celsius with normal VDD and the IC has been assembled on board. If we just consider this 40mg bias error "dropping other error sources" it is 0.392266 m/s^2 so after 10 seconds the position offset will be 1.96133 meter even if you don't move the Arduino. I suggest you read "MEMS-Based Integrated Navigation" book here it will give you a good vision about MEMS based inertial sensors and basic navigation concepts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.