Pages

30 March, 2012

Arduino - Sparkfun 9DOF IMU Sensor Stick


I got Sparkfuns 9 Degrees of Freedom IMU a few days ago, and it seems to be working quite well. I have got readings from all of the three sensors, but I left the filtering and rotation algorithms for later. This is just a short introduction on how to get your IMU up and running.

Specifications
Accelerometer: ADXL345
Magnetometer: HMC5883L
Gyro: ITG-3200
Price: ~$99.95
Supply voltage: 3.3V (5V should also be fine)

Connecting to an Arduino
The sensor stick is marked underneath with names of the four different pins, and some sketches of our three sensor. The upper pin is marked "SCL", the neighbor is marked "SDA" and the next two are "GND" and "VCC". I prefer to connect VCC to 3.3V, but it should be fine to connect it to 5V, since the schematics shows a voltage regulator. GND is of course connected to GND on the Arduino. SCL should be connected to A5, and SDA to A4. This may vary depending on the Arduino you are using, but I believe Diecimila, Duemilanove, UNO and R3 are all using A5 and A4.

Code (Raw data)
#include <Wire.h>

#define  ADXL345_ADDRESS (0xA6 >> 1)
#define ADXL345_REGISTER_XLSB (0x32)
#define ADXL_REGISTER_PWRCTL (0x2D)
#define ADXL_PWRCTL_MEASURE (1 << 3)

#define ITG3200_ADDRESS (0xD0 >> 1)
#define ITG3200_REGISTER_XMSB (0x1D)
#define ITG3200_REGISTER_DLPF_FS (0x16)
#define ITG3200_FULLSCALE (0x03 << 3)
#define ITG3200_42HZ (0x03)

#define HMC5843_ADDRESS (0x3C >> 1)
#define HMC5843_REGISTER_XMSB (0x03)
#define HMC5843_REGISTER_MEASMODE (0x02)
#define HMC5843_MEASMODE_CONT (0x00)

int accelerometer_data[3];
int gyro_data[3];
int magnetometer_data[3];

char c;

void setup() {
  Wire.begin();
  Serial.begin(9600);

  for(int i = 0; i < 3; ++i) {
    accelerometer_data[i] = magnetometer_data[i] = gyro_data[i] = 0;
  }
  
  init_adxl345();
  init_hmc5843();
  init_itg3200();
}

void loop() {
   read_adxl345();

   Serial.print("ACCEL: ");
   Serial.print(accelerometer_data[0]);
   Serial.print("\t");
   Serial.print(accelerometer_data[1]);
   Serial.print("\t");
   Serial.print(accelerometer_data[2]);
   Serial.print("\t");

   read_hmc5843();

   Serial.print("MAG: ");
   Serial.print(magnetometer_data[0]);
   Serial.print(",");
   Serial.print(magnetometer_data[1]);
   Serial.print(",");
   Serial.print(magnetometer_data[2]);
   Serial.print("\t");

   read_itg3200();

   Serial.print("GYRO: ");
   Serial.print(gyro_data[0]);
   Serial.print("\t");
   Serial.print(gyro_data[1]);
   Serial.print("\t");
   Serial.print(gyro_data[2]);
   Serial.print("\n");

   delay(100);
}

void i2c_write(int address, byte reg, byte data) {
  Wire.beginTransmission(address);
  Wire.write(reg);
  Wire.write(data);
  Wire.endTransmission();
}

void i2c_read(int address, byte reg, int count, byte* data) {
 int i = 0;

 Wire.beginTransmission(address);
 Wire.write(reg);
 Wire.endTransmission();
 Wire.beginTransmission(address);
 Wire.requestFrom(address,count);
 while(Wire.available()){
   c = Wire.read();
   data[i] = c;
   i++;
 }
 Wire.endTransmission();
} 

void init_adxl345() {
  byte data = 0;

  i2c_write(ADXL345_ADDRESS, ADXL_REGISTER_PWRCTL, ADXL_PWRCTL_MEASURE);

  i2c_read(ADXL345_ADDRESS, ADXL_REGISTER_PWRCTL, 1, &data);
  Serial.println((unsigned int)data);
}

void read_adxl345() {
 byte bytes[6];
 memset(bytes,0,6);

 i2c_read(ADXL345_ADDRESS, ADXL345_REGISTER_XLSB, 6, bytes);

 for (int i=0;i<3;++i) {
 accelerometer_data[i] = (int)bytes[2*i] + (((int)bytes[2*i + 1]) << 8);
 }
}

void init_itg3200() {
  byte data = 0;

  i2c_write(ITG3200_ADDRESS, ITG3200_REGISTER_DLPF_FS, ITG3200_FULLSCALE | ITG3200_42HZ);

  i2c_read(ITG3200_ADDRESS, ITG3200_REGISTER_DLPF_FS, 1, &data);

  Serial.println((unsigned int)data);
}

void read_itg3200() {
  byte bytes[6];
  memset(bytes,0,6);

  i2c_read(ITG3200_ADDRESS, ITG3200_REGISTER_XMSB, 6, bytes);
  for (int i=0;i<3;++i) {
  gyro_data[i] = (int)bytes[2*i + 1] + (((int)bytes[2*i]) << 8);
  }
}

