Giroscopio MEMS BMI055: picos altos aleatorios en los datos

Estoy usando el BMI055 en mi AVR a través de I2C.
Hoja de datos: http://ae-bst.resource.bosch.com/media/products/dokumente/bmi055/BST-BMI055-DS000-06.pdf

Lo configuré para salida filtrada a un ODR de 1000 Hz y lo sondeé cada 1005us.
Lo configuré a una sensibilidad de 1000 grados / s, a una salida de 16 bits. Eso da 32,8 LSB/grado.
Estoy leyendo los valores del FIFO en modo de derivación.

Ahora, para probar, tengo una función que hace lo siguiente (pseudo):

dt = microseconds passed since last call (around 1000)
scale = 1/32.8/1000000;
deltaANGLE[axis] = dt * scale;
static sum[axis] += deltaANGLE[axis];
Every 1000 calls:
{
   print the sums[] to serial;
   sum[axis]=0;
}

Habría esperado un poco de ruido y deriva durante 1 segundo (1000 muestras), pero obtengo un valor de compensación de -3 a -11 en los 3 ejes cuando lo tengo en la mesa fija.
Además, los valores cambian mucho, incluso una corrección promedio no ayudaría mucho.

Time dif 995 us
Angles: -9.944047 -9.904691 -10.001564
Time dif 1003 us
Angles: -9.846170 -9.824638 -9.923825
Time dif 998 us
Angles: -5.871545 -5.805600 -5.935478
Time dif 1005 us
Angles: -8.871223 -9.628742 -8.884630
Time dif 1009 us
Angles: -8.874594 -8.875291 -8.956609
Time dif 1007 us
Angles: -5.902205 -5.916657 -5.970954

También me desconcertó que los tres ejes muestren siempre el mismo desplazamiento extraño.
Al mover el tablero dentro del segundo de integración, muestra 'aproximadamente' el cambio correcto (=-15 grados del valor esperado)

Creo que hago algo mal pero no encuentro el problema.

Addon1: Acabo de descubrir que aumentar el tiempo de mi rutina de sondeo reduce significativamente el error. Tengo el ODR configurado a 1000 Hz, si tiro a 500 Hz obtengo poco ruido y un resultado bastante preciso. Aunque debería significar que el sensor está saturado el 50% del tiempo y espera mi encuesta. ¿Puede ese ruido ser el resultado de un problema entre mi sondeo y la configuración de ODR/ancho de banda de los sensores?

Addon2: Otras horas desperdiciadas. Experimenté con varias configuraciones relacionadas con la tasa de sondeo y el ODR/ancho de banda del sensor.
Cuando sondeo más rápido que ODR, obtengo valores completamente locos del FIFO,
la hoja de datos dice que debería dar valores CERO. veces más rápido que la tasa de muestreo.
Cuando sondeo más lento que la frecuencia de muestreo, obtengo mejores valores, pero el ángulo Y salta esporádicamente a -3 grados cada pocos segundos (todavía se acumula, ahora 2 segundos). El eje Z es bastante estable, después de unos minutos de acumulación total muestra un desplazamiento de 7 grados. El eje X muestra alrededor de 36. El eje Y -133 grados.

No puedo pensar en una forma de compensar picos tan repentinos, no es una compensación general. Mi conclusión actual es que el chip en sí es malo. (?)

Actualización con código real: Inicialización:

    data[0]=0x0F;data[1]=0b000; //001 = 1000deg/sec,000 =2000
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x10;data[1]=0b0011; // 0011 = 400hz odr 2khz = 0001. decimation factor 2, odr 1000hz (1k=0b0010)
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x13;data[1]=0b0; // filter 1, shadow 1
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x15;data[1]=0b0; // all interrupts off
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x15;data[1]=0b0; // all interrupts off
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x3E;data[1]=0b00; // FIFO bypass und XYZ modus
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);


    data[0]=0x31;data[1]=0b11101111; // try to run offset comp
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_ms(1300);    



    data[0]=0x15;data[1]=0b10000010; // auto offset  .. doesnt help
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 2 );
    _delay_us(5);

    data[0]=0x00;
    error += twiSend( ACC_BM055_ADDR_GYRO, data, 1 );   
    error += twiReceive( ACC_BM055_ADDR_GYRO, result, 1 );
    if (result[0] != 0b00001111) error+=32;

    if (error == 100) error=0;
    return error;
}

Estoy sondeando el búfer FIFO para 6 bytes (lectura en ráfaga desde la dirección 0x3F) usando un temporizador que golpea cada n microsegundos.
Tan pronto como he recibido los 6 bytes sucede esto:

uint8_t axis;
float scale, deltaGyroAngle[3];
static uint16_t time_last;
uint16_t time_now = get_micros(); 

scale = (time_now - time_last) * GYRO_TO_RAD_FACTOR; // gyro * dt


for (axis = 0; axis < 3; axis++) 
{
    deltaGyroAngle[axis] = attitude.gyro_raw[axis]  * scale; 
}


