8/27/2014: Arduino Uno as a IMU interface Device (updated 8/28/2014)

You can get a pretty good IMU board for under a hundred dollars. The illustration above shows the hookup I am using to get started with IMU data processing. The Arduino (blue) controller board above is a general purpose device that contains an onboard CPU chip which you can program using a fee cross compiler on your PC. I bought the Arduino Uno at Radio Shack as part of a package called "Arduino Starter Kit." I ordered the 6DOF Digital (red) board from Karlsson robotics for $65. Later, I found out the same unit is available from Sparkfun for $35.

The IMU board finally showed up on Monday and I was eager to find out if I could pass the first hurdle: wire the IMU up and program the Arduino to read data from it. Fortunately, there is ready made Arduino code that I could use for testing. You can view the source code here. This sample by Kristian Lauszus appears to be intended as a platform leveler and it includes a Kalman filter that combines the accelerometer data and the gyro data to measure the attitude of a platform relative to the horizontal plane.

For a navigation application, we need to get the gyro and accelerometer data out to another computer so we can combine it with our GPS position fixes from the Garmin GPS-12. Lauszas code was a good starting point, so I modified it to write the gyro rate and accumulated angle data out to serial port. My program (or "Sketch" as the Arduino folks prefer to call it) looks like this:


#include 
#define gyroAddress 0x68
#define adxlAddress 0x53
double zeroValue[6] = { 0,0,0,38,31,-16}; // Found by experimenting
/* All the angles start at 0 degrees */
double gyroXangle = 0;
double gyroYangle = 0;
double gyroZangle = 0;
unsigned long timer;
void setup() {
  Serial.begin(115200);
  Wire.begin();
  i2cWrite(gyroAddress, 0x16, 0x1A); // this puts your gyro at +-2000deg/sec  and 98Hz Low pass filter
  i2cWrite(gyroAddress, 0x15, 0x09); // this sets your gyro at 100Hz sample rate
  timer = micros();
}
void loop() {
  double seconds = (double)micros()/1000000;
  double gyroXrate = -(((double)readGyroX() - zeroValue[3]) / 14.375);
  gyroXangle += gyroXrate * ((double)(micros() - timer) / 1000000); // Without any filter
  double gyroYrate = (((double)readGyroY() - zeroValue[4]) / 14.375);
  gyroYangle += gyroYrate * ((double)(micros() - timer) / 1000000); // Without any filter
  double gyroZrate = (((double)readGyroZ() - zeroValue[5])/ 14.375);
  gyroZangle += gyroZrate *((double)(micros() - timer)/1000000);
  timer = micros();
  /* print data to processing */
  Serial.print(seconds); Serial.print("\t");
  Serial.print(gyroXrate); Serial.print("\t");
  Serial.print(gyroYrate); Serial.print("\t");
  Serial.print(gyroZrate); Serial.print("\t");
  Serial.print(gyroXangle); Serial.print("\t");
  Serial.print(gyroYangle); Serial.print("\t");
  Serial.print(gyroZangle); Serial.print("\t");
  Serial.print("\n");
  delay(10);
}
void i2cWrite(uint8_t address, uint8_t registerAddress, uint8_t data) {
  Wire.beginTransmission(address);
  Wire.write(registerAddress);
  Wire.write(data);
  Wire.endTransmission();
}
uint8_t* i2cRead(uint8_t address, uint8_t registerAddress, uint8_t nbytes) {
  static uint8_t data[12];
  Wire.beginTransmission(address);
  Wire.write(registerAddress);
  Wire.endTransmission();
  Wire.beginTransmission(address);
  Wire.requestFrom(address, nbytes);
  for (uint8_t i = 0; i < nbytes; i++)
    data[i] = Wire.read();
  Wire.endTransmission();
  return data;
}
int readGyroX() { // This really measures the x-axis of the gyro
  uint8_t* data = i2cRead(gyroAddress, 0x1D, 2);
  return ((data[0] << 8) | data[1]);
}
int readGyroY() { // This really measures the y-axis of the gyro
  uint8_t* data = i2cRead(gyroAddress, 0x1F, 2);
  return ((data[0] << 8) | data[1]);
}
int readGyroZ() { // read z axis of the gyro
  uint8_t* data = i2cRead(gyroAddress,0x21, 2);
  return ((data[0] << 8) | data[1]);
}

Here is a plot of the raw gyro rate data.

The following plot shows accumulated drift over 75 seconds.

These results look pretty good. I had previously reported seeing large anomalous spikes in the gyro rate data, but that appears to be due to a memory problem which has been corrected in the sample source code included.

In the course of my testing of the hardware, I have observed changes in the gyro biases from one session to another of about 25%. It seems likely that the application software will need to go through a bias computation phase during startup in order to achieve good navigation results.

Next update, we'll take a look at the accelerometer data.

Thanks for visiting my web-site -- Cary Semar

Return to Index