MPU6050 freezing/crashing

I am using a really simple code to read data from MPU6050. The problem is that sometimes I need to use delay(100); and MPU6050 does not look to like that.

I discovered that my arduino freezes at the line:

mpuIntStatus = mpu.getIntStatus();

Is there someway to prevent that?

I am using the standard code of MPU6050.

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;
uint8_t mpuIntStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
volatile bool mpuInterrupt = false;
void dmpDataReady() {mpuInterrupt = true;}

void setup() {

    Wire.begin();
    TWBR = 24;
    mpu.initialize();
    mpu.dmpInitialize();
    mpu.setXAccelOffset(-1343);
    mpu.setYAccelOffset(-1155);
    mpu.setZAccelOffset(1033);
    mpu.setXGyroOffset(19);
    mpu.setYGyroOffset(-27);
    mpu.setZGyroOffset(16);
    mpu.setDMPEnabled(true);
    attachInterrupt(0, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();
    packetSize = mpu.dmpGetFIFOPacketSize();

    Serial.begin(115200);

}

void loop() {

    while (!mpuInterrupt && fifoCount < packetSize) {

		//Sometimes I use a delay here.
           delay(15);

    }

    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        mpu.resetFIFO();
        //COMENTAR_OFICIAL
        Serial.println(F("FIFO overflow!"));
    }
    else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        
        //COMENTAR_OFICIAL
        Serial.print("ypr\t");
        Serial.print(ypr[0]*180/PI);
        Serial.print("\t");
        Serial.print(ypr[1]*180/PI);
        Serial.print("\t");
        Serial.print(ypr[2]*180/PI);
        Serial.println();

    }

}

Discovered the same problem. I ended up re-coding and simplifying the example with success
The
void GetDMP() {
function has the resolution to the lockup issues you are facing.
note that I simplified the loop() and removed all the DMP code to functions.
I documented it well and hope you and others can avoid my headaches.

Please if you find additional fixes or improvements please let me know this is a work in progress for me as well

p.s. about your delay(100) look at this alternative way to do that :slight_smile:
look for it in the example attached

  static long QTimer = millis();
  if ((long)( millis() - QTimer ) >= 100) {
    QTimer = millis();
    Serial.print(F("\t Yaw")); Serial.print(Yaw);
    Serial.print(F("\t Pitch ")); Serial.print(Pitch);
    Serial.print(F("\t Roll ")); Serial.print(Roll);
    Serial.println();
  }
}

MPU6050_Test_Code.ino (9.56 KB)

Thank you so much! I see your code and it's looks promising! But it still relies on getIntStatus() function which is causing the problem I am facing.

Your code is good and IMHO you should change:

if (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available GetDMP(); // Gets the MPU Data and canculates angles }

to

while (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available GetDMP(); // Gets the MPU Data and canculates angles }

This way, if you read the fifo and there is still an item there, you can read it again and prevent overflow!

Thank you I have looked into your concerns and have solutions.

batata004:
Thank you so much! I see your code and it’s looks promising! But it still relies on getIntStatus() function which is causing the problem I am facing.

The first item is the getintStatus()

  fifoCount = mpu.getFIFOCount();
  uint16_t MaxPackets = 20;// 20*42=840 leaving us with  2 Packets (out of a total of 24 packets) left before we overflow.
  if ((fifoCount % packetSize) || (fifoCount > (packetSize * MaxPackets)) || (fifoCount < packetSize)) { // we have failed Reset and wait till next time!
    digitalWrite(LED_PIN, LOW); // lets turn off the blinking light so we can see we are failing.
    Serial.println(F("Reset FIFO"));
     mpuIntStatus = mpu.getIntStatus(); // reads MPU6050_RA_INT_STATUS       0x3A  

    mpu.resetFIFO();// clear the buffer and start over
    mpu.getIntStatus(); // make sure status is cleared we will read it again.
  } else {
    while (fifoCount  >= packetSize) { // Get the packets until we have the latest!
      if (fifoCount < packetSize) break; // Something is left over and we don't want it!!!
      mpu.getFIFOBytes(fifoBuffer, packetSize); // lets do the magic and get the data
      fifoCount -= packetSize;
    }
    if (!Startup) MPUMath(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<< On success MPUMath() <<<<<<<<<<<<<<<<<<<
    digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink the Light
    if (fifoCount > 0) mpu.resetFIFO(); // clean up any leftovers Should never happen! but lets start fresh if we need to. this should never happen.
  }

I removed most of my notes so I could keep the explanation simple:
I do not use getIntStatus(); to test for a good packet or accept a failure i only use the fifoCount which will tell me everything i need to know

 if ((fifoCount % packetSize) || (fifoCount > (packetSize * MaxPackets)) || (fifoCount < packetSize)) { // we have failed Reset and wait till next time!
// you can remove everything here it is only error messages to diagnose connection problems.  
  mpu.resetFIFO();// clear the buffer and start over <<<< only line that is required.
 //  mpu.getIntStatus(); // make sure status is cleared we will read it again. << redundant but I put it there just in case... You can remark it out not needed
  } else {// Get the packets until we have the latest!

Everything except resetFIFO(); can be removed, I only get the getIntStatus(); to see what the MPU6050 thinks the problem is

As for this concern

Your code is good and IMHO you should change:

if (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available
GetDMP(); // Gets the MPU Data and canculates angles
}

to

while (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available
GetDMP(); // Gets the MPU Data and canculates angles
}

This way, if you read the fifo and there is still an item there, you can read it again and prevent overflow!

I capture all the packets or I throw everything away always each trip around.
The MPU6050 with the included #include “MPU6050_6Axis_MotionApps20.h” with no changes to the .h file will generate a interrupt approximately every 10 milliseconds 100hz.
using “while” instead of “if” as far as i can tell will make no difference unless the code in the GetDMP() takes longer than 10 milliseconds and then we will have other problems.
As for the getting everything from the FIFO buffer this is accomplished in the GetDMP() function. and for the most part shouldn’t loop.

    while (fifoCount  >= packetSize) { // Get the packets until we have the latest!
      if (fifoCount < packetSize) break; // Something is left over and we don't want it!!!
      mpu.getFIFOBytes(fifoBuffer, packetSize); // lets do the magic and get the data
      fifoCount -= packetSize;
    }

For my robot I only need the most recent value anything that is old will only give me grief. so I throw it away and only keep the last one.
Now with that said my code has no issues keeping up with the 10 Millisecond 100Hz window and so I never have more than 1 packet there to get. only during startup does this come into play.
so if you need more than 10 Milliseconds you can alter the MPU6050_6Axis_MotionApps20.h to cause a longer delay between interrupts
look for this code it is on line 305 of MPU6050_6Axis_MotionApps20.h file

    0x02,   0x16,   0x02,   0x00, 0x01                // D_0_22 inv_set_fifo_rate

    // This very last 0x01 WAS a 0x09, which drops the FIFO rate down to 20 Hz. 0x07 is 25 Hz,
    // 0x01 is 100Hz. Going faster than 100Hz (0x00=200Hz) tends to result in very noisy data.
    // DMP output frequency is calculated easily using this equation: (200Hz / (1 + value))

    // It is important to make sure the host processor can keep up with reading and processing
    // the FIFO output at the desired rate. Handling FIFO overflow cleanly is also a good idea.

note: that the instructions tell you how to adjust it down to 20Hz from the default 100Hz
save and compile and now you have more time between interrupts to do stuff.

Nice, now I read again your code and I could understand it much better.

It works, indeed :slight_smile: But I would like to check with you somethings:

  1. why do you use “(fifoCount % packetSize)” AND “fifoCount < packetSize” in the same conditional? As I see “(fifoCount % packetSize)” will always be true if “fifoCount < packetSize” so you would not need “fifoCount < packetSize” in the conditional right?

  2. when you execute “MPUMath();” you cannot be sure that you indeed received a packet. In the “while” loop right above the “MPUMath()” there is a “break” condition, if that “break” condition is hit right in the first time the loop is executed, then “MPUMath();” will have no new data to play with;

  3. why do you use “fifoCount < packetSize” in the conditional? This should never happen right? Anyway, you use this code in the conditional and also another time when you use “break”. If it hit in the conditional it should not need the “break” later correct?

  4. why do you store fifoCount and keep updating it as you read the FIFO? Why dont you just use mpu.getFIFOCount() everytime? This value will always be updated, correct?

  5. why do you think fifo only holds 24 packets?

  6. why fifoBuffer[64]? fifoBuffer should hold only 42 bytes which is the default packetSize correct?

@zhomeslice your code was of a great help :slight_smile: Feel free to reply my questions or if you dont have time please take a look at my code attached. IMHO this code is better than yours and I would like you to give it a try. I dont have redundant “conditions” and it works really well.

I just have a problem: take a look at the line 61. You see I used a delay(1)? I dont like this but I have to otherwise arduino crashes/freezes after 1 or 2 minutes. Please, just give it a try: remove the delay(1) and you will see the data (containing angles) in the serial of your Arduino IDE will stop arriving after some time. For some reason if you call getFIFOCount too many times and too fast, Arduino will crash. Any idea how to solve this problem sir?

aaa.txt (2.19 KB)

Thank you :slight_smile:

batata004:

  1. why do you use “(fifoCount % packetSize)” AND “fifoCount < packetSize” in the same conditional? As I see “(fifoCount % packetSize)” will always be true if “fifoCount < packetSize” so you would not need “fifoCount < packetSize” in the conditional right?

Explination for the %:
(fifoCount % packetSize) so FIFO by default should always have a packet that is exactly 42 bytes in size.
PacketSize = 42; refference in MPU6050_6Axis_MotionApps20.h Line 527

so the % returns a remainder after division and should always return zero! if not we have some corrupted data. and do you trust the first 42 bytes to be the good ones or the last 42 bytes… I chose to trash it if it isn’t divisible exactly by 42
as for the second fifoCount < packetSizer Good call i’ll delete it :slight_smile: this code came about from many attempts to eliminate problems and it looks like a redundant check. also if (fifoCount < packetSize) break; // Something is left over and we don’t want it!!!
is redundant on line 682
and if (fifoCount > 0) mpu.resetFIFO(); // clean up any leftovers Should never happen! but lets start fresh if we need to. this should never happen.
could also be considered redundant because of the newly added: (fifoCount % packetSize)
I guess you could call me paranoid I just wanted to take out any trash :o

  1. when you execute “MPUMath();” you cannot be sure that you indeed received a packet. In the “while” loop right above the “MPUMath()” there is a “break” condition, if that “break” condition is hit right in the first time the loop is executed, then “MPUMath();” will have no new data to play with;

one of the fail conditions is (fifoCount < packetSize) so to pass we should have at least 1 packet to get… but if you see something that would improve this please I welcome a second set of eyes.

  1. why do you use “fifoCount < packetSize” in the conditional? This should never happen right? Anyway, you use this code in the conditional and also another time when you use “break”. If it hit in the conditional it should not need the “break” later correct?

This is mentioned above but for specifics we need to fail if a interrupt is triggered and the fifo count is 0
thinking about it with what you’ve pointed out

  if ((fifoCount % packetSize) || (fifoCount > (packetSize * MaxPackets)) || (fifoCount == 0)) { // we have failed Reset and wait till next time!

condition 1) no extra bits
condition 2) we have way too many packets and are too close to overflow
condition 3) we must have at least one packet
if not we must fail and wait 10 milliseconds for the next interrupt

  1. why do you store fifoCount and keep updating it as you read the FIFO? Why dont you just use mpu.getFIFOCount() everytime? This value will always be updated, correct?

The call for fifocount requires communication with the MPU over i2c

uint16_t MPU6050::getFIFOCount() {
    I2Cdev::readBytes(devAddr, MPU6050_RA_FIFO_COUNTH, 2, buffer);
    return (((uint16_t)buffer[0]) << 8) | buffer[1];
}

It shouldn’t change at all until the next interrupt occurs. and so in the sake of saving processor time I just save it.

  1. why do you think fifo only holds 24 packets? As I understand it holds fifoBuffer[64] (64 packets).

PacketSize = 42; refference in MPU6050_6Axis_MotionApps20.h Line 527
the fifo buffer size of 1024 bytes can be discovered in the MPU6050 datasheet on page 30 under 7.17 FIFO
My code cuts it at 20. so 2042=840 leaving us with 2 Packets (out of a total of 24 packets) if we get 25 packets the buffer is corrupted (2542=1050 2 bytes of data are lost) unless we can figure out how to test for the start of the packet and capture 42 bytes I can’t trust this any more… this could be helpful.
I’m not sure where you found the 64 packets reference. note that the MPU6050_6Axis_MotionApps20.h alters the code in the MPU6050 to include calculations that add additional data to the FIFO buffer over the default code
We upload the source each time we initialize the MPU6050. I would like to get my hands on the source code for that. all we get is the compiled code. The compiled code starts on line 133 in MPU6050_6Axis_MotionApps20.h
This could be the cause of the misunderstanding.

I found a problem with MPU6050 library!

Inside the file MPU6050.cpp there is a code like this:

uint16_t MPU6050::getFIFOCount() {
I2Cdev::readBytes(devAddr, MPU6050_RA_FIFO_COUNTH, 2, buffer);
return (((uint16_t)buffer[0]) << 8) | buffer[1];
}

I checked the function “readBytes()” inside I2Cdev.cpp and I found this:

I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout)

You see the problem? The function readBytes accepts one last parameter which is “timeout” but the function getFIFOCount uses readBytes without the timeout parameter! That’s probably a bug and someone should fix it, that’s why sometimes MPU6050 hangs on Arduino.

link MPU6050 with DMP active hangs indefinitely using Arduino Wire library · Issue #252 · jrowberg/i2cdevlib · GitHub

nice and simple
My thoughts on this is that you should never receive an interrupt from the MPU unless you have at least 1 packet in the buffer so if for some reason the

 while (!mpuInterrupt) {

    //Insira aqui o código que normalmente viria dentro da função "loop" que tudo funcionará normalmente.

  }

releases the program to process the MPU6050 FIFO buffer you should have a packet to get
so all this section of code can do is trap you for about 10 milliseconds and then your buffer could be corrupted

    	while (fifoCount < packetSize) {
         	fifoCount = mpu.getFIFOCount();
                delay(1);
       	}

I would bail if the packet is too small and wait for the next interrupt
Altered code:

//Código do MPU6050.
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
volatile bool mpuInterrupt = false;
void dmpDataReady() {
  mpuInterrupt = true;
}

void setup() {

  //Código do MPU6050.
  Wire.begin();
  TWBR = 24;
  mpu.initialize();
  mpu.dmpInitialize();
  mpu.setXAccelOffset(-1343);
  mpu.setYAccelOffset(-1155);
  mpu.setZAccelOffset(1033);
  mpu.setXGyroOffset(19);
  mpu.setYGyroOffset(-27);
  mpu.setZGyroOffset(16);
  mpu.setDMPEnabled(true);
  attachInterrupt(0, dmpDataReady, RISING);
  packetSize = mpu.dmpGetFIFOPacketSize();

  //Se utilizar "9600" ou um "baud rate" baixo é provável que ocorrerá estouro do buffer do MPU6050.
  Serial.begin(115200);

}

void loop() {

  //Código do MPU6050.
  while (!mpuInterrupt) {

    //Insira aqui o código que normalmente viria dentro da função "loop" que tudo funcionará normalmente.

  }

  //Código do MPU6050.
  mpuInterrupt = false;
  fifoCount = mpu.getFIFOCount();

  if (fifoCount == 1024) {

    mpu.resetFIFO();
    Serial.println(F("FIFO overflow!"));

  }
  else {
    
    if ((fifoCount % packetSize != 0) || (fifoCount < packetSize) ) {
      mpu.resetFIFO();
    } 
    else {

      while (fifoCount >= packetSize) {

        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;

      }

      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

      Serial.print("ypr\t");
      Serial.print(ypr[0] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[1] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[2] * 180 / PI);
      Serial.println();

    }

  }

}

you may also consider that your Serial.print() consumes time and may be the cause of your crash you are pounding you serial port faster than it can empty.
consider using a no delay timer to avoid over spamming your serial port:

  static long Timer = millis();
  if ((long)( millis() - Timer ) >= 100) { //<<< 100 milliseconds is skipping about 10 MPU6050 data samples.
    Timer = millis();
      Serial.print("ypr\t");
      Serial.print(ypr[0] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[1] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[2] * 180 / PI);
      Serial.println();
    Serial.println();
  }
}

