Skip to content

Commit 871d542

Browse files
author
Eugene
committed
if statements for pos vel fusion adapted to external nav, pos check still causing issues
1 parent cf2714e commit 871d542

File tree

1 file changed

+107
-63
lines changed

1 file changed

+107
-63
lines changed

libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp

Lines changed: 107 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,10 @@ void NavEKF3_core::SelectVelPosFusion()
511511
posVelFusionDelayed = false;
512512
}
513513

514-
#if EK3_FEATURE_EXTERNAL_NAV
514+
const AP_NavEKF_Source::SourceXY posxy_source = frontend->sources.getPosXYSource();
515+
#if EK3_FEATURE_EXTERNAL_NAV
515516
// 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);
517518
if (extNavDataToFuse) {
518519
CorrectExtNavForSensorOffset(extNavDataDelayed);
519520
}
@@ -534,7 +535,7 @@ void NavEKF3_core::SelectVelPosFusion()
534535
readGpsYawData();
535536

536537
// 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;
538539

539540
if (gpsDataToFuse) {
540541
CorrectGPSForAntennaOffset(gpsDataDelayed);
@@ -545,7 +546,7 @@ void NavEKF3_core::SelectVelPosFusion()
545546
}
546547

547548
// 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);
549550
if (posxy_source != posxy_source_last) {
550551
posxy_source_reset = (posxy_source != AP_NavEKF_Source::SourceXY::NONE);
551552
posxy_source_last = posxy_source;
@@ -606,6 +607,7 @@ void NavEKF3_core::SelectVelPosFusion()
606607

607608
// if we are using GPS, check for a change in receiver and reset position and height
608609
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);
609611
// mark a source reset as consumed
610612
posxy_source_reset = false;
611613

@@ -698,70 +700,111 @@ void NavEKF3_core::FuseVelPosNED()
698700
// data from sensors like GPS receivers; it is the only assumption we can make
699701
// so we might as well take advantage of the computational efficiencies
700702
// 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));
717707
} 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+
{
718720
#if EK3_FEATURE_EXTERNAL_NAV
719-
const bool extNavUsedForVel = extNavVelToFuse && frontend->sources.useVelXYSource(AP_NavEKF_Source::SourceXY::EXTNAV);
720721
if (extNavUsedForVel) {
721722
R_OBS[2] = R_OBS[0] = sq(constrain_ftype(extNavVelDelayed.err, 0.05f, 50.0f));
722-
} else
723+
} else
723724
#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;
732741
}
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+
{
735750
#if EK3_FEATURE_EXTERNAL_NAV
736751
if (extNavUsedForPos) {
737752
R_OBS[3] = sq(constrain_ftype(extNavDataDelayed.posErr, 0.01f, 100.0f));
738753
} 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+
{
743759
// 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+
}
746767
}
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;
759772
}
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??
761781
}
762-
R_OBS[5] = posDownObsNoise;
763-
for (uint8_t i=3; i<=5; i++) R_OBS_DATA_CHECKS[i] = R_OBS[i];
764782

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
765808
// if vertical GPS velocity data and an independent height source is being used, check to see if the GPS vertical velocity and altimeter
766809
// innovations have the same sign and are outside limits. If so, then it is likely aliasing is affecting
767810
// the accelerometers and we should disable the GPS and barometer innovation consistency checks.
@@ -794,13 +837,15 @@ void NavEKF3_core::FuseVelPosNED()
794837
}
795838
}
796839

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];
803846

847+
// TODO (EF): enabling this pos check causes conflict with GPS using external nav
848+
if (gpsDataToFuse) {
804849
// Apply an innovation consistency threshold test
805850
// Don't allow test to fail if not navigating and using a constant position
806851
// assumption to constrain tilt errors because innovations can become large
@@ -819,7 +864,6 @@ void NavEKF3_core::FuseVelPosNED()
819864
lastGpsPosPassTime_ms = imuSampleTime_ms;
820865
varInnovVelPos[3] *= posTestRatio;
821866
varInnovVelPos[4] *= posTestRatio;
822-
posCheckPassed = true;
823867
lastGpsPosPassTime_ms = imuSampleTime_ms;
824868
}
825869

@@ -861,13 +905,14 @@ void NavEKF3_core::FuseVelPosNED()
861905
fusePosData = false;
862906
}
863907
}
908+
}
864909

865910
// Test velocity measurements
866911
if (fuseVelData) {
867912
uint8_t imax = 2;
868913
// Don't fuse vertical velocity observations if disabled in sources or not available
869914
if ((!frontend->sources.haveVelZSource() || PV_AidingMode != AID_ABSOLUTE ||
870-
!gpsDataDelayed.have_vz) && !useExtNavVel) {
915+
!gpsDataDelayed.have_vz) && !useExtNavVel) {
871916
imax = 1;
872917
}
873918

@@ -882,6 +927,7 @@ void NavEKF3_core::FuseVelPosNED()
882927
varInnovVelPos[i] = P[stateIndex][stateIndex] + R_OBS_DATA_CHECKS[i];
883928
varVelSum += varInnovVelPos[i];
884929
}
930+
// Use the same EK3_VEL_I_GATE for external nav and GPS
885931
velTestRatio = innovVelSumSq / (varVelSum * sq(MAX(0.01 * (ftype)frontend->_gpsVelInnovGate, 1.0)));
886932
bool velCheckPassed = false; // boolean true if velocity measurements have passed innovation consistency checks
887933
if (velTestRatio < 1.0) {
@@ -917,7 +963,6 @@ void NavEKF3_core::FuseVelPosNED()
917963
fuseVelData = false;
918964
}
919965
}
920-
921966
// Test height measurements
922967
if (fuseHgtData) {
923968
// Calculate height innovations
@@ -1154,7 +1199,6 @@ void NavEKF3_core::FuseVelPosNED()
11541199
} else if (obsIndex == 5) {
11551200
faultStatus.bad_dpos = true;
11561201
}
1157-
}
11581202
}
11591203
}
11601204
}

0 commit comments

Comments
 (0)