void init_hmc5843() {
  byte data = 0;
  
  i2c_write(HMC5843_ADDRESS, HMC5843_REGISTER_MEASMODE, HMC5843_MEASMODE_CONT);

  i2c_read(HMC5843_ADDRESS, HMC5843_REGISTER_MEASMODE, 1, &data);
  Serial.println((unsigned int)data);
}

void read_hmc5843() {
 byte bytes[6];
 memset(bytes,0,6);

 i2c_read(HMC5843_ADDRESS, HMC5843_REGISTER_XMSB, 6, bytes);

 for (int i=0;i<3;++i) {
 magnetometer_data[i] = (int)bytes[2*i + 1] + (((int)bytes[2*i]) << 8);
 }
}
Code (Yaw, Pitch and Roll)
After some minor modifications to this Razor AHRS code, I managed to plot a graph of yaw, pitch and roll:

17 comments:

  1. what differences you would have done if you were using a mega board instead of uno
    since the scl and sda in these case are the digital pins 20 and 21?

    ReplyDelete
    Replies
    1. I beleive you can simply connect the sensor stick to the ports you mention. But I don't have a Mega, so you should google it.

      Delete
  2. Can you share how did you change the code to allow the plotting of a graph?

    ReplyDelete
    Replies
    1. I would, but I'm not sure what version of the code I used. And I also made the software running on Windows, so there is quite a lot of code in total. The program I made is not the best, so I would suggest you use something else, or make something yourself. If you are new to UI-programming, take a look at Processing (http://processing.org/). Good luck!

      Delete
  3. Hi, can I know what are the values the raw data's are in? eg Acceleration in m/s^2 ?

    ReplyDelete
    Replies
    1. I'm not sure, but most sensors I use give me a value between 0 and 1023. This is because of the 10-bit ADC (Analog-to-Digital Converter) on the ATMega328. The value is depending on the voltage level adjusted by the sensor.

      The following link might help. Notice that it is for the Razor IMU.
      https://forum.sparkfun.com/viewtopic.php?f=14&t=23115

      Delete
  4. Hi, may i know why there is a need to do bitshift in the initialization of the address? And in reading the values from the sensor, what is the purpose of the byte data/bytes/memset?

    ReplyDelete
    Replies
    1. It's because the I2C address don't need to be more than 7 bit long. The data-reference and the byte-array is just a temporary storage for the bytes received from the I2C device. Memset is used to reset the byte-array to zero. I guess there are better ways to do this.

      Delete
  5. we are planing to make a guided rocket into space......can we use this stuff for our INS section...that to control the rocket attitude by INS..???please help.....

    ReplyDelete
    Replies
    1. Hi. I have never made an INS before, but I would guess the 9DOF IMU would be useable. But depending on your needs, there might be a better solution out there. Good luck with the rocket!

      Delete
  6. Hi, may i know which values are for the various axis? eg, data 1 = x-axis, data 2 = y-axis, data 3 = z-axis?

    ReplyDelete
  7. What range and resolution did you pick for the accelerometer?

    ReplyDelete
  8. I'm getting all zeros from the stick. I did make a mistake at first, I connected it to arduino's 5V instead of 3.3V. Do you think I killed it? The LED is still alive, but I'm guessing that's not a good indication, it's probably just connected between the power and ground in series with a resistor

    ReplyDelete
    Replies
    1. Nevermind, the connection was wrong. I'm using arduino micro and the requiered pins are elsewhere

      Delete
    2. hi, how to interpret the data graphically or if there is a software like labview to represent my data. thank you in advance

      Delete
    3. Hi Siaka konaté, LabView should work, but if you are looking for an alternative, Processing might be it. I used C# and WPF, but it may take more practice.

      http://www.processing.org/

      Delete
  9. I used the same program. All seem to work fine except for Accelerometer Z-Axis reading. It doesn't change at all. It gives constant value of 511

    ACCEL: -148 136 511 MAG: 192,-162,439 GYRO: 1821 -2663 5404
    ACCEL: 8 165 511 MAG: 356,-213,216 GYRO: 745 -1716 2312
    ACCEL: 67 127 511 MAG: 415,-202,32 GYRO: 724 -616 2126
    ACCEL: 155 53 511 MAG: 392,-183,-163 GYRO: 113 -244 1809
    ACCEL: 182 -4 511 MAG: 316,-165,-307 GYRO: -16 -629 1953
    ACCEL: 156 -68 511 MAG: 227,-160,-379 GYRO: -77 61 818
    ACCEL: 147 -90 511 MAG: 240,-182,-356 GYRO: 245 1005 -368
    ACCEL: 145 8 511 MAG: 337,-240,-185 GYRO: 116 2837 -6976
    ACCEL: -163 122 511 MAG: 105,-173,465 GYRO: -131 1397 -3814
    ACCEL: -313 72 511 MAG: -74,-7,546 GYRO: -284 2573 -2353


    Also read the accelerometer registers:
    ACCEL DEVID: 0xE5
    ACCEL Data Format: 0x88
    ACCEL Data Format: 0x08
    ADXL_THRESH_ACT: 0
    ADXL_INT_ENABLE: 0
    ADXL_THRESH_INACT: 0
    ADXL_INACT_CTL: 0
    ADXL_X_OFFSET: 0 ADXL_Y_OFFSET: 0 ADXL_Z_OFFSET: 0

    Should I assume problem with the hardware?

    ReplyDelete