AP_NavEKF: Allow EKF to pull data from range finder object

This commit is contained in:
Paul Riseborough 2015-04-17 19:22:51 +10:00 committed by Randy Mackay
parent 7f1749dc1c
commit 1c8e3f9444
2 changed files with 75 additions and 20 deletions

View File

@ -382,9 +382,10 @@ const AP_Param::GroupInfo NavEKF::var_info[] PROGMEM = {
};
// constructor
NavEKF::NavEKF(const AP_AHRS *ahrs, AP_Baro &baro) :
NavEKF::NavEKF(const AP_AHRS *ahrs, AP_Baro &baro, const RangeFinder &rng) :
_ahrs(ahrs),
_baro(baro),
_rng(rng),
state(*reinterpret_cast<struct state_elements *>(&states)),
gpsNEVelVarAccScale(0.05f), // Scale factor applied to horizontal velocity measurement variance due to manoeuvre acceleration - used when GPS doesn't report speed error
gpsDVelVarAccScale(0.07f), // Scale factor applied to vertical velocity measurement variance due to manoeuvre acceleration - used when GPS doesn't report speed error
@ -737,6 +738,9 @@ void NavEKF::UpdateFilter()
covPredStep = false;
}
// Read range finder data which is used by both position and optical flow fusion
readRangeFinder();
// Update states using GPS, altimeter, compass, airspeed and synthetic sideslip observations
SelectVelPosFusion();
SelectMagFusion();
@ -4205,7 +4209,7 @@ void NavEKF::readAirSpdData()
// write the raw optical flow measurements
// this needs to be called externally.
void NavEKF::writeOptFlowMeas(uint8_t &rawFlowQuality, Vector2f &rawFlowRates, Vector2f &rawGyroRates, uint32_t &msecFlowMeas, uint8_t &rangeHealth, float &rawSonarRange)
void NavEKF::writeOptFlowMeas(uint8_t &rawFlowQuality, Vector2f &rawFlowRates, Vector2f &rawGyroRates, uint32_t &msecFlowMeas)
{
// The raw measurements need to be optical flow rates in radians/second averaged across the time since the last update
// The PX4Flow sensor outputs flow rates with the following axis and sign conventions:
@ -4244,21 +4248,6 @@ void NavEKF::writeOptFlowMeas(uint8_t &rawFlowQuality, Vector2f &rawFlowRates, V
} else {
newDataFlow = false;
}
// Use range finder if 3 or more consecutive good samples. This reduces likelihood of using bad data.
if (rangeHealth >= 3) {
statesAtRngTime = statesAtFlowTime;
rngMea = rawSonarRange;
newDataRng = true;
rngValidMeaTime_ms = imuSampleTime_ms;
} else if (!vehicleArmed) {
statesAtRngTime = statesAtFlowTime;
rngMea = RNG_MEAS_ON_GND;
newDataRng = true;
rngValidMeaTime_ms = imuSampleTime_ms;
} else {
// set flag that will trigger fusion of height data
newDataRng = false;
}
}
// calculate the NED earth spin vector in rad/sec
@ -4937,4 +4926,65 @@ bool NavEKF::calcGpsGoodToAlign(void)
}
}
// Read the range finder and take new measurements if available
// Read at 20Hz and apply a median filter
void NavEKF::readRangeFinder(void)
{
static float storedRngMeas[3];
static uint32_t storedRngMeasTime_ms[3];
static uint32_t lastRngMeasTime_ms = 0;
static uint8_t rngMeasIndex = 0;
uint8_t midIndex;
uint8_t maxIndex;
uint8_t minIndex;
// get theoretical correct range when the vehicle is on the ground
rngOnGnd = _rng.ground_clearance_cm() * 0.01f;
if (_rng.status() == RangeFinder::RangeFinder_Good && (imuSampleTime_ms - lastRngMeasTime_ms) > 50) {
// store samples and sample time into a ring buffer
rngMeasIndex ++;
if (rngMeasIndex > 2) {
rngMeasIndex = 0;
}
storedRngMeasTime_ms[rngMeasIndex] = imuSampleTime_ms;
storedRngMeas[rngMeasIndex] = _rng.distance_cm() * 0.01f;
// check for three fresh samples and take median
bool sampleFresh[3];
for (uint8_t index = 0; index <= 2; index++) {
sampleFresh[index] = (imuSampleTime_ms - storedRngMeasTime_ms[index]) < 500;
}
if (sampleFresh[0] && sampleFresh[1] && sampleFresh[2]) {
if (storedRngMeas[0] > storedRngMeas[1]) {
minIndex = 1;
maxIndex = 0;
} else {
maxIndex = 0;
minIndex = 1;
}
if (storedRngMeas[2] > storedRngMeas[maxIndex]) {
midIndex = maxIndex;
} else if (storedRngMeas[2] < storedRngMeas[minIndex]) {
midIndex = minIndex;
} else {
midIndex = 2;
}
rngMea = max(storedRngMeas[midIndex],rngOnGnd);
newDataRng = true;
rngValidMeaTime_ms = imuSampleTime_ms;
// recall vehicle states at mid sample time for range finder
RecallStates(statesAtRngTime, storedRngMeasTime_ms[midIndex] - 25);
} else if (!vehicleArmed) {
// if not armed and no return, we assume on ground range
rngMea = rngOnGnd;
newDataRng = true;
rngValidMeaTime_ms = imuSampleTime_ms;
// assume synthetic measurement is at current time (no delay)
statesAtRngTime = state;
} else {
newDataRng = false;
}
lastRngMeasTime_ms = imuSampleTime_ms;
}
}
// Detect takeoff for optical flow navigation
#endif // HAL_CPU_CLASS

