Now that you understand the very basics of raspberry pi, it is time to move forward and study different communication protocols in raspberry pi. If you are not yet sure about, how to begin with a raspberry pi, I would recommend you to skim through ‘getting started guide‘ and ‘GPIO and PWM in Raspberry Pi‘. In this article, we will look at I2C in raspberry pi. We will interface MPU6050, 3-axis accelerometer and gyroscope with Rpi using I2C.

I2C in raspberry pi

Raspberry Pi provides I2C interface through pins 3(SDA) and 5(SCL) on the 40 pin header. Along with being GPIO pins, these pins have I2C as their alternate functions. Both the pins are internally pulled up using 1.8K resistors to 3.3V. So you don’t really need to add external pull-ups to your circuit. To turn on the I2C interface, you will have to enable I2C interface on your Raspberry Pi. Open Raspberry Pi configuration –> interfaces and then turn on I2C. The same can be done through the terminal window using,

sudo raspi-config

Next, you will have to download ‘i2c-tools‘ which is basically an I2C package for Linux that comes with a set of I2C tools and commands. Open your Raspberry Pi’s terminal an type,

sudo apt-get install -y i2c-tools

 

MPU 6050 Accelerometer and Gyroscope

MPU6050 module

MPU6050

MPU6050 is a 3-axis accelerometer and gyroscope with a provision to interface an external magnetometer. It also comes with an onboard temperature sensor. It has individual 16-bit ADC’s for each, Gyroscope and Accelerometer axis for digitizing output. The full-scale range for the accelerometer can be adjusted to either ±2g, ±4g, ±8g, ±16g. The lower the g-force scale, the more sensitive the device is to acceleration measurement. Similarly, the full-scale range for gyroscope can be adjusted to ±250°/s, ±500°/s, ±1000°/s, ±2000°/s.

The MPU6050 uses I2C in fast mode for communication. The RPi’s default I2C speed though is set to 1KHz. You can change the default speed through the config file in the boot directory.

sudo nano /boot/config.txt
Add ‘dtparam=i2c_baudrate=400000’

Changing raspberry pi I2C speed

Raspberry pi I2C_speed

MPU6050 has 2 separate I2C buses. One for communicating with the Master and an auxiliary bus for communicating with external sensors. The MPU6050 acts as a slave on the main I2C bus, but can behave as a master on the auxiliary bus when communicating with an external sensor like a magnetometer.

The slave address of MPU6050 is 110100X. The LSB bit of the 7-bit address is determined by the logic level on AD0 pin. If you connect the AD0 pin to ground, your device address would be 0x68 and the same would be 0x69 when AD0 is connected to VCC. This allows for 2 different MPU’s on the same bus.

The connections you do with the MPU6050 are pretty straight forward. Connect the SDA and SCL pins of the MPU6050 to pin 3 and 5 on your Raspberry pi respectively. The MPU6050 uses 3.3V to power the module. Connect the power and ground pins on your raspberry pi appropriately.

I2C and Python SMBus

Once you’re done with the connections, open the terminal and type,
i2cdetect -y 1.
It is a bus probing tool which is one of the few tools that comes with ‘i2c-tools’. It will give you the list of all address connected on the Rpi I2C bus.

i2cdetect for checking address on the bus

i2cdetect

Next, you will have to install python’s SMBus library which allows SMBus access to the I2C device. You can read or write a single byte or a block of data using this library. For more information on smbus2, you can refer https://smbus2.readthedocs.io/en/latest/. To install SMBus,

pip3 install smbus2

python smbus2

Installing smbus2

Now that you have all the required tools, let us create a python script which will read accelerometer, gyroscope and temperature values from the MPU6050 module.

 

MPU6050 program for Raspberry Pi.

First, we import the time and the smbus2 library that we just installed using pip3.

import time 
import smbus2

 

Next, we assign variables to all the register addresses that we are going to deal with.

PWR_MGT_1 = 0x6B
CONFIG = 0x1A 
SAMPLE_RATE = 0x19
GYRO_CONFIG = 0x1B
ACCEL_CONFIG = 0x1C

ACCEL_X_HIGH = 0x3B
ACCEL_Y_HIGH = 0x3D
ACCEL_Z_HIGH = 0x3F

GYRO_X_HIGH = 0x43
GYRO_Y_HIGH = 0x45
GYRO_Z_HIGH = 0x47

TEMP_OUT_HIGH = 0x41

 

We then create 2 functions, one for writing values to the MPU6050 registers, and the second to read values from the registers. The ‘bus.write_byte_data()’ will take the device address, register address and value to be written as parameters. In this function, we write into all the necessary registers of the MPU6050.

The second function is used to pass the register address, and will return the value in present in the register. Since both, the accelerometer and gyroscope digitize the output using 16-bit ADC’s, the values are stored in a set of 2, 8-bit registers with consecutive addresses.

The values stored by these registers is in 2’s complement form. So to display the signed value, we subtract the concatenated value with 65536.

def MPU_initilization():

    bus.write_byte_data(Device_Address, PWR_MGT_1, 1)
    bus.write_byte_data(Device_Address, SAMPLE_RATE, 7)
    bus.write_byte_data(Device_Address, CONFIG, 0)
    bus.write_byte_data(Device_Address, GYRO_CONFIG, 24)

