ZHomeSlice / Simple_MPU6050

Going Live
MIT License
88 stars 24 forks source link

Arduino still getting stuck #16

Closed filipcoja closed 2 years ago

filipcoja commented 3 years ago

I'm now already trying for a whole year to get this sensor working properly, problem is I just cant get it to work reliably.

As already a lot of other people figured out, the MPU6050 somehow gets the master (arduino) stuck, I've now tried doing the following:

My last resort is still using the built in watchdog, but this is such a bad workaround I'd really just want the watchdog to work as a backup, not as a regular backdrop if the MPU6050 gets stuck.

Maybe you can guide me in a direction to get this thing finally working.

(This is my repo, you can look through the code if you want to) https://github.com/filipppp/airplane

ZHomeSlice commented 3 years ago

FYI I just added it fix a Few days ago related to:

"the classic I2C bus 'freeze' problem, and if so, it has nothing at all to do with the MPU6060. I2C bus freezes are a known problem with Arduino, and it has only been recently addressed. See this post for all the gory details. The good news is, if you use the latest Wire library code and add the timeout setting line to your setup() function like this

Wire.setWireTimeout(3000, true); //timeout value in uSec

then the I2C freeze problem should go away. Note that if you aren't using the latest Wire library, the above code line won't compile, so it's easy to tell one way or the other." jrowberg/i2cdevlib#543 (comment)

filipcoja commented 3 years ago

I already added the Wire.setWireTimeout() in my Code

ZHomeSlice commented 3 years ago

mpu.on_FIFO(refresh_data); on_FIFO does the following empties the FIFO buffer and captures the latest packet in the most efficient way and passes it to your function as input variables. No new data will become available between on_FIFO events. attempting to capture data with mpu.dmp_read_fifo(true); may cause other issues.

You won't need a separate function outside of your refresh_data

void refresh_angles(float *q_arr) {
    mpu.dmp_read_fifo(true);
    for (int i = 0; i < 4; ++i) {
        q_arr[0] = q.w;
        q_arr[1] = q.x;
        q_arr[2] = q.y;
        q_arr[3] = q.z;
    }
}

consider adding refresh_angles to the refresh_data function Spamming your serial port at 100Hz will likely be your crash mpu.Set_DMP_Output_Rate(DMP_100Hz);

// Because of mpu.on_FIFO(refresh_data); the following line will be triggered only when new data is retrieved
// from the fifo buffer. afterwords the fifo buffer will be empty and the latest packet will populate the variables. 
// Everything realted to this data retrieval should reside here. 
void refresh_data(int16_t *gyro, int16_t *accel, int32_t *quat, uint32_t *timestamp) {
    mpu.GetQuaternion(&q, quat);

//    for (int i = 0; i < 4; ++i) { // Not shure why we need to loop 4 times
        q_arr[0] = q.w;
        q_arr[1] = q.x;
        q_arr[2] = q.y;
        q_arr[3] = q.z;
//    }

// added a spam timer to keep the serial port alive.
  static unsigned long SpamTimer;
  if ((millis() - SpamTimer) >= (100)) { // only 10Hz insted of 100Hz
       SpamTimer= millis();
       Serial.println("test");
//    mpu.GetYawPitchRoll(test, &q);
//    Serial.print(test[0] * 180 / PI);
//    Serial.print(';');
//    Serial.print(test[1] * 180 / PI);
//    Serial.print(';');
//    Serial.println(test[2] * 180 / PI);
  }

}

Z


And just a fun FYI MPU 6050 Temperature

int16_t TEMP_OUT ;
mpu.TEMP_OUT_H_READ_TEMP_OUT(*TEMP_OUT);

The math: Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 36.53

filipcoja commented 3 years ago

Oh, I completely missed out on the temperature sensor on the mpu, thanks!

I don't understand it quite, the dmp_read_fifo is also in your example, so should I remove that function call?

I will try changing the code when I get back home, big thanks for your help!

filipcoja commented 3 years ago

I should add that it works line 99% of the time, it gets stuck rarely so debugging it is quite hard..

filipcoja commented 3 years ago

Added your suggestions, but I have to keep mpu.dmp_read_fifo(true) since if this is missing, the mpu doesn't do anything. Besides, if I do mpu.dmp_read_fifo(false) and still have the interrupt to pin 2 connected, it still gets interrupted

ZHomeSlice commented 3 years ago

Sorry about that, I didn't look over the rest of your code.

