kriswiner / MPU9250

Arduino sketches for MPU9250 9DoF with AHRS sensor fusion
1.03k stars 471 forks source link

Verical Data Restricted #340

Open VGiaglisis opened 5 years ago

VGiaglisis commented 5 years ago

Hello Kris, First of all thank you for the great contributions you have made with the MPU9250. I have followed your instructions on calibrating the magnetometer and used the most recent code on an Arduino Nano. I am getting really stable results in terms of lateral and horizontal axes (pitch, roll) but the vertical data seem to be resticted between around +- 40 deg. I am transmiting quaternion data directly to a Unity script where the calculations are made for visualisation on a simple cubic object. I have not used any king of Euler or Tait-Bryan conversion functions. Also I checked the local mag bias and compared them to the calibration results. One axis seemed to be off bt a lot. Could you please suggest some ideas on getting correct yaw data without restrictions?

Here is my code:

`

include "quaternionFilters.h"

include "MPU9250.h"

define AHRS true // Set to false for basic data read

define SerialDebug true // Set to true to get Serial output for debugging

// Pin definitions int intPin = 12; // These can be changed, 2 and 3 are the Arduinos ext int pins int myLed = 13; // Set up pin 13 led for toggling int j = 1; int buttonState;

define I2Cclock 400000

define I2Cport Wire

//#define MPU9250_ADDRESS MPU9250_ADDRESS_AD0 // Use either this line or the next to select which I2C address your device is using

define MPU9250_ADDRESS MPU9250_ADDRESS_AD1

MPU9250 myIMU(MPU9250_ADDRESS, I2Cport, I2Cclock);

void setup() { Wire.begin(); // TWBR = 12; // 400 kbit/sec I2C speed Serial.begin(38400);

while(!Serial){};

// Set up the interrupt pin, its set as active high, push-pull pinMode(intPin, INPUT); digitalWrite(intPin, LOW); pinMode(myLed, OUTPUT); digitalWrite(myLed, HIGH);

// Read the WHO_AM_I register, this is a good test of communication byte c = myIMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); Serial.print(F("MPU9250 I AM 0x")); Serial.print(c, HEX); Serial.print(F(" I should be 0x")); Serial.println(0x71, HEX);

if (c == 0x71) // WHO_AM_I should always be 0x71 { Serial.println(F("MPU9250 is online..."));

// Start by performing self test and reporting values
myIMU.MPU9250SelfTest(myIMU.selfTest);
Serial.print(F("x-axis self test: acceleration trim within : "));
Serial.print(myIMU.selfTest[0],1); Serial.println("% of factory value");
Serial.print(F("y-axis self test: acceleration trim within : "));
Serial.print(myIMU.selfTest[1],1); Serial.println("% of factory value");
Serial.print(F("z-axis self test: acceleration trim within : "));
Serial.print(myIMU.selfTest[2],1); Serial.println("% of factory value");
Serial.print(F("x-axis self test: gyration trim within : "));
Serial.print(myIMU.selfTest[3],1); Serial.println("% of factory value");
Serial.print(F("y-axis self test: gyration trim within : "));
Serial.print(myIMU.selfTest[4],1); Serial.println("% of factory value");
Serial.print(F("z-axis self test: gyration trim within : "));
Serial.print(myIMU.selfTest[5],1); Serial.println("% of factory value");

// Calibrate gyro and accelerometers, load biases in bias registers
myIMU.calibrateMPU9250(myIMU.gyroBias, myIMU.accelBias);

myIMU.initMPU9250();
// Initialize device for active mode read of acclerometer, gyroscope, and
// temperature
Serial.println("MPU9250 initialized for active data mode....");

// Read the WHO_AM_I register of the magnetometer, this is a good test of
// communication
byte d = myIMU.readByte(AK8963_ADDRESS, WHO_AM_I_AK8963);
Serial.print("AK8963 ");
Serial.print("I AM 0x");
Serial.print(d, HEX);
Serial.print(" I should be 0x");
Serial.println(0x48, HEX);

if (d != 0x48)
{
  // Communication failed, stop here
  Serial.println(F("Communication failed, abort!"));
  Serial.flush();
  abort();
}

// Get magnetometer calibration from AK8963 ROM
myIMU.initAK8963(myIMU.factoryMagCalibration);
// Initialize device for active mode read of magnetometer
Serial.println("AK8963 initialized for active data mode....");

if (SerialDebug)
{
  //  Serial.println("Calibration values: ");
  Serial.print("X-Axis factory sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[0], 2);
  Serial.print("Y-Axis factory sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[1], 2);
  Serial.print("Z-Axis factory sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[2], 2);
}

// Get sensor resolutions, only need to do this once
myIMU.getAres();
myIMU.getGres();
myIMU.getMres();

// The next call delays for 4 seconds, and then records about 15 seconds of
// data to calculate bias and scale.

// myIMU.magCalMPU9250(myIMU.magBias, myIMU.magScale); myIMU.magBias[0]= +265.; myIMU.magBias[1]= +20.; myIMU.magBias[2]= +375.; Serial.println("AK8963 mag biases (mG)"); Serial.println(myIMU.magBias[0]); Serial.println(myIMU.magBias[1]); Serial.println(myIMU.magBias[2]);

Serial.println("AK8963 mag scale (mG)");
Serial.println(myIMU.magScale[0]);
Serial.println(myIMU.magScale[1]);
Serial.println(myIMU.magScale[2]);

// delay(2000); // Add delay to see results before serial spew of data

if(SerialDebug)
{
  Serial.println("Magnetometer:");
  Serial.print("X-Axis sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[0], 2);
  Serial.print("Y-Axis sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[1], 2);
  Serial.print("Z-Axis sensitivity adjustment value ");
  Serial.println(myIMU.factoryMagCalibration[2], 2);
}

} // if (c == 0x71) else { Serial.print("Could not connect to MPU9250: 0x"); Serial.println(c, HEX);

// Communication failed, stop here
Serial.println(F("Communication failed, abort!"));
Serial.flush();
abort();

} }

void loop() { // If intPin goes high, all data registers have new data // On interrupt, check if data ready interrupt if (myIMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01) { myIMU.readAccelData(myIMU.accelCount); // Read the x/y/z adc values

// Now we'll calculate the accleration value into actual g's
// This depends on scale being set
myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes; // - myIMU.accelBias[0];
myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes; // - myIMU.accelBias[1];
myIMU.az = (float)myIMU.accelCount[2] * myIMU.aRes; // - myIMU.accelBias[2];

myIMU.readGyroData(myIMU.gyroCount);  // Read the x/y/z adc values

// Calculate the gyro value into actual degrees per second
// This depends on scale being set
myIMU.gx = (float)myIMU.gyroCount[0] * myIMU.gRes;
myIMU.gy = (float)myIMU.gyroCount[1] * myIMU.gRes;
myIMU.gz = (float)myIMU.gyroCount[2] * myIMU.gRes;

myIMU.readMagData(myIMU.magCount);  // Read the x/y/z adc values

// Calculate the magnetometer values in milliGauss
// Include factory calibration per data sheet and user environmental
// corrections
// Get actual magnetometer value, this depends on scale being set
myIMU.mx = (float)myIMU.magCount[0] * myIMU.mRes
           * myIMU.factoryMagCalibration[0] - myIMU.magBias[0];
myIMU.my = (float)myIMU.magCount[1] * myIMU.mRes
           * myIMU.factoryMagCalibration[1] - myIMU.magBias[1];
myIMU.mz = (float)myIMU.magCount[2] * myIMU.mRes
           * myIMU.factoryMagCalibration[2] - myIMU.magBias[2];

} // if (readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01)

// Must be called before updating quaternions! myIMU.updateTime();

MahonyQuaternionUpdate(-myIMU.ax, -myIMU.ay, myIMU.az, myIMU.gx DEG_TO_RAD, myIMU.gy DEG_TO_RAD, -myIMU.gz * DEG_TO_RAD, myIMU.my, myIMU.mx, myIMU.mz, myIMU.deltat);

if (!AHRS) { myIMU.delt_t = micros() - myIMU.count; if (myIMU.delt_t > 500) { if(SerialDebug) { // Print acceleration values in milligs! Serial.print("X-acceleration: "); Serial.print(1000 myIMU.ax); Serial.print(" mg "); Serial.print("Y-acceleration: "); Serial.print(1000 myIMU.ay); Serial.print(" mg "); Serial.print("Z-acceleration: "); Serial.print(1000 * myIMU.az); Serial.println(" mg ");

    // Print gyro values in degree/sec
    Serial.print("X-gyro rate: "); Serial.print(myIMU.gx, 3);
    Serial.print(" degrees/sec ");
    Serial.print("Y-gyro rate: "); Serial.print(myIMU.gy, 3);
    Serial.print(" degrees/sec ");
    Serial.print("Z-gyro rate: "); Serial.print(myIMU.gz, 3);
    Serial.println(" degrees/sec");

    // Print mag values in degree/sec
    Serial.print("X-mag field: "); Serial.print(myIMU.mx);
    Serial.print(" mG ");
    Serial.print("Y-mag field: "); Serial.print(myIMU.my);
    Serial.print(" mG ");
    Serial.print("Z-mag field: "); Serial.print(myIMU.mz);
    Serial.println(" mG");

    myIMU.tempCount = myIMU.readTempData();  // Read the adc values
    // Temperature in degrees Centigrade
    myIMU.temperature = ((float) myIMU.tempCount) / 333.87 + 21.0;
    // Print temperature in degrees Centigrade
    Serial.print("Temperature is ");  Serial.print(myIMU.temperature, 1);
    Serial.println(" degrees C");
  }

  myIMU.count = micros();
  digitalWrite(myLed, !digitalRead(myLed));  // toggle led
} // if (myIMU.delt_t > 500)

} // if (!AHRS) else { myIMU.delt_t = micros() - myIMU.count;

if (myIMU.delt_t > 500)
{
  if(SerialDebug)
  {
    Serial.print("1");
    Serial.print(",");
    Serial.print(*getQ());
    Serial.print(","); 
    Serial.print(*(getQ() + 1));
    Serial.print(","); 
    Serial.print(*(getQ() + 2));
    Serial.print(","); 
    Serial.print(*(getQ() + 3));
    Serial.print(","); 
    Serial.println(buttonState);
  }

/ if(SerialDebug) { Serial.print("rate = "); Serial.print((float)myIMU.sumCount / myIMU.sum, 2); Serial.println(" Hz"); } /

  myIMU.count = micros();
  myIMU.sumCount = 0;
  myIMU.sum = 0;
} // if (myIMU.delt_t > 500)

} // if (AHRS) }`

