MPU6050 Library
by Electronic Cats / Jeff Rowberg
This library drives the MPU6050, a 6-axis motion sensor that combines a 3-axis gyroscope and a 3-axis accelerometer (plus a small temperature sensor). It is based on Jeff Rowberg's I2Cdevlib and maintained by Electronic Cats. Besides raw readings it gives access to the chip's Digital Motion Processor (DMP), a hardware engine that fuses the sensors on the chip and outputs a stable orientation without you running a filter on your microcontroller. Decide what you actually need first. If you only want acceleration and rotation values, or a tilt angle for a self-balancing robot or a gesture controller, read the raw data and use a simple complementary filter, as in the examples below. If you want stable yaw, pitch and roll with little code, use the DMP. If you want the simplest possible API, the Adafruit MPU6050 library is also a good choice. Keep in mind that the MPU6050 has no magnetometer, so yaw drifts slowly over time with any method; only pitch and roll are stable. Know the numbers when you convert raw readings. At the default ±2 g accelerometer range, 16384 raw units equal 1 g, and at the default ±250 °/s gyro range, 131 raw units equal 1 °/s. Higher ranges give smaller sensitivity (8192, 4096, 2048 LSB/g for ±4, ±8, ±16 g; 65.5, 32.8, 16.4 LSB/(°/s) for ±500, ±1000, ±2000 °/s). The temperature in °C is the raw value divided by 340, plus 36.53. The module's I2C address is 0x68, or 0x69 if the AD0 pin is pulled high. If `testConnection()` returns false, check the wiring and address first. The next suspect is the board itself: many cheap boards sold as "MPU6050" actually carry a different chip such as the MPU6500 or MPU9250. These report a different WHO_AM_I value, so this library does not recognise them. Our IMU comparison article explains how to tell them apart and what to use instead. Calibration matters. Every sensor has offsets, so a board lying flat reads slightly off zero. Call `CalibrateAccel(6)` and `CalibrateGyro(6)` at startup while the board is flat and perfectly still, and the library finds the offsets for you. With the DMP, the other usual problems are an `FIFO overflow` message, which means you are not reading packets fast enough, and a failed `dmpInitialize()`, which returns a non-zero status. The DMP loads a firmware image of several kilobytes when it starts, which is tight on an 8-bit Uno but comfortable on an ESP32. Power the GY-521 module from 3.3 V or 5 V (it has an on-board regulator). On an Uno, SDA is A4 and SCL is A5. On most ESP32 boards the defaults are GPIO21 and GPIO22.
Installation
Arduino IDE — Library Manager
Sketch → Include Library → Manage Libraries → search MPU6050 (by Electronic Cats) in the Library Manager
PlatformIO
lib_deps = electroniccats/MPU6050Supported boards
Examples
Read raw acceleration, rotation and temperature
The simplest way to use the sensor, with values converted to g, degrees per second and degrees Celsius. It checks the connection first.
#include <Wire.h>
#include <MPU6050.h>
MPU6050 mpu;
int16_t ax, ay, az, gx, gy, gz;
void setup() {
Serial.begin(115200);
Wire.begin();
mpu.initialize();
if (!mpu.testConnection()) {
Serial.println(F("MPU6050 not found - check wiring, address and chip type"));
while (true);
}
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2); // +/-2 g -> 16384 LSB/g
mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250); // +/-250 deg/s -> 131 LSB/(deg/s)
}
void loop() {
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
Serial.print(F("Accel g: "));
Serial.print(ax / 16384.0); Serial.print(" ");
Serial.print(ay / 16384.0); Serial.print(" ");
Serial.print(az / 16384.0);
Serial.print(F(" Gyro deg/s: "));
Serial.print(gx / 131.0); Serial.print(" ");
Serial.print(gy / 131.0); Serial.print(" ");
Serial.println(gz / 131.0);
delay(100);
}Tilt angle (roll and pitch) with a complementary filter
Combines the smooth but drifting gyro with the noisy but stable accelerometer. Use this for balancing robots, levels and gesture control. Start the program with the board held still.
#include <Wire.h>
#include <MPU6050.h>
#include <math.h>
MPU6050 mpu;
int16_t ax, ay, az, gx, gy, gz;
float roll = 0, pitch = 0;
unsigned long lastTime;
const float ALPHA = 0.98; // trust the gyro 98%, the accelerometer 2%
void setup() {
Serial.begin(115200);
Wire.begin();
mpu.initialize();
lastTime = micros();
}
void loop() {
unsigned long now = micros();
float dt = (now - lastTime) / 1000000.0;
lastTime = now;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
float accRoll = atan2((float)ay, (float)az) * 180.0 / PI;
float accPitch = atan2(-(float)ax, sqrt((float)ay * ay + (float)az * az)) * 180.0 / PI;
roll = ALPHA * (roll + (gx / 131.0) * dt) + (1.0 - ALPHA) * accRoll;
pitch = ALPHA * (pitch + (gy / 131.0) * dt) + (1.0 - ALPHA) * accPitch;
Serial.print(F("Roll: ")); Serial.print(roll);
Serial.print(F(" Pitch: ")); Serial.println(pitch);
}Read stable orientation via the onboard DMP
Yaw, pitch and roll computed on the chip. Needs a few kilobytes of RAM, so it is best on an ESP32 or a Mega. Yaw drifts slowly because there is no magnetometer.
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;
bool dmpReady = false;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
void setup() {
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000);
mpu.initialize();
if (!mpu.testConnection()) {
Serial.println(F("MPU6050 not found"));
while (true);
}
uint8_t status = mpu.dmpInitialize();
if (status == 0) {
mpu.CalibrateAccel(6); // keep the board flat and still
mpu.CalibrateGyro(6);
mpu.setDMPEnabled(true);
dmpReady = true;
} else {
Serial.print(F("DMP init failed, code "));
Serial.println(status);
}
}
void loop() {
if (!dmpReady) return;
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print(F("Yaw: ")); Serial.print(ypr[0] * 180 / M_PI);
Serial.print(F(" Pitch: ")); Serial.print(ypr[1] * 180 / M_PI);
Serial.print(F(" Roll: ")); Serial.println(ypr[2] * 180 / M_PI);
}
}Calibrate the offsets at startup
Add this after mpu.initialize(). Lay the board flat with the chip facing up and do not touch it for a few seconds. Raw readings will then sit near 0, 0, 1 g.
Serial.println(F("Calibrating - keep the sensor flat and still..."));
mpu.CalibrateAccel(6); // 6 loops gives a good average
mpu.CalibrateGyro(6);
mpu.PrintActiveOffsets(); // prints the offsets it found