@zhomeslice I read your entire explanation and you are not being paranoid at all, you are trying to cover all your base. But look:

  1. you should indeed not use “(fifoCount % packetSize)” AND “fifoCount < packetSize”. YOu see: when the second term is true the first will always be true. So the second term is “inside” the first, you would not need to use “fifoCound < packetSize”. I know % means the remainder, and I think you dont need this.

I tried your code and it works but you wanna know what? It’s discards and misses lots of packets because you “cant wait just a little bit more” to the buffer gets filled a number of bytes that multiple of 42. I did a Serial.print in all the packets your code is wasting and it’s a lot. I am running a quadcopter with MPU6050 so i really need every single reading even at 100Hz.

Everything else you explained was great, I really appreciate and you made me understand better this module and jeff’s library. But I would like, if I am not abusing your patience, you to run my code. I did some tests and it is more efficient than yours and I discard much less readings believing falsely they are “corrupted” (which in most cases they are not corrput, theere were not enought time yet to the buffer be filled with more bytes).

Could you please run my code and read my previous post (or this link MPU6050 with DMP active hangs indefinitely using Arduino Wire library · Issue #252 · jrowberg/i2cdevlib · GitHub) and check that your serial/arduino also hangs/freezes?

EDIT: I read your last post about my code and I dont like using delays but the only way I could find to avoid arduino freezing is using that delay(1). Please, try it out withtout the delay and you will see that your arduino will hang right in the getFIFOCount (I placed a Serial.print before it and another after it and I can see the first message but not the seconds when it freezes).

Nice a quad copter!!! Mine is just a balancing bot :) https://youtu.be/jv3LOUeeyAI I'm not missing any packets with my code add the following line Serial.print(millis()); right after mpu.getFIFOBytes(fifoBuffer, packetSize); the output should be close to 10 milliseconds apart

