Ruido de aceleración/giroscopio de la MPU6050 que se comporta de forma extraña. ¿Qué podría estar provocando esto?

Estoy experimentando con un acelerómetro/giroscopio de seis ejes MPU6050 leyendo datos con una Raspberry Pi a través de I2C. La respuesta de seis ejes tiene sentido en general, ya que la giro con la mano, la rotación mueve el vector de gravedad correctamente según los canales del acelerómetro y las rotaciones cortas alrededor de cada eje generan valores de giroscopio que parecen razonables.

Pero cuando lo coloco en algo que debería aislarlo de las vibraciones y solo tomar datos durante mucho tiempo, veo un ruido extraño no estadístico en algunos canales.

Escribí un guión corto (que se muestra a continuación) que muestra los seis canales para 400 iteraciones, luego incrementa el filtro de paso bajo (siete niveles de a 0x00) 0x06y luego incrementa la ganancia tanto para aceleración como para giroscopio (cuatro niveles; 0x00, 0x08, 0x10, 0x18). Son 28 pruebas con 400 muestras cada una. La tasa de datos es de aproximadamente 55 a 60 mediciones de los seis ejes por segundo. La frecuencia característica para cada configuración del filtro de paso bajo digital del mapa de registro pdf es:

ingrese la descripción de la imagen aquí

y la ficha técnica en pdf .

A continuación muestro los datos que van desde -/+ 32.767. Lo único que he cambiado es restar la media de las 400 mediciones en cada configuración para que solo se muestre el ruido.

A medida que aumentan las siete configuraciones del filtro de paso bajo, la frecuencia disminuye y el ruido disminuye como se esperaba. Sin embargo, existen estos picos repentinos de +/- 200 a 300 recuentos de ADC. No son exactamente 256, pero en ese estadio de béisbol parece un poco sospechoso.

También muestro los datos sin procesar y las desviaciones estándar por prueba en la segunda gráfica.

Pregunta: ¿Este tipo de comportamiento, este ruido puntiagudo no estadístico, le parece familiar a alguien? Estoy esperando un segundo giroscopio para comparar, pero eso llevará muchos días y me gustaría ver si hay algo que pueda hacer mientras tanto. Cada uno de los seis canales tiene un comportamiento muy diferente al ruido. Dentro del IC hay seis dispositivos MEM separados, cada uno conectado a su propio ADC dedicado.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Script para que Raspberry Pi lea el módulo a través de 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()

Respuestas (2)

Los errores parecen +/- 256 +/- desviación esperada.

Esto sugiere algún tipo de error de sincronización, como leer el LSByte de una muestra y el MSByte de la siguiente o viceversa. ¿Cómo maneja esto su giroscopio? ¿Hay alguna forma de ponerlo en espera temporalmente mientras lee los datos?

Además, examine los datos sin procesar en torno a algunos de estos errores para ver si sucede cuando una señal que se desplaza lentamente cruza un límite de MSByte. Obviamente, concéntrese en el Y Gyro, los errores se separan más claramente del ruido.

¡Este es exactamente el tipo de información que esperaba! Puedo intentar mirar los datos sin procesar e intercambiar bytes a mano por algunos puntos de datos para ver qué efecto tiene. Dado que leer un byte a la vez como lo hago en el script de Raspberry Pi es totalmente asíncrono con el reloj de muestreo interno del chip, tengo la sensación de que esta no es la forma correcta de usar el dispositivo, y será mejor que aprenda más sobre cómo sincronizar el dos.
actualización: parece que el paquete RPi python smbustiene bus.read_word_data()métodos bus.read_i2c_block_data(), 1 , 2 . Lo intentaré y te comento que sucede.
No leeré hojas de datos ni daré detalles. Pero un enfoque es descubrir (sondeando un registro de estado) cuando una conversión ACABA de comenzar, dándote varios ms para leer la anterior. Otra es hacer que el R-PI le diga que comience, ... el mismo efecto. read_word_data puede o no ser "atómico" (término de búsqueda útil para la lectura de fondo)
¡Lo has clavado! El ruido aparente era exactamente lo que sugirió, emparejamiento asincrónico e incorrecto de bytes bajos y altos. Agregué una respuesta complementaria con la corrección y los nuevos datos, se ve mucho mejor. ¡Gracias!

@BrianDrummong identificó la fuente del aparente ruido en la respuesta aceptada . La lectura de un byte a la vez en I2C dio como resultado un comportamiento asíncrono, de modo que los bytes alto y bajo correspondían a diferentes conversiones. El uso bus.read_i2c_block_data()resolvió el problema de enganche. Al leer catorce bytes (siete palabras) (tres acelerómetros, temperatura, tres giroscopios) como una sola instrucción I2C, el "ruido" ha desaparecido.

def read_sevenblock():

    # read fourteen bytes starting at address 0x3b. This will cycle through
    # ax, ay, az, temp, gx, gy, and gz

    fourteen_bytes = bus.read_i2c_block_data(0x68, 0x3b, 14)  # Read them all at once

    his, los       = fourteen[0::2], fourteen[1::2]  # high bytes are first

    values = []
    for hi, lo in zip(his, los):
        value  = (hi << 8) + lo            # combine high and low byte
        if value >= 0x8000:
            value = -((65535 - value) + 1)   # convert signed negative values 
        values.append(value)
    return values

ingrese la descripción de la imagen aquí

¡Gracias por la solución! ¿Qué tenemos en la lista vals? ¿Está en el siguiente orden: acc_x, acc_y, acc_z, temp, gyro_x, gyro_y, gyro_z? ¿ Puede explicar también por qué lo usamos 0x3ben el comando? Pensé 0x3bque es solo el registro para la aceleración en la dirección x.
hola @hoangtran Aquí hay una respuesta rápida, actualizaré la publicación en un momento. La instrucción bus.read_i2c_block_data(0x68, 0x3b, 14)dice que lea 14 bytes a partir de 0x3b . Los ADC son de 12 bits, por lo que cada medida necesita dos bytes, para un total de 14 bytes. El orden es bits altos primero, luego bits bajos, por lo que debe combinar los dos con val = (hi << 8) + lo(¡Ajá! ¡Hay un error tipográfico en mi guión!) Por cierto, para una lectura constante de mayor velocidad, también hay un FiFo disponible. Si pregunta sobre eso en una pregunta separada, puedo publicar ese script.
¡excelente! ¡gracias! Haré una pregunta aparte. ¡Espero tener suficiente reputación para eso!
Hice esta pregunta ayer: raspberrypi.stackexchange.com/questions/92631/… ¿Tal vez puedas responderla usando FiFo? ¿O debería hacer una nueva pregunta con un tema específico de lectura de datos de MPU usando FiFo?
@hoangtran He publicado algo allí ahora, echa un vistazo.