Home

Awesome

upy-motion

An MPU6050 driver written in micropython. This driver should be compatible with any micropython device. This driver does not support quaternion

Features:

  1. Auto-calibration if the ofs argument is omitted
  2. After auto-calibration the ofs argument is supplied to you
  3. Automatic FIFO if an interrupt pin and callback are supplied
  4. Kalman and complimentary filters are built in and automatically applied to data based on flags you set
  5. Data can be retrieved as raw gyroscope and accelerometer data or as angles (roll, pitch only)
  6. Temperature can be retrieved as Celsius or Fahrenheit
  7. Numerous print options available that format the data into a very neat and easy-to-read display
  8. Self-test is built in and using just one property will tell you if your device is functioning properly
  9. Everything you can do is well-documented below

Community:

To officially file a bug report or feature request you can use these templates: bug report | feature request

To discus features, bugs or share your own project that utilize code in this repo: join the discussion

<br />
<br />

Ports:

MPU6050.py

This can be uploaded directly to the board, but is intended to be used as a frozen module. For information regarding how to setup the sdk and freeze a module you can refer to this post on the Raspberry Pi forum.

MPU6050.mpy

This is a cross-compiled version of MPU6050.py. It is intended to be uploaded to your board as you would any normal .py script.

<br />
<br />

Docs:

MPU6050(bus, sda, scl, ofs, intr, callback, angles, clock, gyro, accel, dlpf, rate, filtered, anglefilter, R, Q, A, addr, freq)

The argument for this constructor may seem daunting, but it can be broken up into sections that make it far easier to manage. From bus through scl sets up I2C connection with the device. ofs is the configuration offsets that help your device function accurately. Examples are provided later in this document that explain how to get this value. From intr through angles are interrupt related and only used if you want to use FIFO. From clock through rate are device specific settings. From filtered through A are filter specific settings. addr and freq are the device address and the frequency it should run at. There is very little reason why you should ever have to change these, which is why they are the very last arguments.

Most things are evidenced later in this document, but there are a couple of things that are easier to simply explain right here. Providing an interrupt pin and a callback will automatically trigger the script to use FIFO. The rate argument has 2 purposes. Whatever value you supply will be the divisor for gyroscope clock output, which is it's main intended purpose. However, my driver also uses half of this number to determine how many samples to average when using a complementary filter.

ArgTypeDescriptionDefault
busintI2C bus idREQUIRED
sdaint or Pindata pinREQUIRED
sclint or Pinclock pinREQUIRED
ofstupleaxis offsetsNone
intrint or Pininterrupt pin (FIFO only)None
callbackfunctionfunction to call on interrupt (FIFO only)None
anglesintreturn angles instead of data (FIFO only)False
clockintclock source to useCLK_PLL_XGYRO
gyrointgyroscope full scale rangeGYRO_FS_500
accelintaccelerometer full scale rangeACCEL_FS_2
dlpfintdigital low-pass filterDLPF_BW_188
rateintsample rate4
filteredintwhich properties to filterNONE
anglefilterintwhich filters to apply to anglesNONE
RfloatKalman filter measure0.003
QfloatKalman filter bias0.001
Afloatcomplementary filter alpha.8
addrintdevice I2C address0x68
freqintI2C frequency400000
<br />
<br />

Constants:

<br />

clock

Possible values for the clock constructor argument are the following. The default clock is CLK_PLL_XGYRO. The documents recommend that you use one of the gyro clocks. All clocks (except external) have their typical frequency listed. Actual frequency may vary +/- 3 Khz.

ConstValueFrequency
CLK_INTERNAL0x008 Mhz
CLK_PLL_XGYRO0x0133 Khz
CLK_PLL_YGYRO0x0230 Khz
CLK_PLL_ZGYRO0x0327 Khz
CLK_PLL_EXT32K0x0432.768 Khz
CLK_PLL_EXT19M0x0519.2 Mhz
CLK_KEEP_RESET0x070
<br />

gyro

Possible values for the gyro constructor argument are the following. The default gyro is GYRO_FS_500.

ConstValue
GYRO_FS_2500x00
GYRO_FS_5000x01
GYRO_FS_10000x02
GYRO_FS_20000x03
<br />

