jrowberg / i2cdevlib

I2C device library collection for AVR/Arduino or other C++-based MCUs
http://www.i2cdevlib.com
3.92k stars 7.52k forks source link

MPU-6050 - Problem with Accelerometer #505

Open cherbin opened 4 years ago

cherbin commented 4 years ago

Hi,

I'm using your code for the MPU-6050 on the Pi 4.

I'm having a very hard time getting correct results and not sure who else to ask. I'de really appreciate any help. It seems I'm getting random data. Also the programs say failed to connect.

I' ve also tried to use some other MPU-6050 python code and it always has 0's for the accelerometer data. The gyro data always seems to count down from some value.

I've got the following GND -> GND SLC -> SLC SDA -> SDA VCC -> 3.3V AD0 -> Gnd

i2cdetect -y 1

 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f

00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --

demo_raw :

Initializing I2C devices... Testing device connections... MPU6050 connection failed a/g: 8 32 0 2048 0 2 a/g: 8 36 0 2049 2 0 a/g: 0 0 0 2048 0 0 a/g: 0 36 0 2305 0 0 a/g: 8 0 0 2305 2 2 a/g: 0 4 0 2048 2 1 a/g: 0 4 256 2304 2 3

./demo_dmp

Initializing I2C devices... Testing device connections... MPU6050 connection failed Initializing DMP... DMP Initialization failed (code 1)

thanks Coby

ZHomeSlice commented 4 years ago

VCC -> 3.3V Does you breakout board have a 3.3v voltage regulator on it? You may be getting less than 3.3v to the i2c bus and your chip if your supplying the 3.3v regulator with 3.3v causing your problems.

cherbin commented 4 years ago

Hi

I’m using this mpu HiLetgo 3pcs GY-521 MPU-6050 MPU6050 3 Axis Accelerometer Gyroscope Module 6 DOF 6-axis Accelerometer Gyroscope Sensor Module 16 Bit AD Converter Data Output IIC I2C for Arduino https://www.amazon.com/dp/B00LP25V1A/ref=cm_sw_r_cp_api_i_DVZhEbV9N8HFZ

With a raspberry pi 4

Sent from my iPhone

On Jan 15, 2020, at 07:43, Homer Creutz notifications@github.com wrote:

VCC -> 3.3V Does you breakout board have a 5v voltage regulator on it?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

cherbin commented 4 years ago

Also.. I'm using the demo_raw...

I'm getting this as an output, but I'm not sure if its correct, and if it is correct, how do I convert the numbers to something measurable ?

a/g: 8 36 2308 6176 12544 3 a/g: 8 32 2304 6180 12546 3 a/g: 0 4 2308 6144 12546 0 a/g: 8 4 2080 6144 12546 1 a/g: 0 36 2084 6144 12544 3 a/g: 0 0 2084 6144 12288 3 a/g: 8 36 2052 6176 12544 0 a/g: 0 32 2308 6176 12546 3 a/g: 8 32 2048 6400 12544 0 a/g: 0 4 2084 6432 12546 2 a/g: 8 32 32 8224 12546 2 a/g: 0 4 32 8224 12544 2 a/g: 0 0 4 8228 12546 0 a/g: 0 0 4 8192 12544 2 a/g: 8 32 36 8224 12546 1 a/g: 8 4 4 8228 12546 1 a/g: 8 4 32 8196 12546 1 a/g: 8 4 32 8192 12544 0 a/g: 0 36 36 8228 12546 1 a/g: 0 0 0 8228 12546 1 a/g: 0 4 4 8224 12546 0 a/g: 0 4 4 8196 12544 2 a/g: 8 32 0 8192 12544 0 a/g: 0 4 0 8224 12546 1 a/g: 8 0 32 8228 12546 3 a/g: 8 36 4 8228 12546 0 a/g: 8 0 4 8228 12544 1 a/g: 0 0 32 8192 12546 0 a/g: 0 32 32 8196 12546 3 a/g: 0 32 32 8196 12544 2 a/g: 8 32 32 8224 12546 3 a/g: 8 36 0 8196 12546 1 a/g: 8 32 32 8192 12546 2 a/g: 0 0 36 8192 12544 3 a/g: 0 36 4 8224 12546 0 a/g: 8 32 32 8228 12546 1 a/g: 0 0 32 8196 12544 1 a/g: 8 36 4 8192 12544 3 a/g: 8 4 36 8224 12544 3 a/g: 8 4 4 8224 12546 1

