NXP SensorFusion/NXPMotionSense using a MPU-9250

Status
Not open for further replies.

mjs513

Senior Member+
SensorFusion/NXPMotionSense using a MPU-9250

After using various Kalman filters decided to see if I could get the SensorFusion algorithm working with a MPU-9250 instead of the propshield. I did manage to get it operational but... The but is that yaw does converge to a solution but very very slowly on the order of minute or two. Pitch and Roll work fine and are responsive to imu movement. Any suggestion on what parameters that I can changed in SensorFusion.cpp would be appreciated.

Here is some added info:

I did have to make a couple of changes to SensorFusion.cpp and NXPMotionSense.h to get yaw working:
1. Added a function to return quaternions to NXPMotionSense.h:
Code:
	void getQuaternion(float quat[4]) { 
		quat[0] = qPl.q0; 
		quat[1] = qPl.q1; 
		quat[2] = qPl.q2; 
		quat[3] = qPl.q3; 
	}

2. changed the limits on the validCal to:
Code:
	if (fabsf(mx) >= 0.0f && fabsf(my) >= 0.0f && fabsf(mz) >= 0.0f) {
        //Note was 20 for all cases
		ValidMagCal = 1;
	} else {
		ValidMagCal = 0;
	}


SENSORFUSION.CPP Parameters:
Code:
// kalman filter noise variances
#define FQVA_9DOF_GBY_KALMAN 2E-6F              // accelerometer noise g^2 so 1.4mg RMS
#define FQVM_9DOF_GBY_KALMAN 0.1F               // magnetometer noise uT^2
#define FQVG_9DOF_GBY_KALMAN 0.3F               // gyro noise (deg/s)^2
#define FQWB_9DOF_GBY_KALMAN 1E-9F              // gyro offset drift (deg/s)^2: 1E-9 implies 0.09deg/s max at 50Hz
#define FQWA_9DOF_GBY_KALMAN 1E-4F              // linear acceleration drift g^2 (increase slows convergence to g but reduces sensitivity to shake)
#define FQWD_9DOF_GBY_KALMAN 0.5F               // magnetic disturbance drift uT^2 (increase slows convergence to B but reduces sensitivity to magnet)
// initialization of Qw covariance matrix
#define FQWINITTHTH_9DOF_GBY_KALMAN 2000E-5F    // th_e * th_e terms
#define FQWINITBB_9DOF_GBY_KALMAN 250E-3F       // b_e * b_e terms
#define FQWINITTHB_9DOF_GBY_KALMAN 0.0F         // th_e * b_e terms
#define FQWINITAA_9DOF_GBY_KALMAN 10E-5F        // a_e * a_e terms (increase slows convergence to g but reduces sensitivity to shake)
#define FQWINITDD_9DOF_GBY_KALMAN 600E-3F       // d_e * d_e terms (increase slows convergence to B but reduces sensitivity to magnet)
// linear acceleration and magnetic disturbance time constants
#define FCA_9DOF_GBY_KALMAN 0.5F                // linear acceleration decay factor
#define FCD_9DOF_GBY_KALMAN 0.5F                // magnetic disturbance decay factor
// maximum geomagnetic inclination angle tracked by Kalman filter
#define SINDELTAMAX 0.9063078F      // sin of max +ve geomagnetic inclination angle: here 65.0 deg
#define COSDELTAMAX 0.4226183F      // cos of max +ve geomagnetic inclination angle: here 65.0 deg
#define DEFAULTB 50.0F              // default geomagnetic field (uT)
#define X 0                         // vector components
#define Y 1
#define Z 2
#define FDEGTORAD 0.01745329251994F		// degrees to radians conversion = pi / 180
#define FRADTODEG 57.2957795130823F		// radians to degrees conversion = 180 / pi
#define ONEOVER48 0.02083333333F		// 1 / 48
#define ONEOVER3840 0.0002604166667F	// 1 / 3840

And finally, here is the sketch I am using:
Code:
/*
NXPSensorfusion_MPU9250.ino
*/

