Arduino Uno and the InvenSense MPU6050 6DOF IMU
A while back I bought the InvenSense MPU-6050 sensor in a “GY-521” breakout board from eBay. For a long time it sat quietly in my box of “possibly cool things to check in the future”. Recently, I decided to finally get to building a self-balancing robot and dug it out. As with almost anything from eBay, it came with no documentation.
The MPU-6050 breakout boards are quite popular in the Arduino community and information was easy to find. Even too easy: it took me a while to sift through many partial, or “almost” working implementations before I found a relatively easy to use, clean and reliable set of instructions and Arduino sample code. So here it is documented for future reference!
According to the InvenSense MPU-6050 datasheet, this chip contains a 3-axis gyroscope and a 3-axis accelerometer. This makes it a “6 degrees of freedom inertial measurement unit” or 6DOF IMU, for short. Other features include a built in 16-bit analog to digital conversion on each channel and a proprietary Digital Motion Processor™ (DMP) unit.
The DMP combines the raw sensor data and performs some complex calculations onboard to minimize the errors in each sensor. Accelerometers and gyros have different inherent limitations, when used on their own. By combining the data from the two types of sensors and using some math wizardry (a process referred to as sensor fusion), you apparently can get a much more accurate and robust estimate of the heading. The DMP on the MPU6050 does exactly that and returns the result in “quaternions”. These can then can be converted to yaw-pitch-roll, or to Euler angles for us humans to read and understand. The DMP also has a built in auto-calibration function that definitely comes in handy, as we will see later.
The biggest advantage of the DMP is that it eliminates the need to perform complex and resource intensive calculations on the Arduino side. The main downside is that it seems that the manufacturer did not provide much information on the proprietary inner workings of the DMP. Nevertheless, smart and creative folks figured out how to use its main features, and were nice enough to share the results with the rest of us. You can still pull the raw, accelerometer and gyro data as well, disabling the DMP, if this works better for your application, or you want to apply your own filtering and sensor fusion algorithms.
The MPU-6050 communicates with a microcontroller through an I2C interface. It even has a built in an additional I2C controller, that allows it to act as a master on a second I2C bus. The intention is for the IMU to read data from say, an external magnetometer (hooked up via those XDA / XCL pins you see on the breakout board) and send it to the DMP for processing. I have not found much detail on how to make the DMP use external magnetometer data yet, but fortunately that is not needed for my self-balancing robot at this point.
Lastly, the MPU-6050 has a FIFO buffer, together with a built-in interrupt signal. It can be instructed to place the sensor data in the buffer and the interrupt pin will tell the Arduino, when data is ready to be read.
MPU-6050 / GY-521 break-out board schematics
Below is the schematic of the GY-521 break-out board for the MPU6050 chip.
Hooking the MPU-6050 / GY-521 to an Arduino Uno
The InvenSense MPU6050 chip is a 3.3V IC, with a working voltage range of 2.375V-3.46V, according to its datasheet. As you can see from the schematics above, the GY-521 breakout board has a built in low drop-out voltage regulator, so it is safe to power the chip through the Arduino 5V rail. This is recommended, as due to the voltage drop-out of the regulator on the VCC line, using the Arduino 3.3V rail may not provide enough voltage. I tested powering the chip both with 3.3V and 5V from the Arduino successfully, but in my final set-up opted for the 5V input.
Based on what I have read online and what I saw on my tests, the 3.3V SDA / SCL lines of the IMU work fine connected directly to the corresponding Arduino 5V I2C pins. If you want to be absolutely safe, you could use a level shifter, voltage divider, or an inline 10k resistor to protect the MPU6050 I2C lines. I opted for simplicity over safety, in my set-up and (so far) all is well.
|MPU6050 / GY-521||Arduino UNO Pin|
|VCC||5V (the GY-521 has a voltage regulator)|
|SDA||A4 (I2C SDA)|
|SCL||A5 (I2C SLC)|
|INT||D2 (interrupt #0)|
Arduino libraries and example code
Here is where credit and a big thanks is due to Jeff Rowberg for his I2Cdev library and sample code for interfacing with the InvenSense MPU6050 chip and partially reverse-engineering the DMP functions. Also, you might check out the “teapot demo” post from Debra at “Geek Mom Projects” that pointed me to the i2cdev library in the first place.
To get started you need to follow these simple steps:
- Download the I2C Device Library ( i2cdevlib ) master zip file and extract the contents to a convenient location on your hard-drive.
- You should see a folder called “i2cdevlib-master” that will contain an “Arduino” subfolder in it and a couple of other items, that we do not need.
- Open the Arduino folder and locate the “I2Cdev” and “MPU6050” sub-folders. Those are the two Arduino libraries we will need to copy to your Arduino libraries folder (here is how to install an Arduino library, in case you have not done this before).
Under the Sketch->Examples menu, you should now see a menu item for the newly installed MPU6050 library. Load the MPU6050_DMP6 example and follow the instructions in the sketch comments to define what type of serial output you would like to see from the sensor. I suggest using yaw-pitch-roll or Euler while you are testing things out, as the data is a bit more intuitive.
Find the section in the code (around line 100) in the MPU6050_DMP6 example sketch and uncomment the #define OUTPUT_READABLE_YAWPITCHROLL line. Then make sure that all other output options are commented out. Here is the section for the yaw/pitch/roll output for reference:
// uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/
// pitch/roll angles (in degrees) calculated from the quaternions coming
// from the FIFO. Note this also requires gravity vector calculations.
// Also note that yaw/pitch/roll angles suffer from gimbal lock (for
// more info, see: http://en.wikipedia.org/wiki/Gimbal_lock)
If all is well, when you upload the sketch to the Arduino and open your serial monitor (remember to set it at the correct baud rate), you will be prompted to send a random character via serial.
Once you type any character in the serial input field and hit “Send”, a few status messages will appear and (if all is well) a steady stream of data from the IMU will follow!
I charted the DMP output of the sensor (the yaw-pitch-roll data), while the breakout board was set still on a “relatively” flat service. As you can see, initially some sort of calibration algorithm is run by the DMP. Once that completes, the sensor values are very stable.
With 6 axis IMUs you can expect yaw drift. After the initial auto-calibration, the DMP compensates for most of that and only a very slight yaw drift remains (the light blue line).
Even better results can be achieved with some additional fine-tuning of the offsets in the sample code of the MPU-6050. Arduino MPU-6050 auto-calibration sketch courtesy of Luis Rodenas.
For my self-balancing robot, I will initially use the roll axis only which is very steady. Next: use the MPU-6050 to get my self-balancing robot to…well, balance!