move dmp_read_fifo() to here or create a separate function in sensors.cpp that triggers dmp_read_fifo()

void loop() {

    handle_servo_change();
    update_power_led(last_control_update);
    mpu.dmp_read_fifo(false); // true means interrupt is required to have triggered. false will query the mpu for FIFO buffer size (slower).
                                             // once the resulting interrupt or FIFO size is true then the callback function is triggered.
                                             //  mpu.on_FIFO(refresh_data);  ---> refresh_data() function is your callback function 
    update_sensor_data(); 
    check_calibration();
    handle_radio();

//    Serial.print(sensors.temperature);
//    Serial.print(";");
//    Serial.print(sensors.altitude);
//    for (int i = 0; i < 4; ++i) {
//        Serial.print(";");
//        Serial.print(sensors.q[i]);
//    }
//    Serial.print(';');
//    Serial.println(millis() - time);
//    wdt_reset();
//    Serial.println(millis() - time);
}

Z

filipcoja commented 3 years ago

You can look at my code again, it should be updated, hopefully I got everything right.

ZHomeSlice commented 3 years ago

Made some changed and did a pull request for your convenience. Z

filipcoja commented 3 years ago

Set_DMP_Output_Rate_HZ doesnt exist in your repo, do you have it locally maybe and its not pushed yet?

ZHomeSlice commented 3 years ago

Looks to be there now forgot to push one button :)

Starting at line 364:

Simple_MPU6050 & Simple_MPU6050::Set_DMP_Output_Rate(uint16_t value){  // 100 HZ Default
    DMP_Output_Rate[0] = (uint8_t)((value & 0xFF00) >> 8);
    DMP_Output_Rate[1] = (uint8_t)(value & 0x00FF);
    return *this;
}
Simple_MPU6050 & Simple_MPU6050::Set_DMP_Output_Rate_Hz(float rate){  // 100 HZ Default

    rate = (rate>200) ? 200 : rate;
    rate = (rate<0) ? 0.0032 : rate;
    uint16_t div = (uint16_t)( 200 / rate - 1);
    Set_DMP_Output_Rate(div);
    return *this;
}
Simple_MPU6050 & Simple_MPU6050::Set_DMP_Output_Rate_Seconds(float rate){  // 1Hz Default
    rate = (rate>300) ? 300 : rate;
    rate = (rate<0) ? 0 : rate;
    uint16_t div = (uint16_t)( 200 / (1/rate) - 1);
    Set_DMP_Output_Rate(div);
    return *this;
}
Simple_MPU6050 & Simple_MPU6050::Set_DMP_Output_Rate_Minutes(float rate){  // 1 minute Default
    rate = (rate>5) ? 5 : rate;
    rate = (rate<0) ? 0 : rate;
    Set_DMP_Output_Rate_Seconds(rate/60);
    return *this;
}

Z

filipcoja commented 3 years ago

Thanks!

filipcoja commented 3 years ago

Tried it out, still gets stuck sometimes, this looks like a sensor error? The "L" Led on my Arduino Mega blinks tho.. Also I recognized that when I move my IMU the output gets slower so something takes longer to execute

ZHomeSlice commented 3 years ago

You are polling the mpu6050 every loop through the i2c buss but you are only requesting data 10 times a second mpu.Set_DMP_Output_Rate_Hz(10); If the MPU data isn't a high-value item then use a blink without delay timer to decrease the number of checks caused by mpu.dmp_read_fifo();

something like

static unsigned long FIFO_DelayTimer; 
if ((millis() - FIFO_DelayTimer) >= (100)) { // only 10Hz insted of ?Hz
    FIFO_DelayTimer= millis();
    mpu.dmp_read_fifo();
}

your readings will be within 1/100 of a second of when it was live.

I realized I can improve the performance of this so... I made a change in my library that should improve performance the change allows for this code to work.

static unsigned long FIFO_DelayTimer;
if ((millis() - FIFO_DelayTimer) >= (99)) { // 99ms insted of 100ms to start polling the MPU 1ms prior to data arriving.
   if( mpu.dmp_read_fifo()) FIFO_DelayTimer= millis() ; when data arrives reset the timer
}

your readings will now be live

with these changes, your load on your processor and i2c bus will be 1000 times faster. Z

filipcoja commented 3 years ago

Yea well, I guess there is something fundamentaly wrong with my sensor or I don't know.. but gonna try that one too.