#include <NXPMotionSense.h>
#include "MPU9250.h"    //Brian Taylor's MPU9250 library from Bolderfilight
#include "EEPROM.h"
#include <elapsedMillis.h>

  // IMU Declares ----------------------------------
  #define IMU_BUS      Wire  //Wire // SPI
  #define IMU_ADDR     0x68  //0x69 // 0x68 // SPI 9
  #define IMU_SCL        19  //47 // 0x255
  #define IMU_SDA        18  //48 // 0x255
  #if (F_CPU == 240000000)
    #define IMU_SPD   1000000  //1000000 // 0==NULL or other
  #else
    #define IMU_SPD   1000000  //1000000 // 0==NULL or other
  #endif
  #define IMU_SRD         9  // Used in initIMU setSRD() - settin gSRD to 9 for a 100 Hz update rate
  #define IMU_INT_PIN    24  //50 // 1 // 16

// an MPU-9250 object on SPI bus 0 with chip select 10
MPU9250 Imu(IMU_BUS, IMU_ADDR);
int status;
// a Sensor Fusion object
NXPSensorFusion filter;

// a flag for when the MPU-9250 has new data
volatile int newData;

// EEPROM buffer and variables to load accel and mag bias 
// and scale factors from CalibrateMPU9250.ino
uint8_t EepromBuffer[48];
float axb, axs, ayb, ays, azb, azs;
float hxb, hxs, hyb, hys, hzb, hzs;

float q[4];
float ax, ay, az;
float gx, gy, gz;
float mx, my, mz;

// timers to measure performance
unsigned long tstart, tstop;

elapsedMillis sincePrint;

float roll, pitch, heading;

void setup() {
  // serial to display data
  Serial.begin(115200);
  while(!Serial && millis()<2000) {}

  // start communication with IMU 
  status = Imu.begin();
  Wire.setClock(400000);
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }
  Serial.println("IMU initialization successful");
  
  // load and set accel and mag bias and scale
  // factors from CalibrateMPU9250.ino 
  for (size_t i=0; i < sizeof(EepromBuffer); i++) {
    EepromBuffer[i] = EEPROM.read(i);
  }
  memcpy(&axb,EepromBuffer+0,4);
  memcpy(&axs,EepromBuffer+4,4);
  memcpy(&ayb,EepromBuffer+8,4);
  memcpy(&ays,EepromBuffer+12,4);
  memcpy(&azb,EepromBuffer+16,4);
  memcpy(&azs,EepromBuffer+20,4);
  memcpy(&hxb,EepromBuffer+24,4);
  memcpy(&hxs,EepromBuffer+28,4);
  memcpy(&hyb,EepromBuffer+32,4);
  memcpy(&hys,EepromBuffer+36,4);
  memcpy(&hzb,EepromBuffer+40,4);
  memcpy(&hzs,EepromBuffer+44,4);

  //Print calibration values
  Serial.print( axb,6); Serial.print(", "); Serial.println(axs,6);
  Serial.print( ayb,6); Serial.print(", "); Serial.println(ays,6);
  Serial.print( azb,6); Serial.print(", "); Serial.println(azs,6);
  Serial.print( hxb,6); Serial.print(", "); Serial.println(hxs,6);
  Serial.print( hyb,6); Serial.print(", "); Serial.println(hys,6);
  Serial.print( hzb,6); Serial.print(", "); Serial.println(hzs,6);

  Serial.println("Accel axes offset/scale factors:");
  Serial.printf("%f, %f, \n%f, %f, \n%f, %f\n", axb, axs, ayb, ays, azb, azs);
  Serial.println("Magnetometer axes offset/scale factors:");
  Serial.printf("%f, %f, \n%f, %f, \n%f, %f\n", hxb, hxs, hyb, hys, hzb, hzs);

  //Load calibration values into sketch
  Imu.setAccelCalX(axb,axs);
  Imu.setAccelCalY(ayb,ays);
  Imu.setAccelCalZ(azb,azs);

  Imu.setMagCalX(hxb,hxs);
  Imu.setMagCalY(hyb,hys);
  Imu.setMagCalZ(hzb,hzs);

  //Options to change ranges.
  // setting the accelerometer full scale range to +/-8G 
  //Imu.setAccelRange(MPU9250::ACCEL_RANGE_16G);
  // setting the gyroscope full scale range to +/-500 deg/s
  //Imu.setGyroRange(MPU9250::GYRO_RANGE_2000DPS);

  // setting a 20 Hz DLPF bandwidth
  Imu.setDlpfBandwidth(MPU9250::DLPF_BANDWIDTH_20HZ);
  // setting SRD to 9 for a 100 Hz update rate
  // 1000/(1+SRD) = update rate
  // SRD = (1000/rate)-1,9
  Imu.setSrd(9);
  
  filter.begin(100); // 100 measurements per second

  //Calibrate Gyro, do not move board
  Imu.calibrateGyro();
  
  // enabling the data ready interrupt
  Imu.enableDataReadyInterrupt();
   //attaching the interrupt to microcontroller pin 1
   pinMode(IMU_INT_PIN,INPUT);
   attachInterrupt(IMU_INT_PIN,runFilter,RISING);


}