ya we need everything the PID routines hate messy data!

absolutely I'm trying it now :)

ok back :slight_smile:

I tested 2 examples out
first was your code no changes except I added Serial.print to test theories

else {

    while (fifoCount < packetSize) {

      Serial.print(fifoCount); Serial.print(" ");
      delay(1);
      fifoCount = mpu.getFIFOCount();
    }
    

    Serial.print(fifoCount); Serial.print(" * ");
    if (fifoCount % packetSize != 0) {
//    if ((fifoCount % packetSize != 0) || (fifoCount < packetSize)) {

      mpu.resetFIFO();
      Serial.print("resetFIFO");
    }
    else {

      while (fifoCount >= packetSize) {

        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;

      }

      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
      unsigned long T;
      static unsigned long LastT ;
      T = millis();
      Serial.print("ypr\t");
      Serial.print(ypr[0] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[1] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[2] * 180 / PI);
      Serial.print("\t");
      Serial.print(T);
      Serial.print("\t");
      Serial.print(T - LastT);
      Serial.println();
      LastT = T;

    }

  }

I got interesting results

0 0 0 0 42 * ypr	-132.63	-72.34	-9.75	1420	11
0 0 0 42 * ypr	-132.66	-72.35	-9.74	1429	9
0 0 0 42 * ypr	-132.66	-72.35	-9.73	1439	10
0 0 0 42 * ypr	-132.67	-72.35	-9.72	1449	10
0 0 0 42 * ypr	-132.67	-72.35	-9.72	1459	10
0 0 0 42 * ypr	-132.68	-72.36	-9.71	1469	10
0 0 0 42 * ypr	-132.67	-72.36	-9.71	1478	9
0 0 0 0 42 * ypr	-132.68	-72.36	-9.70	1489	11
0 0 0 42 * ypr	-132.69	-72.37	-9.69	1500	11
0 0 0 42 * ypr	-132.70	-72.37	-9.69	1510	10
0 0 0 42 * ypr	-132.69	-72.37	-9.68	1519	9
0 0 0 42 * ypr	-132.71	-72.38	-9.68	1529	10
0 0 0 42 * ypr	-132.70	-72.38	-9.67	1539	10
0 0 0 42 * ypr	-132.69	-72.38	-9.67	1549	10
0 0 0 0 42 * ypr	-132.68	-72.39	-9.66	1560	11
0 0 0 42 * ypr	-132.68	-72.39	-9.66	1569	9
0 0 0 42 * ypr	-132.67	-72.39	-9.66	1580	11

