MPU6050 Gyro overflows and resets a lot

I have a GY-521 board with MPU6050 IMU on it connected to a Nano clone, and am running a variant of the basic Jeff Rowberg program to extract the x, y and z gyroscope values. Thanks Jeff. I added an OLED display to see the values. The problems I am seeing are twofold. One is that the circuit will often reset, meaning that I see the Nano onboard LED flash 5 times and then the values blank out, go to zero and start again. Since there is no LED code in the sketch, I'm assuming that there is code in the library that flashes it. While trying to figure out how the code works, I see that it is constantly overflowing. Here is what my output looks like during a typical run;

Initializing IMU...
Testing device connections...
MPU6050 connection successful
Initializing DMP...
Enabling DMP...
Enabling interrupt detection
DMP ready! Waiting for first interrupt...
0.12, 1.94, -5.24
OVERFLOW
0.15, 1.99, -5.16
0.15, 1.99, -5.16
OVERFLOW
0.16, 2.01, -5.11
0.15, 2.00, -5.11
OVERFLOW
0.17, 2.01, -5.07
0.17, 2.02, -5.07
OVERFLOW
0.18, 2.03, -5.06
0.17, 2.02, -5.06
OVERFLOW
OVERFLOW
0.19, 2.03, -5.04
0.19, 2.03, -5.04

The sketch itself looks like this. The overflow statement is in the part of the routine that says this should never happen.

Is it possible that the resetting problem is related to voltage or current in the data lines. I use the circuit connected to a laptop because I need the gyro values in another program. I have tried using powered USB hubs vs plugging directly into a laptop USB port but the resetting problem still happens randomly.

Lastly, I am using this gyro in a lab environment, not on a moving thing like a drone, so is there a simpler version of the program I can use that doesn't rely on interrupts and FIFO buffers?

Image of circuit is here (Amazon Photos)

/* Program to use the GY-521 board with MPU6050 and a small OLED display
 *  and Arduino Nano
 * 
 * 
 */
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
MPU6050 mpu;            // create gyro object

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer


// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector
float yaw = 0;          // initial setting for yaw
float pitch = 0;        // initial setting for pitch
float roll = 0;         // initial setting for roll
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high


// ================================================================
// ===                      INITIAL SETUP                       ===
// ================================================================

void setup() {
  Serial.begin(115200);
  u8g.setColorIndex(255);     // white

  Serial.println(F("Initializing IMU..."));
  mpu.initialize();

  // Set gyro sensitivity
  mpu.setFullScaleGyroRange(MPU6050_GYRO_FS_250);

  // verify connection
  Serial.println(F("Testing device connections..."));
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  // load and configure the DMP
  Serial.println(F("Initializing DMP..."));
  devStatus = mpu.dmpInitialize();

  // supply your own gyro offsets here, scaled for min sensitivity (use calibration program to get values)
  mpu.setXGyroOffset(56);
  mpu.setYGyroOffset(-9);
  mpu.setZGyroOffset(32);

  // make sure it worked (returns 0 if so)
  if (devStatus == 0) {
    // turn on the DMP, now that it's ready
    Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);

    // enable Arduino interrupt detection
    Serial.println(F("Enabling interrupt detection"));
    attachInterrupt(0, dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();

    // set our DMP Ready flag so the main loop() function knows it's okay to use it
    Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;

    // get expected DMP packet size for later comparison
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    // ERROR!
    // 1 = initial memory load failed
    // 2 = DMP configuration updates failed
    // (if it's going to break, usually the code will be 1)
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));
  }

  // picture loop to display initial screen on OLED display
  u8g.firstPage();
  do {
    display_progress();
  } while ( u8g.nextPage() );

}

