From 01551a44233112957d22c96926c09fabda0d33b6 Mon Sep 17 00:00:00 2001 From: priseborough Date: Sat, 28 Jan 2017 22:01:35 +1100 Subject: [PATCH] AP_NavEKF3: handle position jump caused by change in GPS receiver If the GPS receiver selection changes and we are using GPS for height, the vertical position will be reset to the new GPS height measurement. correct output observer history when doing a GPS height reset --- .../AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp | 73 +++++++++++++++++-- libraries/AP_NavEKF3/AP_NavEKF3_core.cpp | 2 +- libraries/AP_NavEKF3/AP_NavEKF3_core.h | 2 +- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp b/libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp index 1a6de1fc0e..54151542f6 100644 --- a/libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp +++ b/libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp @@ -92,6 +92,8 @@ void NavEKF3_core::ResetPosition(void) } else { // Use GPS data as first preference if fresh data is available if ((imuSampleTime_ms - lastTimeGpsReceived_ms < 250 && posResetSource == DEFAULT) || posResetSource == GPS) { + // record the ID of the GPS for the data we are using for the reset + last_gps_idx = gpsDataNew.sensor_idx; // write to state vector and compensate for offset between last GPS measurement and the EKF time horizon stateStruct.position.x = gpsDataNew.pos.x + 0.001f*gpsDataNew.vel.x*(float(imuDataDelayed.time_ms) - float(gpsDataNew.time_ms)); stateStruct.position.y = gpsDataNew.pos.y + 0.001f*gpsDataNew.vel.y*(float(imuDataDelayed.time_ms) - float(gpsDataNew.time_ms)); @@ -239,14 +241,6 @@ void NavEKF3_core::SelectVelPosFusion() gpsDataToFuse = storedGPS.recall(gpsDataDelayed,imuDataDelayed.time_ms); // Determine if we need to fuse position and velocity data on this time step if (gpsDataToFuse && PV_AidingMode == AID_ABSOLUTE) { - // Don't fuse velocity data if GPS doesn't support it - if (frontend->_fusionModeGPS <= 1) { - fuseVelData = true; - } else { - fuseVelData = false; - } - fusePosData = true; - // correct GPS data for position offset of antenna phase centre relative to the IMU Vector3f posOffsetBody = _ahrs->get_gps().get_antenna_offset(gpsDataDelayed.sensor_idx) - accelPosOffset; if (!posOffsetBody.is_zero()) { @@ -262,6 +256,16 @@ void NavEKF3_core::SelectVelPosFusion() gpsDataDelayed.pos.y -= posOffsetEarth.y; gpsDataDelayed.hgt += posOffsetEarth.z; } + + + // Don't fuse velocity data if GPS doesn't support it + if (frontend->_fusionModeGPS <= 1) { + fuseVelData = true; + } else { + fuseVelData = false; + } + fusePosData = true; + } else { fuseVelData = false; fusePosData = false; @@ -275,6 +279,59 @@ void NavEKF3_core::SelectVelPosFusion() // Select height data to be fused from the available baro, range finder and GPS sources selectHeightForFusion(); + // if we are using GPS, check for a change in receiver and reset position and height + if (gpsDataToFuse && PV_AidingMode == AID_ABSOLUTE && gpsDataDelayed.sensor_idx != last_gps_idx) { + // record the ID of the GPS that we are using for the reset + last_gps_idx = gpsDataDelayed.sensor_idx; + + // Store the position before the reset so that we can record the reset delta + posResetNE.x = stateStruct.position.x; + posResetNE.y = stateStruct.position.y; + + // Set the position states to the position from the new GPS + stateStruct.position.x = gpsDataNew.pos.x; + stateStruct.position.y = gpsDataNew.pos.y; + + // Calculate the position offset due to the reset + posResetNE.x = stateStruct.position.x - posResetNE.x; + posResetNE.y = stateStruct.position.y - posResetNE.y; + + // Add the offset to the output observer states + for (uint8_t i=0; i