accel

Possible values for the accel constructor argument are the following. The default accel is ACCEL_FS_2

ConstValue
ACCEL_FS_20x00
ACCEL_FS_40x01
ACCEL_FS_80x02
ACCEL_FS_160x03
<br />

dlpf

Possible values for the dlpf constructor argument include the following. The default dlpf is DLPF_BW_188. Headers marked ms below represent the milliseconds of delay a DLPF will create.

ConstValueAccel(ms)Gyro(ms)FS (Khz)
DLPF_BW_2560x0000.988
DLPF_BW_1880x012.01.91
DLPF_BW_980x023.02.81
DLPF_BW_420x034.94.81
DLPF_BW_200x048.58.31
DLPF_BW_100x0513.813.41
DLPF_BW_50x0619.018.61
<br />

filtered

Possible values for the filtered constructor argument include the following. The default filter is NONE. Applying one or more of these flags tells the driver which data to filter. For accel and gyro Kalman filters will be applied. For angles another flag must be used to determine which filters you want applied.

FlagValue
NONE0x00
FILTER_ACCEL0x01
FILTER_GYRO0x02
FILTER_ANGLES0x04
FILTER_ALL0x07
<br />

anglefilter

Possible values for the anglefilter constructor argument include the following. The default anglefilter is NONE.

FlagValue
NONE0x00
ANGLE_KAL0x01
ANGLE_COMP0x02
ANGLE_BOTH0x03
<br />
<br />

Properties:

<br />

.device_id

The id of the device

<br />

.connected

True or False device is connected

<br />

.data

Returns gyroscope and accelerometer data. This data may be filtered with a Kalman filter if the appropriate flag is supplied to the filtered argument in the constructor. The filters section contains more information on how to use filters. This is a namedtuple with the following fields

FieldTypeDescription
.acc_xfloataccelerometer x
.acc_yfloataccelerometer y
.acc_zfloataccelerometer z
.gyro_xfloatgyroscope x
.gyro_yfloatgyroscope y
.gyro_zfloatgyroscope z
<br />

.angles

Returns angles concocted from accelerometer data. These angles may be filtered (with Kalman, complementar or both) according to the flag supplied for the anglefilter argument in the constructor. The filters section contains more information on how to use filters. This is a namedtuple with the following fields

FieldTypeDescription
.rollfloatroll angle
.pitchfloatpitch angle
<br />

.int_angles

Returns angles concocted from accelerometer data as ints. These angles may be filtered (with Kalman, complementar or both) according to the flag supplied for the anglefilter argument in the constructor. The filters section contains more information on how to use filters. This is a namedtuple with the following fields

FieldTypeDescription
.rollintroll angle
.pitchintpitch angle
<br />

.passed_self_test

True or False passed system self-test

<br />

.celsius

Returns the temperature in Celsius

<br />

.fahrenheit

Returns the temperature in Fahrenheit

<br />
<br />

Methods:

<br />

.start()

If an interrupt pin and callback were supplied to the constructor, this will start FIFO interrupts

<br />

.stop()

If an interrupt pin and callback were supplied to the constructor, this will stop FIFO interrupts

<br />

.print_data()

Prints the gyroscope and accelerometer data with any flagged filters automatically applied. The filters section contains more information on how to use filters.

<br />

.print_from_data(data:tuple)

Prints the gyroscope and accelerometer data that was passed to it

<br />

.print_angles(asint:bool=False)

Prints the roll and pitch angles with any flagged filters automatically applied. If asint is True angles will be gathered from .int_angles. The filters section contains more information on how to use filters.

<br />

.print_from_angles(angles:tuple)

Prints the angle data that was passed to it

<br />

.print_celsius()

Prints the temperature in Celsius

<br />

.print_fahrenheit()

Prints the temperature in Fahrenheit

<br />

.print_offsets()

Prints the offsets as a line of code to be used as the ofs argument when instantiating MPU6050

<br />

.print_all()

Prints everything except offsets

<br />
<br />

Usage

All the below examples can be copy/pasted, but you must make sure to provide the bus, sda and scl pins (or pin numbers) that apply to your wiring scheme. If an interrupt pin or calibration offsets are used in an example, those too must be replaced with the data that applies to you.