it looks like it is taking 3 ish milliseconds to get a packet and now I was thinking what!!! is it that lagged.
so I was even more curious and changed it to my routine without the while and got this:

  else {
/*
    while (fifoCount < packetSize) {

      Serial.print(fifoCount); Serial.print(" ");
      delay(1);
      fifoCount = mpu.getFIFOCount();
    }
    
   */ 
    Serial.print(fifoCount); Serial.print(" * ");
//    if (fifoCount % packetSize != 0) {
    if ((fifoCount % packetSize != 0) || (fifoCount < packetSize)) {

      mpu.resetFIFO();
      Serial.print("resetFIFO");
    }
    else {

      while (fifoCount >= packetSize) {

        mpu.getFIFOBytes(fifoBuffer, packetSize);
        fifoCount -= packetSize;

      }

      mpu.dmpGetQuaternion(&q, fifoBuffer);
      mpu.dmpGetGravity(&gravity, &q);
      mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
      unsigned long T;
      static unsigned long LastT ;
      T = millis();
      Serial.print("ypr\t");
      Serial.print(ypr[0] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[1] * 180 / PI);
      Serial.print("\t");
      Serial.print(ypr[2] * 180 / PI);
      Serial.print("\t");
      Serial.print(T);
      Serial.print("\t");
      Serial.print(T - LastT);
      Serial.println();
      LastT = T;

    }

42 it the buffer size * [your data] Millis() & difference in time 9~11 milliseconds
consistant with no fifo resets

42 * ypr	-117.18	-69.97	-13.27	9601	11
42 * ypr	-117.18	-69.98	-13.27	9611	10
42 * ypr	-117.18	-69.98	-13.27	9621	10
42 * ypr	-117.18	-69.98	-13.27	9630	9
42 * ypr	-117.16	-69.97	-13.27	9640	10
42 * ypr	-117.16	-69.97	-13.27	9651	11
42 * ypr	-117.14	-69.98	-13.27	9661	10
42 * ypr	-117.15	-69.98	-13.27	9671	10
42 * ypr	-117.15	-69.98	-13.27	9680	9
42 * ypr	-117.15	-69.98	-13.27	9691	11
42 * ypr	-117.15	-69.98	-13.27	9701	10
42 * ypr	-117.14	-69.98	-13.27	9711	10
42 * ypr	-117.14	-69.98	-13.27	9721	10
42 * ypr	-117.14	-69.98	-13.27	9731	10
42 * ypr	-117.15	-69.98	-13.26	9741	10
42 * ypr	-117.15	-69.98	-13.26	9751	10
42 * ypr	-117.15	-69.98	-13.26	9761	10
42 * ypr	-117.15	-69.98	-13.26	9771	10
42 * ypr	-117.15	-69.98	-13.26	9781	10
42 * ypr	-117.15	-69.98	-13.26	9791	10
42 * ypr	-117.17	-69.98	-13.26	9801	10
42 * ypr	-117.17	-69.98	-13.26	9811	10
... More of the same

no delays no FIFO resets just 42 bytes… what am I missing?
wow I’m more curious than ever!

Do you get the same?

p.s. used my calibration values :slight_smile: you may want to change them to yours

Alternate_MPU6050.ino (2.25 KB)

Update on further testing.
This portion of code is causing all kinds of problems…

    while (fifoCount < packetSize) {
      delay(1);
      fifoCount = mpu.getFIFOCount();
    }

It is with the “while” statement and nothing else I change it to an “if” statement and it works like a champ it also never needs it because it has the entire 42 byte packet!!! Wow that is confusing!

I even tried another trick I know using an alternitive to “while” using “for” and there is no change from using the “while” statement I couldn’t tell any difference I’m getting the same errors.

    for(;fifoCount < packetSize;fifoCount = mpu.getFIFOCount()){
       Serial.print(fifoCount); Serial.print(" ");
       delay(1);
    }

conclusion for me is, it doesn’t even need it. When using “while” or even my “for” trick to loop when testing for fifo buffer count becomes flawed. I do not know why!!!
I have to assume that somehow i2c is causing the glitch but it is there!

I just commented the while loop out and had no problems.
your code is sound as far as I can tell just get rid of that darn “while”. :slight_smile:

And I have to say Thanks! I’ve refined my code even more after looking it over with you.

Side Note:
let me know if you find a better PID routine for your quad copter than the PID_V1.h that comes with arduino. It has a fixed time window that must be held to or the calculations are off. The MPU6050 has trouble being exactly 10 microseconds it varies between 9 and 11 usually. Feel free to message me with that if you have something.
Thanks.

We are getting somewhere! :) Your tests showed really surprising results, I am really curious what is causing it! I also believe it's a I2C glitch.

