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;
}