void loop() {
  //newData = 1;
  if (newData == 1) {
    newData = 0;
    tstart = micros();
    // read the sensor
    Imu.readSensor();
    // update the filter

    gx = Imu.getGyroY_rads();
    gy = Imu.getGyroX_rads();
    gz = Imu.getGyroZ_rads();
    ax = Imu.getAccelY_mss();
    ay = Imu.getAccelX_mss();
    az = Imu.getAccelZ_mss();
    mx = Imu.getMagX_uT();
    my = Imu.getMagY_uT();
    mz = Imu.getMagZ_uT();
    
    filter.update(gx, -gy, gz, ax, -ay, -az, -my, mx, mz);
    //filter.update(gx*180/PI, -gy*180/PI, gz*180/PI, ax*9.8203, -ay*9.8203, -az*9.8203, -my, mx, mz);
    
    tstop = micros();

    if (sincePrint > 100){
      sincePrint=0;

      //Uncomment to print orientation based on
      //Euler Angles
      //Serial.print(filter.getPitch());
      //Serial.print(", ");
      //Serial.print(filter.getRoll());
      //Serial.print(", ");
      //Serial.println(filter.getYaw());

      //Determine orientation based on Quaternion
      filter.getQuaternion(q);
      getYawPitchRollDeg();
     
    }
  }
}

void runFilter() {
  newData = 1;
}


void getYawPitchRollDeg() {
  float ypr[4];
  float gx, gy, gz; // estimated gravity direction
  //getQ(q, val);
  
  gx = 2 * (q[1]*q[3] - q[0]*q[2]);
  gy = 2 * (q[0]*q[1] + q[2]*q[3]);
  gz = q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3];
  
  ypr[0] = (180/PI) * atan2(2 * q[1] * q[2] - 2 * q[0] * q[3], 2 * q[0]*q[0] + 2 * q[1] * q[1] - 1);
  ypr[1] = -(180/PI) * atan(gx / sqrt(gy*gy + gz*gz));
  ypr[2] = (180/PI) * atan(gy / sqrt(gx*gx + gz*gz));

  Serial.print(ypr[1]); Serial.print(","); 
  Serial.print(ypr[2]); Serial.print(",");
  Serial.print(ypr[0]); Serial.println();

}
 
Last edited:
Don't think its the filter factors. Think it the orientation and units issue for gyro and accel. Working it.
 
Been doing some more work on this and the only way to make it work is to keep the gyro with degrees per second and accel at m/s. I did forget that the MPU9250 library already rotates the accel/gyro axis to align itself with the magnetometer axis. So bottom line here are the final changes for now until I can figure out whats causing the slow convergence of yaw.

Code:
    gx = Imu.getGyroY_rads()*180/PI;
    gy = Imu.getGyroX_rads()*180/PI;
    gz = Imu.getGyroZ_rads()*180/PI;
    ax = Imu.getAccelY_mss();
    ay = Imu.getAccelX_mss();
    az = Imu.getAccelZ_mss();
    mx = Imu.getMagX_uT();
    my = Imu.getMagY_uT();
    mz = Imu.getMagZ_uT();
/*    Serial.print(ax,3); Serial.print(", ");
    Serial.print(ay,3); Serial.print(", ");
    Serial.print(az,3); Serial.print(", ");
    Serial.print(gx,3); Serial.print(", ");
    Serial.print(gy,3); Serial.print(", ");
    Serial.print(gz,3); Serial.print(", ");
    Serial.print(mx,3); Serial.print(", ");
    Serial.print(my,3); Serial.print(", ");
    Serial.println(mz,3);
*/
    filter.update(gx, gy, gz, ax, ay, az, mx, my, mz);
 
Status
Not open for further replies.
Back
Top