ZHomeSlice commented 4 years ago

They are rates. Havre you discovered and set the offsets for your mpu6050

With nothing moving and it is flat, the first 2 numbers and the last 3 should be near zero. The third should represent 1g of gravity. If this isn't the case calibrating is needed to correct for factory defects. Z

cherbin commented 4 years ago

Hi,

How do I set the offsets ? Can you please give an exact example?

Thanks

cherbin commented 4 years ago

Also I'm still getting these errors when running ./demo_dmp

Initializing I2C devices... Testing device connections... MPU6050 connection failed Initializing DMP... DMP Initialization failed (code 1)

demo_raw output

./demo_raw | more Initializing I2C devices... Testing device connections... MPU6050 connection failed a/g: 8 4 21760 22272 2 0 a/g: 0 4 21760 22272 0 3 a/g: 0 32 22016 22274 2 0 a/g: 8 0 21760 22272 2 2 a/g: 8 32 22016 22018 2 0 a/g: 0 0 21760 22018 2 2 a/g: 8 0 21760 22016 2 3 a/g: 8 0 22016 22016 0 2 a/g: 0 4 22016 22016 0 3 a/g: 8 36 22016 22018 0 1 a/g: 8 36 21760 22016 2 1

ZHomeSlice commented 4 years ago

I have not gone through the code for Demo_raw. so I am not familiar with the coding DMP is not needed for raw values but with that DMP does have raw values available for you to use

use this code https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050/examples/MPU6050_DMP6_using_DMP_V6.12

with the MPU6050_DMP6_using_DMP_V6.12 boilerplate,

Add this function to get the FIFO packet Seems bulletproof no more overflow errors etc and interrupts are not necessary but they do save time.

uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
  int16_t fifoC;
  // This section of code is for when we allowed more than 1 packet to be acquired
  uint32_t BreakTimer = micros();
  do {
    if ((fifoC = mpu.getFIFOCount())  > length) {

      if (fifoC > 200) { // if you waited to get the FIFO buffer to > 200 bytes it will take longer to get the last packet in the FIFO Buffer than it will take to  reset the buffer and wait for the next to arrive
        mpu.resetFIFO(); // Fixes any overflow corruption
        fifoC = 0;
        while (!(fifoC = mpu.getFIFOCount()) && ((micros() - BreakTimer) <= (11000))); // Get Next New Packet
      } else { //We have more than 1 packet but less than 200 bytes of data in the FIFO Buffer
        uint8_t Trash[BUFFER_LENGTH];
        while (fifoC = mpu.getFIFOCount() > length) { // Test each time just in case the MPU is writing to the FIFO Buffer
          fifoC = fifoC - length; // Save the last packet
          uint16_t  RemoveBytes;
          while (fifoC) { // fifo count will reach zero so this is safe
            RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
            mpu.getFIFOBytes(Trash, (uint8_t)RemoveBytes);
            fifoC -= RemoveBytes;
          }
        }
      }
    }
    if (!fifoC) return 0; // Called too early no data or we timed out after FIFO Reset
    // We have 1 packet
    if ((micros() - BreakTimer) > (11000)) return 0;
  } while (fifoC != length);
  mpu.getFIFOBytes(data, length); //Get 1 packet
  return 1;
}

Replace the main loop with this one to use the above function raw data is available, let me know if you need an example

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

void loop() {
// Place non blocking code here if possible delaying longer than about 70ms will cause a longr delay  up to 10ms when retrieving the packet as the FIFO buffer gets quite large
  if (!GetCurrentFIFOPacket(fifoBuffer, packetSize)) return;
// Triggers every 10ms
  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.print(ypr[2] * 180 / M_PI);
  Serial.println();
  return;
}

Z

cherbin commented 4 years ago

Hi.. The code above is for Arduino. I'm using a Raspberry Pi. Can you give me an example to modify this so it does the calibration on the Raspberry Pi ? The above output is also coming from this code.

