Electronics Software Development

Interfacing An MPU6050 (Gyroscope + Accelerometer) Sensor Module To An Arduino Uno

Arduino IMU Graphic
Written by John Woolsey

Introduction

This tutorial teaches how to connect an MPU-6050 based accelerometer and gyroscope sensor module to an Arduino Uno using the I2C bus interface along with retrieving and displaying sensor readings from the module. A basic understanding of electronics and programming is expected along with some familiarity with the Arduino platform. If you are new to the Arduino platform or would just like to refresh your knowledge, please see our Blink: Making An LED Blink On An Arduino Uno tutorial before proceeding with this one. Detailed versions of all source code used in this tutorial are available on GitHub for your reference.

What Is Needed

Background Information

An MPU6050 sensor module contains the MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device by InvenSense Inc. and provides acceleration, rotation, and temperature sensor readings over an I2C or SPI serial bus interface. The module provides more advanced configuration and functionality than what is covered in this tutorial, but for those interested in learning more about its capabilities, please check out the datasheet and register map documents for the MPU-6050 device for detailed information.

My development board is the Arduino Uno R3 and my sensor module is the SunFounder MPU6050 Module for Arduino and Raspberry Pi, 3-axis Gyroscope and 3-axis Accelerator that communicates over an I2C serial bus interface. If you are using different Arduino or MPU6050 sensor models, the vast majority of this tutorial should still apply, however, some minor changes may be necessary.

Building The Circuit

My MPU6050 sensor module did not have a pin header already attached to the module. The vendor did, however, include both straight pin and right-angle pin headers in the shipping package. I soldered the straight pin header to the bottom of the module so that when the module is plugged into a breadboard, the positive z-axis points to the ceiling.

Before connecting the sensor module to your Arduino board, disconnect the Arduino from power and your computer. This avoids accidental damage during wiring.

Attach the sensor module via the pin header to the breadboard.

Connect the VCC and GND pins of the sensor module to the 5V and GND power pins respectively on the Arduino board with the jumper wires.

For the I2C serial bus connection, use the jumper wires to connect the SDA and SCL pins of the sensor module to the SDA (A4) and SCL (A5) pins respectively on the Arduino.

You can now connect your Arduino to your computer with the USB cable.

Writing The Software

I researched various libraries that can be used with MPU6050 sensor modules and settled on the I2Cdevlib library by Jeff Rowberg because of its popularity. The top level I2Cdev library focuses specifically on I2C serial bus communication. The library also contains sub-libraries devoted to various I2C enabled devices. One of them is the MPU6050 sub-library.

Let’s manually install the I2Cdev and MPU6050 libraries into your Arduino contributed libraries location so that they can be found by the Arduino IDE. This is typically located in the libraries directory of your default sketchbook location. Clone or download the top level library from the https://github.com/jrowberg/i2cdevlib URL. Go into the library’s Arduino directory and copy the I2Cdev and MPU6050 directories to your Arduino contributed libraries location.

Once the libraries are installed, let’s utilize the IMU_Zero example sketch from the MPU6050 library to calibrate the module with new offsets for the onboard accelerometer and gyroscope data registers. This essentially “resets” the sensor readings to the current orientation of the module. Open the Arduino IDE and select File > Examples > MPU6050 > IMU_Zero from the main menu to open the example sketch. Open the Serial Monitor window so that you can see the program’s output. Follow the instructions within the comments section of the sketch to calibrate your module. Once completed, you should see something like the following.

[-906,-905] --> [0,1]  [-83,-82] --> [-8,8]  [773,773] --> [16372,16405]  [97,97] --> [-3,4]  [34,35] --> [-2,2]  [20,21] --> [-1,3]
-------------- done --------------

This means that the new calibration offsets are XAccel = -906, YAccel = -83, ZAccel = 773, XGyro = 97, YGyro = 34, and ZGyro = 20 for my MPU6050 sensor module. Since the module does not retain user specified calibration offsets once it is powered off, write down the offsets for your module as we will include them later in our program.

Now let’s create a new sketch aptly named MPU6050 with the code shown below.

// MPU6050 - MPU6050.ino
//
// Description:
// Retrieves motion data from an MPU6050 sensor module using the
// I2Cdevlib (top level library) and MPU6050 (sub-library) combination.
//
// Created by John Woolsey on 07/21/2018.
// Copyright © 2018 Woolsey Workshop.  All rights reserved.


#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>


// MPU6050 library constructor for module
// Uses default I2C address of 0x68; use mpu6050(0x69) to set alternate address
// if needed.
MPU6050 mpu6050;


int16_t ax, ay, az;  // raw accelerometer data register values
int16_t gx, gy, gz;  // raw gyroscope data register values
int16_t tr;          // raw temperature data register value
char buffer[7];      // temporary string buffer; used with dtostrf() function