I use my own PID algorithm on my quadcopter. And I also already built a balancing robot too! You can check my both projects below, they work really fine.

Here is my quadcopter: https://www.youtube.com/watch?v=scug89PNQlg Here is my balancing robot: https://www.youtube.com/watch?v=BjrJEmjz8go

I completely hate using other's people code. I always create my own code so I can easily debug it. The MPU6050 is the only thing that I still hate cause its code is too buggy if you start changing things around.

I am trying to minize problems with MPU6050 and this morning I found a great solution. I decided I was gonna remove the need of interrupt pin even using DMP. Check this out: http://forum.arduino.cc/index.php?topic=408980.0

Could you please take a look at that code and tell me the reason why it freezes arduino?

Complementing last post, I finally came up with a code that works really fine and does not freeze. I have no idea why arduino freezes if you make small changes in the "workings" of the code below, but at least it works really fine.

Try to type one letter in the serial, you will see it will delay the code for 3 seconds and even with that delay nothing goes wrong! Arduino recovers fine and keep working as normal!

I have the code below, I have no idea why if you make some changes to it the code starts freezing at really simple functions like "getFIFOCount". I really hope someone can help us into this and discover what is causing so many glitches.

But anyway, the code below is safe to use and you should not get any freeze. It's really efficient code and works fine. I really would like you to take a look at my other post at http://forum.arduino.cc/index.php?topic=408980.0 and tell me why it freezes!

