When it comes to sensing motion, both the accelerometer and the gyroscope are impressive on their own. An accelerometer measures linear acceleration, which means it can detect when you’re walking forward, jumping, or even falling. A gyroscope, on the other hand, measures angular velocity, which means it detects when you’re turning or twisting.
Each sensor is useful on its own, but when you combine them together, you get incredibly precise data about an object’s position and orientation in 3D space. This is exactly where the MPU6050 comes in.
The MPU6050 is a small but powerful module that packs both a gyroscope and an accelerometer into one chip. This combination allows it to measure rotation along all three axes (X, Y, and Z), static acceleration caused by gravity, and dynamic acceleration caused by motion, impacts, or vibrations.
In this tutorial, you’ll learn everything you need to know about the MPU6050. We’ll cover how the sensor works, walk through the wiring to connect it to an Arduino, write code to read the sensor data, and even display that data visually using the Serial Plotter.
Before we jump straight into the hardware, though, let’s quickly cover the basics of how accelerometers and gyroscopes work. If you’re already familiar with these concepts, feel free to skip ahead to the Hardware Overview section.
How Does an Accelerometer Work?
To understand how accelerometers work, imagine a small, transparent cube with a ball suspended in its center by springs connected to each inner wall — front, back, left, right, top, and bottom.

When the cube isn’t moving, the ball stays perfectly centered. But as soon as the cube moves or accelerates in any direction, the ball lags slightly behind due to inertia (the tendency of objects to resist changes in motion). This lag stretches some springs more than others, and by measuring how much tension is in each spring, you can figure out the direction and strength of the force being applied.
Accelerometers often express the strength of this force in terms of g-force — like 1g, 2g, or 3g. So before we go further, let’s talk about what exactly “1g” means.
When we say “1g,” we’re referring to the acceleration due to gravity on Earth’s surface — about 9.8 m/s². Even when your phone is just sitting still on a table, it still senses a force of 1g pulling straight down due to gravity. It’s important to know that accelerometers don’t distinguish between gravitational acceleration and acceleration from actual movement — they simply detect the total acceleration in all directions.
Going back to our example, imagine the cube floating in outer space, in zero gravity. The ball would just float motionless in the center. Since there’s no gravity or motion, the springs wouldn’t stretch, and the accelerometer would register 0g on all three axes — X, Y, and Z.

Now, if you suddenly moved the cube quickly to the left, the ball would lag behind and push against the right-side spring. The accelerometer would then sense a force to the right, which means the box is accelerating to the left. In this case, you’d see 1g of acceleration on the X-axis, even though there’s still no gravity — it’s purely from motion.

Let’s see what happens when we place that cube on Earth. If you place the cube on a table and leave it there, gravity pulls the ball downward. There’s no motion, but the force of gravity alone causes the sensor to read 1g on the Z-axis. The X and Y axes would still read 0g, because there’s no force acting in those directions.

Things get interesting when you tilt the box. Imagine tilting it so it’s leaning at a 45-degree between the Z-axis and the X-axis. Gravity still pulls straight down toward Earth, but because the cube is tilted, that pull is now divided between the Z and X directions. The accelerometer senses this and shows about 0.71g on both axes. The value of 0.71 isn’t random; it’s the cosine of 45 degrees times 1g. The ball is effectively pulling equally on two springs now, so both the X and Z sensors register force.

While this box-and-ball model isn’t exactly how real accelerometers are built, it helps us understand why accelerometers measure forces in g’s, why they read 1g in the Z direction when sitting still, and what readings you might see when the device is held at different angles.
In the real world, accelerometers are built using Micro-Electro-Mechanical Systems (MEMS) technology. So, let’s explore how a MEMS accelerometer works.
How Does a MEMS Accelerometer Work?
A MEMS (Micro-Electro-Mechanical System) accelerometer is essentially a microscopic mechanical system fabricated directly onto a silicon chip.
At its core is a small mass, often called the “proof mass.” This mass is suspended between fixed plates by flexible beams or springs. Both the proof mass and the fixed plates are designed to work together as parts of a capacitor.