void setup() {
   Wire.begin();          // initialize I2C bus (MPU6050 module)
   Serial.begin(9600);    // initialize serial bus (Serial Monitor)
   mpu6050.initialize();  // initialize MPU6050 sensor module

   // Verify module connection
   Serial.print("MPU6050 module connection ");
   Serial.println(mpu6050.testConnection() ? "successful." : "failed.");

   // Optionally update accelerometer and gyroscope data register offsets
   // Offsets are not retained when module is disconnected from power.
   // Use offset values obtained from running IMU_Zero calibration sketch.
   // setMPU6050Offsets(-906, -83, 773, 97, 34, 20);

   Serial.println();  // blank line
}


void loop() {
   // Read raw accel/gyro/temp sensor readings from module
   mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
   tr = mpu6050.getTemperature();

   printMPU6050Values();  // print sensor readings in human readable format
   delay(1000);           // wait one second between readings
}


// Prints current MPU6050 values
void printMPU6050Values() {
   Serial.print("aX = ");  Serial.print(dtostrf(ax/16384.0, 4, 1, buffer));  Serial.print(" g, ");
   Serial.print("aY = ");  Serial.print(dtostrf(ay/16384.0, 4, 1, buffer));  Serial.print(" g, ");
   Serial.print("aZ = ");  Serial.print(dtostrf(az/16384.0, 4, 1, buffer));  Serial.print(" g, ");
   Serial.print("gX = ");  Serial.print(dtostrf(gx/131.0, 6, 1, buffer));  Serial.print(" °/s, ");
   Serial.print("gY = ");  Serial.print(dtostrf(gy/131.0, 6, 1, buffer));  Serial.print(" °/s, ");
   Serial.print("gZ = ");  Serial.print(dtostrf(gz/131.0, 6, 1, buffer));  Serial.print(" °/s, ");
   Serial.print("T = ");  Serial.print(dtostrf(tr/340.0+36.53, 5, 1, buffer));  Serial.println(" °C");
}


// Prints current MPU6050 offsets
void printMPU6050Offsets() {
    Serial.print("MPU6050 offsets: ");
    Serial.print("aX = ");  Serial.print(dtostrf(mpu6050.getXAccelOffset(), 5, 0, buffer));
    Serial.print(", aY = ");  Serial.print(dtostrf(mpu6050.getYAccelOffset(), 5, 0, buffer));
    Serial.print(", aZ = ");  Serial.print(dtostrf(mpu6050.getZAccelOffset(), 5, 0, buffer));
    Serial.print(", gX = ");  Serial.print(dtostrf(mpu6050.getXGyroOffset(), 5, 0, buffer));
    Serial.print(", gY = ");  Serial.print(dtostrf(mpu6050.getYGyroOffset(), 5, 0, buffer));
    Serial.print(", gZ = ");  Serial.println(dtostrf(mpu6050.getZGyroOffset(), 5, 0, buffer));
}


// Sets new MPU6050 offsets
void setMPU6050Offsets(int16_t aX, int16_t aY, int16_t aZ, int16_t gX, int16_t gY, int16_t gZ) {
   Serial.print("Old ");  printMPU6050Offsets();
   mpu6050.setXAccelOffset(aX);
   mpu6050.setYAccelOffset(aY);
   mpu6050.setZAccelOffset(aZ);
   mpu6050.setXGyroOffset(gX);
   mpu6050.setYGyroOffset(gY);
   mpu6050.setZGyroOffset(gZ);
   Serial.print("New ");  printMPU6050Offsets();
}

Lines 11-13 load the libraries needed to communicate with the MPU6050 sensor module over the I2C bus.

Line 19 instantiates the MPU6050 class as mpu6050 that we will use in our program to communicate with the module. If you are not using the default I2C address of 0x68, add the alternate address of 0x69 as an argument.

Lines 22-24 declare the variables that will hold our raw sensor data that correspond with the 16-bit signed data registers used in the module.

Line 25 declares a 7-byte character buffer (a string) that will be used in conjunction with the dtostrf() function that is used throughout our program for displaying floating point numbers as nicely formatted strings. A value of 7 was used to allow for our longest string size of 6 and the trailing null character.

Lines 29-30 initialize the I2C and standard serial buses.

Line 31 initializes the sensor module itself. Part of this initialization is the MPU6050 library setting the full-scale range of the accelerometer to ±2g and the gyroscope to ±250°/sec.

Lines 34-35 uses the library’s testConnection() function to let us know if a proper connection to the sensor module was achieved.

