The MPU6050 is a 3-axis accelerometer and 3-axis gyro on one I2C chip. MicroPython has no built-in driver, but you don’t need one: wake the chip, read 14 bytes, scale them.
Wire the GY-521 to 3V3 and I2C0 (GP4/GP5). The script prints acceleration in g, rotation in degrees per second, the chip temperature, and pitch/roll worked out from gravity.
Wiring
| Raspberry Pi Pico W | MPU6050 (GY-521) | Wire | Notes |
|---|---|---|---|
| 3V3 | VCC | red | 3V3 is pin 36. The GY-521 also has its own regulator. |
| GND | GND | black | |
| GP5 | SCL | yellow | GP5 is physical pin 7 (I2C0 SCL). |
| GP4 | SDA | blue | GP4 is physical pin 6 (I2C0 SDA). AD0 left open = address 0x68. |
3.3–5 V (on-board 3.3 V regulator) part, 3.3 V board. The GY-521 has a 3.3 V regulator and pulls SDA/SCL up to 3.3 V, so it works on both 3.3 V boards and a 5 V Uno without a level shifter.
Board quirks
- The MPU6050 boots asleep and returns all zeros until you write 0 to register
0x6B— the first thing the script does. - All seven values come from one 14-byte read starting at
0x3B, unpacked withstruct.unpack(">7h", …)(big-endian signed 16-bit). - Pitch and roll from the accelerometer are only right while the board is still; for a balancing robot you need a complementary filter with the gyro.
- Many cheap “MPU6050” boards carry an MPU6500 or a clone, and WHO_AM_I reads something other than 0x68 (0x70 for an MPU6500). The accel and gyro registers used here are the same; only the temperature formula differs slightly.
Code
# MPU6050 (GY-521) accelerometer + gyro on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# AD0 unconnected = address 0x68.
from machine import Pin, I2C
import struct
import math
import time
ADDR = 0x68
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
if ADDR not in i2c.scan():
raise SystemExit("No MPU6050 at 0x68 - found {}".format([hex(a) for a in i2c.scan()]))
who = i2c.readfrom_mem(ADDR, 0x75, 1)[0] # WHO_AM_I: 0x68 on a genuine MPU6050
print("MPU6050 found, WHO_AM_I = 0x%02X" % who)
i2c.writeto_mem(ADDR, 0x6B, b"\x00") # PWR_MGMT_1: wake up (it boots in sleep mode)
i2c.writeto_mem(ADDR, 0x1C, b"\x00") # accel range +-2 g -> 16384 LSB/g
i2c.writeto_mem(ADDR, 0x1B, b"\x00") # gyro range +-250 dps -> 131 LSB/(deg/s)
time.sleep_ms(100)
def read():
ax, ay, az, t, gx, gy, gz = struct.unpack(">7h", i2c.readfrom_mem(ADDR, 0x3B, 14))
return (ax / 16384, ay / 16384, az / 16384, t / 340 + 36.53, gx / 131, gy / 131, gz / 131)
while True:
ax, ay, az, temp, gx, gy, gz = read()
pitch = math.degrees(math.atan2(-ax, math.sqrt(ay * ay + az * az)))
roll = math.degrees(math.atan2(ay, az))
print("Accel g: {:+.2f} {:+.2f} {:+.2f} | Gyro dps: {:+6.1f} {:+6.1f} {:+6.1f} | Pitch {:+5.1f} Roll {:+5.1f} | {:.1f} C".format(
ax, ay, az, gx, gy, gz, pitch, roll, temp))
time.sleep_ms(250)# MPU6050 (GY-521) accelerometer + gyro on a Raspberry Pi Pico W (MicroPython, no library).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, SCL -> GP5 (pin 7), SDA -> GP4 (pin 6). I2C0.
# AD0 unconnected = address 0x68.
from machine import Pin, I2C
import struct
import math
import time
ADDR = 0x68
i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400_000)
if ADDR not in i2c.scan():
raise SystemExit("No MPU6050 at 0x68 - found {}".format([hex(a) for a in i2c.scan()]))
who = i2c.readfrom_mem(ADDR, 0x75, 1)[0] # WHO_AM_I: 0x68 on a genuine MPU6050
print("MPU6050 found, WHO_AM_I = 0x%02X" % who)
i2c.writeto_mem(ADDR, 0x6B, b"\x00") # PWR_MGMT_1: wake up (it boots in sleep mode)
i2c.writeto_mem(ADDR, 0x1C, b"\x00") # accel range +-2 g -> 16384 LSB/g
i2c.writeto_mem(ADDR, 0x1B, b"\x00") # gyro range +-250 dps -> 131 LSB/(deg/s)
time.sleep_ms(100)
def read():
ax, ay, az, t, gx, gy, gz = struct.unpack(">7h", i2c.readfrom_mem(ADDR, 0x3B, 14))
return (ax / 16384, ay / 16384, az / 16384, t / 340 + 36.53, gx / 131, gy / 131, gz / 131)
while True:
ax, ay, az, temp, gx, gy, gz = read()
pitch = math.degrees(math.atan2(-ax, math.sqrt(ay * ay + az * az)))
roll = math.degrees(math.atan2(ay, az))
print("Accel g: {:+.2f} {:+.2f} {:+.2f} | Gyro dps: {:+6.1f} {:+6.1f} {:+6.1f} | Pitch {:+5.1f} Roll {:+5.1f} | {:.1f} C".format(
ax, ay, az, gx, gy, gz, pitch, roll, temp))
time.sleep_ms(250)Expected serial output
MPU6050 found, WHO_AM_I = 0x68
Accel g: +0.01 -0.02 +1.00 | Gyro dps: -1.2 +0.8 -0.4 | Pitch -0.6 Roll -1.1 | 29.4 C
Accel g: +0.48 -0.03 +0.87 | Gyro dps: +12.6 -3.1 +0.9 | Pitch -28.9 Roll -2.0 | 29.4 CMPU6050 found, WHO_AM_I = 0x68 Accel g: +0.01 -0.02 +1.00 | Gyro dps: -1.2 +0.8 -0.4 | Pitch -0.6 Roll -1.1 | 29.4 C Accel g: +0.48 -0.03 +0.87 | Gyro dps: +12.6 -3.1 +0.9 | Pitch -28.9 Roll -2.0 | 29.4 C
Common errors
No MPU6050 at 0x68 - found ['0x69']
AD0 is pulled HIGH on your board. Change ADDR to 0x69.
Gyro never reads exactly zero when still
Every MEMS gyro has an offset. Average 200 readings at start-up while the board is still and subtract them.
OSError: [Errno 5] EIO
SDA and SCL are swapped, or the wires are on a pair that is not I2C0. GP4 = SDA (pin 6), GP5 = SCL (pin 7).