Measuring acceleration and rotation with a Raspberry Pi and MPU6050 IMU
About MPU6050
The MPU6050 consists of a 3-axis gyroscope and 3-axis accelerometer. It also contains a DMP (digital motion processor) to perform complex calculations, which frees up the controller to do other things.
The MPU6050 has a 16-bit ADC (analog to digital) chip. Because of this, it can receive motion in all three planes.
The MPU6050 uses the I2C interface.
MPU6050 Pinout
Pin
Description
VCC
3-5 V supply voltage
GND
Ground connection
SCL
I2C clock connection
SDA
I2C data connection
XDA
See below
XCL
AD0
Address pin
INT
Interrupt pin
XDA and XCL stand for auxiliary data and auxiliary clock, respectively. These pins can be used for interfacing with other I2C devices.
The address pin can be used to change the address of the MPU6050. (default is 0x68)
The interrupt pin is used to indicate that data is available for the microcontroller to read.
MPU6050 Registers
Address
Name in code
Purpose
0x6B
PWR_MGMT_1
Writing to power management register
0x19
SMPLRT_DIV
Writing to sample rate register
0x1A
CONFIG
Writing to configuration register
0x1B
GYRO_CONFIG
Writing to gyro configuration register
0x38
INT_ENABLE
Writing to interrupt enable register
0x3B
ACCEL_X
Reading X Accelerometer raw data
0x3D
ACCEL_Y
Reading Y Accelerometer raw data
0x3F
ACCEL_Z
Reading Z Accelerometer raw data
0x43
GYRO_X
Reading X Gyro raw data
0x45
GYRO_Y
Reading Y Gyro raw data
0x47
GYRO_Z
Reading Z Gyro raw data
Connections to Raspberry Pi
MPU6050 pin
Connects to RPi pin
VCC
3.3 V power
GND
GND
SCL
GPIO 3 (SCL)
SDA
GPIO 2 (SDA)
Code
I2C needs to be enabled on your Raspberry Pi before running this code. See "ADS1115 with Raspberry Pi" for details.
This code prints the acceleration and gyro values on each of the three axes.
from time import time, sleepimport smbusbus = smbus.SMBus(1)previous, current, elapsed = 0, 0, 0x, y, z = 0, 0, 0# MPU6050 registersPWR_MGMT_1 = 0x6BSMPLRT_DIV = 0x19CONFIG = 0x1AGYRO_CONFIG = 0x1BINT_ENABLE = 0x38ACCEL_X = 0x3BACCEL_Y = 0x3DACCEL_Z = 0x3FGYRO_X = 0x43GYRO_Y = 0x45GYRO_Z = 0x47device_address = 0x68def init(): # Write to sample rate register bus.write_byte_data(device_address, SMPLRT_DIV, 7) # Write to power management register bus.write_byte_data(device_address, PWR_MGMT_1, 1) # Write to Configuration register bus.write_byte_data(device_address, CONFIG, 0) # Write to Gyro configuration register bus.write_byte_data(device_address, GYRO_CONFIG, 24) # Write to interrupt enable register bus.write_byte_data(device_address, INT_ENABLE, 1)def read_data(addr): # Get elapsed time for calculating gyro angle global current previous = current current = time() elapsed = current - previous # Accel and Gyro value are 16-bit high = bus.read_byte_data(device_address, addr) low = bus.read_byte_data(device_address, addr + 1) # Concatenate higher and lower value value = (high << 8) | low # Get signed value from sensor if value > 32768: value -= 65536 return valuedef scale_gyro(val): return val / 131.0def scale_accel(val): return val / 16384.0init()while True: try: x_accel = scale_accel(read_data(ACCEL_X)) y_accel = scale_accel(read_data(ACCEL_Y)) z_accel = scale_accel(read_data(ACCEL_Z)) x_gyro = scale_accel(read_data(GYRO_X)) y_gyro = scale_accel(read_data(GYRO_Y)) z_gyro = scale_accel(read_data(GYRO_Z)) print("Accel X: %.3f Accel Y: %.3f Accel Z: %.3f Gyro X: %.3f Gyro Y: %.3f Gyro Z: %.3f" % (x_accel, y_accel, z_accel, x_gyro, y_gyro, z_gyro)) sleep(0.2) except KeyboardInterrupt: print("Stopped") break
The gyroscope measures degrees per second (how many degrees it has rotated in a second, or speed of rotation). We can plug in deg/sec for rate and seconds for time, so (degrees per second) * (seconds) equals degrees in rotation.
Below is the code showing this:
from time import time, sleepimport smbusbus = smbus.SMBus(1)previous, current, elapsed = 0, 0, 0x, y, z = 0, 0, 0# MPU6050 registersPWR_MGMT_1 = 0x6BSMPLRT_DIV = 0x19CONFIG = 0x1AGYRO_CONFIG = 0x1BINT_ENABLE = 0x38ACCEL_X = 0x3BACCEL_Y = 0x3DACCEL_Z = 0x3FGYRO_X = 0x43GYRO_Y = 0x45GYRO_Z = 0x47device_address = 0x68 # MPU6050 addressdef init(): # Write to sample rate register bus.write_byte_data(device_address, SMPLRT_DIV, 7) # Write to power management register bus.write_byte_data(device_address, PWR_MGMT_1, 1) # Write to Configuration register bus.write_byte_data(device_address, CONFIG, 0) # Write to Gyro configuration register bus.write_byte_data(device_address, GYRO_CONFIG, 24) # Write to interrupt enable register bus.write_byte_data(device_address, INT_ENABLE, 1)def read_data(addr): # Get elapsed time for calculating gyro angle global current, elapsed previous = current current = time() elapsed = current - previous # Accel and Gyro value are 16-bit high = bus.read_byte_data(device_address, addr) low = bus.read_byte_data(device_address, addr + 1) # Concatenate higher and lower value value = (high << 8) | low # Get signed value from sensor if value > 32768: value -= 65536 return valuedef scale_gyro(val): return val / 131.0def scale_accel(val): return val / 16384.0def get_rotation(): x_ang = scale_gyro(read_data(GYRO_X)) # Read gyro data (degrees per second) y_ang = scale_gyro(read_data(GYRO_Y)) z_ang = scale_gyro(read_data(GYRO_Z)) global x, y, z x += round(x_ang * elapsed * 1000) # Degrees/second multiplied by seconds = degrees y += round(y_ang * elapsed * 1000) # Round values to prevent drift z += round(z_ang * elapsed * 1000)init()while True: try: get_rotation() print("X: %d Y: %d Z: %d" % (x, y, z)) sleep(0.2) except KeyboardInterrupt: print("Stopped") break