Electronic – MPU6050 accel/gyro noise that behaves strangely – what might be doing this

accelerometerdebuggingnoise

I'm experimenting with an MPU6050 six-axis accelerometer/gyro reading data with a Raspberry Pi via I2C. The six-axis response makes sense in general as I rotate it by hand, rotating moves the gravity vector correctly per the accelerometer channels, and short rotations around each axis generate reasonable-looking gyroscope values.

But when I set it down on something that should isolate it from vibrations and just take data for a long time, I see strange non-statistical noise in some channels.

I wrote a short script (shown below) that samples all six channels for 400 iterations, then increments the low pass filter (seven levels from 0x00 to 0x06) and then increments the gain for both accel and gyro (four levels; 0x00, 0x08, 0x10, 0x18). So that's 28 tests with 400 samples each. The data rate is about 55 to 60 measurements of all six axes per second. The characteristic frequency for each setting of the digital low-pass filter from the register map pdf is:

enter image description here

and the data sheet pdf.

Below I show the data which ranges from -/+ 32,767. The only thing I've changed is to subtract the mean of the 400 measurements at each setting so just the noise is displayed.

As the seven low-pass filter settings increase, the frequency decreases and the noise decreases as expected. However, there are these sudden spikes of +/- 200 to 300 ADC counts. They are not exactly 256, but in that ballpark with seems slightly suspicious.

I also show the raw data and standard deviations per test in the second plot.

Question: Does this kind of behavior – this non-statistical, spiky noise – look familliar to anyone? I'm waiting on a second gyro to compare, but that will take many days, and I'd like to see if there is anything I can do in the mean time. Each of the six channels has a very different behavior wrt noise. Inside the IC there are six separate MEMs devices each connected to its own dedicated ADC.

enter image description here

enter image description here

Script for the Raspberry Pi to read the module via I2C:

#!/usr/bin/python

import web
import smbus
import math
import time

urls = ('/', 'index')

pwrmgmt_1 = 0x6b
pwrmgmt_2 = 0x6c

dlpf_set_addr    = 0x1a
gyro_scale_addr  = 0x1b
accel_scale_addr = 0x1c

scales = 0x00, 0x08, 0x10, 0x18
dlpfs  = 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06

pairs = ((0x3b, 0x3c), (0x3d, 0x3e), (0x3f, 0x40),
         (0x43, 0x44), (0x45, 0x46), (0x47, 0x48))

setups = []
for scale in scales:
    for dlpf in dlpfs:
        setups.append((scale, dlpf))
nsetups = len(setups)

bus = smbus.SMBus(1)

address = 0x68

ic       = 0
isetup   = 0
nsamples = 400

def read_six():
    vals = []
    for ahi, alo in pairs:
        high = bus.read_byte_data(address, ahi)
        low  = bus.read_byte_data(address, alo)
        val  = (high << 8) + low
        if val >= 0x8000:
            val = -((65535 - val) + 1)
        vals.append(val)
    return vals

class index:
    def GET(self):

        global ic, nsamples
        global isetup, nsetups, setups
        global accel_scale_addr, gyro_scale_addr, dlpf_set_addr

        six = read_six()
        six_str = str(six)[1:-1]

        ic += 1

        if not ic % nsamples:
            isetup += 1
            scale, dlpf = setups[isetup % nsetups]
            bus.write_byte_data(address, accel_scale_addr, scale)
            bus.write_byte_data(address, gyro_scale_addr,  scale)
            bus.write_byte_data(address, dlpf_set_addr,    dlpf)

        return six_str + ", " + str(isetup)

if __name__ == "__main__":

    # wake the 6050 up since it starts in sleep mode
    bus.write_byte_dta(address, pwrmgmt_1, 0)

    time.sleep(0.5)

    scale, dlpf = setups[isetup]

    bus.write_byte_data(address, accel_scale_addr, scale)
    bus.write_byte_data(address, gyro_scale_addr,  scale)
    bus.write_byte_data(address, dlpf_set_addr,    dlpf)

    print "setup scale: ", scale
    print "setup dlpf:  ", dlpf

    time.sleep(0.1)

    ic  = 0

    app = web.application(urls, globals())
    app.run()

Best Answer

Errors look like +/-256 +/- expected drift.

This suggests some kind of synchronising error - such as reading the LSByte of one sample and the MSByte of the next or vice versa. How does your gyro handle this, is there some way to temporarily put it on hold while you read data?

Also, examine the raw data around a few of these errors to see if it happens when a slowly drifting signal crosses an MSByte boundary. Obviously, focus on the Y Gyro, the errors are most clearly separated from the noise.