23. Chapter Attitude Sensor MPU6050

In this chapter, we will learn about a MPU6050 Attitude sensor, which integrates an Accelerometer and Gyroscope.

23.1. Project Read a MPU6050 Sensor Module

In this project, we will read Acceleration and Gyroscope Data of the MPU6050 Sensor.

23.1.1. Component List

  1. Raspberry Pi (with 40 GPIO) x1

  2. GPIO Extension Board & Ribbon Cable x1

  3. Breadboard x1

Jumper Wires x4

jumper-wire

MPU6050

MPU6050

23.1.2. Component knowledge

23.1.2.1. MPU6050

MPU6050 Sensor Module is a complete 6-axis Motion Tracking Device. It combines a 3-axis Gyroscope, a 3-axis Accelerometer and a DMP (Digital Motion Processor) all in a small package. The settings of the Accelerometer and Gyroscope of MPU6050 can be changed. A precision wide range digital temperature sensor is also integrated to compensate data readings for changes in temperature, and temperature values can also be read. The MPU6050 Module follows the I2C communication protocol and the default address is 0x68.

../../../_images/MPU6050_1.png

The port description of the MPU6050 Module is as follows:

Pin name

Pin number

Description

VCC

1

Positive pole of power supply with voltage 5V

GND

2

Negative pole of power supply

SCL

3

I2C communication clock pin

SDA

4

I2C communication data pin

XDA

5

I2C host data pin which can be connected to other devices.

XCL

6

I2C host clock pin which can be connected to other devices.

AD0

7

I2C address bit control pin.

Low level: the device address is 0x68

High level: the device address is 0x69

INT

8

Output interrupt pin

For more detail, please refer to the MPU6050 datasheet.

MPU6050 is widely used to assist with balancing vehicles, robots and aircraft, mobile phones and other products which require stability to control stability and attitude or which need to sense same.

23.1.3. Circuit

Schematic diagram

MPU6050_Sc

Hardware connection. If you need any support,please feel free to contact us via:

support@freenove.com

MPU6050_Fr

23.1.4. Sketch

In this chapter, we will learn to obtain MPU6050 data and print them.

23.1.4.1. Sketch_MPU6050

First, enter where the project is located:

$ cd ~/Freenove_Kit/Pi4j/Sketches/Sketch_23_MPU6050
../../../_images/java_mpu6050.png

Enter the command to run the code.

$ jbang MPU6050RAW.java
../../../_images/java_mpu6050_run.png

When the code is running, pick up the entire board with and make any movements such as shaking it left and right, turning it upside down, etc. You can observe the changes in data on the terminal interface.

../../../_images/java_mpu6050_mes.png

Press Ctrl+C to exit the program.

You can run the following command to open the code with Geany to view and edit it.

$ geany MPU6050RAW.java

Click the icon to run the code.

../../../_images/java_mpu6050_code.png

If the code fails to run, please check Geany Configuration.

