Introduction
This tutorial teaches how to connect an MPU-6050 based accelerometer and gyroscope sensor module to a Raspberry Pi using the I2C bus interface along with retrieving and displaying sensor readings from the module using the Swift programming language. A basic understanding of electronics and programming is expected along with some familiarity with the Raspberry Pi platform. If you are new to the Raspberry Pi platform or the Swift language or would just like to refresh your knowledge, please see our Blink: Making An LED Blink On A Raspberry Pi and Hello World: Writing Your First Swift Program tutorials before proceeding with this one. Detailed versions of all source code used in this tutorial are available on GitHub for your reference.
What Is Needed
- Raspberry Pi Running Raspbian Or Similar Linux Based OS (available on Raspberry Pi Foundation and Adafruit)
- Solderless Breadboard (available on Adafruit and SparkFun)
- 4 x Male-Female Jumper Wires (available on Adafruit and Arrow)
- MPU-6050 Motion Sensor Module With I2C Interface (available on Amazon and Sunfounder)
Background Information
An MPU6050 sensor module contains the MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device by InvenSense Inc. and provides acceleration, rotation, and temperature sensor readings over an I2C or SPI serial bus interface. The module provides more advanced configuration and functionality than what is covered in this tutorial, but for those interested in learning more about its capabilities, please check out the datasheet and register map documents for the MPU-6050 device for detailed information.
My development board is a Raspberry Pi 3 Model B running the Raspbian OS and my sensor module is the SunFounder MPU6050 Module for Arduino and Raspberry Pi, 3-axis Gyroscope and 3-axis Accelerator that communicates over an I2C serial bus interface. If you are using a different model of the Raspberry Pi, a different Linux based OS that is similar to Raspbian, or a different MPU-6050 based sensor module, the vast majority of this tutorial should still apply, however, some minor changes may be necessary.
Building The Circuit
My MPU6050 sensor module did not have a pin header already attached to the module. The vendor did, however, include both straight pin and right-angle pin headers in the shipping package. I soldered the straight pin header to the bottom of the module so that when the module is plugged into a breadboard, the positive z-axis points to the ceiling.
Before connecting the sensor module to your Raspberry Pi, shutdown and disconnect the Raspberry Pi from power. This avoids accidental damage during wiring.
Attach the sensor module via the pin header to the breadboard.
Connect the VCC and GND pins of the sensor module to the 3v3 (physical pin 1) and GND (physical pin 9) power pins respectively on the Raspberry Pi with the jumper wires.
For the I2C serial bus connection, use the jumper wires to connect the SDA and SCL pins of the sensor module to the SDA (physical pin 3) and SCL (physical pin 5) pins respectively on the Raspberry Pi.
You can now connect power to your Raspberry Pi and boot it up.
In order to communicate with the sensor module, we need to verify the I2C serial bus is enabled on the Raspberry Pi. This can be accomplished by running the Raspberry Pi Software Configuration Tool from the command line.
% sudo raspi-config
Use your cursor keys to move around and select Interfacing Options, then I2C, then Yes, then Ok to enable the I2C serial bus. Reboot if prompted. When done, select Finish to exit the program.
We also need to determine the I2C bus address that is being used for the sensor module. Many modules have a default I2C hexadecimal address of 0x68. To determine the address being used for your module, run the following command and jot down the address shown as we will need it later.
% sudo i2cdetect -y 1
68 (row 60, column 8) is displayed for me.
Writing The Software
There are an assortment of libraries and sample code available for connecting an MPU6050 sensor module to the Raspberry Pi using programming languages like C/C++ or Python. However, since I chose to use the Swift programming language for this tutorial, the only available option I found was the MPU-6050.swift library from Umberto Raimondi, the same author as the very popular SwiftyGPIO library. While this library is fully functional in its current form, it did not have some of the features that I wanted to include in this tutorial, so I forked and modified that library into my own library that I will use here.
Let’s begin by creating a new Swift Package Manager (SPM) project aptly named mpu6050.
% mkdir mpu6050 % cd mpu6050 % swift package init --type executable
Edit and save the Package.swift file to add the MPU-6050.swift library dependency so that it looks like the following.
// swift-tools-version:3.1 import PackageDescription let package = Package( name: "mpu6050", dependencies: [ .Package(url: "https://github.com/woolseyj/MPU-6050.swift.git", "3.0.0") ] )
Then fetch the library with the following command.
% swift package update
Next, edit and save the Sources/main.swift file to look like the following.
// mpu6050 - main.swift // // Description: // Retrieves motion data from an MPU6050 sensor module using the SwiftyGPIO and // MPU-6050.swift libraries. // // Created by John Woolsey on 08-10-2018. // Copyright © 2018 Woolsey Workshop. All rights reserved. import Foundation import SwiftyGPIO import MPU6050 // Sets MPU6050 offsets func setMPU6050Offsets(_ device: MPU6050, aX: Int, aY: Int, aZ: Int, gX: Int, gY: Int, gZ: Int) { print(String(format: "Old Offsets: aX = %5d, aY = %5d, aZ = %5d, gX = %5d, gY = %5d, gZ = %5d", arguments: [device.AccelOffsetX, device.AccelOffsetY, device.AccelOffsetZ, device.GyroOffsetX, device.GyroOffsetY, device.GyroOffsetZ])) device.AccelOffsetX = aX device.AccelOffsetY = aY device.AccelOffsetZ = aZ device.GyroOffsetX = gX device.GyroOffsetY = gY device.GyroOffsetZ = gZ print(String(format: "New Offsets: aX = %5d, aY = %5d, aZ = %5d, gX = %5d, gY = %5d, gZ = %5d", arguments: [device.AccelOffsetX, device.AccelOffsetY, device.AccelOffsetZ, device.GyroOffsetX, device.GyroOffsetY, device.GyroOffsetZ])) } // Initialize I2C bus guard let i2c = SwiftyGPIO.hardwareI2Cs(for:.RaspberryPi3)?[1] else { fatalError("Could not initialize I2C bus") } // Initialize MPU6050 sensor module // Uses default I2C address of 0x68. // Use MPU6050(i2c, address: 0x69) to set alternate address if needed. let mpu6050 = MPU6050(i2c) // MPU6050 sensor module handle mpu6050.enable(true) // Full-scale range settings mpu6050.AccelRange = .fs2g // set full-scale range to ±2g (default) mpu6050.GyroRange = .fs250ds // set full-scale range to ±250°/s (default) print("Accelerometer full-scale range: ", terminator:"") if let range = mpu6050.AccelRange { print(range.description) } else { print("unknown") } print("Gyroscope full-scale range: ", terminator:"") if let range = mpu6050.GyroRange { print(range.description) } else { print("unknown") } // Optionally update accelerometer and gyroscope data register offsets. // Offsets are reset to factory defaults when module is disconnected from power. // Use offset values obtained from running mpu6050_calibration program. // setMPU6050Offsets(mpu6050, aX: -906, aY: -83, aZ: 773, gX: 97, gY: 34, gZ: 20) print() while (true) { // Read raw accel/gyro/temp sensor readings from module let (ax,ay,az,t,gx,gy,gz) = mpu6050.getAll() // Convert raw register values to human readable values for default // ±2g accelerometer and ±250°/s gyroscope full-scale ranges let aX = Double(ax)/16384.0 let aY = Double(ay)/16384.0 let aZ = Double(az)/16384.0 let gX = Double(gx)/131.0 let gY = Double(gy)/131.0 let gZ = Double(gz)/131.0 // Print formatted results print(String(format: "aX = %4.1f g, aY = %4.1f g, aZ = %4.1f g, gX = %6.1f °/s, gY = %6.1f °/s, gZ = %6.1f °/s, T = %5.1f °C", arguments: [aX, aY, aZ, gX, gY, gZ, t])) sleep(1) // wait for one second }
Lines 11-13 load the libraries needed to communicate with the MPU6050 sensor module over the I2C bus.
Lines 32-34 initialize the I2C bus for use.
Lines 39-40 initialize and enable the MPU6050 sensor module for use. If the I2C bus address for your sensor module we determined previously is not the default value of 68, you can specify the address to use by adding the optional address
argument to the initialization, which becomes MPU6050(i2c, address: 0x69)
, and specifying the address for your display in place of the 0x69
shown here.
Lines 43-56 set and display the current full-scale range settings for the onboard accelerometer and gyroscope.
Line 61, in conjunction with lines 17-28 that define the setMPU6050Offsets()
function, will optionally update the accelerometer and gyroscope data register offset values along with displaying the old and new values. Uncomment this line and enter your own offset values if you have them. More on this later in the Calibrating The MPU6050 Sensor Module section.
Lines 64-82 loop through reading the raw sensor values, converting them to human readable values, and then printing the values every second.
Specifically, line 66 retrieves the accelerometer, temperature, and gyroscope sensor data from the MPU6050 module and places them into the ax
, ay
, az
, t
, gx
, gy
, and gz
variables respectively.
Since the full scale range of of the accelerometer is set to ±2g, the raw 16-bit register values are divided by 16384 (2^16 = 65,536 divided by ±2 = 4) to give us values in g. Likewise, the raw gyroscope values are divided by 131 (2^16 = 65,536 divided by ±250 = 500) to give us values in °/sec. These values are utilized within lines 70-75 to give us human readable values.
The formula for the temperature is already incorporated into the MPU-6050.swift library.
Lines 78-79 print the nicely formatted values to the screen.
Compile the new program with the SPM build command
% swift build
and then execute the program with the following.
% .build/debug/mpu6050
You should now see sensor readings being displayed to the screen like shown below.
Play around with the sensor module by moving it around in 3-D space and watching the different values being displayed.
Once your ready to exit the program, press CTRL-C on the keyboard to terminate it.
Calibrating The MPU6050 Sensor Module
If you are not seeing sensor values close to 0.0 for aX, aY, gX, gY, and gZ along with a value close to 1.0 for aZ while the module is lying flat on a table, you may need to calibrate the MPU6050 sensor module with new offsets for the onboard accelerometer and gyroscope data registers. This essentially “resets” the sensor readings to the current orientation of the module.
To calibrate the MPU6050 sensor module, place the module on a flat horizontal surface and leave the previous program running for 5-10 minutes in order for the module to reach a stable temperature. Then download the mpu6050_calibration project, created by yours truly, from GitHub and run it to calibrate your module.
% cd mpu6050_calibration % swift package update % swift build % .build/debug/mpu6050_calibration
When the program completes, you will be presented with your new offsets along with new human readable sensor readings using those new offsets as shown below.
With the calibration offsets set properly and the module lying on a flat surface, you should see acceleration values of around 0.0 g for the X and Y axes, 1.0 g for the Z axis, and around 0.0 °/sec for all rotational axes. If this is not the case, you may want to go through the calibration procedure again.
Once determined, these offsets can then be entered on line 61 of the previous mpu6050 program so that when it is run again in the future, you should see much more accurate sensor values.
Note, the mpu6050_calibration program does set the new offsets within the module for you, but they are reset to factory defaults when the sensor module is disconnected from power. This is why it is a good idea to include them in your program, if you have them, and care about the accuracy of your sensor readings.
Summary
In this tutorial we learned how to connect an MPU-6050 based accelerometer and gyroscope sensor module to a Raspberry Pi development board using the I2C bus interface, calibrate the module, and retrieve and display acceleration, rotation, and temperature sensor readings.
The final source code for this tutorial is located on GitHub.
Thank you for joining me in this journey and I hope you enjoyed the experience. Please feel free to share your thoughts in the comments section below.
Hi. I just wonder where this code write the accelomerer mpu6050 data for later view.
let say i install pu6050 my bicycle suspended front fork. and i would like to analyse data later. where I find it
The program currently only writes the data to the screen. You would have to write it to a file somewhere if you wanted to save the data for later analysis.
Have you tried to take the data you get and convert it into a 3d plot? I’m thinking that you know the acceleration, you can calculate the distance — A=delta D / delta T and solve for delta D. Then you can calculate the angle based on starting at an arbitrary 0deg, then applying the delta angle. This would, effectively give you polar notation which is pretty easy to convert to X, Y and Z points?
Or is it way more complicated than I’m thinking?
I have not tried that, but it sounds like an interesting exercise. Let us know if you get it working.