Using the MPU6050 with pi4j

Hey,

for the inertial navigation system of my Pathfinder project I’m in need of an three-axis accelerometer and gyroscope. I first used the ADXL337, which is simply an analogue accelerometer as described here. Because I additionally needed a gyroscope I switched to the MPU6050, which is a digital and much more complex device.

About the MPU6050

It’s cheap. You can get it for about 7 EUR.

It has a bunch of features:

  • Built-in 16-bit AD-converter
  • Communication over I2C, slave address configurable
  • Second I2C bus for external sensors
  • FIFO buffer
  • DMP – programmable firmware
  • Scale of gyroscope and accelerometer is configurable
  • Sample rate and clock is configurable
  • Standby and Wake-Up options for every sensor
  • Configurable interrupt pin
  • Digital low pass filter
  • 3-axis gyroscope with self-test functionality
  • 3-axis acccelerometer with self-test functionality

So you see it’s a much more advanced device than the ADXL337. So lets get connect it to the pi.

Cabling

Because there’s no circuit for this in Fritzing, I have to tell the cabling this way (it’s quite easy):

The pins of the MPU6050 are:

VCC – Power supply, 3.3 V
GND – Ground
SCL – I2C clock
SDA – I2C data
XDA – Second I2C bus data
XCL – Second I2C bus clock
ADO – Selection of I2C slave address 0x68(=low) 0x69(=high)
INT – Interrupt pin

  1. Connect VCC to the 3.3V pin of the Raspberry pi (in case of B+ it’s pin 1)
  2. Connect GND to the ground pin of the Raspberry pi (in case of B+ it’s pin 6)
  3. Connect ADO to ground (this means the MPU6050 uses I2C address 0x68)

The following cabling depends on which I2C bus you want to use on the Raspberry pi. I chose to use bus 1, because bus 0 didn’t work for some reason. In case of B+ with I2C bus 1 you have connect the MPU6050 to the Raspberry pi this way:

  1. Connect SCL to the SCL-1 pin of the Raspberry pi (in case of B+ it’s pin 5)
  2. Connect SDA to the SDA-1 pin of the Raspberry pi (in case of B+ it’s pin 3)

You can see the pin numbering here.

Basic testing

You can use the I2C tools, which I described here (linking to here), to check whether the MPU6050 is registered correctly on the relevant bus:

pi@raspberrypi ~ $ i2cdetect 1
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-1.
I will probe address range 0x03-0x77.
Continue? [Y/n] y
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

The binary i2cdetect only needs on parameter, the I2C bus number. If you attached the MPU6050 to the pins SDA-0 and SCL-0 you should use 0 here, if you attached the MPU6050 to the pins SDA-1 and SCL-1 you should use 1 here.

The output should show one device with address 0x68 as shown above. The address 0x68 is chosen by setting ADO to ground. If you want to use the MPU6050 with I2C address 0x69 you have to set ADO to 3.3V.

The next step is to configure the MPU6050.

Communication

This was the easy part. To get the MPU6050 really output data, it took me some time. The first thing you need to know is, that you always talk to the registers of the MPU6050 (don’t know whether all I2C devices behave this way). This means you have to choose which values (= 1 byte) you want to write to which register of the MPU6050 (= 1 byte).

There are many ways to do this. I will describe how to achieve this with the I2C tools and how to achieve this with pi4j.

 

First, the I2C tools

There are two binaries you can use to communicate with the MPU6050.

i2cget [bus-number] [device-address] [register-address]

E.g. if you want to read from bus 1, device address 0X68 and register 0x0D, you can just run this command:

i2cget -yr 1 0x68 0x0D

To write data you can use i2cset:

i2cset [bus-number] [device-address] [register-address] [data]

E.g. if you want to write to bus 1, device address 0X68, register 0x0D the data 0xff, you can just run this command:

i2cset -yr 1 0x68 0x0D 0xff

Don’t be scared if your write to 0x0D doesn’t return the value 0xff after you have written it. It’s a register which returns self-test values. Just ignore this for the moment.

 

Second, pi4j.

With pi4j it’s even straight forward to write and read to the I2C bus.

Reading:

 private static I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
private static I2CDevice mpu6050 = bus.getDevice(0x68);
byte data = mpu6050.read(0x0D);

Writing:

 private static I2CBus bus = I2CFactory.getInstance(I2CBus.BUS_1);
private static I2CDevice mpu6050 = bus.getDevice(0x68);
byte data = mpu6050.write(0x0d, 0xff);

Just test whether the code works without exceptions. If not, try with the I2C tools, double-check the cabling and perhaps even double-check the I2C configuration.

Configuration

Now it’s the question which values should be set to which register. First take a close look at this document. It’s the description of the registers of the MPU6050. It’s really important to read this document cause otherwise you’re just guessing what you are doing.

The important registers to get the MPU6050 running are the following (given as Java variables):

public static final byte MPU6050_RA_PWR_MGMT_1 = 107;
public static final byte MPU6050_RA_SMPLRT_DIV = 25;
public static final byte MPU6050_RA_CONFIG = 26;
public static final byte MPU6050_RA_GYRO_CONFIG = 27;
public static final byte MPU6050_RA_ACCEL_CONFIG = 28;
public static final byte MPU6050_RA_INT_ENABLE = 56;
public static final byte MPU6050_RA_PWR_MGMT_2 = 108;

