Accelerometers and gyroscopes (IMU)
What you’ll learn
- What accelerometers and gyroscopes measure
- How to get tilt from gravity
- Why gyroscopes drift, and how robots combine both
Accelerometer
Measures acceleration in three directions (x, y, z), including gravity. Lying flat and still, it reads about 9.8 m/s² (1 g) on the axis pointing up and about 0 on the others. Tilt it and gravity shifts between axes, which gives the tilt angle.
Gyroscope
Measures rotation speed around each axis (degrees or radians per second). Add up (integrate) the rotation speed over time and you get the angle turned.
IMU = both together
The popular MPU6050 has a 3-axis accelerometer and a 3-axis gyroscope, and talks over I²C (on an UNO: SDA → A4, SCL → A5).
Drift and noise
- The accelerometer is noisy and gets confused by bumps and turns (they’re acceleration too), but it doesn’t drift.
- The gyroscope is smooth, but tiny errors add up when you integrate, so the angle drifts over time.
Robots combine them with a complementary filter: mostly trust the gyro for quick changes, and slowly correct towards the accelerometer’s angle.
angle = 0.98 * (angle + gyroRate * dt) + 0.02 * accelAngle;Robot uses
- Turn exactly 90° (gyro)
- Detect when the robot is tipping or has been picked up (accelerometer)
- Balancing robots (both, plus PID control)
Example: tilt angle from the accelerometer
float pitch = atan2(a.acceleration.x, a.acceleration.z) * 180.0 / PI;Flat gives about 0°; tilting forward makes it larger.
Example: turning 90° with a gyro
float heading = 0;unsigned long last = millis();
void loop() { sensors_event_t a, g, t; mpu.getEvent(&a, &g, &t); float dt = (millis() - last) / 1000.0; last = millis(); heading += g.gyro.z * 180.0 / PI * dt; // rad/s → degrees turned if (abs(heading) < 90) { // keep spinning } else { // stop: we've turned 90° }}Try it in the virtual Arduino
Press Start simulator. Replace diagram.json with the wiring below, then open the Library Manager tab and add Adafruit MPU6050. Paste the sketch, press ▶, and click the sensor to change its acceleration and rotation. If Wokwi says a library is missing, click its Install button and press ▶ again.
{ "version": 1, "author": "RoboLearn", "editor": "wokwi", "parts": [ { "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} }, { "type": "wokwi-mpu6050", "id": "imu", "top": -90, "left": 120, "attrs": {} } ], "connections": [ [ "imu:VCC", "uno:5V", "red", [] ], [ "imu:GND", "uno:GND.1", "black", [] ], [ "imu:SCL", "uno:A5", "blue", [] ], [ "imu:SDA", "uno:A4", "green", [] ] ], "dependencies": {}}#include <Adafruit_MPU6050.h>#include <Adafruit_Sensor.h>#include <Wire.h>
Adafruit_MPU6050 mpu;
void setup() { Serial.begin(9600); if (!mpu.begin()) { Serial.println("MPU6050 not found - check wiring"); while (true) {} }}
void loop() { sensors_event_t a, g, temp; mpu.getEvent(&a, &g, &temp); Serial.print("accel x/y/z (m/s^2): "); Serial.print(a.acceleration.x); Serial.print(" "); Serial.print(a.acceleration.y); Serial.print(" "); Serial.print(a.acceleration.z); Serial.print(" gyro z (rad/s): "); Serial.println(g.gyro.z); delay(250);}Runs on Wokwi, free, no account needed.
Find gravityEasy
With the virtual sensor still, which axis reads about 9.8 m/s²? What happens when you change the acceleration values?
Tilt alarmMedium
Turn the built-in LED on when the x acceleration is more than 5 m/s² (the board is tilted a lot).
After getEvent, add digitalWrite(LED_BUILTIN, abs(a.acceleration.x) > 5 ? HIGH : LOW); and set pinMode(LED_BUILTIN, OUTPUT) in setup().
Why drift?Hard
A gyro has a tiny constant error of 0.5°/s. How far off is the integrated heading after 2 minutes? 0.5 × 120 = 60°. That’s why gyros are combined with other sensors or re-zeroed often.
Quick check
Finished this lesson?