<br />

calibration

The very first thing you should do is calibrate the device. When it completes it will print a small line of code that you need to copy and paste for use with the ofs argument. Failure to provide an ofs argument will result in your device auto-calibrating every time you instance it. Make sure your device is as flat and level as you can get it before running calibration. Only run calibration from a fresh power-up of the device. If you do a good job calibrating, the numbers this returns can be used constantly, and you should not need to calibrate again unless you customize any of the device configuration arguments (ie. clock, dlpf, rate, gyro or accel). If you do intend to change any of the configuration arguments, you should add those changes to the script below before running it.

from mpu6050 import MPU6050

MPU6050(1, 6, 7)
<br />

FIFO

Supplying an interrupt pin and a callback will trigger the driver to use FIFO automatically. You must also call start() for interrupts to begin. The data argument in the handler will contain all of the accelerometer and gyroscope data, unless you set the angles constructor argument to True, in which case data will then contain angles values.

from mpu6050 import MPU6050

def handler(data:tuple):
    if 'mpu' in globals():
        print('[{:<16}] {:<10.2f}'.format('TEMPERATURE', mpu.fahrenheit))
        mpu.print_from_data(data)

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51), 2, handler)
if mpu.passed_self_test:
    mpu.start()
<br />

polling

If an interrupt pin and callback are not supplied the driver assumes you want to manage your own polling

from mpu6050 import MPU6050
import utime

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51))

if mpu.passed_self_test:
    while True:
        print('[{:<16}] {:<10.2f}'.format('TEMPERATURE', mpu.fahrenheit))
        mpu.print_data()
        utime.sleep_ms(100)
<br />

accessing data

data is a namedtuple and can be used like any other namedtuple. You can either unpack the properties or use them directly. The below examples illustrate both of these methods.

from mpu6050 import MPU6050
import utime

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51))

if mpu.passed_self_test:
    while True:
        ax, ay, az, gx, gy, gz = mpu.data

or

from mpu6050 import MPU6050

def handler(data:tuple):
    if 'mpu' in globals():
        asum = data.acc_x  + data.acc_y  + data.acc_z
        gsum = data.gyro_x + data.gyro_y + data.gyro_z

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51), 2, handler)
if mpu.passed_self_test:
    mpu.start()
<br />

angles

angles are handled no different than data

from mpu6050 import MPU6050

def handler(data:tuple):
    if 'mpu' in globals():
        roll, pitch = mpu.angles

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51), 2, handler)
if mpu.passed_self_test:
    mpu.start()

just like data, angles has its own print method, as well

from mpu6050 import MPU6050
import utime

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51))

if mpu.passed_self_test:
    while True:
        mpu.print_angles()
        utime.sleep_ms(100)

when using fifo you can tell the script to send angles instead of axis data to the handler callback by setting the angles constructor argument to True

from mpu6050 import MPU6050

def handler(data:tuple):
    if 'mpu' in globals():
        roll, pitch = data
        mpu.print_from_angles(data)

mpu = MPU6050(1, 6, 7, (1314, -1629, 410, 28, -17, 51), 2, handler, True)
if mpu.passed_self_test:
    mpu.start()

<br />

filters

This driver supports 2 different types of filters (Kalman and complementary). Complementary filters can only be applied to angles. If a complementary filter is flagged on angles it will return the average of all the samples taken. The amount of samples that are taken will be half of the rate argument that was supplied to the constructor.

from mpu6050 import MPU6050, FILTER_GYRO, FILTER_ANGLES, ANGLE_COMP

def handler(data:tuple):
    if 'mpu' in globals():
        mpu.print_from_angles(data)
        
cfg = dict(
    rate        = 20,                          #MPU6050_SPLRTDIV ~ comp filter samples at half of this number
    filtered    = FILTER_GYRO | FILTER_ANGLES, #wont filter accelerometer raw readings
    anglefilter = ANGLE_COMP,                  #apply only complementary filter to angles
    angles      = True                         #send data to handler as angles
)
mpu = MPU6050(1, 6, 7, (1368, -1684, 416, 20, -6, 49), 2, handler, **cfg)

if mpu.passed_self_test:
    mpu.start()