The following is program code:

  1// Shebang line for JBang to execute this script directly      
  2///usr/bin/env jbang "$0" "$@" ; exit $?      
  3
  4// Dependencies for this script      
  5//DEPS org.slf4j:slf4j-api:2.0.12      
  6//DEPS org.slf4j:slf4j-simple:2.0.12      
  7//DEPS com.pi4j:pi4j-core:2.7.0      
  8//DEPS com.pi4j:pi4j-plugin-raspberrypi:2.7.0      
  9//DEPS com.pi4j:pi4j-plugin-gpiod:2.7.0      
 10//DEPS com.pi4j:pi4j-plugin-linuxfs:2.7.0      
 11
 12// Importing necessary Pi4J and Java libraries  
 13import com.pi4j.Pi4J;    
 14import com.pi4j.context.Context;    
 15import com.pi4j.io.i2c.I2C;    
 16import com.pi4j.io.i2c.I2CConfig;    
 17import com.pi4j.io.i2c.I2CConfigBuilder;    
 18import com.pi4j.io.i2c.I2CProvider;    
 19import com.pi4j.util.Console;    
 20
 21import java.io.File;    
 22import java.util.ArrayList;    
 23import java.util.Arrays;    
 24
 25// MPU6050 class to interface with the MPU6050 sensor  
 26class MPU6050 {    
 27    // MPU6050 Register Addresses  
 28    private static final byte WHO_AM_I = 0x75;    
 29    private static final byte SMPLRT_DIV = 0x19;    
 30    private static final byte CONFIG = 0x1A;    
 31    private static final byte GYRO_CONFIG = 0x1B;    
 32    private static final byte ACCEL_CONFIG = 0x1C;    
 33    private static final byte PWR_MGMT_1 = 0x6B;    
 34
 35    private static final byte ACCEL_XOUT_H = 0x3B;    
 36    private static final byte GYRO_XOUT_H = 0x43;    
 37
 38    private I2C i2c;    
 39    private int bus;    
 40    private int address;    
 41
 42    // Constructor to initialize MPU6050 with bus and address  
 43    public MPU6050(int bus, int address) {    
 44        this.bus = bus;    
 45        this.address = address;    
 46        initializeI2C();    
 47        initializeMPU6050();    
 48    }    
 49
 50    // Constructor to initialize MPU6050 with bus string and address  
 51    public MPU6050(String busString, int address) {    
 52        this.address = address;    
 53        try {    
 54            this.bus = Integer.parseInt(busString.split("i2c-")[1]);    
 55        } catch (Exception e) {    
 56            this.bus = 1;    
 57        }    
 58        initializeI2C();    
 59        initializeMPU6050();    
 60    }    
 61
 62    // Method to initialize I2C communication  
 63    private void initializeI2C() {    
 64        Context pi4j = Pi4J.newAutoContext();    
 65        I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c");    
 66        I2CConfigBuilder i2cConfigBuilder = I2C.newConfigBuilder(pi4j).bus(bus);    
 67        I2CConfig i2cConfig = i2cConfigBuilder.device(address).build();    
 68        this.i2c = i2CProvider.create(i2cConfig);    
 69    }    
 70
 71    // Static method to list all I2C devices  
 72    public static String[] listI2CDevices() {    
 73        ArrayList<String> devs = new ArrayList<>();    
 74        File dir = new File("/dev");    
 75        File[] files = dir.listFiles();    
 76        if (files != null) {    
 77            for (File file : files) {    
 78                if (file.getName().startsWith("i2c-")) {    
 79                    devs.add(file.getName());    
 80                }    
 81            }    
 82        }    
 83        String[] tmp = devs.toArray(new String[devs.size()]);    
 84        Arrays.sort(tmp);    
 85        return tmp;    
 86    }    
 87
 88    // Method to initialize MPU6050 settings  
 89    private void initializeMPU6050() {    
 90        i2c.writeRegister(PWR_MGMT_1, 0x01);    
 91        i2c.writeRegister(SMPLRT_DIV, 0x00);    
 92        i2c.writeRegister(CONFIG, 0x00);    
 93        i2c.writeRegister(GYRO_CONFIG, 0x08);    
 94        i2c.writeRegister(ACCEL_CONFIG, 0x00);    
 95    }    
 96
 97    // Method to read the WHO_AM_I register for device identification  
 98    public byte testWhoAmI() {    
 99        byte[] whoAmI = new byte[1];    
100        i2c.readRegister(WHO_AM_I, whoAmI);    
101        return whoAmI[0];    
102    }    
103
104    // Method to get raw accelerometer data  
105    public int[] getRawAccel() {    
106        int[] data = new int[3];    
107        byte[] buffer = new byte[6];    
108        i2c.readRegister(ACCEL_XOUT_H, buffer, buffer.length);    
109        data[0] = (buffer[0] << 8) | (buffer[1] & 0xFF);    
110        data[1] = (buffer[2] << 8) | (buffer[3] & 0xFF);    
111        data[2] = (buffer[4] << 8) | (buffer[5] & 0xFF);   
112        return data;    
113    }    
114
115    // Method to get raw gyroscope data  
116    public int[] getRawGyro() {    
117        int[] data = new int[3];    
118        byte[] buffer = new byte[6];    
119        i2c.readRegister(GYRO_XOUT_H, buffer, buffer.length);    
120        data[0] = (buffer[0] << 8) | (buffer[1] & 0xFF);    
121        data[1] = (buffer[2] << 8) | (buffer[3] & 0xFF);    
122        data[2] = (buffer[4] << 8) | (buffer[5] & 0xFF);   
123        return data;    
124    }    
125
126    // Method to close the I2C connection  
127    public void close() {    
128        i2c.close();    
129    }    
130}  
131
132public class MPU6050RAW {  
133    public static final int MPU6050_ADDRESS = 0x68;  
134
135    public static void myPrintln(String format, Object... args) {  
136        Console console = new Console();  
137        console.println(String.format("\u001B[32m" + format + "\u001B[0m", args));  
138    }  
139
140    public static void main(String[] args) {  
141        MPU6050 mpu = null;  
142        try {  
143            mpu = new MPU6050(MPU6050.listI2CDevices()[0], MPU6050_ADDRESS);  
144
145            // Test WHO AM I register  
146            int whoAmI = mpu.testWhoAmI();  
147            myPrintln("WHO AM I: 0x%02X", whoAmI);  
148            if (whoAmI == MPU6050_ADDRESS) {  
149                myPrintln("MPU6050 device identified correctly.");  
150            } else {  
151                myPrintln("Failed to identify MPU6050 device. Got: 0x%02X", whoAmI);  
152            }  
153
154            while (true) {  
155                int[] accel = mpu.getRawAccel();  
156                int[] gyro = mpu.getRawGyro();  
157                myPrintln("a/g: %8d %8d %8d     %8d %10d %10d", 
158                          accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);  
159                myPrintln("a/g:   %.2f g   %.2f g   %.2f g     %.2f d/s   %.2f d/s   %.2f d/s\n", 
160                          (float)accel[0]/16384, (float)accel[1]/16384, (float)accel[2]/16384, 
161                          (float)gyro[0]/131, (float)gyro[1]/131, (float)gyro[2]/131);  
162                Thread.sleep(300);  
163            }  
164        } catch (InterruptedException e) {  
165            e.printStackTrace();  
166            Thread.currentThread().interrupt();  
167        } finally {  
168            if (mpu != null) {  
169                mpu.close();  
170            }  
171        }  
172    }  
173}