The demo_raw.cpp I have is this:

demo_raw.cpp.txt

ZHomeSlice commented 4 years ago

try adding the following in the setup portion of your code mpu.CalibrateGyro(6 ); mpu.CalibrateAccel(6);

Also, you have a duplicate GetCurrentFIFOPacket function definition, I don't know if this will compile I haven't run this on a Rasberry Pi so your feedback is welcome. Z

cherbin commented 4 years ago

I used accelgyro instead of mpu , since accelgyro is defined.. but I get the following:

Where are the CalibrateGyro and CalibrateAccel defined ?

demo_raw.cpp: In function ‘void setup()’: demo_raw.cpp:20:11: error: ‘class MPU6050’ has no member named ‘CalibrateGyro’ accelgyro.CalibrateGyro(6 ); ^~~~~ demo_raw.cpp:21:11: error: ‘class MPU6050’ has no member named ‘CalibrateAccel’ accelgyro.CalibrateAccel(6); ^~~~~~ make: *** [: demo_raw.o] Error 1

ZHomeSlice commented 4 years ago

MPU6050.cpp it was updated a few months ago. CalibrateAccel and CalibrateGyro

cherbin commented 4 years ago

Where can I download the updated MPU6050.cpp for the raspberry pi that contains these functions? I cant find it anywhere.

cherbin commented 4 years ago

Here is my current MPU6050.cpp , but it does not contain the CalibrateAccel and CalibrateGyro. I do not see the update on github for Raspberry pi .. Can you please let me know where it's at.

MPU6050.cpp.txt

ZHomeSlice commented 4 years ago

Try adding these to your MPU6050 routine they should be generic enough to compile on your Pi For MPU6050.h

        // Calibration Routines
        void CalibrateGyro(uint8_t Loops = 15); // Fine tune after setting offsets with less Loops.
        void CalibrateAccel(uint8_t Loops = 15);// Fine tune after setting offsets with less Loops.
        void PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops);  // Does the math

For MPU6050.cpp

//***************************************************************************************
//**********************           Calibration Routines            **********************
//***************************************************************************************
/**
  @brief      Fully calibrate Gyro from ZERO in about 6-7 Loops 600-700 readings
*/
void MPU6050::CalibrateGyro(uint8_t Loops ) {
  double kP = 0.3;
  double kI = 90;
  float x;
  x = (100 - map(Loops, 1, 5, 20, 0)) * .01;
  kP *= x;
  kI *= x;

  PID( 0x43,  kP, kI,  Loops);
}

/**
  @brief      Fully calibrate Accel from ZERO in about 6-7 Loops 600-700 readings
*/
void MPU6050::CalibrateAccel(uint8_t Loops ) {

    float kP = 0.3;
    float kI = 20;
    float x;
    x = (100 - map(Loops, 1, 5, 20, 0)) * .01;
    kP *= x;
    kI *= x;
    PID( 0x3B, kP, kI,  Loops);
}