VGiaglisis commented 5 years ago

Also these are my magnetometer plots before and after fixed calibration

image image

kriswiner commented 5 years ago

Could be better, especially Mxz.

Are you feeding the sensor data to the fusion algorithm as NED or ENU?

On Fri, Jan 11, 2019 at 5:47 AM VGiaglisis notifications@github.com wrote:

Also these are my magnetometer plots before and after fixed calibration

[image: image] https://user-images.githubusercontent.com/46599678/51037131-0b581b00-15b8-11e9-8af2-e6eb91f543eb.png [image: image] https://user-images.githubusercontent.com/46599678/51037146-18750a00-15b8-11e9-8500-7f52bf489578.png

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/340#issuecomment-453521470, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qtVOIflzhu2gJgk9aD92FNe8Vh3Pks5vCJXmgaJpZM4Z7ewR .

VGiaglisis commented 5 years ago

I am using NED I think. As for the calibration the variable showing big divergence from the expected is My.

kriswiner commented 5 years ago

How do you know you are using NED? It is a user choice, and the sensor data need to be provided then in a particular order.

Maybe increase the calibration time to get My better calibrated?

On Fri, Jan 11, 2019 at 2:52 PM VGiaglisis notifications@github.com wrote:

I am using NED I think. As for the calibration the variably showing big divergence from the expected is my

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/340#issuecomment-453682520, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qkczjSy2P64Ca2car9DTHfSK9F75ks5vCRWhgaJpZM4Z7ewR .

