Is it possible to use the MPU6050 mounted upside down with DMP for angle measurements? I'm using this library with the MPU6050_DMP6 example code outputting ypr values.
It seems like if it is initialized upside down, the rotation reported by the accelerometer and the rotation reported by the gyro have opposite signs, so when its rotated, it spikes in the direction the gyro is reporting, then settles down in the direction the accelerometer is reporting.
I.E if I initialize the MPU upside down, then quickly rotate it 30 degrees, the pitch (or roll) will spike to -30, then slowly move to +30.
There's the set gyro/accel offset functions which seem promising but I cant find any documentation on them. I have tried changing around the z accel offset and xyz gyro offsets but that didn't seem to significantly change anything.
I also tried inverting the quaternion and gravity values from dmpGetQuaternion() and dmpGetGravity, but it seems to be more of an issue with DMP rather than the library.
The code is the example code for the library I'm using. Ill paste a version simplified to what I'm specifically doing. The MPU needs to be upside down because its mounted on the underside of a custom pcb which has other GPIO and a button that would be much harder to access if the entire board was mounted upside down.
Ultimately this will be used for a quadcopter but the current project is just getting functional gyro measurements so there's not much to take a picture of that would show anything other than SDA is connected to SDA, SCL is connected to SCL, the MPU has power and ground and the interrupt pin is connected to pin 2.
#define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards
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 euler[3]; // [psi, theta, phi] Euler angle container
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)
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
// 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"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// 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(")"));
}
}
// ================================================================
// === 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
// 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);
}
}
Hi,
If the IMU is on its own PCB, why not mount it upside down with respect to you PCB, that way I will be the right way round when you fit the PCB to the copter.
If the IMU has header pins on it, just mount them the other way in their board.
Just a thought.
The IMU isn't on its own PCB, its on a board with the ATMEGA1284 I'm using to control it along with other peripherals. While I could mount the header pins the other way, I wouldn't be able to get to the reset button or see the status LEDs. Plus the top side has some components that stick off the board making mounting upside down weird so I wanted to leave mounting upside down as a last resort.