dcm
DCM.cpp
- Committer:
- wisnup
- Date:
- 2014-02-20
- Revision:
- 0:2b4ec92bff8b
File content as of revision 0:2b4ec92bff8b:
#include "DCM.h" DCM::DCM(float dt) { for(int i = 0; i < 3; i++) { Accel_Vector[i] = 0; // Store the acceleration in a vector Gyro_Vector[i] = 0; // Store the gyros turn rate in a vector Omega_Vector[i] = 0; // Corrected Gyro_Vector data Omega_P[i] = 0; // Omega Proportional correction Omega_I[i] = 0; // Omega Integrator Omega[i]= 0; errorRollPitch[i] = 0; errorYaw[i] = 0; } int k = 1; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { DCM_Matrix[i][j] = 0; Update_Matrix[i][j] = k; Temporary_Matrix[i][j] = 0; k++; } k++; } G_Dt = dt; reset_sensor_fusion(); } void DCM::FilterInit(int rawAccX, int rawAccY, int rawAccZ, int rawGyroX, int rawGyroY, int rawGyroZ, int rawMagX, int rawMagY, int rawMagZ) { setAccelRawX(rawAccX); setAccelRawY(rawAccY); setAccelRawZ(rawAccZ); setGyroRawX(rawGyroX); setGyroRawY(rawGyroY); setGyroRawZ(rawGyroZ); setMagnetRawX(rawMagX); setMagnetRawY(rawMagY); setMagnetRawZ(rawMagZ); reset_sensor_fusion(); } void DCM::init_rotation_matrix(float m[3][3], float yaw, float pitch, float roll) { float c1 = cos(roll); float s1 = sin(roll); float c2 = cos(pitch); float s2 = sin(pitch); float c3 = cos(yaw); float s3 = sin(yaw); // Euler angles, right-handed, intrinsic, XYZ convention // (which means: rotate around body axes Z, Y', X'') m[0][0] = c2 * c3; m[0][1] = c3 * s1 * s2 - c1 * s3; m[0][2] = s1 * s3 + c1 * c3 * s2; m[1][0] = c2 * s3; m[1][1] = c1 * c3 + s1 * s2 * s3; m[1][2] = c1 * s2 * s3 - c3 * s1; m[2][0] = -s2; m[2][1] = c2 * s1; m[2][2] = c1 * c2; } void DCM::ReadMagnetometer() { rawMagnet[0] = ((int16_t)magnetRaw[0]); rawMagnet[1] = ((int16_t)magnetRaw[1]); rawMagnet[2] = ((int16_t)magnetRaw[2]); magnet[0] = ((float)(rawMagnet[0] - MAGN_X_OFFSET) * MAGN_X_SCALE); magnet[1] = ((float)(rawMagnet[1] - MAGN_Y_OFFSET) * MAGN_Y_SCALE); magnet[2] = ((float)(rawMagnet[2] - MAGN_Z_OFFSET) * MAGN_Z_SCALE); } void DCM::ReadAccelerometer() { accel[0] = (((int16_t)accelRaw[0]) - ACCEL_X_OFFSET) * ACCEL_X_SCALE; accel[1] = (((int16_t)accelRaw[1]) - ACCEL_Y_OFFSET) * ACCEL_Y_SCALE; accel[2] = (((int16_t)accelRaw[2]) - ACCEL_Z_OFFSET) * ACCEL_Z_SCALE; } void DCM::ReadGyroscope() { gyro[0] = (gyroRaw[0] - GYRO_BIAS_X); gyro[1] = (gyroRaw[1] - GYRO_BIAS_Y); gyro[2] = (gyroRaw[2] - GYRO_BIAS_Z); } float DCM::constrain(float in, float min, float max) { in = in > max ? max : in; in = in < min ? min : in; return in; } void DCM::Compass_Heading() { float mag_x; float mag_y; float cos_roll; float sin_roll; float cos_pitch; float sin_pitch; cos_roll = cos(roll); sin_roll = sin(roll); cos_pitch = cos(pitch); sin_pitch = sin(pitch); // Tilt compensated magnetic field X mag_x = magnet[0]*cos_pitch + magnet[1]*sin_roll*sin_pitch + magnet[2]*cos_roll*sin_pitch; // Tilt compensated magnetic field Y mag_y = magnet[1]*cos_roll - magnet[2]*sin_roll; // Magnetic Heading MAG_Heading = atan2(-mag_y, mag_x); } void DCM::Normalize(void) { float error=0; float temporary[3][3]; float renorm=0; error= -Vector_Dot_Product(&DCM_Matrix[0][0],&DCM_Matrix[1][0])*.5; //eq.19 Vector_Scale(&temporary[0][0], &DCM_Matrix[1][0], error); //eq.19 Vector_Scale(&temporary[1][0], &DCM_Matrix[0][0], error); //eq.19 Vector_Add(&temporary[0][0], &temporary[0][0], &DCM_Matrix[0][0]);//eq.19 Vector_Add(&temporary[1][0], &temporary[1][0], &DCM_Matrix[1][0]);//eq.19 Vector_Cross_Product(&temporary[2][0],&temporary[0][0],&temporary[1][0]); // c= a x b //eq.20 renorm= .5 *(3 - Vector_Dot_Product(&temporary[0][0],&temporary[0][0])); //eq.21 Vector_Scale(&DCM_Matrix[0][0], &temporary[0][0], renorm); renorm= .5 *(3 - Vector_Dot_Product(&temporary[1][0],&temporary[1][0])); //eq.21 Vector_Scale(&DCM_Matrix[1][0], &temporary[1][0], renorm); renorm= .5 *(3 - Vector_Dot_Product(&temporary[2][0],&temporary[2][0])); //eq.21 Vector_Scale(&DCM_Matrix[2][0], &temporary[2][0], renorm); } /**************************************************/ void DCM::Drift_correction(void) { float mag_heading_x; float mag_heading_y; float errorCourse; //Compensation the Roll, Pitch and Yaw drift. static float Scaled_Omega_P[3]; static float Scaled_Omega_I[3]; float Accel_magnitude; float Accel_weight; //*****Roll and Pitch*************** // Calculate the magnitude of the accelerometer vector Accel_magnitude = sqrt(Accel_Vector[0]*Accel_Vector[0] + Accel_Vector[1]*Accel_Vector[1] + Accel_Vector[2]*Accel_Vector[2]); Accel_magnitude = Accel_magnitude / GRAVITY; // Scale to gravity. // Dynamic weighting of accelerometer info (reliability filter) // Weight for accelerometer info (<0.5G = 0.0, 1G = 1.0 , >1.5G = 0.0) Accel_weight = constrain(1 - 2*abs(1 - Accel_magnitude),0,1); // Vector_Cross_Product(&errorRollPitch[0],&Accel_Vector[0],&DCM_Matrix[2][0]); //adjust the ground of reference Vector_Scale(&Omega_P[0],&errorRollPitch[0],Kp_ROLLPITCH*Accel_weight); Vector_Scale(&Scaled_Omega_I[0],&errorRollPitch[0],Ki_ROLLPITCH*Accel_weight); Vector_Add(Omega_I,Omega_I,Scaled_Omega_I); //*****YAW*************** // We make the gyro YAW drift correction based on compass magnetic heading mag_heading_x = cos(MAG_Heading); mag_heading_y = sin(MAG_Heading); errorCourse=(DCM_Matrix[0][0]*mag_heading_y) - (DCM_Matrix[1][0]*mag_heading_x); //Calculating YAW error Vector_Scale(errorYaw,&DCM_Matrix[2][0],errorCourse); //Applys the yaw correction to the XYZ rotation of the aircraft, depeding the position. Vector_Scale(&Scaled_Omega_P[0],&errorYaw[0],Kp_YAW);//.01proportional of YAW. Vector_Add(Omega_P,Omega_P,Scaled_Omega_P);//Adding Proportional. Vector_Scale(&Scaled_Omega_I[0],&errorYaw[0],Ki_YAW);//.00001Integrator Vector_Add(Omega_I,Omega_I,Scaled_Omega_I);//adding integrator to the Omega_I } void DCM::Matrix_update(void) { Gyro_Vector[0]=GYRO_SCALED_RAD(gyro[0]); //gyro x roll Gyro_Vector[1]=GYRO_SCALED_RAD(gyro[1]); //gyro y pitch Gyro_Vector[2]=GYRO_SCALED_RAD(gyro[2]); //gyro z yaw Accel_Vector[0]=accel[0]; Accel_Vector[1]=accel[1]; Accel_Vector[2]=accel[2]; Vector_Add(&Omega[0], &Gyro_Vector[0], &Omega_I[0]); //adding proportional term Vector_Add(&Omega_Vector[0], &Omega[0], &Omega_P[0]); //adding Integrator term Update_Matrix[0][0]=0; Update_Matrix[0][1]=-G_Dt*Omega_Vector[2];//-z Update_Matrix[0][2]=G_Dt*Omega_Vector[1];//y Update_Matrix[1][0]=G_Dt*Omega_Vector[2];//z Update_Matrix[1][1]=0; Update_Matrix[1][2]=-G_Dt*Omega_Vector[0]; Update_Matrix[2][0]=-G_Dt*Omega_Vector[1]; Update_Matrix[2][1]=G_Dt*Omega_Vector[0]; Update_Matrix[2][2]=0; Matrix_Multiply(Temporary_Matrix,DCM_Matrix,Update_Matrix); //a*b=c for(int x=0; x<3; x++) //Matrix Addition (update) { for(int y=0; y<3; y++) { DCM_Matrix[x][y]+=Temporary_Matrix[x][y]; } } } void DCM::Euler_angles(void) { pitch = -asin(DCM_Matrix[2][0]); roll = atan2(DCM_Matrix[2][1],DCM_Matrix[2][2]); yaw = atan2(DCM_Matrix[1][0],DCM_Matrix[0][0]); } void DCM::Sensors() { ReadAccelerometer(); ReadGyroscope(); ReadMagnetometer(); Compass_Heading(); } void DCM::UpdateFilter() { Sensors(); Matrix_update(); Normalize(); Drift_correction(); Euler_angles(); } void DCM::reset_sensor_fusion() { float temp1[3]; float temp2[3]; float xAxis[] = {1.0f, 0.0f, 0.0f}; Sensors(); // GET PITCH // Using y-z-plane-component/x-component of gravity vector pitch = -atan2(accel[0], sqrt(accel[1] * accel[1] + accel[2] * accel[2])); Vector_Cross_Product(temp1, accel, xAxis); Vector_Cross_Product(temp2, xAxis, temp1); roll = atan2(temp2[1], temp2[2]); // GET YAW Compass_Heading(); yaw = MAG_Heading; // Init rotation matrix init_rotation_matrix(DCM_Matrix, yaw, pitch, roll); } float DCM::getYaw() { return TO_DEG(yaw); } float DCM::getPitch() { return TO_DEG(pitch); } float DCM::getRoll() { return TO_DEG(roll); } void DCM::setAccelRawX(int accelRawX) { accelRaw[0] = (uint16_t)accelRawX; } void DCM::setAccelRawY(int accelRawY) { accelRaw[1] = (uint16_t)accelRawY; } void DCM::setAccelRawZ(int accelRawZ) { accelRaw[2] = (uint16_t)accelRawZ; } void DCM::setGyroRawX(int gyroRawX) { gyroRaw[0] = gyroRawX; } void DCM::setGyroRawY(int gyroRawY) { gyroRaw[1] = gyroRawY; } void DCM::setGyroRawZ(int gyroRawZ) { gyroRaw[2] = gyroRawZ; } void DCM::setMagnetRawX(int magnetRawX) { magnetRaw[0] = (uint16_t)magnetRawX; } void DCM::setMagnetRawY(int magnetRawY) { magnetRaw[1] = (uint16_t)magnetRawY; } void DCM::setMagnetRawZ(int magnetRawZ) { magnetRaw[2] = (uint16_t)magnetRawZ; } float DCM::getTestVariable() { return MAG_Heading; }