Arduino UNO Gyroscope Module (MPU6050)

In this project, we will interface the MPU6050 gyroscope module with the Arduino UNO to measure orientation and angular velocity. The MPU6050 module provides both accelerometer and gyroscope data, allowing us to track motion and detect changes in angle.

The project will demonstrate how to set up the sensor and program the Arduino to continuously read sensor data, displaying it via the Serial Monitor.

How It Works

The MPU6050 combines a three-axis accelerometer and a three-axis gyroscope in one package, with an I²C interface. Both are MEMS devices: microscopic silicon structures whose movement changes a capacitance that the chip measures and digitises.

The accelerometer measures proper acceleration, which includes gravity. At rest it reads 1 g on whichever axis points down — that is how it determines tilt. The gyroscope measures angular rate in degrees per second, and says nothing about absolute orientation on its own.

Each sensor fails in a way the other compensates for. Accelerometer readings are stable long-term but extremely noisy when the device vibrates or moves. Gyroscope readings are smooth and immune to vibration but must be integrated to yield an angle, and any small bias accumulates — drift that grows without bound.

Combining them gives good results from both. A complementary filter high-passes the gyroscope and low-passes the accelerometer, typically weighting around 98% gyro and 2% accelerometer, so short-term response comes from the gyro and long-term reference from gravity. A Kalman filter does the same job more rigorously at greater computational cost.

Components Needed

  • Arduino Uno board
  • MPU6050 Accelerometer and Gyroscope module
  • Breadboard and jumper wires
  • USB cable for programming and power
  • Arduino IDE 2.x with the correct board package installed

Wiring to the Arduino Uno

Connect SDA and SCL to A4 (SDA) and A5 (SCL), with VCC on the 5 V rail and GND to ground. I²C pin assignment is fixed by hardware, so wiring copied from a different Arduino will not necessarily match this board.

I²C requires pull-up resistors on both lines. Breakout boards almost always include them, but stacking several modules puts those pull-ups in parallel and can overload the bus — remove the extras if the bus becomes unreliable.

Run an I²C scanner sketch first. Confirming the device answers at the expected address takes a minute and eliminates the most common cause of a module that "does not work".

The default address is 0x68, changing to 0x69 if AD0 is tied high — which is how two MPU6050s share one bus.

Mount the module rigidly and aligned with the axes you care about. A sensor on a flexible wire measures the wire's motion, and misalignment introduces a constant angular error no filter will remove.

Module pinArduino Uno pinFunction
SDAA4I²C data
SCLA5I²C clock
VCC5VSupply
GNDGNDCommon ground
INTany digital pinOptional data-ready interrupt

Example Code

Complementary filter fusing accelerometer and gyroscope into a stable tilt angle. Upload it with the board set to Arduino Uno and open the Serial Monitor at 9600 baud.

Complementary filter fusing accelerometer and gyroscope into a stable tilt angle
#include <Wire.h>

const int MPU_ADDR = 0x68;
float pitch = 0, roll = 0;
float gyroBiasX = 0, gyroBiasY = 0;
unsigned long lastUpdate = 0;

void readRaw(int16_t *ax, int16_t *ay, int16_t *az,
             int16_t *gx, int16_t *gy, int16_t *gz) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);

  *ax = Wire.read() << 8 | Wire.read();
  *ay = Wire.read() << 8 | Wire.read();
  *az = Wire.read() << 8 | Wire.read();
  Wire.read(); Wire.read();              // skip temperature
  *gx = Wire.read() << 8 | Wire.read();
  *gy = Wire.read() << 8 | Wire.read();
  *gz = Wire.read() << 8 | Wire.read();
}

void setup() {
  Serial.begin(9600);
  Wire.begin();

  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B); Wire.write(0);       // wake from sleep
  Wire.endTransmission(true);
  delay(100);

  // Gyro bias must be measured with the board completely still
  Serial.println("Calibrating — keep the sensor motionless");
  long sx = 0, sy = 0;
  int16_t ax, ay, az, gx, gy, gz;
  for (int i = 0; i < 500; i++) { readRaw(&ax,&ay,&az,&gx,&gy,&gz); sx += gx; sy += gy; delay(3); }
  gyroBiasX = sx / 500.0;
  gyroBiasY = sy / 500.0;
  lastUpdate = millis();
}

