Razor 9DOF IMU – I2C to Arduino


 

I2C bus "hijack" - glued with epoxy - one of them uses a via through whole, another is soldered on the back

This is obviously related to my endless post about the home made quadcopter

But it’s a much more generic problem, so here I am, talking about it in a post of its own…

The default way of interacting with Sparkfun’s 9DOF Razor IMU , as per its documentation, is through its serial interface.

This was ok for me initially, but now I’m about to re-design the quadcopter to use an Arduino as the main board instead of the initial FEZ Domino, and the problem with the Atmega 328 is that it has only 1 hardware serial port, which I use for debugging. I could obviously use a software serial library to talk to the IMU, but this poses several problems, among which the fact that it uses a lot of CPU cycles…

And anyhow, WHY not use the hardware I2C port that not only supports plenty of different peripherals on the same bus, but it’s already used on the IMU ?

So here’s the theory:

  • I’ve installed this code base on the IMU, which is basically Arduino code that aggregates the data from all the sensors and does some filtering, in order to provide you with a pretty acceptable AHRS
  • this already uses the I2C bus to get the data from 2 of the sensors (the HMC5843 compass and ADXL345 accelerometer)
  • the IMU’s Atmega is already acting as I2C master, and given that we’ll connect the main Arduino board on the same bus, this will have to be a slave. Slightly counter intuitive, but that’s ok, this main board does its balancing job and just gets told by the IMU master whenever new sensors data is available

Hardware

This is the hard part, as the Razor IMU board does NOT have the I2C bus connections readily available.

It was and still is a pain, as I had to connect to some vias on the board, which only worked for 1 of the signals, and then I’ve soldered a wire directly to one of the MCU’s pins, which is really NOT pretty ! (and also broke 1 hour later…!)

Sparkfun guys, if you do read this, then pleeeease, do add a simple connector on this board for the I2C bus !

 

Razor 9DOF IMU eagle file - with the 2 I2C lines highlighted

I2C wires soldering - awful !!!!

Thist first version, lasted only about 1 hour, afer which one of the wires broke loose…

In the final version (that you can see at the beginning of the post), the soldering is so bad mechanically speaking that I had to drown everything in epoxy glue ! Let’s hope this will be sturdy enough, as I don’t think I’ll ever be able to remove that glue to solder them back again…

Another problem specific to my configuration is that the Arduino is 5V whereas the IMU is 3.3V. So here comes this little Logic Level Converter from Sparkfun:

 

Sparkfun Logic Level Converter - using both TX lines so that it's fully bi-directional

Important point here, as you can see in the previous picture, you’ll have to solder both SDA and SCL to  TX lines (rather than a TX and a RX), as the I2C protocol is bi-directional on both lines ! (see the comments on the Sparkfun’s page for more details)

Software

This is quite easy:

On the IMU

It’s Arduino code and it already uses the Wire library, so the changes are quite easy. Rather than doing Serial.print() we do Wire.send(), AFTER having started a connection with the main board, which is a I2C slave:

#if PRINT_EULER_BINARY == 1
 Wire.beginTransmission(PILOT_ADDR);

 // make everything positive (+ 200 ) and include first 2 decimals ( * 100)
 tempint=(ToDeg(roll) + 200) * 100;  //Roll (degrees) * 100 in 2 bytes
 _buffer[0]=tempint & 0xff;
 _buffer[1]=(tempint >> 8) & 0xff;

 tempint=(ToDeg(pitch) + 200) * 100;   //Pitch (degrees) * 100 in 2 bytes
 _buffer[2]=tempint & 0xff;
 _buffer[3]=(tempint >> 8) & 0xff;

 tempint=(ToDeg(yaw) + 200) * 100;  //Yaw (degrees) * 100 in 2 bytes
 _buffer[4]=tempint & 0xff;
 _buffer[5]=(tempint >> 8) & 0xff;

 ck = 0;
 for (int i=0; i<6; i++) {
 Wire.send(_buffer[i]);
 ck += _buffer[i];  //Calculates checksum
 }
 Wire.send(ck);

 Wire.endTransmission();
 #endif

On the main Arduino board

Just connect to I2C as a slave (with the same address as the IMU expects you to have 🙂 ) and then register a handler that will be called whenever the master (the IMU) sends anything:

#include <Wire.h>

#define I2C_SLAVE_ADDR 0x2A
#define MSG_SIZE 7
byte _buff[MSG_SIZE], _ck;

void setup_RazorIMU(){
 Wire.begin(I2C_SLAVE_ADDR); // start as slave
 Wire.onReceive(IMUDataHandler); // what to call when new IMU data has arrived
}

void IMUDataHandler(int numBytes){
 if(_imuDataStatus >= 0){ // nobody is using this data right now
 _imuDataStatus == -1;
 if(MSG_SIZE == numBytes) {
 for(i = 0; i  < MSG_SIZE; i++) _buff[i] = Wire.receive();

 // the checksum is simply the sum module 256 of all the data (excluding itself 🙂 )
 _ck = 0;
 for(i = 0; i < MSG_SIZE - 1; i ++) _ck += _buff[i];

 // last byte is the check sum, it should match !!!
 _imuDataStatus == -2;
 if (_ck == _buff[MSG_SIZE - 1]){
 _roll = getIntFrom2Bytes(_buff, 0);
 _pitch = getIntFrom2Bytes(_buff, 2);
 _yaw = getIntFrom2Bytes(_buff, 4);

 // data updated correctly
 _imuDataStatus == 1;
 }
 }
 }
}

int getIntFrom2Bytes(byte buff[], byte pos){
 return (buff[pos] | buff[pos + 1] << 8) - 20000;
}

7 Responses to Razor 9DOF IMU – I2C to Arduino

  1. Kevin says:

    Thanks! for your documentation: Arduino as I2C slave, sample code, etc. all got me headed down the path of successfully transmitting data from SparkFun’s latest Razor IMU to my Arduino. This should be on SparkFun’s site.
    I2C pins nicely available on this Razor:
    https://www.sparkfun.com/products/14001

    • trandi says:

      Hi Kevin,
      Super glad to hear it’s been so useful for you !
      Feel free to ask Sparkfun to put a link on their page to my post, I’d be honoured… 🙂

      Thanks,
      Dan

  2. Cory says:

    So did you update the AHRS firmware to work with the ITG-3200 Gyros? It looks like the AHRS firmware does not yet support this part.

  3. Jesper Taxbøl says:

    Did you get any feedback from Sparkfun, related to exposing the I2C pins in their design?

    Kind regards

    Jesper

    • trandi says:

      Nope, I don’t think they read my blog 🙂 and I haven’t sent them an e-mail…

      However, they now have introduced these which communicate over I2C. They don’t have an on board uC to do the DCM calculations for you, but still, you can access ALL the sensors nicely over the same bus and without blocking your hardware serial port on the main board !

Leave a comment