View File

@ -29,6 +29,7 @@
#include <AP_Param.h>
#include <AP_Nav_Common.h>
#include <GCS_MAVLink.h>
#include <RangeFinder.h>
// #define MATH_CHECK_INDEXES 1
@ -88,7 +89,7 @@ public:
#endif
// Constructor
NavEKF(const AP_AHRS *ahrs, AP_Baro &baro);
NavEKF(const AP_AHRS *ahrs, AP_Baro &baro, const RangeFinder &rng);
// This function is used to initialise the filter whilst moving, using the AHRS DCM solution
// It should NOT be used to re-initialise after a timeout as DCM will also be corrupted
@ -193,9 +194,8 @@ public:
// rawFlowRates are the optical flow rates in rad/sec about the X and Y sensor axes.
// rawGyroRates are the sensor rotation rates in rad/sec measured by the sensors internal gyro
// The sign convention is that a RH physical rotation of the sensor about an axis produces both a positive flow and gyro rate
// rawSonarRange is the range in metres measured by the range finder
// msecFlowMeas is the scheduler time in msec when the optical flow data was received from the sensor.
void writeOptFlowMeas(uint8_t &rawFlowQuality, Vector2f &rawFlowRates, Vector2f &rawGyroRates, uint32_t &msecFlowMeas, uint8_t &rangeHealth, float &rawSonarRange);
void writeOptFlowMeas(uint8_t &rawFlowQuality, Vector2f &rawFlowRates, Vector2f &rawGyroRates, uint32_t &msecFlowMeas);
// return data for debugging optical flow fusion
void getFlowDebug(float &varFlow, float &gndOffset, float &flowInnovX, float &flowInnovY, float &auxInnov, float &HAGL, float &rngInnov, float &range, float &gndOffsetErr) const;
@ -245,6 +245,7 @@ public:
private:
const AP_AHRS *_ahrs;
AP_Baro &_baro;
const RangeFinder &_rng;
// the states are available in two forms, either as a Vector34, or
// broken down as individual elements. Both are equivalent (same
@ -424,6 +425,10 @@ private:
// Assess GPS data quality and return true if good enough to align the EKF
bool calcGpsGoodToAlign(void);
// Read the range finder and take new measurements if available
// Apply a median filter to range finder data
void readRangeFinder();
// EKF Mavlink Tuneable Parameters
AP_Float _gpsHorizVelNoise; // GPS horizontal velocity measurement noise : m/s
AP_Float _gpsVertVelNoise; // GPS vertical velocity measurement noise : m/s