Line 40 uses the setMPU6050Offsets() function, defined later, to load new calibration offsets into our sensor module. Replace my specific offsets with the ones you determined and wrote down earlier during calibration with the IMU_Zero example sketch.

Lines 48-49 read the raw sensor values from the module and place them into our data register variables. Note that I also included temperature in addition to the standard accelerometer and gyroscope values.

Line 51 prints the sensor data to the Serial Monitor using the printMPU6050Values() function defined later.

Line 52 creates a delay of 1 second between sensor readings.

Lines 57-65 define our printMPU6050Values() function that takes the raw register data, converts them to human readable format, and prints the values to the Serial Monitor. Since the full scale range of the accelerometer is set to ±2g, the raw 16-bit register values are divided by 16384 (2^16 = 65,536 divided by ±2 = 4) to give us values in g. Likewise, the raw gyroscope values are divided by 131 (2^16 = 65,536 divided by ±250 = 500) to give us values in °/sec. The formula for the temperature was obtained from section 4.18 of the MPU-6050 device register map. The dtostrf() function converts the floating point value in the first argument to a formatted ASCII string and places it in the variable in the last argument (buffer) using a total character length defined by the second argument and the number of decimal points in the third argument.

Lines 69-77 define our printMPU6050Offsets() function that gets and prints the current calibration offset values.

Lines 81-90 define our setMPU6050Offsets() function that loads new calibration offset values into the sensor module while also printing the old and new offsets.

Upload and run the sketch on the Arduino. You should see the sensor values being displayed in the Serial Monitor like shown below.

Arduino Uno MPU6050 Serial Monitor

With the calibration offsets set properly and the module lying on a flat surface, you should see acceleration values of around 0.0 g for the X and Y axes, 1.0 g for the Z axis, and around 0.0 °/sec for all rotational axes. If this is not the case, you may want to go through the calibration procedure again.

Once your numbers look good, play around with the sensor module by moving it around in 3-D space and watching the different values being displayed.

Summary

In this tutorial, we learned how to connect an MPU-6050 based accelerometer and gyroscope sensor module to an Arduino Uno development board using the I2C bus interface, calibrate the module, and retrieve and display acceleration, rotation, and temperature sensor readings.

The final source code for this tutorial is located on GitHub.

Thank you for joining me on this journey and I hope you enjoyed the experience. Please feel free to share your thoughts in the comments section below.

About the author

John Woolsey

John is an electrical engineer who loves science, math, and technology and teaching it to others even more.
 
He knew he wanted to work with electronics from an early age, building his first robot when he was in 8th grade. His first computer was a Timex/Sinclair 2068 followed by the Tandy 1000 TL (aka really old stuff).
 
He put himself through college (The University of Texas at Austin) by working at Motorola where he worked for many years afterward in the Semiconductor Products Sector in Research and Development.
 
John started developing mobile app software in 2010 for himself and for other companies. He has also taught programming to kids for summer school and enjoyed years of judging kids science projects at the Austin Energy Regional Science Festival.
 
Electronics, software, and teaching all culminate in his new venture to learn, make, and teach others via the Woolsey Workshop website.

7 Comments

  • John – this rocks! Made our lives MUCH easier. My daughter is going to use this as part of a demo for her science fair project. She’s now learning how to use the accelerometers and gyros to detect posture imbalances. We are hoping this takes her to ISEF for the second year in a row. Thanks for posting! – Mike and Ariel

  • Hi Sir I interfaced MPU6050 sensor with Arduino using provided code i installed all Libraries for mpu6050 but arduino code shows the Error ( error compiling for board Arduino/Genuino Uno. ) how to fix this problem please tell us sir

    • Sorry to hear you are having difficulty with the code compiling. I am also seeing that error now, even with the source downloaded directly from GitHub. I know that both the Arduino IDE and my operating system have been upgraded since this article was released, and probably the libraries used as well. I plan to investigate this issue early next week and will get back to you with my findings.

    • Are you using the Arduino IDE on macOS by chance? I looked into the issue you described and found (for me at least) that it was related to 32-bit versus 64-bit tools on macOS Catalina. Once I downloaded and reinstalled the Arduino IDE, everything worked again. Note, if you happen to be using the arduino-cli command line tool, I also had to replace the 32-bit version of the ctags tool with the 64-bit version from within the Arduino app in order for it to compile.

  • Hello,
    Thank you for this great job
    I’ve a simple remark: when you talk about wiring I think it’s better to show it by pictures in order that beginer people can confirme
    thank you again,
    Best regadrs

    • I agree. When I wrote this tutorial, I thought the connections were simple enough to not need a picture, but I have recently decided to add pictures in new tutorials for the exact reason you stated. The next time I update this tutorial, I will add a picture. Thank you for your valuable input.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.