MPU-9250 and Arduino (9-Axis IMU)

This post presents a simple example of how to interface the MPU-9250 with an Arduino board. The breakout board used here is the IMU 9DOF - MPU9250 breakout board manufactured by Drotek.

The MPU-9250 is a multi-chip module (MCM) consisting of:

  • 3-Axis accelerometer
  • 3-Axis gyroscope
  • 3-Axis magnetometer

AxisOrientation

Wiring

Arduino mega

wiring

Source code

#include 

#define    MPU9250_ADDRESS            0x68
#define    MAG_ADDRESS                0x0C

#define    GYRO_FULL_SCALE_250_DPS    0x00  
#define    GYRO_FULL_SCALE_500_DPS    0x08
#define    GYRO_FULL_SCALE_1000_DPS   0x10
#define    GYRO_FULL_SCALE_2000_DPS   0x18

#define    ACC_FULL_SCALE_2_G        0x00  
#define    ACC_FULL_SCALE_4_G        0x08
#define    ACC_FULL_SCALE_8_G        0x10
#define    ACC_FULL_SCALE_16_G       0x18



// This function read Nbytes bytes from I2C device at address Address. 
// Put read bytes starting at register Register in the Data array. 
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.endTransmission();
  
  // Read Nbytes
  Wire.requestFrom(Address, Nbytes); 
  uint8_t index=0;
  while (Wire.available())
    Data[index++]=Wire.read();
}


// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.write(Data);
  Wire.endTransmission();
}


// Initializations
void setup()
{
  // Arduino initializations
  Wire.begin();
  Serial.begin(115200);
  
  // Configure gyroscope range
  I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
  // Configure accelerometers range
  I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
  // Set by pass mode for the magnetometers
  I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
  
  // Request first magnetometer single measurement
  I2CwriteByte(MAG_ADDRESS,0x0A,0x01);


}


long int cpt=0;
// Main loop, read and display data
void loop()
{
  
  // _______________
  // ::: Counter :::
  
  // Display data counter
  Serial.print (cpt++,DEC);
  Serial.print ("\t");
  
 
 
  // ____________________________________
  // :::  accelerometer and gyroscope ::: 

  // Read accelerometer and gyroscope
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
  
  
  // Create 16 bits values from 8 bits data
  
  // Accelerometer
  int16_t ax=-(Buf[0]<<8 | Buf[1]);
  int16_t ay=-(Buf[2]<<8 | Buf[3]);
  int16_t az=Buf[4]<<8 | Buf[5];

  // Gyroscope
  int16_t gx=-(Buf[8]<<8 | Buf[9]);
  int16_t gy=-(Buf[10]<<8 | Buf[11]);
  int16_t gz=Buf[12]<<8 | Buf[13];
  
    // Display values
  
  // Accelerometer
  Serial.print (ax,DEC); 
  Serial.print ("\t");
  Serial.print (ay,DEC);
  Serial.print ("\t");
  Serial.print (az,DEC);  
  Serial.print ("\t");
  
  // Gyroscope
  Serial.print (gx,DEC); 
  Serial.print ("\t");
  Serial.print (gy,DEC);
  Serial.print ("\t");
  Serial.print (gz,DEC);  
  Serial.print ("\t");

  
  // _____________________
  // :::  Magnetometer ::: 

  
  // Read register Status 1 and wait for the DRDY: Data Ready
  
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS,0x02,1,&ST1);
  }
  while (!(ST1&0x01));

  // Read magnetometer data  
  uint8_t Mag[7];  
  I2Cread(MAG_ADDRESS,0x03,7,Mag);
  

  // Create 16 bits values from 8 bits data
  
  // Magnetometer
  int16_t mx=-(Mag[3]<<8 | Mag[2]);
  int16_t my=-(Mag[1]<<8 | Mag[0]);
  int16_t mz=-(Mag[5]<<8 | Mag[4]);
  
  
  // Magnetometer
  Serial.print (mx+200,DEC); 
  Serial.print ("\t");
  Serial.print (my-70,DEC);
  Serial.print ("\t");
  Serial.print (mz-700,DEC);  
  Serial.print ("\t");
  
  
  
  // End of line
  Serial.println("");
//  delay(100);    
}

Contributors

Source code on BitBucket here.

Download