//Código do MPU6050.
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
Quaternion q;
VectorFloat gravity;
float ypr[3];
volatile bool mpuInterrupt = false;
void dmpDataReady() {mpuInterrupt = true;}

void setup() {

    //Código do MPU6050.
    Wire.begin();
    TWBR = 24;
    mpu.initialize();
    mpu.dmpInitialize();
    mpu.setXAccelOffset(-1343);
    mpu.setYAccelOffset(-1155);
    mpu.setZAccelOffset(1033);
    mpu.setXGyroOffset(19);
    mpu.setYGyroOffset(-27);
    mpu.setZGyroOffset(16);
    mpu.setDMPEnabled(true);
    attachInterrupt(0, dmpDataReady, RISING);
    packetSize = mpu.dmpGetFIFOPacketSize();

    //Se utilizar "9600" ou um "baud rate" baixo é provável que ocorrerá estouro do buffer do MPU6050.
    Serial.begin(115200);

}

void loop() {

    //Código do MPU6050.
    while (!mpuInterrupt) {

        //Insira aqui o código que normalmente viria dentro da função "loop" que tudo funcionará normalmente.
        if (Serial.available()) {
        
            Serial.read();
            
            delay(3000);
        
        }

    }

    //Código do MPU6050.
    mpuInterrupt = false;
    fifoCount = mpu.getFIFOCount();
    
    if (fifoCount == 1024) {
    
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));
        
    }
    else{
    
      if (fifoCount % packetSize != 0) {
        
            mpu.resetFIFO();
            Serial.println(F("Packet is corrupted!"));
            
        }
        else{
    
            while (fifoCount >= packetSize) {
            
                mpu.getFIFOBytes(fifoBuffer,packetSize);
                fifoCount -= packetSize;
                
            }    
        
            mpu.dmpGetQuaternion(&q,fifoBuffer);
            mpu.dmpGetGravity(&gravity,&q);
            mpu.dmpGetYawPitchRoll(ypr,&q,&gravity);          
            
            Serial.print("ypr\t");
            Serial.print(ypr[0]*180/PI);
            Serial.print("\t");
            Serial.print(ypr[1]*180/PI);
            Serial.print("\t");
            Serial.print(ypr[2]*180/PI);
            Serial.println();
            
        }
   
    }

}

Just thought I'd share my experience.

I've found that using the accel & gyro functions works fine, never had any freeze/lock up issues.

I've had problems when using DMP for offloaded calculations. It tends to freeze/lock up within 60 sec.

I noticed that sometimes the data for pitch/yaw/roll became random just before lock up. This got me thinking about the DMP processor being overloaded.

So I changed the digital low pass filter from the default setting of bw256 Hz/8 kHz sampling rate down to bw98Hz/1 kHz sampling rate. This seems to have fixed it! It's been running for an hour with no problems.