def Read_data(reg_add):
    high = bus.read_byte_data(Device_Address, reg_add)
    low = bus.read_byte_data(Device_Address, reg_add+1)
    value = (high<<8)|low

    if value>35768:
        value = value-65536

    return value

 

We then create an instance called ‘bus’ using the smbus.SMBus() class. Inside the ‘while 1’ loop, we pass the higher register addresses for accelerometer and gyroscope axis as well as for temperature. The received values are then divided by the respective sensitivity factor based on the full scale setting. The scale factor for accelerometer and gyroscope is 16384 and 131 respectively for full scale setting of ±2g and ±250°/s as per datasheet.

For temperature, the value in degrees can be obtained by T = (Register value/340)+36.53

bus = smbus2.SMBus(1)
Device_Address = 0x68
MPU_initilization()

while 1:

    ACCEL_X = Read_data(ACCEL_X_HIGH)
    ACCEL_Y = Read_data(ACCEL_Y_HIGH)
    ACCEL_Z = Read_data(ACCEL_Z_HIGH)
    GYRO_X = Read_data(GYRO_X_HIGH)
    GYRO_Y = Read_data(GYRO_Y_HIGH)
    GYRO_Z = Read_data(GYRO_Z_HIGH)
    TEMP = Read_data(TEMP_OUT_HIGH)

    Ax = ACCEL_X/16384.0
    Ay = ACCEL_Y/16384.0
    Az = ACCEL_Z/16384.0

    Gx = GYRO_X/131.0
    Gy = GYRO_Y/131.0
    Gz = GYRO_Z/131.0

    T = (TEMP/340)+36.53

    print("Acceleraton: X=%.2fg\t\t" %Ax, "Y=%.2fg\t" %Ay, "Z=%.2fg" %Az)
    print("Gs Rotation: Gx=%.2f\xb0/s\t" %Gx, "Gy=%.2f\xb0/s\t" %Gy, "Gz=%.2f\xb0/s" %Gz)
    print("Temperature: %.2f\xb0C" %T, "\n")

    time.sleep(1)

 

 

MPU6050 output

Acceleration and rotation output

 

Complete Python Code
import time 
import smbus2
PWR_MGT_1 = 0x6B
CONFIG = 0x1A
SAMPLE_RATE = 0x19
GYRO_CONFIG = 0x1B
ACCEL_CONFIG = 0x1C
ACCEL_X_HIGH = 0x3B
ACCEL_Y_HIGH = 0x3D
ACCEL_Z_HIGH = 0x3F
GYRO_X_HIGH = 0x43
GYRO_Y_HIGH = 0x45
GYRO_Z_HIGH = 0x47
TEMP_OUT_HIGH = 0x41

def MPU_initialization():
    bus.write_byte_data(Device_Address, PWR_MGT_1, 1)
    bus.write_byte_data(Device_Address, SAMPLE_RATE, 7)
    bus.write.byte.data(Device_Address, CONFIG, 0)
    bus.write_byte_data(Device_Address, GYRO_CONFIG, 24)

def Read_data(reg_add):
    high = bus.read_byte_data(Device_Address, reg_add)
    low = bus.read_byte_data(Device_Address, reg_add+1)
    value = (high<<8)|low if value>35768:
    value = value-65536
    return value

bus = smbus2.SMBus(1)
Device_Address = 0x68
MPU_initilization()

while 1:

    ACCEL_X = Read_data(ACCEL_X_HIGH)
    ACCEL_Y = Read_data(ACCEL_Y_HIGH)
    ACCEL_Z = Read_data(ACCEL_Z_HIGH)
    GYRO_X = Read_data(GYRO_X_HIGH)
    GYRO_Y = Read_data(GYRO_Y_HIGH)
    GYRO_Z = Read_data(GYRO_Z_HIGH)
    TEMP = Read_data(TEMP_OUT_HIGH)

    Ax = ACCEL_X/16384.0
    Ay = ACCEL_Y/16384.0
    Az = ACCEL_Z/16384.0

    Gx = GYRO_X/131.0
    Gy = GYRO_Y/131.0
    Gz = GYRO_Z/131.0

    T = (TEMP/340)+36.53

    print("Acceleraton: X=%.2fg\t\t" %Ax, "Y=%.2fg\t" %Ay, "Z=%.2fg" %Az)
    print("Gs Rotation: Gx=%.2f\xb0/s\t" %Gx, "Gy=%.2f\xb0/s\t" %Gy, "Gz=%.2f\xb0/s" %Gz) 
    print("Temperature: %.2f\xb0C" %T, "\n")

    time.sleep(1)

Moiz

Electronics engineer graduated from M.H. Saboo Siddik college of engineering. Currently working as Jr. Innovative engineer. Skilled in 8051, PIC and ARM microcontrollers. Circuit analyzation and Debugging. Constantly looking to acquire more skills which would help myself to become more proficient in embedded domain. Founder and blogger at techetrx.com LinkedIn profile: https://www.linkedin.com/in/moiz-shaikh-305294137

1 Comment

Kilian Zepf · August 6, 2020 at 4:28 pm

where do you change the sensitivity in this code, I want to set it to +-16g
sorry if I’m being stupid .
Thanks in advance

Leave a Reply

Your email address will not be published. Required fields are marked *