As kids, the gyroscopes at the science fair never failed to amaze us because they moved in strange ways and even seemed to defy gravity. Their unique properties make them crucial in everything from small RC helicopters to the advanced navigation system on the space shuttle.

In recent years, ingenious engineers have successfully developed micromachined gyroscopes. These MEMS (microelectromechanical system) gyroscopes have paved the way for an entirely new set of innovative applications, including gesture recognition, enhanced gaming, augmented reality, panoramic photo capture, vehicle navigation, and fitness monitoring, to name a few.

Without a doubt, the gyroscope and accelerometer are each exceptional in their own way. However, when we put them together, we can obtain incredibly precise data about an object’s orientation. This is where the MPU6050 enters the picture. The MPU6050 includes a gyroscope and an accelerometer, allowing us to measure rotation along all three axes, static acceleration due to gravity, and dynamic acceleration due to motion.

Before we use the MPU6050 in our Arduino project, it’s a good idea to understand how accelerometers and gyroscopes work.

Did you know?

The Russian Mir space station relied on 11 gyroscopes to keep its orientation to the sun. The Hubble Space Telescope is equipped with six navigational gyros that ensure accurate pointing during observations.

## How Does an Accelerometer Work?

To understand how accelerometers work, imagine a ball inside a 3D cube.

Assuming that the cube is in outer space, where everything is weightless, the ball will simply float in the center of the cube.

Now, assume that each wall represents a specific axis.

If we suddenly move the box to the left with acceleration 1g (a single G-force 1g is equivalent to gravitational acceleration 9.8 m/s2), the ball will undoubtedly hit the wall X. If we measure the force the ball exerts on wall X, we can obtain an output value of 1g along the X axis.

Let’s see what happens when we place that cube on Earth. The ball will simply fall on the wall Z, exerting a force of 1g as shown in the diagram below:

In this case, the box isn’t moving, but we still get a 1g reading on the Z axis. This is because gravity (which is actually a form of acceleration) is pulling the ball downward with a force of 1g.

While this model does not exactly represent how a real-world accelerometer sensor is built, it is often useful in understanding why an accelerometer’s output signal is typically specified in ±g, or why an accelerometer reads 1g in the z-axis at rest, or what accelerometer readings you can expect at different orientations.

In the real world, accelerometers are based on Micro-Electro-Mechanical Systems (MEMS fabrication technology). So, let’s find out how a MEMS accelerometer works.

### How Does a MEMS Accelerometer Work?

A MEMS (Micro-Electro-Mechanical System) accelerometer is a micro-machined structure built on top of a silicon wafer.

This structure is suspended by polysilicon springs. It allows the structure to deflect when accelerated along the X, Y, and/or Z axes.

As a result of deflection, the capacitance between fixed plates and plates attached to the suspended structure changes. This change in capacitance is proportional to the acceleration along that axis.

The sensor processes this change in capacitance and converts it into an analog output voltage.

## How Does a Gyroscope Work?

While accelerometers measure linear acceleration, gyroscopes measure angular rotation. To accomplish this, they measure the force generated by the Coriolis Effect.

### Coriolis Effect

The Coriolis Effect states that when a mass (m) moves in a specific direction with a velocity (v) and an external angular rate (Ω) is applied (Red arrow), the Coriolis Effect generates a force (Yellow arrow) that causes the mass to move perpendicularly. The value of this displacement is directly related to the angular rate applied.

Consider two masses oscillating in opposite directions at a constant frequency. When an angular rate is applied, the Coriolis effect produced by each mass is in opposite directions, resulting in a proportional change in capacitance between the masses. By measuring this change in capacitance, the angular rate can be calculated.

### How Does a MEMS Gyroscope Work?

The MEMS sensor consists of a proof mass (consisting of four parts M1, M2, M3, and M4) that is maintained in a continuous oscillating movement so that it can respond to the coriolis effect. They simultaneously move inward and outward in the horizontal plane.

When we begin to rotate the structure, the Coriolis force acting on the moving proof mass causes the vibration to change from horizontal to vertical.

There are three modes depending on the axis along which the angular rotation is applied.

#### Roll Mode:

When an angular rate is applied along the X-axis, M1 and M3 will move up and down out of the plane due to the coriolis effect. This causes a change in the roll angle, hence the name Roll Mode.

#### Pitch Mode:

When an angular rate is applied along the Y-axis, M2 and M4 will move up and down out of the plane. This causes a change in the pitch angle, hence the name Pitch Mode.

#### Yaw Mode:

When an angular rate is applied along the Z-axis, M2 and M4 will move horizontally in opposite directions. This causes a change in the yaw angle, hence the name Yaw Mode.

Whenever the coriolis effect is detected, the constant motion of the driving mass will cause a change in capacitance (∆C) that is detected by the sensing structure and converted into a voltage signal.

For your information, this is what the MEMS structure die of a 3-axis digital gyroscope looks like. Thanks to Adam McCombs for sharing this image of a decaped L3GD20HTR MEMS gyroscope.

