@@ -103,6 +103,11 @@ STATIC_FASTRAM pt1Filter_t rotRateFilterY;
103103STATIC_FASTRAM pt1Filter_t rotRateFilterZ ;
104104FASTRAM fpVector3_t imuMeasuredRotationBFFiltered = {.v = {0.0f , 0.0f , 0.0f }};
105105
106+ STATIC_FASTRAM pt1Filter_t accelFilterX ;
107+ STATIC_FASTRAM pt1Filter_t accelFilterY ;
108+ STATIC_FASTRAM pt1Filter_t accelFilterZ ;
109+ FASTRAM fpVector3_t imuMeasuredAccelBFFiltered = {.v = {0.0f , 0.0f , 0.0f }};
110+
106111STATIC_FASTRAM pt1Filter_t HeadVecEFFilterX ;
107112STATIC_FASTRAM pt1Filter_t HeadVecEFFilterY ;
108113STATIC_FASTRAM pt1Filter_t HeadVecEFFilterZ ;
@@ -196,6 +201,10 @@ void imuInit(void)
196201 pt1FilterReset (& rotRateFilterX , 0 );
197202 pt1FilterReset (& rotRateFilterY , 0 );
198203 pt1FilterReset (& rotRateFilterZ , 0 );
204+ // Initialize accel filter
205+ pt1FilterReset (& accelFilterX , 0 );
206+ pt1FilterReset (& accelFilterY , 0 );
207+ pt1FilterReset (& accelFilterZ , 0 );
199208 // Initialize Heading vector filter
200209 pt1FilterReset (& HeadVecEFFilterX , 0 );
201210 pt1FilterReset (& HeadVecEFFilterY , 0 );
@@ -339,17 +348,23 @@ bool isGPSTrustworthy(void)
339348
340349static float imuCalculateMcCogWeight (void )
341350{
342- float wCoG = imuCalculateAccelerometerWeightNearness (& imuMeasuredAccelBF );
351+ float wCoG = imuCalculateAccelerometerWeightNearness (& imuMeasuredAccelBFFiltered );
343352 float rotRateMagnitude = fast_fsqrtf (vectorNormSquared (& imuMeasuredRotationBFFiltered ));
344353 const float rateSlopeMax = DEGREES_TO_RADIANS ((imuConfig ()-> acc_ignore_rate )) * 4.0f ;
345354 wCoG *= scaleRangef (constrainf (rotRateMagnitude , 0.0f , rateSlopeMax ), 0.0f , rateSlopeMax , 1.0f , 0.0f );
346355 return wCoG ;
347356}
357+ static float imuCalculateMcCogAccWeight (void )
358+ {
359+ fpVector3_t accBFNorm ;
360+ vectorScale (& accBFNorm , & imuMeasuredAccelBFFiltered , 1.0f / GRAVITY_CMSS );
361+ float wCoGAcc = constrainf ((accBFNorm .z - 1.0f )* 2 , 0.0f , 1.0f ); //z direction is verified via SITL
362+ return wCoGAcc ;
363+ }
348364
349- static void imuMahonyAHRSupdate (float dt , const fpVector3_t * gyroBF , const fpVector3_t * accBF , const fpVector3_t * magBF , bool useCOG , float courseOverGround , float accWScaler , float magWScaler )
365+ static void imuMahonyAHRSupdate (float dt , const fpVector3_t * gyroBF , const fpVector3_t * accBF , const fpVector3_t * magBF , const fpVector3_t * vCOG , const fpVector3_t * vCOGAcc , float accWScaler , float magWScaler )
350366{
351367 STATIC_FASTRAM fpVector3_t vGyroDriftEstimate = { 0 };
352-
353368 fpQuaternion_t prevOrientation = orientation ;
354369 fpVector3_t vRotation = * gyroBF ;
355370
@@ -358,10 +373,10 @@ static void imuMahonyAHRSupdate(float dt, const fpVector3_t * gyroBF, const fpVe
358373
359374 /* Step 1: Yaw correction */
360375 // Use measured magnetic field vector
361- if (magBF || useCOG ) {
376+ if (magBF || vCOG || vCOGAcc ) {
362377 float wMag = 1.0f ;
363378 float wCoG = 1.0f ;
364- if (magBF ){ wCoG *= imuConfig ()-> gps_yaw_weight / 100.0f ;}
379+ if (magBF ) { wCoG *= imuConfig ()-> gps_yaw_weight / 100.0f ; }
365380
366381 fpVector3_t vMagErr = { .v = { 0.0f , 0.0f , 0.0f } };
367382 fpVector3_t vCoGErr = { .v = { 0.0f , 0.0f , 0.0f } };
@@ -399,7 +414,8 @@ static void imuMahonyAHRSupdate(float dt, const fpVector3_t * gyroBF, const fpVe
399414 quaternionRotateVector (& vMagErr , & vMagErr , & orientation );
400415 }
401416 }
402- if (useCOG ) {
417+ if (vCOG || vCOGAcc ) {
418+ fpVector3_t vCoGlocal = { .v = { 0.0f , 0.0f , 0.0f } };
403419 fpVector3_t vForward = { .v = { 0.0f , 0.0f , 0.0f } };
404420 //vForward as trust vector
405421 if (STATE (MULTIROTOR ) && (!isMixerTransitionMixing )){
@@ -408,49 +424,58 @@ static void imuMahonyAHRSupdate(float dt, const fpVector3_t * gyroBF, const fpVe
408424 vForward .x = 1.0f ;
409425 }
410426 fpVector3_t vHeadingEF ;
411-
412- // Use raw heading error (from GPS or whatever else)
413- while (courseOverGround > M_PIf ) courseOverGround -= (2.0f * M_PIf );
414- while (courseOverGround < - M_PIf ) courseOverGround += (2.0f * M_PIf );
415-
416- // William Premerlani and Paul Bizard, Direction Cosine Matrix IMU - Eqn. 22-23
417- // (Rxx; Ryx) - measured (estimated) heading vector (EF)
418- // (-cos(COG), sin(COG)) - reference heading vector (EF)
419-
420- float airSpeed = gpsSol .groundSpeed ;
421- // Compute heading vector in EF from scalar CoG,x axis of accelerometer is pointing backwards.
422- fpVector3_t vCoG = { .v = { - cos_approx (courseOverGround ), sin_approx (courseOverGround ), 0.0f } };
423- #if defined(USE_WIND_ESTIMATOR )
424- // remove wind elements in vCoG for better heading estimation
425- if (isEstimatedWindSpeedValid () && imuConfig ()-> gps_yaw_windcomp )
426- {
427- vectorScale (& vCoG , & vCoG , gpsSol .groundSpeed );
428- vCoG .x += getEstimatedWindSpeed (X );
429- vCoG .y -= getEstimatedWindSpeed (Y );
430- airSpeed = fast_fsqrtf (vectorNormSquared (& vCoG ));
431- vectorNormalize (& vCoG , & vCoG );
432- }
433- #endif
434- wCoG *= scaleRangef (constrainf ((airSpeed + gpsSol .groundSpeed )/2 , 400 , 1000 ), 400 , 1000 , 0.0f , 1.0f );
435427 // Rotate Forward vector from BF to EF - will yield Heading vector in Earth frame
436428 quaternionRotateVectorInv (& vHeadingEF , & vForward , & orientation );
437-
429+ if (vCOG ) {
430+ LOG_DEBUG (IMU , "vCOG=(%f,%f,%f)" , (double )vCOG -> x , (double )vCOG -> y , (double )vCOG -> z );
431+ vCoGlocal = * vCOG ;
432+ float airSpeed = gpsSol .groundSpeed ;
433+ #if defined(USE_WIND_ESTIMATOR )
434+ // remove wind elements in vCoGlocal for better heading estimation
435+ if (isEstimatedWindSpeedValid () && imuConfig ()-> gps_yaw_windcomp )
436+ {
437+ vectorScale (& vCoGlocal , & vCoGlocal , gpsSol .groundSpeed );
438+ vCoGlocal .x += getEstimatedWindSpeed (X );
439+ vCoGlocal .y -= getEstimatedWindSpeed (Y );
440+ airSpeed = fast_fsqrtf (vectorNormSquared (& vCoGlocal ));
441+ }
442+ #endif
443+ wCoG *= scaleRangef (constrainf ((airSpeed + gpsSol .groundSpeed )/2 , 400 , 1000 ), 400 , 1000 , 0.0f , 1.0f );
444+ } else { //vCOG is not avaliable and vCOGAcc is avaliable, set the weight of vCOG to zero
445+ wCoG = 0.0f ;
446+ }
438447 if (STATE (MULTIROTOR )){
439448 //when multicopter`s orientation or speed is changing rapidly. less weight on gps heading
440449 wCoG *= imuCalculateMcCogWeight ();
441- //scale accroading to multirotor`s tilt angle
450+ //handle acc based vector
451+ if (vCOGAcc ){
452+ float wCoGAcc = imuCalculateMcCogAccWeight ();//stronger weight on acc if body frame z axis greate than 1G
453+ LOG_DEBUG (IMU , "accFiltZ=%f" , (double )imuMeasuredAccelBFFiltered .z );
454+ LOG_DEBUG (IMU , "wCoGAcc=%f wCoG=%f" , (double )wCoGAcc , (double )wCoG );
455+ LOG_DEBUG (IMU , "vHeadingEF=(%f,%f,%f)" , (double )vHeadingEF .x , (double )vHeadingEF .y , (double )vHeadingEF .z );
456+ LOG_DEBUG (IMU , "vCOGAcc=(%f,%f,%f)" , (double )vCOGAcc -> x , (double )vCOGAcc -> y , (double )vCOGAcc -> z );
457+ if (wCoGAcc > wCoG ){
458+ //when copter is accelerating use gps acc vector instead of gps speed vector
459+ wCoG = wCoGAcc ;
460+ vCoGlocal = * vCOGAcc ;
461+ }
462+ }
463+ //scale according to multirotor`s tilt angle
442464 wCoG *= scaleRangef (constrainf (vHeadingEF .z , COS20DEG , COS10DEG ), COS20DEG , COS10DEG , 1.0f , 0.0f );
443- //for inverted flying, wCoG is lowered by imuCalculateMcCogWeight no additional processing needed
465+ // Inverted flight relies on the existing tilt scaling(scaleRangef); there is no extra handling here
444466 }
467+ LOG_DEBUG (IMU , " wCoG=%f" , (double )wCoG );
468+ LOG_DEBUG (IMU , "vCoGlocal=(%f,%f,%f)" , (double )vCoGlocal .x , (double )vCoGlocal .y , (double )vCoGlocal .z );
445469 vHeadingEF .z = 0.0f ;
446470
447471 // We zeroed out vHeadingEF.z - make sure the whole vector didn't go to zero
448- if (vectorNormSquared (& vHeadingEF ) > 0.01f ) {
472+ if (vectorNormSquared (& vHeadingEF ) > 0.01f && vectorNormSquared ( & vCoGlocal ) > 0.01f ) {
449473 // Normalize to unit vector
450474 vectorNormalize (& vHeadingEF , & vHeadingEF );
475+ vectorNormalize (& vCoGlocal , & vCoGlocal );
451476
452477 // error is cross product between reference heading and estimated heading (calculated in EF)
453- vectorCrossProduct (& vCoGErr , & vCoG , & vHeadingEF );
478+ vectorCrossProduct (& vCoGErr , & vCoGlocal , & vHeadingEF );
454479
455480 // Rotate error back into body frame
456481 quaternionRotateVector (& vCoGErr , & vCoGErr , & orientation );
@@ -637,6 +662,11 @@ static void imuCalculateFilters(float dT)
637662 imuMeasuredRotationBFFiltered .x = pt1FilterApply4 (& rotRateFilterX , imuMeasuredRotationBF .x , IMU_ROTATION_LPF , dT );
638663 imuMeasuredRotationBFFiltered .y = pt1FilterApply4 (& rotRateFilterY , imuMeasuredRotationBF .y , IMU_ROTATION_LPF , dT );
639664 imuMeasuredRotationBFFiltered .z = pt1FilterApply4 (& rotRateFilterZ , imuMeasuredRotationBF .z , IMU_ROTATION_LPF , dT );
665+
666+ imuMeasuredAccelBFFiltered .x = pt1FilterApply4 (& accelFilterX , imuMeasuredAccelBF .x , IMU_ROTATION_LPF , dT );
667+ imuMeasuredAccelBFFiltered .y = pt1FilterApply4 (& accelFilterY , imuMeasuredAccelBF .y , IMU_ROTATION_LPF , dT );
668+ imuMeasuredAccelBFFiltered .z = pt1FilterApply4 (& accelFilterZ , imuMeasuredAccelBF .z , IMU_ROTATION_LPF , dT );
669+
640670 HeadVecEFFiltered .x = pt1FilterApply4 (& HeadVecEFFilterX , rMat [0 ][0 ], IMU_ROTATION_LPF , dT );
641671 HeadVecEFFiltered .y = pt1FilterApply4 (& HeadVecEFFilterY , rMat [1 ][0 ], IMU_ROTATION_LPF , dT );
642672 HeadVecEFFiltered .z = pt1FilterApply4 (& HeadVecEFFilterZ , rMat [2 ][0 ], IMU_ROTATION_LPF , dT );
@@ -646,7 +676,7 @@ static void imuCalculateFilters(float dT)
646676 GPS3DspeedFiltered = pt1FilterApply4 (& GPS3DspeedFilter , GPS3Dspeed , IMU_ROTATION_LPF , dT );
647677}
648678
649- static void imuCalculateGPSacceleration (fpVector3_t * vEstcentrifugalAccelBF , float * acc_ignore_slope_multipiler )
679+ static void imuCalculateGPSacceleration (fpVector3_t * vEstAccelEF , fpVector3_t * vEstcentrifugalAccelBF , float * acc_ignore_slope_multipiler )
650680{
651681 static rtcTime_t lastGPSNewDataTime = 0 ;
652682 static bool lastGPSHeartbeat ;
@@ -660,17 +690,16 @@ static void imuCalculateGPSacceleration(fpVector3_t *vEstcentrifugalAccelBF, flo
660690 if (lastGPSHeartbeat != gpsSol .flags .gpsHeartbeat && time_delta_ms > 0 )
661691 {
662692 // on new gps frame, update accEF and estimate centrifugal accleration
663- fpVector3_t vGPSacc = {.v = {0.0f , 0.0f , 0.0f }};
664- vGPSacc .x = - (currentGPSvel .x - lastGPSvel .x ) / (MS2S (time_delta_ms )); // the x axis of accerometer is pointing backward
665- vGPSacc .y = (currentGPSvel .y - lastGPSvel .y ) / (MS2S (time_delta_ms ));
666- vGPSacc .z = (currentGPSvel .z - lastGPSvel .z ) / (MS2S (time_delta_ms ));
693+ vEstAccelEF -> x = - (currentGPSvel .x - lastGPSvel .x ) / (MS2S (time_delta_ms )); // the x axis of accerometer is pointing backward
694+ vEstAccelEF -> y = (currentGPSvel .y - lastGPSvel .y ) / (MS2S (time_delta_ms ));
695+ vEstAccelEF -> z = (currentGPSvel .z - lastGPSvel .z ) / (MS2S (time_delta_ms ));
667696 // Calculate estimated centrifugal accleration vector in body frame
668- quaternionRotateVector (vEstcentrifugalAccelBF , & vGPSacc , & orientation ); // EF -> BF
697+ quaternionRotateVector (vEstcentrifugalAccelBF , vEstAccelEF , & orientation ); // EF -> BF
669698 lastGPSNewDataTime = currenttime ;
670699 lastGPSvel = currentGPSvel ;
671700 }
672701 lastGPSHeartbeat = gpsSol .flags .gpsHeartbeat ;
673- * acc_ignore_slope_multipiler = 4 ;
702+ * acc_ignore_slope_multipiler = 4.0f ;
674703}
675704
676705static void imuCalculateTurnRateacceleration (fpVector3_t * vEstcentrifugalAccelBF , float dT , float * acc_ignore_slope_multipiler )
@@ -684,14 +713,14 @@ static void imuCalculateTurnRateacceleration(fpVector3_t *vEstcentrifugalAccelBF
684713 * acc_ignore_slope_multipiler = 4.0f ;
685714 }
686715#ifdef USE_PITOT
687- if (sensors (SENSOR_PITOT ) && pitotIsHealthy () && currentspeed < 0 )
716+ else if (sensors (SENSOR_PITOT ) && pitotIsHealthy ())
688717 {
689718 // second choice is pitot
690719 currentspeed = getAirspeedEstimate ();
691720 * acc_ignore_slope_multipiler = 2.0f ;
692721 }
693722#endif
694- if ( currentspeed < 0 )
723+ else
695724 {
696725 //third choice is fixedWingReferenceAirspeed
697726 currentspeed = pidProfile ()-> fixedWingReferenceAirspeed ;
@@ -738,10 +767,11 @@ static void imuCalculateEstimatedAttitude(float dT)
738767#else
739768 const bool canUseMAG = false;
740769#endif
741-
742- float courseOverGround = 0 ;
770+ static fpVector3_t vCOG ;
771+ static fpVector3_t vCOGAcc ;
743772 bool useMag = false;
744773 bool useCOG = false;
774+ bool useCOGAcc = false;
745775#if defined(USE_GPS )
746776 bool canUseCOG = isGPSHeadingValid ();
747777
@@ -753,7 +783,16 @@ static void imuCalculateEstimatedAttitude(float dT)
753783 // Use GPS (if available)
754784 if (canUseCOG ) {
755785 if (gpsHeadingInitialized ) {
756- courseOverGround = DECIDEGREES_TO_RADIANS (gpsSol .groundCourse );
786+ float courseOverGround = DECIDEGREES_TO_RADIANS (gpsSol .groundCourse );
787+ while (courseOverGround > M_PIf ) courseOverGround -= (2.0f * M_PIf );
788+ while (courseOverGround < - M_PIf ) courseOverGround += (2.0f * M_PIf );
789+ // William Premerlani and Paul Bizard, Direction Cosine Matrix IMU - Eqn. 22-23
790+ // (Rxx; Ryx) - measured (estimated) heading vector (EF)
791+ // (-cos(COG), sin(COG)) - reference heading vector (EF)
792+ vCOG .x = - cos_approx (courseOverGround ); // the x axis of accerometer is pointing tail
793+ vCOG .y = sin_approx (courseOverGround );
794+ vCOG .z = 0 ;
795+ // LOG_DEBUG(IMU, "currentGPSvel=(%f,%f,%f)", -(double)gpsSol.velNED[X], (double)gpsSol.velNED[Y], (double)gpsSol.velNED[Z]);
757796 useCOG = true;
758797 }
759798 else if (!canUseMAG ) {
@@ -775,7 +814,9 @@ static void imuCalculateEstimatedAttitude(float dT)
775814 float acc_ignore_slope_multipiler = 1.0f ; // when using gps centrifugal_force_compensation, AccelerometerWeightRateIgnore slope will be multiplied by this value
776815 if (isGPSTrustworthy ())
777816 {
778- imuCalculateGPSacceleration (& vEstcentrifugalAccelBF_velned , & acc_ignore_slope_multipiler );
817+ LOG_DEBUG (IMU , "vCOG=(%f,%f,%f)" , (double )vCOG .x , (double )vCOG .y , (double )vCOG .z );
818+ imuCalculateGPSacceleration (& vCOGAcc , & vEstcentrifugalAccelBF_velned , & acc_ignore_slope_multipiler );
819+ useCOGAcc = true; //currently only for multicopter
779820 }
780821 if (STATE (AIRPLANE ))
781822 {
@@ -824,7 +865,8 @@ static void imuCalculateEstimatedAttitude(float dT)
824865 imuMahonyAHRSupdate (dT , & imuMeasuredRotationBF ,
825866 useAcc ? & compansatedGravityBF : NULL ,
826867 useMag ? & measuredMagBF : NULL ,
827- useCOG , courseOverGround ,
868+ useCOG ? & vCOG : NULL ,
869+ useCOGAcc ? & vCOGAcc : NULL ,
828870 accWeight ,
829871 magWeight );
830872 imuUpdateTailSitter ();
0 commit comments