mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-27 10:17:45 +08:00
feat(ekf2): add ranging beacon fusion support
- Add Symforce-derivation - No altitude correction - EKF2 replay - New params
This commit is contained in:
committed by
Marco Hauswirth
parent
c260794122
commit
f4c820c7e1
@@ -21,7 +21,7 @@ float32 test_ratio_filtered # signed filtered test ratio
|
|||||||
bool innovation_rejected # true if the observation has been rejected
|
bool innovation_rejected # true if the observation has been rejected
|
||||||
bool fused # true if the sample was successfully fused
|
bool fused # true if the sample was successfully fused
|
||||||
|
|
||||||
# TOPICS estimator_aid_src_baro_hgt estimator_aid_src_ev_hgt estimator_aid_src_gnss_hgt estimator_aid_src_rng_hgt
|
# TOPICS estimator_aid_src_baro_hgt estimator_aid_src_ev_hgt estimator_aid_src_gnss_hgt estimator_aid_src_rng_hgt estimator_aid_src_ranging_beacon
|
||||||
# TOPICS estimator_aid_src_airspeed estimator_aid_src_sideslip
|
# TOPICS estimator_aid_src_airspeed estimator_aid_src_sideslip
|
||||||
# TOPICS estimator_aid_src_fake_hgt
|
# TOPICS estimator_aid_src_fake_hgt
|
||||||
# TOPICS estimator_aid_src_gnss_yaw estimator_aid_src_ev_yaw
|
# TOPICS estimator_aid_src_gnss_yaw estimator_aid_src_ev_yaw
|
||||||
|
|||||||
@@ -111,6 +111,21 @@ void LatLonAlt::computeRadiiOfCurvature(const double latitude, double &meridian_
|
|||||||
transverse_radius_of_curvature = Wgs84::equatorial_radius / sqrt_tmp;
|
transverse_radius_of_curvature = Wgs84::equatorial_radius / sqrt_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
matrix::Dcmf LatLonAlt::computeRotEcefToNed() const
|
||||||
|
{
|
||||||
|
const double cos_lat = cos(_latitude_rad);
|
||||||
|
const double sin_lat = sin(_latitude_rad);
|
||||||
|
const double cos_lon = cos(_longitude_rad);
|
||||||
|
const double sin_lon = sin(_longitude_rad);
|
||||||
|
|
||||||
|
const float val[] = {(float)(-sin_lat * cos_lon), (float)(-sin_lat * sin_lon), (float)cos_lat,
|
||||||
|
(float) - sin_lon, (float)cos_lon, 0.f,
|
||||||
|
(float)(-cos_lat * cos_lon), (float)(-cos_lat * sin_lon), (float) - sin_lat
|
||||||
|
};
|
||||||
|
|
||||||
|
return matrix::Dcmf(val);
|
||||||
|
}
|
||||||
|
|
||||||
LatLonAlt LatLonAlt::operator+(const matrix::Vector3f &delta_pos) const
|
LatLonAlt LatLonAlt::operator+(const matrix::Vector3f &delta_pos) const
|
||||||
{
|
{
|
||||||
const matrix::Vector2d d_lat_lon_to_d_xy = deltaLatLonToDeltaXY(latitude_rad(), altitude());
|
const matrix::Vector2d d_lat_lon_to_d_xy = deltaLatLonToDeltaXY(latitude_rad(), altitude());
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
matrix::Vector3f computeAngularRateNavFrame(const matrix::Vector3f &v_ned) const;
|
matrix::Vector3f computeAngularRateNavFrame(const matrix::Vector3f &v_ned) const;
|
||||||
|
|
||||||
|
// Compute the ECEF to NED coordinate transformation matrix at the current position
|
||||||
|
matrix::Dcmf computeRotEcefToNed() const;
|
||||||
|
|
||||||
struct Wgs84 {
|
struct Wgs84 {
|
||||||
static constexpr double equatorial_radius = 6378137.0;
|
static constexpr double equatorial_radius = 6378137.0;
|
||||||
static constexpr double eccentricity = 0.0818191908425;
|
static constexpr double eccentricity = 0.0818191908425;
|
||||||
|
|||||||
@@ -220,6 +220,13 @@ if(CONFIG_EKF2_RANGE_FINDER)
|
|||||||
list(APPEND EKF_MODULE_PARAMS params_range_finder.yaml)
|
list(APPEND EKF_MODULE_PARAMS params_range_finder.yaml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
list(APPEND EKF_SRCS
|
||||||
|
EKF/aid_sources/ranging_beacon/ranging_beacon_control.cpp
|
||||||
|
)
|
||||||
|
list(APPEND EKF_MODULE_PARAMS params_ranging_beacon.yaml)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CONFIG_EKF2_SIDESLIP)
|
if(CONFIG_EKF2_SIDESLIP)
|
||||||
list(APPEND EKF_SRCS EKF/aid_sources/sideslip/sideslip_fusion.cpp)
|
list(APPEND EKF_SRCS EKF/aid_sources/sideslip/sideslip_fusion.cpp)
|
||||||
list(APPEND EKF_MODULE_PARAMS params_sideslip.yaml)
|
list(APPEND EKF_MODULE_PARAMS params_sideslip.yaml)
|
||||||
|
|||||||
@@ -125,6 +125,12 @@ if(CONFIG_EKF2_RANGE_FINDER)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
list(APPEND EKF_SRCS
|
||||||
|
aid_sources/ranging_beacon/ranging_beacon_control.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(CONFIG_EKF2_SIDESLIP)
|
if(CONFIG_EKF2_SIDESLIP)
|
||||||
list(APPEND EKF_SRCS aid_sources/sideslip/sideslip_fusion.cpp)
|
list(APPEND EKF_SRCS aid_sources/sideslip/sideslip_fusion.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ranging_beacon_control.cpp
|
||||||
|
* Control functions for EKF ranging beacon fusion
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ekf.h"
|
||||||
|
#include <ekf_derivation/generated/compute_range_beacon_innov_var_and_h.h>
|
||||||
|
#include <mathlib/mathlib.h>
|
||||||
|
|
||||||
|
void Ekf::controlRangingBeaconFusion(const imuSample &imu_delayed)
|
||||||
|
{
|
||||||
|
if (!_ranging_beacon_buffer || (_params.ekf2_rngbc_ctrl == 0)) {
|
||||||
|
stopRangingBeaconFusion();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rangingBeaconSample ranging_beacon_sample_delayed{};
|
||||||
|
const bool ranging_beacon_data_ready = _ranging_beacon_buffer->pop_first_older_than(
|
||||||
|
imu_delayed.time_us, &ranging_beacon_sample_delayed);
|
||||||
|
|
||||||
|
if (ranging_beacon_data_ready) {
|
||||||
|
|
||||||
|
const rangingBeaconSample &sample = ranging_beacon_sample_delayed;
|
||||||
|
|
||||||
|
const bool measurement_valid = PX4_ISFINITE(sample.range_m)
|
||||||
|
&& (sample.range_m > 0.f)
|
||||||
|
&& PX4_ISFINITE(sample.range_var)
|
||||||
|
&& PX4_ISFINITE(sample.beacon_lat)
|
||||||
|
&& PX4_ISFINITE(sample.beacon_lon)
|
||||||
|
&& PX4_ISFINITE(sample.beacon_alt);
|
||||||
|
|
||||||
|
if (measurement_valid && _local_origin_lat_lon.isInitialized() && PX4_ISFINITE(_local_origin_alt)) {
|
||||||
|
fuseRangingBeacon(sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_control_status.flags.rngbcn_fusion
|
||||||
|
&& isTimedOut(_aid_src_ranging_beacon.time_last_fuse, 2 * RNGBC_MAX_INTERVAL)) {
|
||||||
|
stopRangingBeaconFusion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ekf::fuseRangingBeacon(const rangingBeaconSample &sample)
|
||||||
|
{
|
||||||
|
const matrix::Vector3d vehicle_ecef = _gpos.toEcef();
|
||||||
|
|
||||||
|
const LatLonAlt beacon_lla(sample.beacon_lat, sample.beacon_lon, sample.beacon_alt);
|
||||||
|
const matrix::Vector3d beacon_ecef = beacon_lla.toEcef();
|
||||||
|
|
||||||
|
const matrix::Vector3d delta_ecef = beacon_ecef - vehicle_ecef;
|
||||||
|
const double predicted_range = delta_ecef.norm();
|
||||||
|
|
||||||
|
const float innovation = static_cast<float>(predicted_range) - sample.range_m;
|
||||||
|
const float R = fmaxf(sample.range_var, sq(_params.ekf2_rngbc_noise));
|
||||||
|
|
||||||
|
// Compute beacon position for the symforce H matrix.
|
||||||
|
// _state.pos(0:1) is always 0 in the global-position EKF, so N,E are relative.
|
||||||
|
// _state.pos(2) contains altitude, so beacon_pos(2) must be absolute.
|
||||||
|
const matrix::Dcmf R_ecef_to_ned = _gpos.computeRotEcefToNed();
|
||||||
|
const Vector3f delta_ecef_f(static_cast<float>(delta_ecef(0)),
|
||||||
|
static_cast<float>(delta_ecef(1)),
|
||||||
|
static_cast<float>(delta_ecef(2)));
|
||||||
|
const Vector3f delta_ned = R_ecef_to_ned * delta_ecef_f;
|
||||||
|
const Vector3f beacon_pos(delta_ned(0), delta_ned(1), _state.pos(2) + delta_ned(2));
|
||||||
|
float innov_var;
|
||||||
|
VectorState H;
|
||||||
|
|
||||||
|
sym::ComputeRangeBeaconInnovVarAndH(_state.vector(), P, beacon_pos, R, FLT_EPSILON, &innov_var, &H);
|
||||||
|
|
||||||
|
updateAidSourceStatus(_aid_src_ranging_beacon,
|
||||||
|
sample.time_us,
|
||||||
|
sample.range_m,
|
||||||
|
R,
|
||||||
|
innovation,
|
||||||
|
innov_var,
|
||||||
|
_params.ekf2_rngbc_gate);
|
||||||
|
|
||||||
|
_aid_src_ranging_beacon.device_id = sample.beacon_id;
|
||||||
|
|
||||||
|
if (_aid_src_ranging_beacon.innovation_rejected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorState K = P * H / innov_var;
|
||||||
|
K(State::pos.idx + 2) = 0.f; // altitude is handled by height reference
|
||||||
|
measurementUpdate(K, H, R, innovation);
|
||||||
|
|
||||||
|
_aid_src_ranging_beacon.fused = true;
|
||||||
|
_aid_src_ranging_beacon.time_last_fuse = _time_delayed_us;
|
||||||
|
_time_last_hor_pos_fuse = _time_delayed_us;
|
||||||
|
|
||||||
|
if (!_control_status.flags.rngbcn_fusion) {
|
||||||
|
ECL_INFO("starting ranging beacon fusion");
|
||||||
|
_control_status.flags.rngbcn_fusion = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ekf::stopRangingBeaconFusion()
|
||||||
|
{
|
||||||
|
if (_control_status.flags.rngbcn_fusion) {
|
||||||
|
ECL_INFO("stopping ranging beacon fusion");
|
||||||
|
_control_status.flags.rngbcn_fusion = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,6 +76,8 @@ static constexpr uint64_t GNSS_YAW_MAX_INTERVAL =
|
|||||||
1500e3; ///< Maximum allowable time interval between GNSS yaw measurements (uSec)
|
1500e3; ///< Maximum allowable time interval between GNSS yaw measurements (uSec)
|
||||||
static constexpr uint64_t MAG_MAX_INTERVAL =
|
static constexpr uint64_t MAG_MAX_INTERVAL =
|
||||||
500e3; ///< Maximum allowable time interval between magnetic field measurements (uSec)
|
500e3; ///< Maximum allowable time interval between magnetic field measurements (uSec)
|
||||||
|
static constexpr uint64_t RNGBC_MAX_INTERVAL =
|
||||||
|
5000e3; ///< Maximum allowable time interval between ranging beacon measurements (uSec)
|
||||||
|
|
||||||
// bad accelerometer detection and mitigation
|
// bad accelerometer detection and mitigation
|
||||||
static constexpr uint64_t BADACC_PROBATION =
|
static constexpr uint64_t BADACC_PROBATION =
|
||||||
@@ -262,6 +264,16 @@ struct auxVelSample {
|
|||||||
};
|
};
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
struct rangingBeaconSample {
|
||||||
|
uint64_t time_us{}; ///< timestamp of the measurement (uSec)
|
||||||
|
uint8_t beacon_id{}; ///< beacon identifier
|
||||||
|
float range_m{}; ///< measured range to beacon (m)
|
||||||
|
float range_var{}; ///< range measurement variance (m^2)
|
||||||
|
double beacon_lat{}; ///< beacon latitude (degrees)
|
||||||
|
double beacon_lon{}; ///< beacon longitude (degrees)
|
||||||
|
float beacon_alt{}; ///< beacon altitude AMSL (m)
|
||||||
|
};
|
||||||
|
|
||||||
struct systemFlagUpdate {
|
struct systemFlagUpdate {
|
||||||
uint64_t time_us{};
|
uint64_t time_us{};
|
||||||
bool at_rest{false};
|
bool at_rest{false};
|
||||||
@@ -503,6 +515,14 @@ struct parameters {
|
|||||||
const float auxvel_gate{5.0f}; ///< velocity fusion innovation consistency gate size (STD)
|
const float auxvel_gate{5.0f}; ///< velocity fusion innovation consistency gate size (STD)
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
// ranging beacon fusion
|
||||||
|
int32_t ekf2_rngbc_ctrl{0}; ///< ranging beacon fusion control (0=disabled, 1=enabled)
|
||||||
|
float ekf2_rngbc_delay{0.f}; ///< ranging beacon measurement delay relative to the IMU (mSec)
|
||||||
|
float ekf2_rngbc_noise{1.f}; ///< ranging beacon measurement noise (m)
|
||||||
|
float ekf2_rngbc_gate{5.f}; ///< ranging beacon fusion innovation consistency gate size (STD)
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
union fault_status_u {
|
union fault_status_u {
|
||||||
@@ -592,6 +612,8 @@ uint64_t gnss_hgt_fault :
|
|||||||
1; ///< 47 - true if GNSS measurements (alt) have been declared faulty and are no longer used
|
1; ///< 47 - true if GNSS measurements (alt) have been declared faulty and are no longer used
|
||||||
uint64_t in_transition : 1; ///< 48 - true if the vehicle is in vtol transition
|
uint64_t in_transition : 1; ///< 48 - true if the vehicle is in vtol transition
|
||||||
uint64_t heading_observable : 1; ///< 49 - true when heading is observable
|
uint64_t heading_observable : 1; ///< 49 - true when heading is observable
|
||||||
|
uint64_t rngbcn_fusion : 1; ///< 50 - true when ranging beacon position fusion is active
|
||||||
|
|
||||||
} flags;
|
} flags;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ void Ekf::controlFusionModes(const imuSample &imu_delayed)
|
|||||||
controlGpsFusion(imu_delayed);
|
controlGpsFusion(imu_delayed);
|
||||||
#endif // CONFIG_EKF2_GNSS
|
#endif // CONFIG_EKF2_GNSS
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
controlRangingBeaconFusion(imu_delayed);
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
|
#if defined(CONFIG_EKF2_AUX_GLOBAL_POSITION) && defined(MODULE_NAME)
|
||||||
_aux_global_position.update(*this, imu_delayed);
|
_aux_global_position.update(*this, imu_delayed);
|
||||||
_control_status.flags.aux_gpos = _aux_global_position.anySourceFusing();
|
_control_status.flags.aux_gpos = _aux_global_position.anySourceFusing();
|
||||||
|
|||||||
@@ -413,6 +413,10 @@ public:
|
|||||||
const auto &aid_src_aux_vel() const { return _aid_src_aux_vel; }
|
const auto &aid_src_aux_vel() const { return _aid_src_aux_vel; }
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
const auto &aid_src_ranging_beacon() const { return _aid_src_ranging_beacon; }
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
bool resetGlobalPosToExternalObservation(double latitude, double longitude, float altitude, float eph, float epv,
|
bool resetGlobalPosToExternalObservation(double latitude, double longitude, float altitude, float eph, float epv,
|
||||||
uint64_t timestamp_observation);
|
uint64_t timestamp_observation);
|
||||||
|
|
||||||
@@ -589,6 +593,10 @@ private:
|
|||||||
# endif // CONFIG_EKF2_GNSS_YAW
|
# endif // CONFIG_EKF2_GNSS_YAW
|
||||||
#endif // CONFIG_EKF2_GNSS
|
#endif // CONFIG_EKF2_GNSS
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
estimator_aid_source1d_s _aid_src_ranging_beacon {};
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_GRAVITY_FUSION)
|
#if defined(CONFIG_EKF2_GRAVITY_FUSION)
|
||||||
estimator_aid_source3d_s _aid_src_gravity {};
|
estimator_aid_source3d_s _aid_src_gravity {};
|
||||||
#endif // CONFIG_EKF2_GRAVITY_FUSION
|
#endif // CONFIG_EKF2_GRAVITY_FUSION
|
||||||
@@ -920,6 +928,12 @@ private:
|
|||||||
|
|
||||||
#endif // CONFIG_EKF2_GNSS
|
#endif // CONFIG_EKF2_GNSS
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
void controlRangingBeaconFusion(const imuSample &imu_delayed);
|
||||||
|
void fuseRangingBeacon(const rangingBeaconSample &sample);
|
||||||
|
void stopRangingBeaconFusion();
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_MAGNETOMETER)
|
#if defined(CONFIG_EKF2_MAGNETOMETER)
|
||||||
// control fusion of magnetometer observations
|
// control fusion of magnetometer observations
|
||||||
void controlMagFusion(const imuSample &imu_sample);
|
void controlMagFusion(const imuSample &imu_sample);
|
||||||
|
|||||||
@@ -810,7 +810,8 @@ void Ekf::updateHorizontalDeadReckoningstatus()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// position aiding active
|
// position aiding active
|
||||||
if ((_control_status.flags.gnss_pos || _control_status.flags.ev_pos || _control_status.flags.aux_gpos)
|
if ((_control_status.flags.gnss_pos || _control_status.flags.ev_pos
|
||||||
|
|| _control_status.flags.aux_gpos || _control_status.flags.rngbcn_fusion)
|
||||||
&& isRecent(_time_last_hor_pos_fuse, _params.no_aid_timeout_max)
|
&& isRecent(_time_last_hor_pos_fuse, _params.no_aid_timeout_max)
|
||||||
) {
|
) {
|
||||||
inertial_dead_reckoning = false;
|
inertial_dead_reckoning = false;
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ EstimatorInterface::~EstimatorInterface()
|
|||||||
#if defined(CONFIG_EKF2_AUXVEL)
|
#if defined(CONFIG_EKF2_AUXVEL)
|
||||||
delete _auxvel_buffer;
|
delete _auxvel_buffer;
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
delete _ranging_beacon_buffer;
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate imu data and store to buffer at desired rate
|
// Accumulate imu data and store to buffer at desired rate
|
||||||
@@ -436,6 +439,46 @@ void EstimatorInterface::setAuxVelData(const auxVelSample &auxvel_sample)
|
|||||||
}
|
}
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
void EstimatorInterface::setRangingBeaconData(const rangingBeaconSample &ranging_beacon_sample)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!_initialised) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the required buffer size if not previously done
|
||||||
|
if (_ranging_beacon_buffer == nullptr) {
|
||||||
|
_ranging_beacon_buffer = new TimestampedRingBuffer<rangingBeaconSample>(_obs_buffer_length);
|
||||||
|
|
||||||
|
if (_ranging_beacon_buffer == nullptr || !_ranging_beacon_buffer->valid()) {
|
||||||
|
delete _ranging_beacon_buffer;
|
||||||
|
_ranging_beacon_buffer = nullptr;
|
||||||
|
printBufferAllocationFailed("ranging beacon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int64_t time_us = ranging_beacon_sample.time_us
|
||||||
|
- static_cast<int64_t>(_params.ekf2_rngbc_delay * 1000)
|
||||||
|
- static_cast<int64_t>(_dt_ekf_avg * 5e5f); // seconds to microseconds divided by 2
|
||||||
|
|
||||||
|
// limit data rate to prevent data being lost
|
||||||
|
if (time_us >= static_cast<int64_t>(_ranging_beacon_buffer->get_newest().time_us + _min_obs_interval_us)) {
|
||||||
|
|
||||||
|
rangingBeaconSample ranging_beacon_sample_new{ranging_beacon_sample};
|
||||||
|
ranging_beacon_sample_new.time_us = time_us;
|
||||||
|
|
||||||
|
_ranging_beacon_buffer->push(ranging_beacon_sample_new);
|
||||||
|
_time_last_ranging_beacon_buffer_push = _time_latest_us;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ECL_WARN("ranging beacon data too fast %" PRIi64 " < %" PRIu64 " + %d", time_us,
|
||||||
|
_ranging_beacon_buffer->get_newest().time_us, _min_obs_interval_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
void EstimatorInterface::setSystemFlagData(const systemFlagUpdate &system_flags)
|
void EstimatorInterface::setSystemFlagData(const systemFlagUpdate &system_flags)
|
||||||
{
|
{
|
||||||
if (!_initialised) {
|
if (!_initialised) {
|
||||||
@@ -618,7 +661,8 @@ int EstimatorInterface::getNumberOfActiveHorizontalPositionAidingSources() const
|
|||||||
{
|
{
|
||||||
return int(_control_status.flags.gnss_pos)
|
return int(_control_status.flags.gnss_pos)
|
||||||
+ int(_control_status.flags.ev_pos)
|
+ int(_control_status.flags.ev_pos)
|
||||||
+ int(_control_status.flags.aux_gpos);
|
+ int(_control_status.flags.aux_gpos)
|
||||||
|
+ int(_control_status.flags.rngbcn_fusion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EstimatorInterface::isHorizontalPositionAidingActive() const
|
bool EstimatorInterface::isHorizontalPositionAidingActive() const
|
||||||
|
|||||||
@@ -146,6 +146,10 @@ public:
|
|||||||
void setAuxVelData(const auxVelSample &auxvel_sample);
|
void setAuxVelData(const auxVelSample &auxvel_sample);
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
void setRangingBeaconData(const rangingBeaconSample &ranging_beacon_sample);
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
void setSystemFlagData(const systemFlagUpdate &system_flags);
|
void setSystemFlagData(const systemFlagUpdate &system_flags);
|
||||||
|
|
||||||
// return a address to the parameters struct
|
// return a address to the parameters struct
|
||||||
@@ -454,6 +458,11 @@ protected:
|
|||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
TimestampedRingBuffer<systemFlagUpdate> *_system_flag_buffer {nullptr};
|
TimestampedRingBuffer<systemFlagUpdate> *_system_flag_buffer {nullptr};
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
TimestampedRingBuffer<rangingBeaconSample> *_ranging_beacon_buffer {nullptr};
|
||||||
|
uint64_t _time_last_ranging_beacon_buffer_push{0};
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_BAROMETER)
|
#if defined(CONFIG_EKF2_BAROMETER)
|
||||||
TimestampedRingBuffer<baroSample> *_baro_buffer {nullptr};
|
TimestampedRingBuffer<baroSample> *_baro_buffer {nullptr};
|
||||||
uint64_t _time_last_baro_buffer_push{0};
|
uint64_t _time_last_baro_buffer_push{0};
|
||||||
|
|||||||
@@ -721,6 +721,23 @@ def compute_gravity_z_innov_var_and_h(
|
|||||||
|
|
||||||
return (innov_var, H.T)
|
return (innov_var, H.T)
|
||||||
|
|
||||||
|
def compute_range_beacon_innov_var_and_h(
|
||||||
|
state: VState,
|
||||||
|
P: MTangent,
|
||||||
|
beacon_pos: sf.V3,
|
||||||
|
R: sf.Scalar,
|
||||||
|
epsilon: sf.Scalar
|
||||||
|
) -> (sf.Scalar, VTangent):
|
||||||
|
|
||||||
|
state = vstate_to_state(state)
|
||||||
|
delta = beacon_pos - state["pos"]
|
||||||
|
range_pred = delta.norm(epsilon=epsilon)
|
||||||
|
|
||||||
|
H = jacobian_chain_rule(range_pred, state)
|
||||||
|
innov_var = (H * P * H.T + R)[0,0]
|
||||||
|
|
||||||
|
return (innov_var, H.T)
|
||||||
|
|
||||||
print("Derive EKF2 equations...")
|
print("Derive EKF2 equations...")
|
||||||
generate_px4_function(predict_covariance, output_names=None)
|
generate_px4_function(predict_covariance, output_names=None)
|
||||||
|
|
||||||
@@ -752,5 +769,6 @@ generate_px4_function(compute_gravity_z_innov_var_and_h, output_names=["innov_va
|
|||||||
generate_px4_function(compute_body_vel_innov_var_h, output_names=["innov_var", "Hx", "Hy", "Hz"])
|
generate_px4_function(compute_body_vel_innov_var_h, output_names=["innov_var", "Hx", "Hy", "Hz"])
|
||||||
generate_px4_function(compute_body_vel_y_innov_var, output_names=["innov_var"])
|
generate_px4_function(compute_body_vel_y_innov_var, output_names=["innov_var"])
|
||||||
generate_px4_function(compute_body_vel_z_innov_var, output_names=["innov_var"])
|
generate_px4_function(compute_body_vel_z_innov_var, output_names=["innov_var"])
|
||||||
|
generate_px4_function(compute_range_beacon_innov_var_and_h, output_names=["innov_var", "H"])
|
||||||
|
|
||||||
generate_px4_state(State, tangent_idx)
|
generate_px4_state(State, tangent_idx)
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// This file was autogenerated by symforce from template:
|
||||||
|
// function/FUNCTION.h.jinja
|
||||||
|
// Do NOT modify by hand.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <matrix/math.hpp>
|
||||||
|
|
||||||
|
namespace sym {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function was autogenerated from a symbolic function. Do not modify by hand.
|
||||||
|
*
|
||||||
|
* Symbolic function: compute_range_beacon_innov_var_and_h
|
||||||
|
*
|
||||||
|
* Args:
|
||||||
|
* state: Matrix25_1
|
||||||
|
* P: Matrix24_24
|
||||||
|
* beacon_pos: Matrix31
|
||||||
|
* R: Scalar
|
||||||
|
* epsilon: Scalar
|
||||||
|
*
|
||||||
|
* Outputs:
|
||||||
|
* innov_var: Scalar
|
||||||
|
* H: Matrix24_1
|
||||||
|
*/
|
||||||
|
template <typename Scalar>
|
||||||
|
void ComputeRangeBeaconInnovVarAndH(const matrix::Matrix<Scalar, 25, 1>& state,
|
||||||
|
const matrix::Matrix<Scalar, 24, 24>& P,
|
||||||
|
const matrix::Matrix<Scalar, 3, 1>& beacon_pos, const Scalar R,
|
||||||
|
const Scalar epsilon, Scalar* const innov_var = nullptr,
|
||||||
|
matrix::Matrix<Scalar, 24, 1>* const H = nullptr) {
|
||||||
|
// Total ops: 40
|
||||||
|
|
||||||
|
// Input arrays
|
||||||
|
|
||||||
|
// Intermediate terms (7)
|
||||||
|
const Scalar _tmp0 = beacon_pos(2, 0) - state(9, 0);
|
||||||
|
const Scalar _tmp1 = beacon_pos(1, 0) - state(8, 0);
|
||||||
|
const Scalar _tmp2 = beacon_pos(0, 0) - state(7, 0);
|
||||||
|
const Scalar _tmp3 = std::pow(Scalar(std::pow(_tmp0, Scalar(2)) + std::pow(_tmp1, Scalar(2)) +
|
||||||
|
std::pow(_tmp2, Scalar(2)) + epsilon),
|
||||||
|
Scalar(Scalar(-1) / Scalar(2)));
|
||||||
|
const Scalar _tmp4 = _tmp0 * _tmp3;
|
||||||
|
const Scalar _tmp5 = _tmp2 * _tmp3;
|
||||||
|
const Scalar _tmp6 = _tmp1 * _tmp3;
|
||||||
|
|
||||||
|
// Output terms (2)
|
||||||
|
if (innov_var != nullptr) {
|
||||||
|
Scalar& _innov_var = (*innov_var);
|
||||||
|
|
||||||
|
_innov_var = R - _tmp4 * (-P(6, 8) * _tmp5 - P(7, 8) * _tmp6 - P(8, 8) * _tmp4) -
|
||||||
|
_tmp5 * (-P(6, 6) * _tmp5 - P(7, 6) * _tmp6 - P(8, 6) * _tmp4) -
|
||||||
|
_tmp6 * (-P(6, 7) * _tmp5 - P(7, 7) * _tmp6 - P(8, 7) * _tmp4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (H != nullptr) {
|
||||||
|
matrix::Matrix<Scalar, 24, 1>& _h = (*H);
|
||||||
|
|
||||||
|
_h.setZero();
|
||||||
|
|
||||||
|
_h(6, 0) = -_tmp5;
|
||||||
|
_h(7, 0) = -_tmp6;
|
||||||
|
_h(8, 0) = -_tmp4;
|
||||||
|
}
|
||||||
|
} // NOLINT(readability/fn_size)
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(readability/fn_size)
|
||||||
|
} // namespace sym
|
||||||
@@ -164,6 +164,12 @@ EKF2::EKF2(bool multi_mode, const px4::wq_config_t &config, bool replay_mode):
|
|||||||
_param_ekf2_rng_pos_y(_params->rng_pos_body(1)),
|
_param_ekf2_rng_pos_y(_params->rng_pos_body(1)),
|
||||||
_param_ekf2_rng_pos_z(_params->rng_pos_body(2)),
|
_param_ekf2_rng_pos_z(_params->rng_pos_body(2)),
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
_param_ekf2_rngbc_ctrl(_params->ekf2_rngbc_ctrl),
|
||||||
|
_param_ekf2_rngbc_delay(_params->ekf2_rngbc_delay),
|
||||||
|
_param_ekf2_rngbc_noise(_params->ekf2_rngbc_noise),
|
||||||
|
_param_ekf2_rngbc_gate(_params->ekf2_rngbc_gate),
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||||
_param_ekf2_ev_delay(_params->ekf2_ev_delay),
|
_param_ekf2_ev_delay(_params->ekf2_ev_delay),
|
||||||
_param_ekf2_ev_ctrl(_params->ekf2_ev_ctrl),
|
_param_ekf2_ev_ctrl(_params->ekf2_ev_ctrl),
|
||||||
@@ -365,6 +371,14 @@ void EKF2::AdvertiseTopics()
|
|||||||
|
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
|
||||||
|
if (_param_ekf2_rngbc_ctrl.get()) {
|
||||||
|
_estimator_aid_src_ranging_beacon_pub.advertise();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_SIDESLIP)
|
#if defined(CONFIG_EKF2_SIDESLIP)
|
||||||
|
|
||||||
if (_param_ekf2_fuse_beta.get()) {
|
if (_param_ekf2_fuse_beta.get()) {
|
||||||
@@ -790,6 +804,9 @@ void EKF2::Run()
|
|||||||
#if defined(CONFIG_EKF2_RANGE_FINDER)
|
#if defined(CONFIG_EKF2_RANGE_FINDER)
|
||||||
UpdateRangeSample(ekf2_timestamps);
|
UpdateRangeSample(ekf2_timestamps);
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
UpdateRangingBeaconSample(ekf2_timestamps);
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
UpdateSystemFlagsSample(ekf2_timestamps);
|
UpdateSystemFlagsSample(ekf2_timestamps);
|
||||||
|
|
||||||
// run the EKF update and output
|
// run the EKF update and output
|
||||||
@@ -992,6 +1009,12 @@ void EKF2::PublishAidSourceStatus(const hrt_abstime ×tamp)
|
|||||||
PublishAidSourceStatus(timestamp, _ekf.aid_src_rng_hgt(), _status_rng_hgt_pub_last, _estimator_aid_src_rng_hgt_pub);
|
PublishAidSourceStatus(timestamp, _ekf.aid_src_rng_hgt(), _status_rng_hgt_pub_last, _estimator_aid_src_rng_hgt_pub);
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
// ranging beacon
|
||||||
|
PublishAidSourceStatus(timestamp, _ekf.aid_src_ranging_beacon(), _status_ranging_beacon_pub_last,
|
||||||
|
_estimator_aid_src_ranging_beacon_pub);
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
// fake position
|
// fake position
|
||||||
PublishAidSourceStatus(timestamp, _ekf.aid_src_fake_pos(), _status_fake_pos_pub_last, _estimator_aid_src_fake_pos_pub);
|
PublishAidSourceStatus(timestamp, _ekf.aid_src_fake_pos(), _status_fake_pos_pub_last, _estimator_aid_src_fake_pos_pub);
|
||||||
PublishAidSourceStatus(timestamp, _ekf.aid_src_fake_hgt(), _status_fake_hgt_pub_last, _estimator_aid_src_fake_hgt_pub);
|
PublishAidSourceStatus(timestamp, _ekf.aid_src_fake_hgt(), _status_fake_hgt_pub_last, _estimator_aid_src_fake_hgt_pub);
|
||||||
@@ -2148,6 +2171,30 @@ void EKF2::UpdateAuxVelSample(ekf2_timestamps_s &ekf2_timestamps)
|
|||||||
}
|
}
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
void EKF2::UpdateRangingBeaconSample(ekf2_timestamps_s &ekf2_timestamps)
|
||||||
|
{
|
||||||
|
ranging_beacon_s ranging_beacon;
|
||||||
|
|
||||||
|
if (_ranging_beacon_sub.update(&ranging_beacon)) {
|
||||||
|
const float range_var = PX4_ISFINITE(ranging_beacon.range_accuracy)
|
||||||
|
? sq(ranging_beacon.range_accuracy) : sq(_param_ekf2_rngbc_noise.get());
|
||||||
|
|
||||||
|
rangingBeaconSample sample{
|
||||||
|
.time_us = ranging_beacon.timestamp_sample,
|
||||||
|
.beacon_id = ranging_beacon.beacon_id,
|
||||||
|
.range_m = ranging_beacon.range,
|
||||||
|
.range_var = range_var,
|
||||||
|
.beacon_lat = ranging_beacon.lat,
|
||||||
|
.beacon_lon = ranging_beacon.lon,
|
||||||
|
.beacon_alt = ranging_beacon.alt,
|
||||||
|
};
|
||||||
|
|
||||||
|
_ekf.setRangingBeaconData(sample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_BAROMETER)
|
#if defined(CONFIG_EKF2_BAROMETER)
|
||||||
void EKF2::UpdateBaroSample(ekf2_timestamps_s &ekf2_timestamps)
|
void EKF2::UpdateBaroSample(ekf2_timestamps_s &ekf2_timestamps)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -123,6 +123,10 @@
|
|||||||
# include <uORB/topics/wind.h>
|
# include <uORB/topics/wind.h>
|
||||||
#endif // CONFIG_EKF2_WIND
|
#endif // CONFIG_EKF2_WIND
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
# include <uORB/topics/ranging_beacon.h>
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
extern pthread_mutex_t ekf2_module_mutex;
|
extern pthread_mutex_t ekf2_module_mutex;
|
||||||
|
|
||||||
class EKF2 final : public ModuleParams, public px4::ScheduledWorkItem
|
class EKF2 final : public ModuleParams, public px4::ScheduledWorkItem
|
||||||
@@ -229,6 +233,9 @@ private:
|
|||||||
#if defined(CONFIG_EKF2_RANGE_FINDER)
|
#if defined(CONFIG_EKF2_RANGE_FINDER)
|
||||||
void UpdateRangeSample(ekf2_timestamps_s &ekf2_timestamps);
|
void UpdateRangeSample(ekf2_timestamps_s &ekf2_timestamps);
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
void UpdateRangingBeaconSample(ekf2_timestamps_s &ekf2_timestamps);
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
void UpdateSystemFlagsSample(ekf2_timestamps_s &ekf2_timestamps);
|
void UpdateSystemFlagsSample(ekf2_timestamps_s &ekf2_timestamps);
|
||||||
|
|
||||||
@@ -339,6 +346,10 @@ private:
|
|||||||
hrt_abstime _status_aux_vel_pub_last{0};
|
hrt_abstime _status_aux_vel_pub_last{0};
|
||||||
#endif // CONFIG_EKF2_AUXVEL
|
#endif // CONFIG_EKF2_AUXVEL
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
uORB::Subscription _ranging_beacon_sub {ORB_ID(ranging_beacon)};
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_OPTICAL_FLOW)
|
#if defined(CONFIG_EKF2_OPTICAL_FLOW)
|
||||||
uORB::Subscription _vehicle_optical_flow_sub {ORB_ID(vehicle_optical_flow)};
|
uORB::Subscription _vehicle_optical_flow_sub {ORB_ID(vehicle_optical_flow)};
|
||||||
uORB::PublicationMulti<vehicle_optical_flow_vel_s> _estimator_optical_flow_vel_pub{ORB_ID(estimator_optical_flow_vel)};
|
uORB::PublicationMulti<vehicle_optical_flow_vel_s> _estimator_optical_flow_vel_pub{ORB_ID(estimator_optical_flow_vel)};
|
||||||
@@ -407,6 +418,11 @@ private:
|
|||||||
int _distance_sensor_selected{-1}; // because we can have several distance sensor instances with different orientations
|
int _distance_sensor_selected{-1}; // because we can have several distance sensor instances with different orientations
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
hrt_abstime _status_ranging_beacon_pub_last {0};
|
||||||
|
uORB::PublicationMulti<estimator_aid_source1d_s> _estimator_aid_src_ranging_beacon_pub{ORB_ID(estimator_aid_src_ranging_beacon)};
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
bool _callback_registered{false};
|
bool _callback_registered{false};
|
||||||
|
|
||||||
hrt_abstime _last_event_flags_publish{0};
|
hrt_abstime _last_event_flags_publish{0};
|
||||||
@@ -622,6 +638,14 @@ private:
|
|||||||
(ParamExtFloat<px4::params::EKF2_RNG_POS_Z>) _param_ekf2_rng_pos_z,
|
(ParamExtFloat<px4::params::EKF2_RNG_POS_Z>) _param_ekf2_rng_pos_z,
|
||||||
#endif // CONFIG_EKF2_RANGE_FINDER
|
#endif // CONFIG_EKF2_RANGE_FINDER
|
||||||
|
|
||||||
|
#if defined(CONFIG_EKF2_RANGING_BEACON)
|
||||||
|
// ranging beacon fusion
|
||||||
|
(ParamExtInt<px4::params::EKF2_RNGBC_CTRL>) _param_ekf2_rngbc_ctrl,
|
||||||
|
(ParamExtFloat<px4::params::EKF2_RNGBC_DELAY>) _param_ekf2_rngbc_delay,
|
||||||
|
(ParamExtFloat<px4::params::EKF2_RNGBC_NOISE>) _param_ekf2_rngbc_noise,
|
||||||
|
(ParamExtFloat<px4::params::EKF2_RNGBC_GATE>) _param_ekf2_rngbc_gate,
|
||||||
|
#endif // CONFIG_EKF2_RANGING_BEACON
|
||||||
|
|
||||||
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
#if defined(CONFIG_EKF2_EXTERNAL_VISION)
|
||||||
// vision estimate fusion
|
// vision estimate fusion
|
||||||
(ParamExtFloat<px4::params::EKF2_EV_DELAY>)
|
(ParamExtFloat<px4::params::EKF2_EV_DELAY>)
|
||||||
|
|||||||
@@ -120,6 +120,13 @@ depends on MODULES_EKF2
|
|||||||
---help---
|
---help---
|
||||||
EKF2 range finder fusion support.
|
EKF2 range finder fusion support.
|
||||||
|
|
||||||
|
menuconfig EKF2_RANGING_BEACON
|
||||||
|
depends on MODULES_EKF2
|
||||||
|
bool "ranging beacon fusion support"
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
EKF2 ranging beacon fusion support.
|
||||||
|
|
||||||
menuconfig EKF2_SIDESLIP
|
menuconfig EKF2_SIDESLIP
|
||||||
depends on MODULES_EKF2
|
depends on MODULES_EKF2
|
||||||
bool "sideslip fusion support"
|
bool "sideslip fusion support"
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
module_name: ekf2
|
||||||
|
parameters:
|
||||||
|
- group: EKF2
|
||||||
|
definitions:
|
||||||
|
EKF2_RNGBC_CTRL:
|
||||||
|
description:
|
||||||
|
short: Ranging beacon fusion control
|
||||||
|
long: Enable/disable ranging beacon fusion.
|
||||||
|
type: enum
|
||||||
|
values:
|
||||||
|
0: Disable ranging beacon fusion
|
||||||
|
1: Enable ranging beacon fusion
|
||||||
|
default: 0
|
||||||
|
EKF2_RNGBC_DELAY:
|
||||||
|
description:
|
||||||
|
short: Ranging beacon measurement delay relative to IMU measurements
|
||||||
|
type: float
|
||||||
|
default: 0
|
||||||
|
min: 0
|
||||||
|
max: 1000
|
||||||
|
unit: ms
|
||||||
|
reboot_required: true
|
||||||
|
decimal: 1
|
||||||
|
EKF2_RNGBC_GATE:
|
||||||
|
description:
|
||||||
|
short: Gate size for ranging beacon fusion
|
||||||
|
long: Sets the number of standard deviations used by the innovation consistency test.
|
||||||
|
type: float
|
||||||
|
default: 5.0
|
||||||
|
min: 1.0
|
||||||
|
unit: SD
|
||||||
|
decimal: 1
|
||||||
|
EKF2_RNGBC_NOISE:
|
||||||
|
description:
|
||||||
|
short: Measurement noise for ranging beacon fusion
|
||||||
|
long: Used to lower bound or replace the uncertainty included in the message
|
||||||
|
type: float
|
||||||
|
default: 30.0
|
||||||
|
min: 0.1
|
||||||
|
max: 500.0
|
||||||
|
unit: m
|
||||||
|
decimal: 1
|
||||||
@@ -53,6 +53,7 @@
|
|||||||
#include <uORB/topics/vehicle_magnetometer.h>
|
#include <uORB/topics/vehicle_magnetometer.h>
|
||||||
#include <uORB/topics/vehicle_optical_flow.h>
|
#include <uORB/topics/vehicle_optical_flow.h>
|
||||||
#include <uORB/topics/vehicle_status.h>
|
#include <uORB/topics/vehicle_status.h>
|
||||||
|
#include <uORB/topics/ranging_beacon.h>
|
||||||
#include <uORB/topics/vehicle_odometry.h>
|
#include <uORB/topics/vehicle_odometry.h>
|
||||||
#include <uORB/topics/aux_global_position.h>
|
#include <uORB/topics/aux_global_position.h>
|
||||||
|
|
||||||
@@ -138,6 +139,9 @@ ReplayEkf2::onSubscriptionAdded(Subscription &sub, uint16_t msg_id)
|
|||||||
} else if (sub.orb_meta == ORB_ID(vehicle_global_position_groundtruth)) {
|
} else if (sub.orb_meta == ORB_ID(vehicle_global_position_groundtruth)) {
|
||||||
_vehicle_global_position_groundtruth_msg_id = msg_id;
|
_vehicle_global_position_groundtruth_msg_id = msg_id;
|
||||||
|
|
||||||
|
} else if (sub.orb_meta == ORB_ID(ranging_beacon)) {
|
||||||
|
_ranging_beacon_msg_id = msg_id;
|
||||||
|
|
||||||
} else if (sub.orb_meta == ORB_ID(ekf2_timestamps)) {
|
} else if (sub.orb_meta == ORB_ID(ekf2_timestamps)) {
|
||||||
_ekf2_timestamps_exists = true;
|
_ekf2_timestamps_exists = true;
|
||||||
}
|
}
|
||||||
@@ -160,6 +164,7 @@ ReplayEkf2::publishEkf2Topics(sensor_combined_s &sensor_combined, std::ifstream
|
|||||||
findTimestampAndPublish(sensor_combined.timestamp, _vehicle_magnetometer_msg_id, replay_file);
|
findTimestampAndPublish(sensor_combined.timestamp, _vehicle_magnetometer_msg_id, replay_file);
|
||||||
findTimestampAndPublish(sensor_combined.timestamp, _vehicle_visual_odometry_msg_id, replay_file);
|
findTimestampAndPublish(sensor_combined.timestamp, _vehicle_visual_odometry_msg_id, replay_file);
|
||||||
findTimestampAndPublish(sensor_combined.timestamp, _aux_global_position_msg_id, replay_file);
|
findTimestampAndPublish(sensor_combined.timestamp, _aux_global_position_msg_id, replay_file);
|
||||||
|
findTimestampAndPublish(sensor_combined.timestamp, _ranging_beacon_msg_id, replay_file);
|
||||||
|
|
||||||
// sensor_combined: publish last because ekf2 is polling on this
|
// sensor_combined: publish last because ekf2 is polling on this
|
||||||
if (_last_sensor_combined_timestamp > 0) {
|
if (_last_sensor_combined_timestamp > 0) {
|
||||||
@@ -195,6 +200,7 @@ ReplayEkf2::publishEkf2Topics(const ekf2_timestamps_s &ekf2_timestamps, std::ifs
|
|||||||
handle_sensor_publication(ekf2_timestamps.vehicle_magnetometer_timestamp_rel, _vehicle_magnetometer_msg_id);
|
handle_sensor_publication(ekf2_timestamps.vehicle_magnetometer_timestamp_rel, _vehicle_magnetometer_msg_id);
|
||||||
handle_sensor_publication(ekf2_timestamps.visual_odometry_timestamp_rel, _vehicle_visual_odometry_msg_id);
|
handle_sensor_publication(ekf2_timestamps.visual_odometry_timestamp_rel, _vehicle_visual_odometry_msg_id);
|
||||||
handle_sensor_publication(0, _aux_global_position_msg_id);
|
handle_sensor_publication(0, _aux_global_position_msg_id);
|
||||||
|
handle_sensor_publication(0, _ranging_beacon_msg_id);
|
||||||
handle_sensor_publication(0, _vehicle_local_position_groundtruth_msg_id);
|
handle_sensor_publication(0, _vehicle_local_position_groundtruth_msg_id);
|
||||||
handle_sensor_publication(0, _vehicle_global_position_groundtruth_msg_id);
|
handle_sensor_publication(0, _vehicle_global_position_groundtruth_msg_id);
|
||||||
handle_sensor_publication(0, _vehicle_attitude_groundtruth_msg_id);
|
handle_sensor_publication(0, _vehicle_attitude_groundtruth_msg_id);
|
||||||
@@ -291,6 +297,7 @@ ReplayEkf2::onExitMainLoop()
|
|||||||
print_sensor_statistics(_vehicle_magnetometer_msg_id, "vehicle_magnetometer");
|
print_sensor_statistics(_vehicle_magnetometer_msg_id, "vehicle_magnetometer");
|
||||||
print_sensor_statistics(_vehicle_visual_odometry_msg_id, "vehicle_visual_odometry");
|
print_sensor_statistics(_vehicle_visual_odometry_msg_id, "vehicle_visual_odometry");
|
||||||
print_sensor_statistics(_aux_global_position_msg_id, "aux_global_position");
|
print_sensor_statistics(_aux_global_position_msg_id, "aux_global_position");
|
||||||
|
print_sensor_statistics(_ranging_beacon_msg_id, "ranging_beacon");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace px4
|
} // namespace px4
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ private:
|
|||||||
uint16_t _vehicle_magnetometer_msg_id = msg_id_invalid;
|
uint16_t _vehicle_magnetometer_msg_id = msg_id_invalid;
|
||||||
uint16_t _vehicle_visual_odometry_msg_id = msg_id_invalid;
|
uint16_t _vehicle_visual_odometry_msg_id = msg_id_invalid;
|
||||||
uint16_t _aux_global_position_msg_id = msg_id_invalid;
|
uint16_t _aux_global_position_msg_id = msg_id_invalid;
|
||||||
|
uint16_t _ranging_beacon_msg_id = msg_id_invalid;
|
||||||
uint16_t _vehicle_local_position_groundtruth_msg_id = msg_id_invalid;
|
uint16_t _vehicle_local_position_groundtruth_msg_id = msg_id_invalid;
|
||||||
uint16_t _vehicle_global_position_groundtruth_msg_id = msg_id_invalid;
|
uint16_t _vehicle_global_position_groundtruth_msg_id = msg_id_invalid;
|
||||||
uint16_t _vehicle_attitude_groundtruth_msg_id = msg_id_invalid;
|
uint16_t _vehicle_attitude_groundtruth_msg_id = msg_id_invalid;
|
||||||
|
|||||||
Reference in New Issue
Block a user