@@ -511,9 +511,10 @@ void NavEKF3_core::SelectVelPosFusion()
511
511
posVelFusionDelayed = false ;
512
512
}
513
513
514
- #if EK3_FEATURE_EXTERNAL_NAV
514
+ const AP_NavEKF_Source::SourceXY posxy_source = frontend->sources .getPosXYSource ();
515
+ #if EK3_FEATURE_EXTERNAL_NAV
515
516
// Check for data at the fusion time horizon
516
- extNavDataToFuse = storedExtNav.recall (extNavDataDelayed, imuDataDelayed.time_ms );
517
+ extNavDataToFuse = (posxy_source == AP_NavEKF_Source::SourceXY::EXTNAV) && storedExtNav.recall (extNavDataDelayed, imuDataDelayed.time_ms );
517
518
if (extNavDataToFuse) {
518
519
CorrectExtNavForSensorOffset (extNavDataDelayed);
519
520
}
@@ -534,7 +535,7 @@ void NavEKF3_core::SelectVelPosFusion()
534
535
readGpsYawData ();
535
536
536
537
// get data that has now fallen behind the fusion time horizon
537
- gpsDataToFuse = storedGPS.recall (gpsDataDelayed,imuDataDelayed.time_ms ) && !waitingForGpsChecks;
538
+ gpsDataToFuse = (posxy_source == AP_NavEKF_Source::SourceXY::GPS) && storedGPS.recall (gpsDataDelayed,imuDataDelayed.time_ms ) && !waitingForGpsChecks;
538
539
539
540
if (gpsDataToFuse) {
540
541
CorrectGPSForAntennaOffset (gpsDataDelayed);
@@ -545,7 +546,7 @@ void NavEKF3_core::SelectVelPosFusion()
545
546
}
546
547
547
548
// detect position source changes. Trigger position reset if position source is valid
548
- const AP_NavEKF_Source::SourceXY posxy_source = frontend-> sources . getPosXYSource ( );
549
+ // GCS_SEND_TEXT(MAV_SEVERITY_INFO, " posxy_source: %u",(unsigned)posxy_source );
549
550
if (posxy_source != posxy_source_last) {
550
551
posxy_source_reset = (posxy_source != AP_NavEKF_Source::SourceXY::NONE);
551
552
posxy_source_last = posxy_source;
@@ -606,6 +607,7 @@ void NavEKF3_core::SelectVelPosFusion()
606
607
607
608
// if we are using GPS, check for a change in receiver and reset position and height
608
609
if (gpsDataToFuse && (PV_AidingMode == AID_ABSOLUTE) && (posxy_source == AP_NavEKF_Source::SourceXY::GPS) && (gpsDataDelayed.sensor_idx != last_gps_idx || posxy_source_reset)) {
610
+ GCS_SEND_TEXT (MAV_SEVERITY_INFO, " fuse gps 2, %u" , gpsDataToFuse);
609
611
// mark a source reset as consumed
610
612
posxy_source_reset = false ;
611
613
@@ -698,70 +700,111 @@ void NavEKF3_core::FuseVelPosNED()
698
700
// data from sensors like GPS receivers; it is the only assumption we can make
699
701
// so we might as well take advantage of the computational efficiencies
700
702
// associated with sequential fusion
701
- if (fuseVelData || fusePosData || fuseHgtData) {
702
- // estimate the velocity, horiz position and height measurement variances.
703
- // Use different errors if operating without external aiding using an assumed position or velocity of zero
704
- if (PV_AidingMode == AID_NONE) {
705
- if (tiltAlignComplete && motorsArmed) {
706
- // This is a compromise between corrections for gyro errors and reducing effect of manoeuvre accelerations on tilt estimate
707
- R_OBS[0 ] = sq (constrain_ftype (frontend->_noaidHorizNoise , 0 .5f , 50 .0f ));
708
- } else {
709
- // Use a smaller value to give faster initial alignment
710
- R_OBS[0 ] = sq (0 .5f );
711
- }
712
- R_OBS[1 ] = R_OBS[0 ];
713
- R_OBS[2 ] = R_OBS[0 ];
714
- R_OBS[3 ] = R_OBS[0 ];
715
- R_OBS[4 ] = R_OBS[0 ];
716
- for (uint8_t i=0 ; i<=2 ; i++) R_OBS_DATA_CHECKS[i] = R_OBS[i];
703
+ if (PV_AidingMode == AID_NONE) {
704
+ if (tiltAlignComplete && motorsArmed) {
705
+ // This is a compromise between corrections for gyro errors and reducing effect of manoeuvre accelerations on tilt estimate
706
+ R_OBS[0 ] = sq (constrain_ftype (frontend->_noaidHorizNoise , 0 .5f , 50 .0f ));
717
707
} else {
708
+ // Use a smaller value to give faster initial alignment
709
+ R_OBS[0 ] = sq (0 .5f );
710
+ }
711
+ R_OBS[1 ] = R_OBS[0 ];
712
+ R_OBS[2 ] = R_OBS[0 ];
713
+ R_OBS[3 ] = R_OBS[0 ];
714
+ R_OBS[4 ] = R_OBS[0 ];
715
+ for (uint8_t i=0 ; i<=2 ; i++) R_OBS_DATA_CHECKS[i] = R_OBS[i];
716
+ } else {
717
+ const bool extNavUsedForVel = extNavVelToFuse && frontend->sources .useVelXYSource (AP_NavEKF_Source::SourceXY::EXTNAV);
718
+ if (fuseVelData)
719
+ {
718
720
#if EK3_FEATURE_EXTERNAL_NAV
719
- const bool extNavUsedForVel = extNavVelToFuse && frontend->sources .useVelXYSource (AP_NavEKF_Source::SourceXY::EXTNAV);
720
721
if (extNavUsedForVel) {
721
722
R_OBS[2 ] = R_OBS[0 ] = sq (constrain_ftype (extNavVelDelayed.err , 0 .05f , 50 .0f ));
722
- } else
723
+ } else
723
724
#endif
724
- if (gpsSpdAccuracy > 0 .0f ) {
725
- // use GPS receivers reported speed accuracy if available and floor at value set by GPS velocity noise parameter
726
- R_OBS[0 ] = sq (constrain_ftype (gpsSpdAccuracy, frontend->_gpsHorizVelNoise , 50 .0f ));
727
- R_OBS[2 ] = sq (constrain_ftype (gpsSpdAccuracy, frontend->_gpsVertVelNoise , 50 .0f ));
728
- } else {
729
- // calculate additional error in GPS velocity caused by manoeuvring
730
- R_OBS[0 ] = sq (constrain_ftype (frontend->_gpsHorizVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsNEVelVarAccScale * accNavMag);
731
- R_OBS[2 ] = sq (constrain_ftype (frontend->_gpsVertVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsDVelVarAccScale * accNavMag);
725
+ if (gpsDataToFuse) {
726
+ if (gpsSpdAccuracy > 0 .0f ) {
727
+ // use GPS receivers reported speed accuracy if available and floor at value set by GPS velocity noise parameter
728
+ R_OBS[0 ] = sq (constrain_ftype (gpsSpdAccuracy, frontend->_gpsHorizVelNoise , 50 .0f ));
729
+ R_OBS[2 ] = sq (constrain_ftype (gpsSpdAccuracy, frontend->_gpsVertVelNoise , 50 .0f ));
730
+ } else {
731
+ // calculate additional error in GPS velocity caused by manoeuvring
732
+ R_OBS[0 ] = sq (constrain_ftype (frontend->_gpsHorizVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsNEVelVarAccScale * accNavMag);
733
+ R_OBS[2 ] = sq (constrain_ftype (frontend->_gpsVertVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsDVelVarAccScale * accNavMag);
734
+ }
735
+ }
736
+ // TODO (EF): Beacon/optical flow/wheel encoder cases?
737
+ else
738
+ {
739
+ GCS_SEND_TEXT (MAV_SEVERITY_WARNING, " fuseVel without extnav or GPS" );
740
+ R_OBS[2 ] = R_OBS[0 ] = 5 .0f ;
732
741
}
733
- R_OBS[1 ] = R_OBS[0 ];
734
- // Use GPS reported position accuracy if available and floor at value set by GPS position noise parameter
742
+ } else {
743
+ // No vel data this update, default value
744
+ R_OBS[2 ] = R_OBS[0 ] = 5 .0f ;
745
+ }
746
+ R_OBS[1 ] = R_OBS[0 ];
747
+
748
+ if (fusePosData)
749
+ {
735
750
#if EK3_FEATURE_EXTERNAL_NAV
736
751
if (extNavUsedForPos) {
737
752
R_OBS[3 ] = sq (constrain_ftype (extNavDataDelayed.posErr , 0 .01f , 100 .0f ));
738
753
} else
739
- #endif
740
- if (gpsPosAccuracy > 0 .0f ) {
741
- R_OBS[3 ] = sq (constrain_ftype (gpsPosAccuracy, frontend->_gpsHorizPosNoise , 100 .0f ));
742
- } else {
754
+ #endif
755
+ // estimate the GPS Velocity, GPS horiz position and height measurement variances.
756
+ // Use different errors if operating without external aiding using an assumed position or velocity of zero
757
+ if (gpsDataToFuse)
758
+ {
743
759
// calculate additional error in GPS position caused by manoeuvring
744
- const ftype posErr = frontend->gpsPosVarAccScale * accNavMag;
745
- R_OBS[3 ] = sq (constrain_ftype (frontend->_gpsHorizPosNoise , 0 .1f , 10 .0f )) + sq (posErr);
760
+ ftype posErr = frontend->gpsPosVarAccScale * accNavMag;
761
+ // Use GPS reported position accuracy if available and floor at value set by GPS position noise parameter
762
+ if (gpsPosAccuracy > 0 .0f ) {
763
+ R_OBS[3 ] = sq (constrain_ftype (gpsPosAccuracy, frontend->_gpsHorizPosNoise , 100 .0f ));
764
+ } else {
765
+ R_OBS[3 ] = sq (constrain_ftype (frontend->_gpsHorizPosNoise , 0 .1f , 10 .0f )) + sq (posErr);
766
+ }
746
767
}
747
- R_OBS[4 ] = R_OBS[3 ];
748
- // For data integrity checks we use the same measurement variances as used to calculate the Kalman gains for all measurements except GPS horizontal velocity
749
- // For horizontal GPS velocity we don't want the acceptance radius to increase with reported GPS accuracy so we use a value based on best GPS performance
750
- // plus a margin for manoeuvres. It is better to reject GPS horizontal velocity errors early
751
- ftype obs_data_chk;
752
- #if EK3_FEATURE_EXTERNAL_NAV
753
- if (extNavUsedForVel) {
754
- obs_data_chk = sq (constrain_ftype (extNavVelDelayed.err , 0 .05f , 5 .0f )) + sq (frontend->extNavVelVarAccScale * accNavMag);
755
- } else
756
- #endif
757
- {
758
- obs_data_chk = sq (constrain_ftype (frontend->_gpsHorizVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsNEVelVarAccScale * accNavMag);
768
+ // TODO (EF): Beacon case?
769
+ else {
770
+ GCS_SEND_TEXT (MAV_SEVERITY_WARNING, " fusePos without extnav or GPS" );
771
+ R_OBS[3 ] = 10 .0f ;
759
772
}
760
- R_OBS_DATA_CHECKS[0 ] = R_OBS_DATA_CHECKS[1 ] = R_OBS_DATA_CHECKS[2 ] = obs_data_chk;
773
+ } else {
774
+ // No vel data this update, default value
775
+ R_OBS[3 ] = 10 .0f ;
776
+ }
777
+ R_OBS[4 ] = R_OBS[3 ];
778
+
779
+ if (fuseHgtData) {
780
+ // TODO (EF): Anthing needed here??
761
781
}
762
- R_OBS[5 ] = posDownObsNoise;
763
- for (uint8_t i=3 ; i<=5 ; i++) R_OBS_DATA_CHECKS[i] = R_OBS[i];
764
782
783
+
784
+ // For data integrity checks we use the same measurement variances as used to calculate the Kalman gains for all measurements except GPS horizontal velocity
785
+ // For horizontal GPS velocity we don't want the acceptance radius to increase with reported GPS accuracy so we use a value based on best GPS performance
786
+ // plus a margin for manoeuvres. It is better to reject GPS horizontal velocity errors early
787
+ ftype obs_data_chk;
788
+ if (gpsDataToFuse)
789
+ {
790
+ obs_data_chk = sq (constrain_ftype (frontend->_gpsHorizVelNoise , 0 .05f , 5 .0f )) + sq (frontend->gpsNEVelVarAccScale * accNavMag);
791
+ }
792
+ #if EK3_FEATURE_EXTERNAL_NAV
793
+ else if (extNavUsedForVel) {
794
+ obs_data_chk = sq (constrain_ftype (extNavVelDelayed.err , 0 .05f , 5 .0f )) + sq (frontend->extNavVelVarAccScale * accNavMag);
795
+ } else {
796
+ // TODO (EF): No horizontal vel this update, default value
797
+ obs_data_chk = 5 .0f ;
798
+ }
799
+ #endif
800
+ R_OBS_DATA_CHECKS[0 ] = R_OBS_DATA_CHECKS[1 ] = R_OBS_DATA_CHECKS[2 ] = obs_data_chk;
801
+
802
+ }
803
+
804
+ R_OBS[5 ] = posDownObsNoise;
805
+ for (uint8_t i=3 ; i<=5 ; i++) R_OBS_DATA_CHECKS[i] = R_OBS[i];
806
+
807
+ // TODO (EF): extra indentation for cleaner git diff, remove
765
808
// if vertical GPS velocity data and an independent height source is being used, check to see if the GPS vertical velocity and altimeter
766
809
// innovations have the same sign and are outside limits. If so, then it is likely aliasing is affecting
767
810
// the accelerometers and we should disable the GPS and barometer innovation consistency checks.
@@ -794,13 +837,15 @@ void NavEKF3_core::FuseVelPosNED()
794
837
}
795
838
}
796
839
797
- // Test horizontal position measurements
798
- if (fusePosData) {
799
- innovVelPos[3 ] = stateStruct.position .x - velPosObs[3 ];
800
- innovVelPos[4 ] = stateStruct.position .y - velPosObs[4 ];
801
- varInnovVelPos[3 ] = P[7 ][7 ] + R_OBS_DATA_CHECKS[3 ];
802
- varInnovVelPos[4 ] = P[8 ][8 ] + R_OBS_DATA_CHECKS[4 ];
840
+ // Test horizontal position measurements
841
+ if (fusePosData) {
842
+ innovVelPos[3 ] = stateStruct.position .x - velPosObs[3 ];
843
+ innovVelPos[4 ] = stateStruct.position .y - velPosObs[4 ];
844
+ varInnovVelPos[3 ] = P[7 ][7 ] + R_OBS_DATA_CHECKS[3 ];
845
+ varInnovVelPos[4 ] = P[8 ][8 ] + R_OBS_DATA_CHECKS[4 ];
803
846
847
+ // TODO (EF): enabling this pos check causes conflict with GPS using external nav
848
+ if (gpsDataToFuse) {
804
849
// Apply an innovation consistency threshold test
805
850
// Don't allow test to fail if not navigating and using a constant position
806
851
// assumption to constrain tilt errors because innovations can become large
@@ -819,7 +864,6 @@ void NavEKF3_core::FuseVelPosNED()
819
864
lastGpsPosPassTime_ms = imuSampleTime_ms;
820
865
varInnovVelPos[3 ] *= posTestRatio;
821
866
varInnovVelPos[4 ] *= posTestRatio;
822
- posCheckPassed = true ;
823
867
lastGpsPosPassTime_ms = imuSampleTime_ms;
824
868
}
825
869
@@ -861,13 +905,14 @@ void NavEKF3_core::FuseVelPosNED()
861
905
fusePosData = false ;
862
906
}
863
907
}
908
+ }
864
909
865
910
// Test velocity measurements
866
911
if (fuseVelData) {
867
912
uint8_t imax = 2 ;
868
913
// Don't fuse vertical velocity observations if disabled in sources or not available
869
914
if ((!frontend->sources .haveVelZSource () || PV_AidingMode != AID_ABSOLUTE ||
870
- !gpsDataDelayed.have_vz ) && !useExtNavVel) {
915
+ !gpsDataDelayed.have_vz ) && !useExtNavVel) {
871
916
imax = 1 ;
872
917
}
873
918
@@ -882,6 +927,7 @@ void NavEKF3_core::FuseVelPosNED()
882
927
varInnovVelPos[i] = P[stateIndex][stateIndex] + R_OBS_DATA_CHECKS[i];
883
928
varVelSum += varInnovVelPos[i];
884
929
}
930
+ // Use the same EK3_VEL_I_GATE for external nav and GPS
885
931
velTestRatio = innovVelSumSq / (varVelSum * sq (MAX (0.01 * (ftype)frontend->_gpsVelInnovGate , 1.0 )));
886
932
bool velCheckPassed = false ; // boolean true if velocity measurements have passed innovation consistency checks
887
933
if (velTestRatio < 1.0 ) {
@@ -917,7 +963,6 @@ void NavEKF3_core::FuseVelPosNED()
917
963
fuseVelData = false ;
918
964
}
919
965
}
920
-
921
966
// Test height measurements
922
967
if (fuseHgtData) {
923
968
// Calculate height innovations
@@ -1154,7 +1199,6 @@ void NavEKF3_core::FuseVelPosNED()
1154
1199
} else if (obsIndex == 5 ) {
1155
1200
faultStatus.bad_dpos = true ;
1156
1201
}
1157
- }
1158
1202
}
1159
1203
}
1160
1204
}
0 commit comments