void loop() {
  // OLED display update
  u8g.firstPage();
  do {
    display_ypr();
  } while ( u8g.nextPage() );

  // if programming failed, don't try to do anything
  if (!dmpReady) return;

  // reset interrupt flag and get INT_STATUS byte
  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();

  // get current FIFO count
  fifoCount = mpu.getFIFOCount();
  
  // check for overflow (this should never happen unless our code is too inefficient)
  if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
    // reset so we can continue cleanly
    Serial.println("OVERFLOW");
    mpu.resetFIFO();
    // otherwise, check for DMP data ready interrupt (this should happen frequently)
  } else if (mpuIntStatus & 0x02) {
    // wait for correct available data length, should be a VERY short wait
    while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

    // read a packet from FIFO
    mpu.getFIFOBytes(fifoBuffer, packetSize);

    // track FIFO count here in case there is > 1 packet available
    // (this lets us immediately read more without waiting for an interrupt)
    fifoCount -= packetSize;

    // display Euler angles in degrees
    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

    // calculate yaw, pitch and roll
    yaw = (ypr[0] * 180 / M_PI);
    pitch = (ypr[1] * 180 / M_PI);
    roll = (ypr[2] * 180 / M_PI);

    // display yaw, pitch and roll in serial window
    Serial.print(yaw);
    Serial.print(", ");
    Serial.print(pitch);
    Serial.print(", ");
    Serial.println(roll);

    // display yaw, pitch and roll on OLED display   
    u8g.setPrintPos(70, 15);
    u8g.print(yaw);
    u8g.setPrintPos(70, 35);
    u8g.print(pitch);
    u8g.setPrintPos(70, 55);
    u8g.print(roll);
  }
}

// ================================================================
// ===                   DISPLAY DRAW ROUTINES                  ===
// ================================================================
void display_initscreen(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);
  u8g.drawStr( 0, 15, "INITIALIZATION");
  u8g.drawStr( 0, 35, "Setting up gyro");
  u8g.drawStr( 0, 55, "Please wait");
}

void display_progress(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);
  u8g.drawStr( 0, 15, "Y");
  u8g.drawStr( 0, 35, "P");
  u8g.drawStr( 0, 55, "R");
}

void display_ypr(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);

  u8g.drawStr( 0, 15, "Yaw");
  u8g.setPrintPos(70, 15);
  u8g.print(yaw);

  u8g.drawStr( 0, 35, "Pitch");
  u8g.setPrintPos(70, 35);
  u8g.print(pitch);

  u8g.drawStr( 0, 55, "Roll");
  u8g.setPrintPos(70, 55);
  u8g.print(roll);
}

// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================
void dmpDataReady() {
  mpuInterrupt = true;
}

I can think of 2 cases that cause your system to reset. One is insufficient power. The other one is insufficient memory

Here is a snapshot of memory usage.

Sketch uses 26,446 bytes (86%) of program storage space. Maximum is 30,720 bytes.
Global variables use 884 bytes (43%) of dynamic memory, leaving 1,164 bytes for local variables. Maximum is 2,048 bytes.

As for power, I think that is the right thinking, but it has been hard to track down.

Writing past the end of an array into memory that one does not "own" can also cause resets. Maybe add some prints to keep track of array indexes if you think that is possible.

You're probably getting overflows because the OLED takes a lot of time to draw on every cycle. You also seem to be displaying the same thing several times in each cycle of loop().

Cut down the display frequency - maybe print every 100 milliseconds - and minimise the amount of stuff that it draws on each cycle. In the extreme, only print one digit to the OLED every 10 milliseconds. (Although, if it's like the Adafruit OLED I've used before, this won't work as it always has to send a full screenful of data to the OLED for any update.)

hi, i'm also embarking on the MPU-6050 adventure and maybe this might help.

i use this code which is "simpler" - no library except for the I2C.

and you output direct to the Serial Monitor so you can isolate the problem if it involves the OLED (mine is still on the way ! :slight_smile: )

// MPU-6050 Short Example Sketch  // August 17, 2014
// By Arduino User JohnChi       // Public Domain
#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}

void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)     
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

  Serial.print("AcX\t"); Serial.print(AcX);
  Serial.print("\tAcY\t"); Serial.print(AcY);
  Serial.print("\tAcZ\t"); Serial.print(AcZ);
  Serial.print("\tTmp\t"); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print("\tGyX\t"); Serial.print(GyX);
  Serial.print("\tGyY\t"); Serial.print(GyY);
  Serial.print("\tGyZ\t"); Serial.println(GyZ);
  delay(333);

}

Disclaimer:
i'm not 100% sure that my board is of the GY-521 type, has no other marking other than "MPU-6050" but i believe it is the standard board that is "out there" - so hopefully (it should be) the code is compatible.