VGiaglisis commented 5 years ago

Ok let me rephrase, the biases are set based on NED longitude and latitude data. I am not sure about the order I am using. The calibration timer is set at 15 seconds but just to be sure I need to ask; When you are saying move in a figure 8 movement you are not referring to a 2D planar figure 8 movement, but a spatial movement trying to achieve various acceleration vectors in all the axes, right? If so I will try changing mpu in case this one is faulty and adjust the timer to 20 sec for some new bias comparisons.

kriswiner commented 5 years ago

Yes, the idea of mag calibration is to sample the entire 3D response surface multiple times during the calibration.

The sensor data needs to be fed to the Madgwick filter as AN, AE, AD, GN, GE, GD, MN, ME, MD for NED or you can also use ENU convention, but either way, it needs to be consistent.

On Fri, Jan 11, 2019 at 4:00 PM VGiaglisis notifications@github.com wrote:

Ok let me rephrase, the biases are set based on NED longitude and latitude data. I am not sure about the order I am using. The calibration timer is set at 15 seconds but just to be sure I need to ask; When you are saying move in a figure 8 movement you are not referring to a 2D planar figure 8 movement, but a spatial movement trying to achieve various acceleration vectors in all the axes, right? If so I will try changing mpu in case this one is faulty and adjust the timer to 20 sec for some new bias comparisons.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/340#issuecomment-453695482, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qgIhslEX45MKyPep055U4GWDTTTCks5vCSWDgaJpZM4Z7ewR .

