The MPU6050 is one of the most popular inertial measurement units (IMU) in the hobbyist and maker community. Combining a 3-axis gyroscope and a 3-axis accelerometer on a single chip, it gives your Arduino project the ability to measure orientation, tilt, rotation, and linear acceleration — all through a simple I2C interface. Whether you’re building a self-balancing robot, a drone flight controller, a gesture-controlled device, or a step counter, the MPU6050 is often the sensor of choice.
In this comprehensive Arduino MPU6050 tutorial, we’ll cover everything from hardware wiring and library installation to reading raw sensor data, interpreting angles, and building real projects. By the end, you’ll have a solid foundation to integrate this powerful sensor into your own Arduino builds.
What Is the MPU6050?
The MPU6050, manufactured by InvenSense (now TDK), is a 6-axis MotionTracking device. It packs both a 3-axis MEMS (Micro-Electro-Mechanical System) gyroscope and a 3-axis MEMS accelerometer into a tiny 4×4×0.9 mm package. It communicates via I2C, making it extremely easy to connect to any Arduino board with just four wires.
Key specifications of the MPU6050:
- Gyroscope range: ±250, ±500, ±1000, or ±2000 °/s (configurable)
- Accelerometer range: ±2g, ±4g, ±8g, or ±16g (configurable)
- Communication: I2C (up to 400 kHz fast mode)
- Supply voltage: 2.375V to 3.46V (most modules include a 3.3V regulator)
- Built-in Digital Motion Processor (DMP): for hardware quaternion computation
- Temperature sensor: onboard for compensation
- I2C address: 0x68 (default) or 0x69 (when AD0 is HIGH)
The GY-521 is the most common breakout board for the MPU6050. It includes voltage regulation, pull-up resistors, and convenient 0.1″ pin headers — making it breadboard-friendly and 5V-Arduino compatible.
Wiring the MPU6050 to Arduino
The MPU6050 GY-521 module has the following pins: VCC, GND, SCL, SDA, XDA, XCL, AD0, and INT. For basic use, you only need four connections:
| MPU6050 Pin | Arduino Uno Pin | Description |
|---|---|---|
| VCC | 5V | Power supply (module has onboard 3.3V regulator) |
| GND | GND | Ground |
| SCL | A5 (SCL) | I2C clock line |
| SDA | A4 (SDA) | I2C data line |
If you’re using an Arduino Mega, the I2C pins are located at the dedicated SDA/SCL header (pins 20 and 21). For the Arduino Nano, SDA is A4 and SCL is A5 — same as Uno.
The AD0 pin sets the I2C address. Leave it unconnected or tied to GND for address 0x68. Pull it HIGH (to 3.3V) for address 0x69 — useful when you need two MPU6050 sensors on the same bus.
The INT pin provides a hardware interrupt output, which we’ll use later for DMP-based reading.
Installing the MPU6050 Library
There are two widely-used libraries for the MPU6050:
Option 1: Adafruit MPU6050 Library (Recommended for Beginners)
Open the Arduino IDE, go to Sketch → Include Library → Manage Libraries, search for “MPU6050” and install the Adafruit MPU6050 library along with its dependencies (Adafruit Unified Sensor and Adafruit BusIO). This library uses the Adafruit Sensor abstraction, making it easy to get values in standard units (m/s², rad/s, °C).
Option 2: Jeff Rowberg’s MPU6050 Library (for DMP)
For advanced use — especially reading quaternions from the built-in DMP — install ElectronicCats/mpu6050 (a fork of Jeff Rowberg’s i2cdevlib). Search for “MPU6050” by ElectronicCats in the Library Manager. This library exposes the full DMP capabilities for hardware-computed orientation.
Test Your Connection with I2C Scanner
Before writing sensor code, run a quick I2C scanner to confirm the MPU6050 is wired correctly:
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Scanning I2C bus...");
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.print("Found device at 0x");
Serial.println(addr, HEX);
}
}
}
void loop() {}
You should see “Found device at 0x68” (or 0x69) in the Serial Monitor. If nothing shows up, double-check your SDA/SCL wiring.
Reading Accelerometer and Gyroscope Data
Here’s a complete sketch using the Adafruit MPU6050 library to read all six axes plus temperature:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
void setup() {
Serial.begin(115200);
while (!Serial) delay(10);
if (!mpu.begin()) {
Serial.println("MPU6050 not found! Check wiring.");
while (1) delay(10);
}
Serial.println("MPU6050 found!");
// Configure ranges
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
}
void loop() {
sensors_event_t accel, gyro, temp;
mpu.getEvent(&accel, &gyro, &temp);
Serial.print("Accel X:"); Serial.print(accel.acceleration.x); Serial.print(" m/s^2 | ");
Serial.print("Y:"); Serial.print(accel.acceleration.y); Serial.print(" m/s^2 | ");
Serial.print("Z:"); Serial.println(accel.acceleration.z);
Serial.print("Gyro X:"); Serial.print(gyro.gyro.x); Serial.print(" rad/s | ");
Serial.print("Y:"); Serial.print(gyro.gyro.y); Serial.print(" rad/s | ");
Serial.print("Z:"); Serial.println(gyro.gyro.z);
Serial.print("Temp: "); Serial.print(temp.temperature); Serial.println(" °C");
Serial.println("---");
delay(500);
}
Understanding the output:
- Accelerometer measures proper acceleration in m/s². At rest, the Z-axis reads ~9.81 m/s² (gravity) while X and Y read ~0.
- Gyroscope measures angular velocity in rad/s. At rest, all three axes should read close to 0.
- Gyroscope drift: Gyros are noisy and drift over time. For angle estimation, you’ll need to integrate gyro data and combine it with accelerometer data using a filter.
Calculating Tilt Angles from Accelerometer Data
The accelerometer can give you static tilt angles using trigonometry. When the board is stationary or moving slowly, these formulas give accurate pitch and roll:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <math.h>
Adafruit_MPU6050 mpu;
void setup() {
Serial.begin(115200);
mpu.begin();
mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
}
void loop() {
sensors_event_t accel, gyro, temp;
mpu.getEvent(&accel, &gyro, &temp);
float ax = accel.acceleration.x;
float ay = accel.acceleration.y;
float az = accel.acceleration.z;
// Pitch: tilt forward/backward
float pitch = atan2(ay, sqrt(ax*ax + az*az)) * 180.0 / PI;
// Roll: tilt left/right
float roll = atan2(-ax, az) * 180.0 / PI;
Serial.print("Pitch: "); Serial.print(pitch, 1); Serial.print("° ");
Serial.print("Roll: "); Serial.println(roll, 1);
delay(200);
}
Limitations of accelerometer-only angles: The accelerometer is sensitive to vibration and dynamic acceleration (e.g., when the robot is moving). For stable angle estimation under dynamic conditions, you must fuse gyroscope and accelerometer data using a complementary filter or Kalman filter.
Complementary Filter for Stable Angle Estimation
The complementary filter blends fast gyroscope data with slow-but-stable accelerometer data:
// In loop(), with dt = time since last loop in seconds
float gyroPitch = gyro.gyro.y * (180.0/PI) * dt;
float gyroRoll = gyro.gyro.x * (180.0/PI) * dt;
pitch = 0.96 * (pitch + gyroPitch) + 0.04 * accelPitch;
roll = 0.96 * (roll + gyroRoll) + 0.04 * accelRoll;
The 0.96/0.04 ratio (96% gyro, 4% accelerometer) is a typical starting point. Adjust based on your application’s vibration level and required response speed.
Using the DMP for Hardware Quaternions
The MPU6050’s built-in Digital Motion Processor (DMP) runs a sensor fusion algorithm on-chip and outputs quaternions at up to 200 Hz. This offloads computation from your Arduino and gives very stable orientation data.
Using Jeff Rowberg’s library (ElectronicCats fork), you can initialize the DMP and read quaternions via the INT interrupt pin:
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include <Wire.h>
MPU6050 mpu;
#define INTERRUPT_PIN 2
bool dmpReady = false;
uint8_t mpuIntStatus;
uint16_t packetSize;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3]; // yaw, pitch, roll
volatile bool mpuInterrupt = false;
void dmpDataReady() { mpuInterrupt = true; }
void setup() {
Wire.begin();
Serial.begin(115200);
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
uint8_t devStatus = mpu.dmpInitialize();
mpu.setXGyroOffset(220); // Calibration offsets — tune for your sensor
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788);
if (devStatus == 0) {
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
mpu.setDMPEnabled(true);
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
packetSize = mpu.dmpGetFIFOPacketSize();
dmpReady = true;
}
}
void loop() {
if (!dmpReady) return;
if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) {
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
Serial.print("Yaw:"); Serial.print(ypr[0] * 180/PI);
Serial.print(" Pitch:"); Serial.print(ypr[1] * 180/PI);
Serial.print(" Roll:"); Serial.println(ypr[2] * 180/PI);
}
}
Connect the MPU6050 INT pin to Arduino pin 2 for this example. The DMP approach gives yaw, pitch, and roll angles that are far more stable than the complementary filter, especially under vibration — making it ideal for quadcopter and self-balancing robot projects.
MPU6050 Calibration
Every MPU6050 sensor has inherent offsets — the raw values won’t read zero even when perfectly still. Calibration corrects these offsets and significantly improves accuracy.
Using the Built-in Calibration (ElectronicCats Library)
The ElectronicCats MPU6050 library includes a CalibrateAccel() and CalibrateGyro() function that automatically finds offsets. Place the sensor on a flat, level surface and call these before enabling the DMP (as shown in the DMP example above). The number in parentheses (e.g., 6) is the number of calibration loops — higher values are more accurate but take longer.
Manual Offset Calibration
For manual calibration, use the IMU_Zero example sketch included with the library. It reads thousands of samples and outputs the optimal offset values to paste into your setXGyroOffset() calls. Keep the sensor flat and stationary during this process.
Calibration Tips
- Always calibrate at room temperature — the MPU6050 is temperature-sensitive
- For drones, recalibrate every time you mount the sensor on a new frame
- Store calibration values in EEPROM for production devices so they persist across power cycles
- Gyroscope drift increases with temperature — the onboard temperature sensor can be used for compensation
Real-World MPU6050 Project Ideas
The MPU6050 is extraordinarily versatile. Here are some proven project ideas to inspire your next build:
1. Self-Balancing Robot
The classic MPU6050 application. Read the pitch angle using the DMP, feed it into a PID controller, and drive two DC motors to keep the robot upright. The sub-millisecond response of DMP quaternions makes this feasible even on a basic Arduino Uno.
2. Quadcopter Flight Controller
Use yaw/pitch/roll from the DMP as feedback for three independent PID loops controlling motor speeds via ESCs. Combine with a BMP280 barometric sensor for altitude hold.
3. Gesture-Controlled Systems
Strap a MPU6050 to a glove. Map tilt angles to servo positions or RC channels to control a robotic arm or RC car with hand gestures. Transmit via nRF24L01 or HC-05 Bluetooth.
4. Pedometer / Step Counter
Use accelerometer magnitude changes to detect steps. The MPU6050 even has a built-in step counter in the DMP firmware accessible via dmpGetPedometer().
5. Anti-Theft Tilt Alarm
Wake the MPU6050 from sleep mode on motion detection (using the interrupt), trigger a buzzer or SMS alert when a vehicle or object is moved.
Troubleshooting Common MPU6050 Issues
I2C device not found: Verify SDA→A4 and SCL→A5 on Uno. Check that VCC is 5V (not 3.3V if using GY-521 breakout). Try a different I2C address (0x69 if AD0 is floating).
Noisy, jittery readings: Add 100nF decoupling capacitors between VCC and GND as close to the module as possible. Reduce the Digital Low Pass Filter (DLPF) bandwidth with mpu.setFilterBandwidth().
DMP initialization fails (devStatus != 0): Usually a wiring issue or brown-out on 3.3V line. Add a 10µF capacitor on the 3.3V output of the GY-521 module. Also ensure INT is connected when using DMP.
Yaw drifting constantly: This is normal — the MPU6050 has no magnetometer, so yaw drifts over time (gyroscope integration error). To fix yaw drift, add a magnetometer (like HMC5883L or QMC5883L) connected to the MPU6050’s auxiliary I2C bus for sensor fusion.
Readings fine but angles wrong: Check calibration offsets. Run the IMU_Zero sketch and update your offset values.
Frequently Asked Questions
Can I use two MPU6050 sensors on the same Arduino?
Yes. Connect one MPU6050 with AD0 tied to GND (address 0x68) and the other with AD0 tied to 3.3V (address 0x69). Both share the same SDA/SCL lines. In code, create two separate Adafruit_MPU6050 or MPU6050 objects and begin each with the respective address.
What is the difference between MPU6050 and MPU9250?
The MPU9250 adds a 3-axis magnetometer (compass), making it a 9-axis IMU vs the 6-axis MPU6050. The magnetometer enables absolute yaw (compass heading) without drift. If your project needs heading reference (like a GPS-free compass), choose the MPU9250. For applications where yaw drift is acceptable (self-balancing robots, tilt measurement), the MPU6050 is sufficient and cheaper.
How accurate is the MPU6050?
The gyroscope has a typical total RMS noise of 0.05 °/s (in ±250°/s range) and the accelerometer noise is 400 µg/√Hz. After calibration, you can expect angle accuracy of ±1–2° for roll and pitch using the DMP. Yaw accuracy degrades over time without a magnetometer reference.
Does the MPU6050 work with 3.3V Arduino boards?
Yes, but with a caveat. The GY-521 breakout board includes a 3.3V regulator and level-shifted I2C lines, making it 5V safe. For 3.3V boards (Arduino Due, Nano 33 IoT, ESP32), connect VCC to 3.3V directly — the module works fine. The raw MPU6050 IC itself runs at 3.3V only (the module’s regulator handles 5V input).
What is the maximum I2C speed for the MPU6050?
The MPU6050 supports standard mode (100 kHz) and fast mode (400 kHz). Use Wire.setClock(400000) before mpu.begin() to enable 400 kHz mode and reduce I2C bus overhead, which matters when reading at high sample rates.
Get Started with Arduino Motion Sensing
The MPU6050 is one of the most rewarding sensors to work with in the Arduino ecosystem. Once you understand its outputs and calibration, a wide world of motion-sensing, orientation, and balance projects opens up. From self-balancing robots to wearable gesture controllers, this tiny chip enables sophisticated applications at very low cost.
Ready to start your MPU6050 project? Browse the complete range of Arduino boards and sensor modules at Zbotic.in — India’s trusted source for quality electronics components with fast delivery.
Add comment