## MPU6050 Module Hardware Overview

At the core of the module is a low-power, low-cost 6-axis MotionTracking chip – MPU6050 – that integrates a 3-axis gyroscope, 3-axis accelerometer, and a Digital Motion Processor (DMP) into a tiny 4mm x 4mm package.

It can measure angular momentum or rotation along all three axes, static acceleration caused by gravity, and dynamic acceleration caused by motion, shock, or vibration.

The module includes an on-board LD3985 3.3V regulator, so you can safely use it with a 5V logic microcontroller like Arduino.

The MPU6050 consumes less than 3.6mA during measurements and only 5μA when idle. Because of its low power consumption, it can be used in battery-powered devices.

Additionally, the module has a Power LED that illuminates when the module is powered on.

### Measuring Acceleration

The MPU6050 has an on-chip accelerometer that can measure acceleration over four programmable full scale ranges of ±2g, ±4g, ±8g, and ±16g.

The MPU6050 is equipped with three 16-bit analog-to-digital converters that simultaneously sample the three axes of movement (along the X, Y, and Z axes).

### Measuring Rotation

The MPU6050 has an on-chip gyroscope that can measure angular rotation over four programmable full scale ranges of ±250°/s, ±500°/s, ±1000°/s, and ±2000°/s.

The MPU6050 is equipped with three more 16-bit analog-to-digital converters that simultaneously sample the three axes of rotation (along the X, Y, and Z axes). The sampling rate can be adjusted from 3.9 to 8000 samples per second.

### Measuring Temperature

The MPU6050 includes an embedded temperature sensor that can measure temperatures from -40 to 85°C with a ±1°C accuracy.

Note that this temperature measurement is of the silicon die itself, not the ambient temperature. These measurements are typically used to compensate for accelerometer and gyroscope calibration or to detect temperature changes rather than measuring absolute temperatures.

### The I2C Interface

The module communicates with the Arduino via the I2C interface. It supports two different I2C addresses: 0x68HEX and 0x69HEX. This allows two MPU6050s to be used on the same bus or to avoid address conflicts with other devices on the bus.

The ADO pin determines the I2C address of the module. This pin is pulled down with a 4.7K resistor. Therefore, when you leave the ADO pin unconnected, the default I2C address is 0x68HEX; when you connect it to 3.3V, the line is pulled HIGH, and the I2C address becomes 0x69HEX.

You can improve the accuracy of the MPU6050 module even further by connecting external sensors to it. These external sensors can be connected to the MPU6050 via a second, completely independent I2C bus (XDA and XCL).

This external connection is usually used to attach a magnetometer, which can measure magnetic fields along three axes. The MPU6050 has six Degrees of Freedom (DOF), three for the accelerometer and three for the gyroscope combined. The addition of a magnetometer increases the sensor’s degree of freedom from 6 to 9 DOF.

### 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

## MPU6050 Module Pinout

The MPU6050 module’s pinout is as follows:

VCC supplies power to the module.

GND is the ground pin.

SCL is a serial clock pin for the I2C interface.

SDA is a serial data pin for the I2C interface.

XDA is the external I2C data line. The external I2C bus is for connecting external sensors, such as a magnetometer.

XCL is the external I2C clock line.

AD0 allows you to change the I2C address of the MPU6050 module. It can be used to avoid conflicts between the module and other I2C devices or to connect two MPU6050s to the same I2C bus. When you leave the ADO pin unconnected, the default I2C address is 0x68HEX; when you connect it to 3.3V, the I2C address changes to 0x69HEX.

INT is the Interrupt Output pin. The MPU6050 can be programmed to generate an interrupt upon detection of gestures, panning, zooming, scrolling, tap detection, and shake detection.

## Wiring an MPU6050 Module to an Arduino

Let’s hook the MPU6050 module to the Arduino.

Connections are straightforward. Begin by connecting the VCC pin to the Arduino’s 5V output and the GND pin to ground.

Now we are left with the pins that are used for I2C communication. Note that each Arduino board has different I2C pins that must be connected correctly.  On Arduino boards with the R3 layout, the SDA (data line) and SCL (clock line) are on the pin headers close to the AREF pin. They are also referred to as A5 (SCL) and A4 (SDA).

Check out the table below for quick reference.

 SCL SDA Arduino Uno A5 A4 Arduino Nano A5 A4 Arduino Mega 21 20 Leonardo/Micro 3 2

The diagram below shows how to connect everything.

## Library Installation

Setting up the MPU6050 module to begin capturing the device’s raw data output is fairly simple. Manipulating the data into something meaningful, on the other hand, is more difficult, but there are some libraries at our disposal.

To install the library, navigate to Sketch > Include Library > Manage Libraries… Wait for the Library Manager to download the library index and update the list of installed libraries.

Filter your search by entering ‘mpu6050’. Look for the Adafruit MPU6050 Library by Adafruit. Click on that entry and then choose Install.

The Adafruit MPU6050 library makes use of the Adafruit Unified Sensor Driver and Adafruit Bus IO Library internally. So, search the library manager for Adafruit Unified Sensor and BusIO and install them as well.