67 thoughts on “MPU-9250 and Arduino (9-Axis IMU)

  1. Hello

    I just received a DroTek MPU9250 board.

    Looking at the 9250 specs, I see that VDD is connected to 3.3 V.
    Your illustrations imply that it can be connected to 5 V.

    I was planning to connect the MPU9250 board to an Arduino Uno R3, but from what I see in the chip specs, this would damage it...
    Have you actually done this? No smoke?

    Maybe the board drops the voltage to 3.3 V ...?

    Thanks

  2. The answer is yes.
    Connected and running now, trying to figure why the output is all gibberish...
    ùXÿÅkÿê)ÿ ø§ýˆ‹üŠüÜüqÁ|

    1. Hi Carlos,

      I was wondering how you fixed this. I'm using the Arduino Mega 2560 with the MPU-9250 and the module found here: http://www.ebay.com/itm/SPI-IIC-MPU-9250-9-Axis-Attitude-Gyro-Accelerator-Magnetometer-Sensor-Module-/131185485892

      When I run the code, I get this:
      $����H/�d�P�L��$�J�H_�n������Px
      �8`����^����%�\��X~JG˥� <Ѧ\������G��$OG�}
      And it goes on.

      I know the board and MPU9250 are connected correctly so I'm not sure what the issue might be.

      Thanks!

      1. Nevermind, it's working now - I had to change Serial.begin(115200) to Serial.begin(9600).

  3. Hello,

    Yes, it is, I am receiving data on the serial monitor.
    Now it is a matter of digging deeper: first step is to used Processing
    https://processing.org/
    to capture the data and use it to move a shape on the Mac's screen (using the code created for the Razor).
    After this works, I'll figure how to interface with some other C++ code I wrote.
    (If you are curious, visit Zenith.aero and search my name).
    It's been a steep learning curve: I hadn't touched electronics or programing in (literally) decades - but it's fun.

    Regards from Montreal (-16 C)

  4. Bonjour!

    I thought I'd let you know how my project is going.
    Here's a link to a video that shows the result of a few weeks worth of coding:
    http://www.zenith.aero/video/avionics-test
    (Coded in openFrameworks - the objective is to port this to either a Raspberry Pi or a PCduino.)
    Clearly still needs work, but the gauges are ready.

    I am having trouble with the the filters implementation (open source code).
    This other video shows how pitching and rolling generate pronounced yaw:
    https://www.flickr.com/photos/54366879@N06/16367667000/

    (Source code from https://github.com/richards-tech/RTIMULib-Arduino)

    Regards

    Carlos

  5. Dear

    Thank you for the uploaded source code. i have a question after getting the sensor outputs, i scaled gyro outputs such that it is represented in [rad/s] and used the scaled values in Madgwick algorithm. 3D angles are coming out ok but it is a bit noisy roughly +-3 degree up and down while keeping it on a table. When I look at your youtube it seems there is not much noise. would you mind giving me some insight how you process raw data before putting in Madgwick algorithm? Do I have to do bias tracking for gyros?

    Best,
    min

    1. I used the in-build filter of the MPU-9250. I'm quite busy this time, but as soon as I can, I will publish the source code of the Qt à OpenGL App. Note that the IMU calibration is mandatory.

  6. Looks very cool! What software do you use for visualization (I mean the Windows application on the screen with the cuboid, not the Arduino C Code)?

  7. Hi,
    Great work being done! a beginner here. Could anyone help me to plot these movements on a graph?

  8. Is the Drotek board 5 Volt tolerant? I understood that there's a voltage regulator so it accepts 5V on VDD - but do SCL and SDA also accept 5V?

    1. I talked to Drotek customer service and they strongly advised me to NOT connect 5V to the devices SCL and SDA lines (they said they are not 5V tolerant). Can you please change you schematic?

  9. Hi, thank you a lot for the code...

    I have a 2 problems

    1) Arduino just makes one readm then it stops. If i take off all the MAG part, then it works correcty
    2) Even moving the MPU9250 i get the same data from the MPU9250, nothing change.

    Can you help me there? thank you

  10. Hi,
    In my project i have already configured the A4,A5 pins.So can u suggest me a way in the program to change the pins from A4,A5 to A3 and A4?

  11. I have got this connection working using an UNO board and an RS232 shield attached. Although I have been doing embedded design for30+ years using different microcontrollers, and most of it lately using AVR chips, the Arduino language is new to me so I have a learning curve!
    What I am thinking of is storing the data on an SD card to be analysed later. Have you done anything like that?
    One annoying thing that I have found is that I can't upload programs with the shield attached. It has to be unplugged. I wonder if this is a UNO problem or does it apply to all.

    1. This is probably due to the fact that the RS232 shield shares the same UART than USB. SO you can't communicate via USB when the shield is plugged. Maybe there is a jumper on the shield to switch to another UART. For the SD card storage, I recommend to use a dedicated shield, you'll easily find source code and everything you need ! Be careful to compatibility between shield.

      1. Thanks Phillipe. I have an EtherMega256 which has a micro SD card socket, so that may be the way to go in this case. Will work on that approach.

  12. Did you use the filter inside the board? is available also in the breakout version you bought?
    I can't see the code entirely, could you post it or a github repo? thank you.

    1. Yes, I used the filter. The filter is in the chip, so it is necessary inside the breakout board.

  13. Hi,
    I cannot read/copy the whole source code. Could you please provide a raw file link?
    Thanks

  14. I m not able to copy or download the whole code , only some part of it is visible here. Kindly do something about it .

        1. I contacted InvenSense about it. Here is the answer : "That DMP document is not distributed and should not even be mentioned in the register map. Our apologies for this oversight"

          1. Thank You . Can you suggest how to get accurate yaw pitch and roll , i applied madgwick filter but it wasnt stable like i have seen in your video.

  15. Salut Phillippe. Very nice work you have done. Just want to thank you and add my name to those hoping you can find time to post the source code.
    -Terry

  16. Hi,

    Great job. Tried building it, the opengl app fails build with missing headers
    #include
    #include

    Seems like a missing library ?

    Can you please provide the missing files ?

  17. hello thanks for your answers and i have a question
    is mpu9150 programs works with mpu9250
    is mpu9150 compatible with mpu9250 in software (with i2c)

    1. I think this is compatible, but I'm not sure. You can check it with the documentation. If the registers used in the program have the same addresses, they are compatible.

  18. Thank you for posing sample application. I had problems building OpenGL application for Windows OS, it was missing some code. I also made some improvements so that OpenGL window does not lock up when no data is available in RX buffer. I can send you zip of updated source code? You can review and publish as required.

    Kind Regards, Sean

    1. Thank you for your code. I added your archive, and I also created a repro on Bitbucket for futur contributors.

      1. I do. Also I have a problem when connecting the sensor: sometimes I just get rubbish instead of real data.
        My sensor is a little different than yours: on the right side there are only 3 pins (CS, SD0, INT), but I suggest that difference doesn't matter? (it still is a 9250).

  19. Does this really work in Windows? I tried compiling in OpenGl and got lots of errors -- I assume it needs freeglut. How do I install freeglut in Windows?

    1. I too am having problems getting it to work on windows. I fixed all of the UNIX exclusive function calls and uploaded my fixed code here:

      https://drive.google.com/open?id=0B2q8TR7GSkNEUDlZaFF3VXVmWlk

      I installed QT creator, then installed Freeglut from the file included in the zip (followed the readme in the freeglut folder). I included a copy of the errors, all look like Qt can't find OpenGL. Any help would be appreciated.

  20. To the creator of this project - what license do you have on the Arduino code? Can I use it in my own projects without any limits?

    1. Code should be compatible, but be carreful : wiring is mal functionning with UNO due to voltages.

      1. The schematics in this article is INCORRECT and you will likely fry your IMU board if you use it.

        The MPU-9250 is NOT 5V tolerant. The fact that the Drotek board includes a 3.3V voltage regulator does nothing about the SDA and SCL signal lines which can reach almost 5V when set to high level. That is certainly more than the 3.6V absolute maximum the MPU is rated for.

        You need a bidirectional voltage converter here for using the boards with a 5V Arduino, such as this one:
        http://www.adafruit.com/products/757

        (or build your own from two 2N7000 FETs and 4 10k resistors).

        Furthermore, the schematics doesn't include pull-up resistors - those are *MANDATORY* for I2C. The built-in pull-ups in the AVR chip in the Arduino are very large and will severely compromise the signal integrity due to the low pass filter formed by the high resistance of the pull-up in the AVR and the stray capacitance of the wires.

        Basically, if this schematics worked for someone, it was by luck - the built-in pull-ups in the AVR are too large value, so they limit the current into the MPU-9250 and it didn't burn itself out right away. The same for the signal integrity - you got lucky. Use longer wires/PCB tracks, use a different Arduino with a smaller value of the pull-up resistors or set the SDA/SCL pins to output instead of I2C by accident and BOOM. Magic smoke escapes.

        Some seriously poor engineering here.

        1. Correction - the original Drotek board seems to have 10k pull-ups built-in. However any other board will need external pull-ups.

          1. Your message is quite incisive "Some seriously poor engineering here" ... look at my background first !
            If you look at the datasheet of the ATmega2560, page 355, you'll see that the IO Port Input High Voltage is 0.6Vcc. As the Arduino is supplyed with 5V, the high level is considered from 3V. So the ATmega2560 is 3.3V tolerant and it will work for everybody, since you are using an Arduino 2560...
            Some seriously poor comments here ! Apologies are expected.

  21. Hello

    I just try it with arduino uno with your schematic.
    it give me temp/accelero/gyro... but no magneto

    The code still waiting on this line

    while (!(ST1&0x01));

  22. In your opengl example are a few magic numbers:
    ...
    #define RATIO_ACC (4./32767.)
    #define RATIO_GYRO ((1000./32767.)*(M_PI/180.))
    //#define RATIO_GYRO (1000./32767.)
    #define RATIO_MAG (48./32767.)
    ...
    gx = (igx - 48.4827) * RATIO_GYRO;
    gy = (igy + 76.3552) * RATIO_GYRO;
    gz = (igz + 64.3234) * RATIO_GYRO;
    ...

    What is their purpose? Do I need to change them?

  23. Hello all

    If i run the .pro file in qt 5.5.0 (mingw) , it shows me
    "Error while opening serial device"

    got struck with this

    Please help

Comments are closed.