VGiaglisis commented 5 years ago

Ok thank you, I will try to verify that they are fed correctly and repost with an update. Really appreciate the help!

VGiaglisis commented 5 years ago

Hello again,

I am sorry for the delays. I made numerous atemts of manual calibration (15 seconds of waving) and each time i got different numbers on the mag biases. I am feeding the sesor with: MahonyQuaternionUpdate(-myIMU.ax, -myIMU.ay, myIMU.az, myIMU.gx DEG_TO_RAD, myIMU.gy DEG_TO_RAD, -myIMU.gz * DEG_TO_RAD, myIMU.my, myIMU.mx, myIMU.mz, myIMU.deltat);

Based on NED biases or the Magcal biases. Any ideas?

VGiaglisis commented 5 years ago

I also get values like: AK8963 mag scale (mG) 1.01 0.76 1.44 Which sound way off to me.

kriswiner commented 5 years ago

Yeah, looks like 15 seconds is not enought to fully calibrate the mag. it needs to sample all 3 dimensions of the response surface several times.

On Mon, Jan 21, 2019 at 7:11 AM VGiaglisis notifications@github.com wrote:

I also get values like: AK8963 mag scale (mG) 1.01 0.76 1.44 Which sound way off to me.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/340#issuecomment-456106206, or mute the thread https://github.com/notifications/unsubscribe-auth/AGY1qnk8bAQoPS3vfoCh-FVKFGQ1m4uMks5vFdi2gaJpZM4Z7ewR .

VGiaglisis commented 5 years ago

Update ! I found the problem, my waving calibration motions were too repetitive and i was geting huge (or very small) scalars in 2 planes. I tried waving to greate a planar 8-like shape in each plane (sagittal,coronal,transverse) and then did random figure 8 motions until the calibration was finished. I got way better scales, and much more consistant biases and there seemed to be no restrictions in movement. Maybe if I increased to 20 seconds, I might have gotten even better numbers. I will try it Thank you Kris, the problem was solved. I will try posting a video of the calibration motion just to help others with the same problem.