mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-10 09:58:28 -04:00
AP_NavEKF: Allow EKF to pull data from range finder object
This commit is contained in:
parent
7f1749dc1c
commit
1c8e3f9444
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user