static float sum[3];
static uint16_t counter;
sum[0] += deltaGyroAngle[0];
sum[1] += deltaGyroAngle[1];
sum[2] += deltaGyroAngle[2];
if (counter++==1000) // at current 400hz it hits once per 2.5 sec, at 1000hz it hits once per second
{
    WRITE("\n\nTime dif %u us\n",time_now-time_last);
    WRITE("\nWinkelsnapshot: %f %f %f\n",(sum[0]),(sum[1]),(sum[2]));uart_wait_rx0_empty();
// This shows that Z is stable
// X is slightly unstable
// Y has random -3.5 degree per second spikes (in 1000hz mode -7)
    //sum[0]=0;
    //sum[1]=0;
    //sum[2]=0;
    counter=0;
}
time_last = time_now;

Otra actualización, esta vez más cerca de la fuente:
escribí una rutina promedio para encontrar un sesgo, estoy probando el chip cada 2800 us.
El ODR está configurado en 400 HZ, por lo que 2500 us sería la tarifa mínima.
Los resultados generales son muy buenos, muestra una compensación promedio de cero sobre 1000 muestras.
Pero cada 1-2 segundos obtengo un gran pico en uno de los valores, cerca de la lectura máxima.
El sensor se comporta como si recibiera una patada repentina en dos milisegundos, pero simplemente está sentado sobre la mesa.
Aquí los valores en formato de 16 bits firmado y sin firmar:

Sampled 00001 -0001 00005        00001 65535 00005
Sampled 00001 00000 00002        00001 00000 00002
Sampled 00001 00001 00000        00001 00001 00000
Sampled 00001 00000 00001        00001 00000 00001
Sampled -0001 -0001 00001        65535 65535 00001
Sampled 00001 00000 00000        00001 00000 00000
Sampled 00003 00006 -0001        00003 00006 65535
Sampled 00001 00007 00000        00001 00007 00000
Sampled 00000 00004 00002        00000 00004 00002
Sampled 00001 00000 00002        00001 00000 00002
Sampled 00003 -0001 00001        00003 65535 00001
Sampled 00003 00001 00001        00003 00001 00001
Sampled 00002 00000 00001        00002 00000 00001
Sampled 00002 -18497 -0001       00002 47039 65535   <-----
Sampled -0002 00002 -0002        65534 00002 65534
Sampled 00000 -0001 00000        00000 65535 00000
Sampled 00000 00001 00000        00000 00001 00000
Sampled 00000 00002 -0001        00000 00002 65535
Sampled 00001 00001 -0003        00001 00001 65533
Sampled 00003 -0001 -0002        00003 65535 65534
Sampled 00004 -0001 00001        00004 65535 00001
Sampled 00003 -0001 00002        00003 65535 00002
Sampled 00002 -0004 00000        00002 65532 00000
Sampled 00003 -0003 00000        00003 65533 00000
Sampled 00002 00000 00000        00002 00000 00000
Sampled 00001 00001 00001        00001 00001 00001
Sampled 00002 00000 00002        00002 00000 00002

Puede ver que los valores son realmente bajos con la excepción de un pico de -18497.
Si reduzco el retraso entre las muestras, estos picos se vuelven más frecuentes.

De hecho, empiezo a creer que hago todo bien y que Bosch tiene un problema con su chip BMI055 o que este único chip es una locura.

Una posible solución en la que pensé sería dejar que todo el algoritmo del sensor se retrasara un cuadro (alrededor de 2500 us) e ignorar por completo un pico repentino de 1 ms. Pero agregaría bastante retraso en la respuesta a mi proyecto. Un filtro de paso bajo digital también podría hacer un buen trabajo con menos demora, pero un pico de 0 a 16000 (y también he visto 32k) tendrá un impacto en toda la lectura.

ojala un experto me pueda iluminar

Creo que tendrá que mostrarnos su código real, porque el pseudocódigo no tiene mucho sentido. ¿Dónde se utilizan los valores reales del sensor?
Actualicé mi pregunta y agregué las partes de código relevantes. Mostré la rutina de inicio y la parte de cálculo de datos. Toda la parte debe usarse para equilibrar un dron de vuelo en el aire, ahora mismo solo me estoy asegurando de que los sensores funcionen de manera estable antes de continuar fusionándolos.

Respuestas (2)

Editar: Encontré la causa de los picos. El chip BMI055 tiene fallas internas, ahora estoy seguro. Si lee el FIFO en modo Bypass (eso significa que solo se conserva un cuadro), entonces debe esperar errores de datos. Si lo lee más rápido que la frecuencia de muestreo, recibe un 10 % de 0x8000 (el número más pequeño posible) en la mezcla. Ni cero, ni el último valor.. un valor MÁXIMO!

Si lee los datos un poco más lento que la frecuencia de muestreo, recibirá datos válidos con 1-8 picos por segundo.

Esto sucede si usa el registro FIFO en modo de ráfaga de 6 u 8 bytes.
Ahora tengo curiosidad, leí el registro 0x02 en una ráfaga de 6 bytes y esto da los mismos datos (x, y, z) y no cambié absolutamente nada más.
Los picos se han ido.