When the accelerometer moves or experiences acceleration in a certain direction, the proof mass tries to stay in place because of inertia, while the rest of the device moves around it. This movement changes the distance between the proof mass and the fixed plates. Since capacitance depends directly on the distance between plates, the value of the capacitance changes accordingly.
On-chip circuitry detects this change in capacitance and converts it into an electrical signal. The circuitry then calculates exactly how much acceleration has occurred based on the change.
How Does a Gyroscope Work?
While accelerometers measure linear acceleration, gyroscopes measure angular rotation. They do this by detecting a special force known as the Coriolis effect.
Coriolis Effect
The Coriolis Effect describes what happens when something is moving and you try to rotate it at the same time. Imagine you’re on a merry-go-round throwing a ball to your friend. Even though you threw it straight, the ball curves because the merry-go-round is spinning underneath it. That curving force is the “Coriolis Effect”.
In technical terms, when a mass (m) moves in one direction with a certain speed (v), and you rotate the whole system at an angular rate (Ω, shown by the red arrow), the Coriolis Effect creates a force (yellow arrow) that pushes the mass sideways, perpendicular to its original path. The stronger the rotation, the stronger this sideways push.

In a gyroscope, tiny masses vibrate back and forth in opposite directions at a constant speed. When you rotate this system, the Coriolis Effect pushes each mass in opposite directions. This alters the electrical properties (like capacitance) between them. By measuring these changes, the gyroscope figures out the angular rotation speed.

How Does a MEMS Gyroscope Work?
A MEMS gyroscope is a tiny sensor that uses this same principle. Inside, there’s a central part called the “proof mass” made up of four parts (M1, M2, M3, and M4). These parts are kept in a constantly oscillating movement so that they react to the Coriolis effect when you rotate the device. They move inward and outward simultaneously at a certain frequency in the horizontal plane.

When you rotate the device, the Coriolis force acts on these moving masses and changes their vibration from horizontal to vertical.
There are three modes depending on the axis along which the angular rotation is applied.
Roll Mode:
When an angular rotation is applied along the X-axis, M1 and M3 will move up and down out of the plane due to the Coriolis effect.

Pitch Mode:
When an angular rotation is applied along the Y-axis, M2 and M4 will move up and down out of the plane.

Yaw Mode:
When an angular rotation is applied along the Z-axis, M2 and M4 will move horizontally in opposite directions.

In each mode, whenever the Coriolis Effect occurs, the continuous motion of the proof masses creates a measurable change in capacitance (∆C). The sensing components inside the gyroscope detect this capacitance change and convert it into an electrical voltage signal. This signal tells your device exactly how much and in what direction it’s rotating.
For reference, here’s what the actual MEMS structure of a 3-axis digital gyroscope looks like under a microscope. Thanks to Adam McCombs for sharing this image of a decapped L3GD20HTR MEMS gyroscope.

MPU6050 Module Hardware Overview
At the heart of the module is a low-power, low-cost 6-axis MotionTracking chip called the MPU6050. It combines a 3-axis gyroscope (for measuring rotation), a 3-axis accelerometer (for measuring acceleration), and a Digital Motion Processor (DMP) all in one tiny 4mm by 4mm package.
The module can detect rotation around all three axes and can measure both static acceleration from gravity and dynamic acceleration from motion, shock, or vibration.

The module comes with a built-in LD3985 voltage regulator, so you can safely connect it to 5V microcontrollers like an Arduino without worrying about damaging the sensor.
One of the best features of the MPU6050 is its low power consumption. During active measurements, it uses less than 3.6mA of current, and when it’s not doing anything (idle mode), it uses only 5μA. This makes it perfect for battery-powered devices like wearables or robots.
Plus, it has a power LED that lights up to show when the module is turned on.
Measuring Acceleration
The MPU6050 can measure acceleration over four programmable full scale ranges of ±2g, ±4g, ±8g, and ±16g. Lower ranges like ±2g give you more precise measurements for small movements, while higher ranges like ±16g let you measure more intense forces.

