Serial communication with MPU6050 freezes after a while

Hi there, I'm a school student in year 12 creating a robot for my EPQ (extended project qualification). It involves using some sensor to detect the tilt angle of my robot's frame which it uses to adjust itself to maintain balance. The MPU6050 IMU 3-axis accelerometer and gyroscope seemed like the best sensor for this job, so I bought one off this website: https://kunkune.co.uk/shop/arduino-sensors/mpu-6050-3-axis-analog-gyroscope-accelerometer/
I have used Jeff Rowbergs' i2cdevlib library and his MPU6050_DMP6 sketch for the MPU6050 sensor to calculate yaw, pitch and roll angles with an Arduino Uno Rev3 (I don't need the yaw angles though). I have pasted a drawing of the schematics. The code I am using is the same as the example sketch MPU6050_DMP6 in the MPU6050 library but I have copied it in at the bottom. As I understand it, the sensor uses values from both the accelerometer and gyroscope, combines them to create a reliable average and passes them through a filter to remove 'drift' from the values thus making them more accurate. Once the angle values are calculated, using serial communication (I2C) they are displayed using the print function, in the void loop function. I don't really have a good knowledge of the specifics, I am totally new to coding and electronics, so I'm sorry for any incorrect statements I've made or might make. If there is something terribly incorrect with what I've already said, please let me know.
So the values are printed continuously at a fast rate, providing yaw, pitch and roll angles. However at some random point the new values stop being printed and the program stops, and serial communication also stops as the TX LED switches off, but the red light on the MPU6050 stays on, and the L light on the Arduino Uno also stays on. So I assume in the void loop, !dmpReady, so it performs the 'return' function to stop the code, or it can't get the latest FIFO packet for some reason. I don't know what either mean except that they allow the receiving of raw data from the sensors. First I thought this problem was due to poor connection of the wires as poor connection has the same effect, but I checked for this issue and it turns out this wasn't the case. I've done some research on why it happens and it seems the wires shouldn't be too long so I've made all the wires as short as possible as well, to no effect. Some people have said the AD0 pin shouldn't be left floating and should be attached to GND, so I did that but nothing changed. Some places are also saying it is a problem with the Wire library itself, which doesn't sound like something I can fix.
The potential causes for this problem to the extent of my knowledge:

  • I haven't soldered the pins on the MPU6050 well enough?
  • The MPU6050 is faulty - I tested if the Arduino itself was the source of the problem but in other sketches involving serial communication but without communication with a sensor such as the MPU6050, it worked fine.
    I would really appreciate it if anyone had any ideas to solve this problem? If there is no solution to this problem, I would be grateful for any suggestions for other sensors/alternatives that can provide the same functions I require, namely to provide the roll and pitch angles of an object from the horizontal. I know I might be able to understand why this is happening if I properly understood Jeff Rowberg's sketch that obtains the angle values from the sensors, but that is not the main 'point' of my project and I don't have enough time to do that at the moment as there are many other things I am doing/need to do in this project. Again, sorry for my ignorance of the intricacies of some of this, I'll do my best to keep up.

Schematics:

Code:

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 mpu;

#define OUTPUT_READABLE_YAWPITCHROLL
#define INTERRUPT_PIN 2  // use pin 2 on Arduino Uno & most boards
#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;

// 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
VectorFloat gravity;    // [x, y, z]            gravity vector
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector




// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================

volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}



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

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // initialize serial communication
    Serial.begin(115200);
    while (!Serial); // wait for Leonardo enumeration, others continue immediately

    // initialize device
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);

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

    // wait for ready
    Serial.println(F("\nSend any character to begin DMP programming and demo: "));
    while (Serial.available() && Serial.read()); // empty buffer
    while (!Serial.available());                 // wait for data
    while (Serial.available() && Serial.read()); // empty buffer again

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

    // supply your own gyro offsets here, scaled for min sensitivity
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); // 1688 factory default for my test chip

    // make sure it worked (returns 0 if so)
    if (devStatus == 0) {
        // Calibration Time: generate offsets and calibrate our MPU6050
        mpu.CalibrateAccel(6);
        mpu.CalibrateGyro(6);
        mpu.PrintActiveOffsets();
        // turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // enable Arduino interrupt detection
        Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        Serial.println(F(")..."));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), 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(")"));
    }

    // configure LED for output
    pinMode(LED_PIN, OUTPUT);
}



// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================

void loop() {
    // if programming failed, don't try to do anything
    if (!dmpReady) return;
    // read a packet from FIFO
    if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet 

        #ifdef OUTPUT_READABLE_YAWPITCHROLL
            // display Euler angles in degrees
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
            Serial.print("ypr\t");
            Serial.print(ypr[0] * 180/M_PI);
            Serial.print("\t");
            Serial.print(ypr[1] * 180/M_PI);
            Serial.print("\t");
            Serial.println(ypr[2] * 180/M_PI);
        #endif


        // blink LED to indicate activity
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
    }
}

The problem may be due to the lack of (required) logic level shifters for the 5V Uno to the 3.3V MPU-6050 connections.

This one will work

Ok thanks, so the MPU6050 requires 3.3V connections with the Arduino, could I not just change the power connection to the 3.3V pin on the Uno? (I just tried this, but it doesn't work so your solution is probably required.)

The voltage regulator on the cheap MPU-6050 modules has a large voltage drop, so 3.3V on power often does not work.

It is a bad design all around, but then, the MPU-6050 was discontinued years ago, and what you have is some sort of clone or imitation.

I see, are there any alternative sensors or modules you might suggest to provide pitch and roll angles?

The modern ISM330DHCX is much more accurate than the MPU-6050, and the module includes well designed interface circuitry that works with both 3.3V and 5V Arduinos.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.