## Arduino Example Code

Here is a simple program that reads the linear acceleration, angular rotation, and temperature from the MPU6050 module and prints them on the serial monitor.

``````#include <Adafruit_MPU6050.h>
#include <Wire.h>

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.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");

Serial.println("");
delay(500);
}``````

Make sure you set the baud rate to “115200” in the serial port monitor. Because the MPU6050 returns an excessive amount of data, this higher speed is required to display it.

There will be a lot of information displayed, such as linear acceleration, angular rotation, and temperature. Move your sensor around and observe how the data changes.

### Code Explanation:

At the beginning of the sketch, all the necessary libraries are included. As previously stated, the Adafruit_MPU6050 library implements the hardware functions of the MPU6050, while the Adafruit_Sensor library implements the unified sensor abstraction layer. Wire.h, which allows us to communicate with I2C devices, is also included.

``````#include <Adafruit_MPU6050.h>
#include <Wire.h>``````

Next, an instance of the Adafruit_MPU6050 class is created in order to access its associated methods.

``Adafruit_MPU6050 mpu;``

In the setup section of the code, we first initialize the serial communication with the PC and call the `begin()` function. The `begin()` function initializes the I2C interface and verifies that the chip ID is correct. It then soft-resets the chip and waits for the sensor to calibrate after wake-up.

``````Serial.begin(115200);

// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}``````

The following three functions are then used to configure the measurement range of the MPU6050.

#### setAccelerometerRange(mpu6050_accel_range_t)

The `setAccelerometerRange()` function sets the accelerometer measurement range. This function accepts the following values:

• MPU6050_RANGE_2_G – for ±2g range (default)
• MPU6050_RANGE_4_G – for ±4g range
• MPU6050_RANGE_8_G – for ±8g range
• MPU6050_RANGE_16_G – for ±16g range

Keep in mind that the smaller the range, the more sensitive the accelerometer readings will be.

#### setGyroRange(mpu6050_gyro_range_t)

The `setGyroRange()` function sets the gyroscope measurement range. This function accepts the following values:

• MPU6050_RANGE_250_DEG – for 250 degrees-per-second range (default)
• MPU6050_RANGE_500_DEG – for 500 degrees-per-second range
• MPU6050_RANGE_1000_DEG – for 1000 degrees-per-second range
• MPU6050_RANGE_2000_DEG – for 2000 degrees-per-second range

Remember that a smaller degrees-per-second range leads to a more sensitive output.

#### setFilterBandwidth(mpu6050_bandwidth_t)

The `setFilterBandwidth()` function sets the bandwidth of the Digital Low-Pass Filter. 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 bandwidth
• MPU6050_BAND_94_HZ – for 94 Hz bandwidth
• MPU6050_BAND_44_HZ – for 44 Hz bandwidth
• MPU6050_BAND_21_HZ – for 21 Hz bandwidth
• MPU6050_BAND_10_HZ – for 10 Hz bandwidth
• MPU6050_BAND_5_HZ – for 5 Hz bandwidth

The bandwidth selection allows you to alter the low-pass filter’s cutoff frequency, allowing you to smooth out the signal by removing high-frequency noise.

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 are measuring and set limits based on that. Do you need to measure the rotational speed of a record player (which is extremely slow) or a spinning wheel (which can be extremely fast)?

In the loop section of the code, we create three objects of type `sensors_event_t` to hold our results. `sensors_event_t` is simply a user-defined datatype (structures in C) that stores a variety of sensor data such as acceleration, gyro, temperature, light, pressure, and many others. More information is available on github.

``sensors_event_t a, g, temp;``

The function `getEvent()` is then called. This function reads a new set of values from the sensor (a sensor “event”), converts them to the correct SI units and scale, and then assigns the results to our `mpu` object.

``mpu.getEvent(&a, &g, &temp);``

Finally, the values are displayed on 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.print("Temperature: ");
Serial.print(temp.temperature);
Serial.println(" degC");``````

## Arduino Example Code – Plotting MPU6050 data

Simply looking at the raw data from the MPU6050 will not help. Use a Serial Plotter if you really want to see how your MPU6050 reacts when you move it around.

The Arduino IDE includes a useful tool called the serial plotter. It can provide real-time visualizations of variables. This is extremely useful for visualizing data, debugging code, and visualizing variables as waveforms.

Let’s give it a shot with the updated code below. Compile and upload the program below, then navigate to Tools > Serial Plotter (Ctrl+Shift+L). The code uses a baud rate of 115200; ensure that the serial plotter is also set to 115200.

``````#include <Adafruit_MPU6050.h>
#include <Wire.h>

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);
}``````

When you move the module up and down the Z axis, you should see something like this.

### Code Explanation:

You’ll notice that the majority of this sketch is identical to the previous one, with the exception of:

• Temperature readings are not printed.
• All other readings are printed in such a way that they form a comma-separated list of values.
• The readings are taken every 10 milliseconds.