void loop() {
  int16_t ax, ay, az, gx, gy, gz;
  readRaw(&ax,&ay,&az,&gx,&gy,&gz);

  float dt = (millis() - lastUpdate) / 1000.0;
  lastUpdate = millis();

  // Accelerometer gives absolute tilt but is noisy
  float accPitch = atan2(ay, sqrt((float)ax*ax + (float)az*az)) * 180.0 / PI;
  float accRoll  = atan2(-ax, az) * 180.0 / PI;

  // Gyro gives smooth rate but drifts; 131 LSB per deg/s at default range
  float ratePitch = (gx - gyroBiasX) / 131.0;
  float rateRoll  = (gy - gyroBiasY) / 131.0;

  pitch = 0.98 * (pitch + ratePitch * dt) + 0.02 * accPitch;
  roll  = 0.98 * (roll  + rateRoll  * dt) + 0.02 * accRoll;

  Serial.print("pitch="); Serial.print(pitch, 1);
  Serial.print("  roll="); Serial.println(roll, 1);
  delay(20);
}

Applications

A mpu6050 gyroscope turns up in a wide range of projects. These are the uses where it is the right choice rather than a compromise:

  • Self-balancing robots and inverted pendulums
  • Drone and model aircraft attitude estimation
  • Gesture recognition in wearables and controllers
  • Vibration analysis on machinery
  • Step counting and activity tracking

Working with the Arduino Uno

The Arduino Uno is built around the ATmega328P and runs on 5 V logic with 2 KB of SRAM and 32 KB of program flash. These details change how this circuit is wired and what the sketch can do, so they are worth stating plainly before you build.

The Uno runs at 5 V, so most hobby sensor modules connect directly with no level shifting.

With only 2 KB of SRAM, avoid large buffers and prefer the F() macro for constant strings.

The single hardware UART is shared with the USB connection, so heavy Serial printing competes with uploads.

Arduino Uno characteristicValueWhy it matters here
Logic voltage5 VMatches most hobby modules directly
ADC resolution10-bit (0–1023)Sets how finely an analog reading can be resolved
Analog inputsA0–A5 (six channels)Determines how many analog sensors can share the board
PWM outputsD3, D5, D6, D9, D10 and D11Needed for brightness, speed and tone control
I²C pinsA4 (SDA) and A5 (SCL)Fixed by hardware — wiring copied from another board may not match
Interrupt pinsD2 and D3 onlyRequired for counting fast or asynchronous events
Seriala single hardware UART shared with USBMonitor runs at 9600 baud by default

Troubleshooting

Most problems with this module fall into a handful of categories. Work through these before suspecting the part itself:

  • The angle drifts steadily — gyro bias was not measured, or it was measured while the board was moving.
  • Readings are all zero — the chip is still asleep; write 0 to register 0x6B to wake it.
  • The angle is noisy and jumps — the accelerometer weighting is too high, or the sensor is vibrating. Lower the accelerometer coefficient.
  • The device is not found — address is 0x68 unless AD0 is pulled high.
  • Angles are swapped or inverted — the module is mounted in a different orientation than the formulas assume.
  • Code written for an ESP board gives odd analog values — the Arduino Uno uses a 10-bit ADC returning 0–1023; rescale any constant taken from a 12-bit example.
  • An I²C sensor is not found after copying wiring from another Arduino — on the Arduino Uno I²C is on A4 (SDA) and A5 (SCL).

Taking It Further on the Arduino Uno

Once the basic reading works, where you go next depends very much on which board you are using. These are the directions that suit the Arduino Uno specifically:

The Uno’s shield ecosystem is its real advantage. Once the circuit works on a breadboard, a prototyping shield turns it into something permanent that still stacks with a data-logging or Ethernet shield without rewiring.

Logging to an SD card via a shield is the natural next step, since the Uno has no onboard storage and no network. Timestamp each reading with a DS3231 real-time clock so the log survives power cuts with correct times.

Because SRAM is limited to 2 KB, keep logged strings short and write them out immediately rather than buffering. Building a long String in memory is the most common cause of an Uno sketch that runs for hours and then freezes.

Notes and Practical Limits

Gyro bias changes with temperature, so a calibration taken at power-up slowly becomes wrong as the board warms. For long runs, re-measure bias whenever the device has been still for a few seconds.

The complementary filter coefficient sets the crossover between the two sensors. 0.98 suits a loop running every 20 ms; if your loop rate changes substantially, the coefficient needs adjusting to keep the same time constant.