The MPU6050 has three dedicated 16-bit analog-to-digital converters to measure acceleration along the X, Y, and Z axes simultaneously.
Measuring Rotation
The MPU6050 can measure angular rotation over four programmable full-scale ranges: ±250°/s, ±500°/s, ±1000°/s, and ±2000°/s.

The chip also has three additional 16-bit converters to sample rotation along all three axes at the same time. You can adjust how often the sensor takes measurements—anywhere from 3.9 samples per second to an impressive 8000 samples per second.
Measuring Temperature
The MPU6050 includes a temperature sensor that can measure temperatures from –40°C to 85°C with an accuracy of about ±1°C.
Keep in mind that this temperature sensor measures the temperature of the silicon chip itself, not the ambient temperature. Because the chip’s temperature affects the accuracy of its readings, the MPU6050 uses this information to automatically adjust its calculations and maintain accuracy.
The I2C Interface
The MPU6050 communicates with the Arduino via the I2C interface. It can use one of two different I2C addresses: 0x68 and 0x69. This is helpful if you want to connect two MPU6050 modules on the same I2C bus, or if another sensor is already using one of those addresses.

The ADO pin on the module determines which I2C address is used. Pulling this pin LOW sets the address to 0x68, and pulling it HIGH sets it to 0x69. However, because the pin is already connected to ground through an onboard 4.7 kΩ pulldown resistor, leaving it unconnected defaults the address to 0x68. If you want to switch to 0x69, simply pull the ADO pin HIGH.
Auxiliary I2C Interface
The MPU6050 has an auxiliary I2C bus for connecting additional sensors directly to the MPU6050 module. You access this auxiliary bus through two pins labeled XDA and XCL.

This is often used to add a magnetometer, which measures magnetic fields along three axes. The MPU6050 by itself provides 6 Degrees of Freedom (DOF)—three from the accelerometer and three from the gyroscope. When you add a magnetometer, this increases to 9 DOF, giving your project much more detailed information about its position and orientation in space.
Technical Specifications
Here are the specifications:
| Operating Voltage | 5V (typical) |
| Accelerometer Range | ±2g, ±4g, ±8g, ±16g |
| Gyroscope Range | ±250°/s, ±500°/s, ±1000°/s, ±2000°/s |
| Temperature Range | -40 to +85°C |
| Absolute Maximum Acceleration | Up to 10,000g |
For more information, please refer to the datasheet below.
MPU6050 Module Pinout
The MPU6050 module has eight pins. Here’s what each one does:

VCC is the power supply pin. Connect it to the 5V pin on the Arduino.
GND is the ground pin. Connect it to the Arduino’s GND.
SCL is the serial clock pin used for the I2C interface.
SDA is the serial data pin for the I2C interface.
XDA is the serial data pin for an auxiliary I2C interface. You can use it to connect additional sensors, like a magnetometer, directly to the MPU6050.
XCL is the serial clock pin used for an auxiliary I2C interface. It works with XDA to communicate with those extra external sensors.
AD0 pin lets you choose between the two possible I2C addresses the MPU6050 can use: 0x68 or 0x69. This is helpful if you want to connect two MPU6050 modules on the same I2C bus, or if another sensor is already using one of those addresses. When AD0 is pulled LOW, the address becomes 0x68, and when it is pulled HIGH, the address becomes 0x69. Because this pin is connected to ground through a 4.7 kΩ pulldown resistor, leaving it unconnected automatically sets the address to 0x68.
INT is the interrupt output pin. It allows the MPU6050 to trigger an interrupt when it detects specific events such as gestures, tapping, shaking, panning, zooming, or scrolling.
Wiring an MPU6050 Module to an Arduino
Now let’s connect the MPU6050 module to your Arduino.
Start with the power connections. Connect the VCC pin on the MPU6050 to the 5V pin on your Arduino. Then connect the GND pin to one of the ground pins on your Arduino.
Next, you need to connect the I2C communication pins. Remember, different Arduino boards have their I2C pins in different locations, so make sure you connect them correctly for your specific board. If you’re using an Arduino with the R3 layout, you’ll find the SDA and SCL pins on the header near the AREF pin. These same pins are also labeled as A4 (SDA) and A5 (SCL).
Here’s a quick reference table for the pin connections:
| MPU6050 Module | Arduino | |
| VCC | 5V | |
| GND | GND | |
| SCL | SCL or A5 | |
| SDA | SDA or A4 |
This diagram shows you exactly how to connect everything:

Library Installation
Getting the MPU6050 ready to work with your Arduino is straightforward, especially with helpful libraries that do the heavy lifting. A popular one is the Adafruit MPU6050 Library.
To install the library,
- First open your Arduino IDE program. Then click on the Library Manager icon on the left sidebar.
- Type “mpu6050” in the search box to filter your results.
- Look for the Adafruit MPU6050 Library by Adafruit.
- Click the Install button to add it to your Arduino IDE.

Since the Adafruit MPU6050 Library relies on other libraries to function, you will be prompted to install its dependencies, which include the Adafruit Unified Sensor Driver and the Adafruit Bus IO Library.
When this message appears, simply click INSTALL ALL to ensure everything is set up correctly.

Arduino Example Code
This example program shows how to use an MPU6050 sensor with an Arduino to read linear acceleration, angular rotation, and temperature.
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
/* Print out the values */
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");
Serial.println("");
delay(500);
}Once the code is uploaded to your Arduino, open the serial monitor and set the baud rate to 115200 bps. You’ll see information about linear acceleration, angular rotation, and temperature scrolling on your screen. Try moving the sensor around and watch how the numbers change in response.

Code Explanation:
At the start of the sketch, we include all the necessary libraries.
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>Next, we create an object called “mpu” that represents our sensor. This object gives us access to all the functions we need to control and read from the MPU6050.
Adafruit_MPU6050 mpu;In the setup section, we first begin serial communication so we can see the output on the Serial Monitor.
Then we call the begin() function to start up the MPU6050 sensor. If the sensor isn’t connected properly or something goes wrong, we print a message saying the chip wasn’t found, and the program stops right there in an endless loop. But if everything works, we print “MPU6050 Found!” so we know it’s ready.
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}After that, we configure how sensitive we want our measurements to be. We use three different functions for this:
setAccelerometerRange(mpu6050_accel_range_t)
The setAccelerometerRange() function determines how much acceleration the sensor can measure. This function can take following values:
MPU6050_RANGE_2_G– for ±2g range (default)MPU6050_RANGE_4_G– for ±4g rangeMPU6050_RANGE_8_G– for ±8g rangeMPU6050_RANGE_16_G– for ±16g range
setGyroRange(mpu6050_gyro_range_t)
The setGyroRange() function sets the maximum rotation speed the sensor can detect. This function can take following values:
MPU6050_RANGE_250_DEG– for 250 degrees-per-second range (default)MPU6050_RANGE_500_DEG– for 500 degrees-per-second rangeMPU6050_RANGE_1000_DEG– for 1000 degrees-per-second rangeMPU6050_RANGE_2000_DEG– for 2000 degrees-per-second range
setFilterBandwidth(mpu6050_bandwidth_t)
The setFilterBandwidth() function sets the bandwidth of the Digital Low-Pass Filter, which helps smooth out the signal by getting rid of high-frequency noise. This function accepts the following values:
MPU6050_BAND_260_HZ– for 260 Hz bandwidth (According to the documentation, this disables the filter)MPU6050_BAND_184_HZ– for 184 Hz bandwidthMPU6050_BAND_94_HZ– for 94 Hz bandwidthMPU6050_BAND_44_HZ– for 44 Hz bandwidthMPU6050_BAND_21_HZ– for 21 Hz bandwidthMPU6050_BAND_10_HZ– for 10 Hz bandwidthMPU6050_BAND_5_HZ– for 5 Hz bandwidth
In this example, we set the accelerometer range to ±8G, the gyro range to ±500°/s, and the filter bandwidth to 21 Hz.
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);The measurement range is the maximum acceleration or angular velocity that your MPU6050 can read. Think about what you’re trying to measure and choose limits based on that. For example, do you need to measure the rotational speed of something slow like a record player, or something fast like a spinning wheel?
In the loop section, we collect data from the sensor and print it to the Serial Monitor. To do this, we create three variables—a, g, and temp—to store the data from the accelerometer, gyroscope, and temperature sensor. These variables are created using a special structure type called sensors_event_t, which is designed to hold many kinds of sensor data in one place. If you’re interested, you can find more details about this structure on GitHub.
sensors_event_t a, g, temp;Then we call the getEvent() function. This function reads a new set of values from the sensor, converts them into proper units, and stores everything in our variables.
mpu.getEvent(&a, &g, &temp);Finally, we print all of this data to the Serial Monitor.
Serial.print("Acceleration X: ");
Serial.print(a.acceleration.x);
Serial.print(", Y: ");
Serial.print(a.acceleration.y);
Serial.print(", Z: ");
Serial.print(a.acceleration.z);
Serial.println(" m/s^2");
Serial.print("Rotation X: ");
Serial.print(g.gyro.x);
Serial.print(", Y: ");
Serial.print(g.gyro.y);
Serial.print(", Z: ");
Serial.print(g.gyro.z);
Serial.println(" rad/s");
Serial.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");Arduino Example Code 2 – Plotting MPU6050 data
Just looking at numbers printed from the MPU6050 might not be very helpful when trying to understand how the sensor responds to movement. That’s why it’s a great idea to use the Serial Plotter—a built-in tool in the Arduino IDE that helps you see the data visually in real-time as waveforms.
To try this out, use the updated code shown below. First, compile and upload the sketch to your Arduino board. Once that’s done, go to the top menu and select Tools > Serial Plotter. Make sure the baud rate in the serial plotter is set to 115200.
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
void setup(void) {
Serial.begin(115200);
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
// set accelerometer range to +-8G
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
// set gyro range to +- 500 deg/s
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
// set filter bandwidth to 21 Hz
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
delay(100);
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
/* Print out the values */
Serial.print(a.acceleration.x);
Serial.print(",");
Serial.print(a.acceleration.y);
Serial.print(",");
Serial.print(a.acceleration.z);
Serial.print(", ");
Serial.print(g.gyro.x);
Serial.print(",");
Serial.print(g.gyro.y);
Serial.print(",");
Serial.print(g.gyro.z);
Serial.println("");
delay(10);
}You should see a waveform similar to the one shown below when you move the module up and down along the Z-axis.

Code Explanation:
Most of this sketch works exactly like the previous example we looked at. We still include the same libraries, create our sensor object, initialize everything in the setup, and read sensor data in the loop. However, there are a few key differences that make this version work with the Serial Plotter.
- We don’t print the temperature readings this time. We’re focusing just on the acceleration and rotation data.
- Instead of printing labels like “Acceleration X:” before each number, we just print the raw values separated by commas. This creates what’s called a comma-separated list. The Serial Plotter needs the data formatted this way so it knows how to draw each value as a separate line on the graph.
- We take readings much more frequently. Instead of waiting 500 milliseconds between readings like before, we only wait 10 milliseconds. This faster sampling rate makes the graph look much smoother and lets you see changes in real time as you move the sensor around.
So in the loop, we grab our sensor readings, print all six values (three for acceleration and three for rotation) with commas between them, and then wait just 10 milliseconds before doing it all again.