texto anterior:

Parece que el giroscopio en sí tiene fallas y no es solo ese.

Primero esperaba un error en la comunicación I2C, bajé la velocidad e intercambié el circuito de cambio de voltaje sin ningún cambio en los resultados.

Ahora que identifiqué que el problema provenía de picos altos aleatorios, también pude encontrar muchas otras personas con problemas o informes similares.
Un hecho sorprendente es que rara vez hay respuestas.

Mi primera prueba fue un filtro de promedio exponencial móvil, pero como esperaba, arruina muchas lecturas posteriores y solo amortigua los picos.

La mejor solución que se me ocurre es usar dos giroscopios, eso es lo que haré a largo plazo. Es probable que ambos tengan picos y al comparar ambos marcos entre sí, debería ser posible obtener un resultado muy bueno y sin picos.

La solución simple es filtrar los picos en función de un valor de cambio máximo codificado.
Primero consideré capturar datos al doble de la velocidad actual y luego siempre retrasarme un cuadro.
De esa manera, sabría el 'futuro' y el pasado, si los datos 'actuales' están muy lejos del futuro y el pasado, es un pico (o alguien golpeó un martillo en el sensor).

Pero para giroscopios con resolución de alto grado/s y uso práctico fuera de 2000 grados/seg, el filtrado puede ser más fácil.
Jugué y sacudí fuertemente el giroscopio, los valores brutos rara vez excedían los +10k y no importaba lo que hiciera, no tenían cambios tan repentinos, incluso durante una caída sobre la mesa.
Yo uso esto ahora:

if (abs(old-current)>0x3000) use_value();

Entonces, si el resultado está fuera de más de 12,000 valores sin procesar en comparación con el valor anterior, el valor anterior permanecerá en la variable. De lo contrario, la variable se actualiza con el nuevo valor.

Ahora tengo una deriva bastante baja que incluso funciona durante muchos minutos.

Notas al margen sobre el giroscopio usado:
a) El giroscopio BMI055 está especificado para devolver CERO si lo muestrea demasiado rápido, en realidad devuelve valores aleatorios. b) El giroscopio BMI055 bloquea el bus I2C si le envía un soft_reset (el ACC en chip no hace eso) c) Los picos repentinos no se describen en las hojas de datos de los giroscopios y aún así muchas personas los notan. Eso es bastante extraño.

Agradecería una mejor respuesta, tal vez me equivoque.
Sin embargo, la filtración de picos hizo que mi programa funcionara de manera bastante confiable en comparación con los resultados inutilizables anteriores.

Información adicional para el sensor de aceleración y giroscopio BMI055:

También tengo picos altos aleatorios en los datos convertidos y encontré la razón .
Configuración:

  • ACC: ancho de banda 250 Hz = 500 Hz ODR, modo FIFO STREAM e interrupción de marca de agua habilitados, marca de agua = 60 = 10 tramas de datos, medición para todos los ejes
  • GYR: ODR de 400 Hz, modo FIFO STREAM e interrupción de marca de agua habilitada, marca de agua = 60 = 10 marcos de datos, medición para todos los ejes
  • El microcontrolador lee los datos del sensor (exactamente 10 cuadros) a través de SPI cuando se activan las interrupciones y los convierte en datos enteros de 16 bits

Problema:
a veces, aleatoriamente, los paquetes de datos leídos se llenan con ceros, lo que crea picos altos en el gráfico de datos de medición

Motivo:

  • en la hoja de datos de BMI055: Si se lee FIFO más allá del nivel de llenado de FIFO, se leerán ceros (0). -> esto no debería suceder con la configuración nombrada porque la interrupción de marca de agua FIFO solo se activa cuando hay suficientes datos en FIFO
  • ¡¡¡Pero!!! la interrupción de la marca de agua FIFO se activa nuevamente cuando se lee el PRIMER cuadro y cuando en este momento (o algunos segundos después) el sensor adquiere el siguiente paquete de datos, lo que significa que almacena un nuevo cuadro en el FIFO --> entonces la condición de la marca de agua es completado durante la lectura de SPI y se activa la interrupción -> así que después de leer los 10 cuadros, el microcontrolador vuelve a leer inmediatamente 10 cuadros pero no se han adquirido suficientes datos --> se leen ceros

Solución:
  • cuando se activa la interrupción de la marca de agua -> deshabilite la interrupción en el microcontrolador antes de leer el FIFO sobre SPI
  • vuelva a habilitar la interrupción en el microcontrolador después de que finalice la lectura FIFO -> los datos ahora están bien
También interesante, probablemente relacionado con mi problema también. Ya cambié al BMX055. En general, ya encontré bastantes problemas con el chip bosch, incluidos errores en la hoja de datos y decisiones extrañas que tomaron. Además, su soporte no existe, los correos electrónicos no se responden en absoluto. Si no está utilizando el FIFO, la solución más simple es evitar esa bestia en general, la lectura de los registros no está causando tales problemas en absoluto.