I recently went through the code again and believe that I might have discovered the root cause of this problem: timing of accessing MPU’s buffers. I’ve made an easy-to-use template (with the freezing problem fixed), which I made available on Github (MPU6050-Tutorial/Templates/MPU6050_DMP6_KCH at master · KaiChieh-Kenneth-Huang/MPU6050-Tutorial · GitHub).

So far, I’ve tested this code on a Mega board for a project involving a PID controller and a rotary encoder. A friend of mine just tested it on the Uno board, and it seems to work as well.

Please let me know if there’s any problem. And please feel free to contribute to the Github repository if you’ve found things to improve.

MPU6050_DMP6_KCH.ino (15.1 KB)

KCHuang: I recently went through the code again and believe that I might have discovered the root cause of this problem: timing of accessing MPU's buffers. I've made an easy-to-use template (with the freezing problem fixed), which I made available on Github (https://github.com/KaiChieh-Kenneth-Huang/MPU6050-Tutorial/tree/master/Templates/MPU6050_DMP6_KCH).

So far, I've tested this code on a Mega board for a project involving a PID controller and a rotary encoder. A friend of mine just tested it on the Uno board, and it seems to work as well.

Please let me know if there's any problem. And please feel free to contribute to the Github repository if you've found things to improve.

Thank you for the credits @KCHuang :) this is nicely done. Did you make any changes from my version besides cleaning it up nicely?

Z

@KCHuang
I appreciate your efforts with this code.
I have reviewed it and discovered several lapses back to the original issues I faced during my troubleshooting.
Please review my changes to your code and consider the need to adjust your shared example sketch.

I have tested this with zero issues.

Changes:

I simplified and removed the blocking code in readMPUFIFOBuffer:

bool readMPUFIFOBuffer() {
  fifoCount = mpu.getFIFOCount();
  mpuInterrupt = false; // We caught an interrupt reset for next time

  /************************************
     Check for incorrect packet size any size that is not divisible by 42 (Note: this will only occur when we overflow )
     Check for overflow  (1024 bytes FiFo Buffer divided by 42 bytes Packet Size leaves a remainder of 16)
     If the fifoCount is > Zero we have data so get it
   ************************************/
  if ((!fifoCount) || (fifoCount % packetSize)) { // something's wrong. reset and try again.
    Serial.print(F("Wrong packet size, or overflow! packetSize= "));
    Serial.println(packetSize);
    digitalWrite(LED_PIN, LOW); // lets turn off the blinking light so we can see we are failing.
    mpu.resetFIFO();// clear the buffer and start over
    return (false); //no or corrupt data return false

  } else {

    /************************************
       You will want to empty the fifo buffer because the last packet is the latest reading
       If more than one packet exists then the first packet is already at least 10 MS old!!!
     ************************************/
    while (fifoCount  >= packetSize) { // Get the packets until we have the latest!
      mpu.getFIFOBytes(fifoBuffer, packetSize); // lets do the magic and get the data
      fifoCount -= packetSize;
    }
    digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink the LED to indicate activity
    return (true);
  }
}

and

Removed blocking while() in your main loop:

void loop() {
  // ---- read from the FIFO buffer ---- //
  // The interrupt pin could have changed for some time already.
  // So set mpuInterrupt to false and wait for the next interrupt pin CHANGE signal.
  //  Wait until the next interrupt signal. This ensures the buffer is read right after the signal change.
  if (mpuInterrupt) {
    if (readMPUFIFOBuffer()) {
      // Calculate variables of interest using the acquired values from the FIFO buffer
      // getQuaternion();
      // getEuler();
      getYawPitchRoll();
      // getRealAccel();
      // getWorldAccel();

      static unsigned long SpamTimer;
      if ((millis() - SpamTimer) >= (100)) { // prints only 10 per second rather than 100 (10ms) that the MPU6050 interrupt generates
        SpamTimer = millis();
        // Example printouts of parameters of interest
        // printQuaternion();
        // printEuler();
        printYawPitchRoll();
        // printRealAccel();
        // printWorldAccel();
      }
      // ==========  Your code goes here that uses the MPU6050 readings ========= //
    }
  }

  // ==========  Your code goes here for everything else ========= //

}

Z

ps. Yes, my efforts are based on Jeff Rowberg’s example code.

MPU6050_DMP6_KCH.ino (14.8 KB)