void MPU6050::PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops){
    uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13;

    int16_t  Data;
    float Reading;
    int16_t BitZero[3];
    uint8_t shift =(SaveAddress == 0x77)?3:2;
    float Error, PTerm, ITerm[3];
    int16_t eSample;
    uint32_t eSum ;
    Serial.write('>');
    for (int i = 0; i < 3; i++) {
        I2Cdev::readWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data); // reads 1 or more 16 bit integers (Word)
        Reading = Data;
        if(SaveAddress != 0x13){
            BitZero[i] = Data & 1;                                       // Capture Bit Zero to properly handle Accelerometer calibration
            ITerm[i] = ((float)Reading) * 8;
            } else {
            ITerm[i] = Reading * 4;
        }
    }
    for (int L = 0; L < Loops; L++) {
        eSample = 0;
        for (int c = 0; c < 100; c++) {// 100 PI Calculations
            eSum = 0;
            for (int i = 0; i < 3; i++) {
                I2Cdev::readWords(devAddr, ReadAddress + (i * 2), 1, (uint16_t *)&Data); // reads 1 or more 16 bit integers (Word)
                Reading = Data;
                if ((ReadAddress == 0x3B)&&(i == 2)) Reading -= 16384;  //remove Gravity
                Error = -Reading;
                eSum += abs(Reading);
                PTerm = kP * Error;
                ITerm[i] += (Error * 0.001) * kI;               // Integral term 1000 Calculations a second = 0.001
                if(SaveAddress != 0x13){
                    Data = round((PTerm + ITerm[i] ) / 8);      //Compute PID Output
                    Data = ((Data)&0xFFFE) |BitZero[i];         // Insert Bit0 Saved at beginning
                } else Data = round((PTerm + ITerm[i] ) / 4);   //Compute PID Output
                I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data);
            }
            if((c == 99) && eSum > 1000){                       // Error is still to great to continue 
                c = 0;
                Serial.write('*');
            }
            if((eSum * ((ReadAddress == 0x3B)?.05: 1)) < 5) eSample++;  // Successfully found offsets prepare to  advance
            if((eSum < 100) && (c > 10) && (eSample >= 10)) break;      // Advance to next Loop
            delay(1);
        }
        Serial.write('.');
        kP *= .75;
        kI *= .75;
        for (int i = 0; i < 3; i++){
            if(SaveAddress != 0x13) {
                Data = round((ITerm[i] ) / 8);      //Compute PID Output
                Data = ((Data)&0xFFFE) |BitZero[i]; // Insert Bit0 Saved at beginning
            } else Data = round((ITerm[i]) / 4);
            I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data);
        }
    }
    resetFIFO();
    resetDMP();
}

I Created this for the MPU6050 and have only shared it here unless someone like you finds it and adds it to another library this is porbibly the only spot this specific calibration routine is located. If this works you should share it wherever the MPU6050 Pi version is shared :) Sorry, I can't help further I don't have a Raspberry Pi to test it on.

Z

EwaldJa commented 3 years ago

Hi, I'm using another card, the AdaFruit ESP32 Feather, and on the repo, some functions are missing, such as GetCurrentFIFOPacket. I've copied yours above, however, it seems that some definitions are still missing, such as mpu, BUFFER_LENGTH, Trash...

davewyers commented 2 years ago

The Trash variable requires the BUFFER_LENGTH define value so both problems are related.

The BUFFER_LENGTH define is in the I2Cdev.c file but the #INCLUDE points to the I2Cdev.h file.

When the BUFFER_LENGTH define is added to the header file it compiles fine.

ifndef BUFFER_LENGTH

// band-aid fix for platforms without Wire-defined BUFFER_LENGTH (removed from some official implementations)

define BUFFER_LENGTH 32

endif

ZHomeSlice commented 2 years ago

Buffer length needs to match the i2c buffer length in your processor for most cases it is 32 but it can change. for the Arduino IDE when using the atmega328p chip BUFFER_LENGTH is given to us but for the ESP8266 and others, it is not. so I believe this has been resolved but are you still having problems with this?

eadf commented 2 years ago

It looks like I2CDEVLIB_WIRE_BUFFER_LENGTH should be used instead of BUFFER_LENGTH.

ZHomeSlice commented 2 years ago

@eadf This is a good point Its Definition is as follows:

#ifndef I2CDEVLIB_WIRE_BUFFER_LENGTH
    #if defined(I2C_BUFFER_LENGTH)
        // Arduino ESP32 core Wire uses this
        #define I2CDEVLIB_WIRE_BUFFER_LENGTH I2C_BUFFER_LENGTH
    #elif defined(BUFFER_LENGTH)
        // Arduino AVR core Wire and many others use this
        #define I2CDEVLIB_WIRE_BUFFER_LENGTH BUFFER_LENGTH
    #elif defined(SERIAL_BUFFER_SIZE)
        // Arduino SAMD core Wire uses this
        #define I2CDEVLIB_WIRE_BUFFER_LENGTH SERIAL_BUFFER_SIZE
    #else
        // should be a safe fallback, though possibly inefficient
        #define I2CDEVLIB_WIRE_BUFFER_LENGTH 32
    #endif
#endif

would it be as simple as: #define BUFFER_LENGTH I2CDEVLIB_WIRE_BUFFER_LENGTH

Z