Define the commonly used registers of MPU6050.

1private static final byte WHO_AM_I = 0x75;    
2private static final byte SMPLRT_DIV = 0x19;    
3private static final byte CONFIG = 0x1A;    
4private static final byte GYRO_CONFIG = 0x1B;    
5private static final byte ACCEL_CONFIG = 0x1C;    
6private static final byte PWR_MGMT_1 = 0x6B;    
7
8private static final byte ACCEL_XOUT_H = 0x3B;    
9private static final byte GYRO_XOUT_H = 0x43;    

Initialize the I2C interface of the Raspberry Pi.

1private void initializeI2C() {    
2    Context pi4j = Pi4J.newAutoContext();    
3    I2CProvider i2CProvider = pi4j.provider("linuxfs-i2c");    
4    I2CConfigBuilder i2cConfigBuilder = I2C.newConfigBuilder(pi4j).bus(bus);    
5    I2CConfig i2cConfig = i2cConfigBuilder.device(address).build();    
6    this.i2c = i2CProvider.create(i2cConfig);    
7}    

Configure MPU6050 so that it can work properly.

1private void initializeMPU6050() {    
2    i2c.writeRegister(PWR_MGMT_1, 0x01);    
3    i2c.writeRegister(SMPLRT_DIV, 0x00);    
4    i2c.writeRegister(CONFIG, 0x00);    
5    i2c.writeRegister(GYRO_CONFIG, 0x08);    
6    i2c.writeRegister(ACCEL_CONFIG, 0x00);    
7}    

Get the I2C address of MPU6050. This is only used for testing.

1public byte testWhoAmI() {    
2    byte[] whoAmI = new byte[1];    
3    i2c.readRegister(WHO_AM_I, whoAmI);    
4    return whoAmI[0];    
5}    

Get raw acceleration data.

1public int[] getRawAccel() {    
2    int[] data = new int[3];    
3    byte[] buffer = new byte[6];    
4    i2c.readRegister(ACCEL_XOUT_H, buffer, buffer.length);    
5    data[0] = (buffer[0] << 8) | (buffer[1] & 0xFF);    
6    data[1] = (buffer[2] << 8) | (buffer[3] & 0xFF);    
7    data[2] = (buffer[4] << 8) | (buffer[5] & 0xFF);   
8    return data;    
9}    

Get raw gyroscope data.

1public int[] getRawGyro() {    
2    int[] data = new int[3];    
3    byte[] buffer = new byte[6];    
4    i2c.readRegister(GYRO_XOUT_H, buffer, buffer.length);    
5    data[0] = (buffer[0] << 8) | (buffer[1] & 0xFF);    
6    data[1] = (buffer[2] << 8) | (buffer[3] & 0xFF);    
7    data[2] = (buffer[4] << 8) | (buffer[5] & 0xFF);   
8    return data;    
9}    

Define the I2C address of MPU6050.

public static final int MPU6050_ADDRESS = 0x68;

Get the I2C address from the MPU6050 register and determine whether it is consistent with the predefined address.

1// Test WHO AM I register  
2int whoAmI = mpu.testWhoAmI();  
3myPrintln("WHO AM I: 0x%02X", whoAmI);  
4if (whoAmI == MPU6050_ADDRESS) {  
5    myPrintln("MPU6050 device identified correctly.");  
6} else {  
7    myPrintln("Failed to identify MPU6050 device. Got: 0x%02X", whoAmI);  
8}  

Get the raw data of the accelerometer and gyroscope of MPU6050, convert them and print them out.

 1while (true) {  
 2    int[] accel = mpu.getRawAccel();  
 3    int[] gyro = mpu.getRawGyro();  
 4    myPrintln("a/g: %8d %8d %8d     %8d %10d %10d", 
 5              accel[0], accel[1], accel[2], gyro[0], gyro[1], gyro[2]);  
 6    myPrintln("a/g:   %.2f g   %.2f g   %.2f g     %.2f d/s   %.2f d/s   %.2f d/s\n", 
 7              (float)accel[0]/16384, (float)accel[1]/16384, (float)accel[2]/16384, 
 8              (float)gyro[0]/131, (float)gyro[1]/131, (float)gyro[2]/131);  
 9    Thread.sleep(300);  
10}  

Thread exception capture ensures that the code runs normally.

1catch (InterruptedException e) {
2    e.printStackTrace();
3    Thread.currentThread().interrupt();
4}

When terminating the execution of the code, shut down the MPU6050 device and disable the I2C functionality on the Raspberry Pi.

1finally {
2    if (mpu != null) {
3        mpu.close();
4    }
5}