The values are just decimal values. For usage with the I2C tools you have to convert the address of the registers to hex values. E.g. MPU6050_RA_PWR_MGMT_1 = 107, is 0x6B.

For every of this registers there is at least one page of documentation in the register documentation of InvSense (already linked above). I’m not quite shure whether you really need to set configuration data to all of these registers, but I think you should do so, just to be sure you don’t have any messy presets in there.

The following list contains the values to be written to the configuration registers as byte-values. For use with the I2C tools you have to convert them to hex, too. The effect of the configuration values is described below. If something is not clear, just refer to the register documentation.

All in all, use the I2C tool or pi4j and set all registers listed above to the values listed below. This should get the MPU6050 up and running:

/**
* Just wakes the device up, because it sets the 
* sleep bit to 0. Also sets
* the clock source to internal.
*/
public static final byte MPU6050_RA_PWR_MGMT_1 = 0b00000000;
/**
* Sets the full scale range of the gyroscopes to ± 2000 °/s
*/
public static final byte MPU6050_RA_GYRO_CONFIG = 0b00011000;
/**
* Sets the smaple rate divider for the gyroscopes and 
* accelerometers. This
* means
* acc-rate = 1kHz / 1+ sample-rate
* and
* gyro-rate = 8kHz /
* 1+ sample-rate.
* The concrete value 0 leaves the sample rate on
* default, which means 1kHz for acc-rate and 
* 8kHz for gyr-rate.
*/
public static final byte MPU6050_RA_SMPLRT_DIV = 0b00000000;
/**
* Setting the digital low pass filter to
* Acc Bandwidth (Hz) = 184
* Acc Delay (ms) = 2.0
* Gyro Bandwidth (Hz) = 188
* Gyro Delay (ms) = 1.9
* Fs (kHz) = 1
*
*/
public static final byte MPU6050_RA_CONFIG = 0b00000001;
/**
* Setting accelerometer sensitivity to ± 2g
*/
public static final byte MPU6050_RA_ACCEL_CONFIG = 0b00000000;
/**
* Disabling FIFO buffer
*/
public static final byte MPU6050_RA_FIFO_EN = 0b00000000;
/**
* Disabling interrupts
*/
public static final byte MPU6050_RA_INT_ENABLE = 0b00000000;
/**
* Disabling standby modes
*/
public static final byte MPU6050_RA_PWR_MGMT_2 = 0b00000000;

 

Testing

You can test the configuration by reading the following registers:

/**
* 16-bit 2’s complement value. Stores the most recent X axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_XOUT_H = 59;
/**
* 16-bit 2’s complement value. Stores the most recent X axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_XOUT_L = 60;
/**
* 16-bit 2’s complement value. Stores the most recent Y axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_YOUT_H = 61;
/**
* 16-bit 2’s complement value. Stores the most recent Y axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_YOUT_L = 62;
/**
* 16-bit 2’s complement value. Stores the most recent Z axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_ZOUT_H = 63;
/**
* 16-bit 2’s complement value. Stores the most recent Z axis accelerometer
* measurement.
*/
public static final byte MPU6050_RA_ACCEL_ZOUT_L = 64;
/**
* 16-bit signed value. Stores the most recent temperature sensor
* measurement.
*/
public static final byte MPU6050_RA_TEMP_OUT_H = 65;
/**
* 16-bit signed value. Stores the most recent temperature sensor
* measurement.
*/
public static final byte MPU6050_RA_TEMP_OUT_L = 66;
/**
* 16-bit 2’s complement value. Stores the most recent X axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_XOUT_H = 67;
/**
* 16-bit 2’s complement value. Stores the most recent X axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_XOUT_L = 68;
/**
* 16-bit 2’s complement value. Stores the most recent Y axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_YOUT_H = 69;
/**
* 16-bit 2’s complement value. Stores the most recent Y axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_YOUT_L = 70;
/**
* 16-bit 2’s complement value. Stores the most recent Z axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_ZOUT_H = 71;
/**
* 16-bit 2’s complement value. Stores the most recent Z axis gyroscope
* measurement.
*/
public static final byte MPU6050_RA_GYRO_ZOUT_L = 72;

If most of them are not null, you have set up the MPU6050 correctly.

I myself am working with pi4j. You can get a working example of the configuration on github:
https://github.com/Kaputnik120/AllProjects/blob/MPU/Pathfinder/src/main/java/de/buschbaum/java/pathfinder/device/mpu6050/Mpu6050Controller.java

Just a last tip: Validate the configuration data you have written. Just read the value after write and compare whether the write was correct. This insures proper configuration of the MPU6050.

If you have any questions just leave a comment.

My next blog will be about how to use the output values of the MPU6050 and especially how to calibrate the sensors.

Thanks for reading,

Regards

Uli

Advertisements

3 responses to “Using the MPU6050 with pi4j

  1. Pingback: Using the MPU6050’s DLPF | Dev Stuff·

  2. Pingback: Accelerometers | Matthew Lohbihler·

  3. can we change the sampling frequency of acclerometer from 1khz to something else.not clear in datasheet only given for gyroscope.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s