Commander: Introduce global_position_relaxed (#24280)

To separate accuracy requirements for VTOL hover and cruise.

- global_position_relaxed refers to having a valid horizontal velocity aid source 
in the estimator and a set global reference position, but poses no requirements 
on the accuracy of the provided position estimate. 
- Auto flight modes Mission, Loiter and RTL, while in fixed-wing mode, 
only require the relaxed global position going forward
- COM_POS_FS_EPH is thus no longer used on fixed-wing vehicles (resp. VTOL in FW)
- rename failsafe_flags.local_position_accuracy_low to failsafe_flags.position_accuracy_low
---------

Signed-off-by: RomanBapst <bapstroman@gmail.com>
Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
Co-authored-by: Silvan <silvan@auterion.com>
This commit is contained in:
Roman Bapst
2025-05-28 08:16:10 +02:00
committed by GitHub
co-authored by Silvan
parent eb72925045
commit b26dd4d3f3
25 changed files with 278 additions and 30 deletions
@@ -45,6 +45,7 @@ HealthAndArmingChecks::HealthAndArmingChecks(ModuleParams *parent, vehicle_statu
_failsafe_flags.local_position_invalid_relaxed = true;
_failsafe_flags.local_velocity_invalid = true;
_failsafe_flags.global_position_invalid = true;
_failsafe_flags.global_position_invalid_relaxed = true;
_failsafe_flags.auto_mission_missing = true;
_failsafe_flags.offboard_control_signal_lost = true;
_failsafe_flags.home_position_invalid = true;
@@ -54,7 +55,10 @@ bool HealthAndArmingChecks::update(bool force_reporting, bool is_arming_request)
{
_reporter.reset();
_reporter.prepare(_context.status().vehicle_type);
// treat VTOLs in transition mode as fixed-wing - this is not in line with what's published as vehicle_status_s::vehicle_type
const uint8_t vehicle_type = _context.status().in_transition_mode ? vehicle_status_s::VEHICLE_TYPE_FIXED_WING :
_context.status().vehicle_type;
_reporter.prepare(vehicle_type);
_context.setIsArmingRequest(is_arming_request);
@@ -78,7 +82,7 @@ bool HealthAndArmingChecks::update(bool force_reporting, bool is_arming_request)
_reporter._mavlink_log_pub = &_mavlink_log_pub;
_reporter.reset();
_reporter.prepare(_context.status().vehicle_type);
_reporter.prepare(vehicle_type);
for (unsigned i = 0; i < sizeof(_checks) / sizeof(_checks[0]); ++i) {
if (!_checks[i]) {
@@ -633,10 +633,18 @@ void EstimatorChecks::checkGps(const Context &context, Report &reporter, const s
void EstimatorChecks::lowPositionAccuracy(const Context &context, Report &reporter,
const vehicle_local_position_s &lpos) const
{
const bool local_position_valid_but_low_accuracy = !reporter.failsafeFlags().local_position_invalid
&& (_param_com_low_eph.get() > FLT_EPSILON && lpos.eph > _param_com_low_eph.get());
if (!reporter.failsafeFlags().local_position_accuracy_low && local_position_valid_but_low_accuracy
bool position_valid_but_low_accuracy = false;
if ((reporter.failsafeFlags().mode_req_global_position && !reporter.failsafeFlags().global_position_invalid) ||
(reporter.failsafeFlags().mode_req_global_position_relaxed
&& !reporter.failsafeFlags().global_position_invalid_relaxed) ||
(reporter.failsafeFlags().mode_req_local_position && !reporter.failsafeFlags().local_position_invalid)) {
position_valid_but_low_accuracy = (_param_com_low_eph.get() > FLT_EPSILON && lpos.eph > _param_com_low_eph.get());
}
if (!reporter.failsafeFlags().position_accuracy_low && position_valid_but_low_accuracy
&& _param_com_pos_low_act.get()) {
// only report if armed
@@ -658,7 +666,7 @@ void EstimatorChecks::lowPositionAccuracy(const Context &context, Report &report
}
}
reporter.failsafeFlags().local_position_accuracy_low = local_position_valid_but_low_accuracy;
reporter.failsafeFlags().position_accuracy_low = position_valid_but_low_accuracy;
}
void EstimatorChecks::setModeRequirementFlags(const Context &context, bool pre_flt_fail_innov_heading,
@@ -698,6 +706,12 @@ void EstimatorChecks::setModeRequirementFlags(const Context &context, bool pre_f
!checkPosVelValidity(now, global_pos_valid, gpos.eph, lpos_eph_threshold, gpos.timestamp,
_last_gpos_fail_time_us, !failsafe_flags.global_position_invalid);
// for relaxed global condition we don't have any accuracy requirement
const float pos_eph_relaxed_treshold = INFINITY;
failsafe_flags.global_position_invalid_relaxed = !checkPosVelValidity(now, global_pos_valid, gpos.eph,
pos_eph_relaxed_treshold, gpos.timestamp, _last_gpos_relaxed_fail_time_us,
!failsafe_flags.global_position_invalid_relaxed);
// Additional warning if the system is about to enter position-loss failsafe after dead-reckoning period
const float eph_critical = 2.5f * lpos_eph_threshold; // threshold used to trigger the navigation failsafe
const float gpos_critical_warning_thrld = math::max(0.9f * eph_critical, math::max(eph_critical - 10.f, 0.f));
@@ -712,6 +726,7 @@ void EstimatorChecks::setModeRequirementFlags(const Context &context, bool pre_f
|| estimator_status_flags.cs_wind_dead_reckoning;
if (!failsafe_flags.global_position_invalid
&& failsafe_flags.mode_req_global_position
&& !_nav_failure_imminent_warned
&& gpos.eph > gpos_critical_warning_thrld
&& dead_reckoning) {
@@ -96,6 +96,7 @@ private:
uORB::Subscription _vehicle_gps_position_sub{ORB_ID(vehicle_gps_position)};
hrt_abstime _last_gpos_fail_time_us{0}; ///< Last time that the global position validity recovery check failed (usec)
hrt_abstime _last_gpos_relaxed_fail_time_us{0}; ///< Last time that the global position relaxed validity recovery check failed (usec)
hrt_abstime _last_lpos_fail_time_us{0}; ///< Last time that the local position validity recovery check failed (usec)
hrt_abstime _last_lpos_relaxed_fail_time_us{0}; ///< Last time that the relaxed local position validity recovery check failed (usec)
hrt_abstime _last_lvel_fail_time_us{0}; ///< Last time that the local velocity validity recovery check failed (usec)
@@ -173,6 +173,8 @@ void ExternalChecks::checkAndReport(const Context &context, Report &reporter)
reporter.failsafeFlags().mode_req_local_position_relaxed);
setOrClearRequirementBits(reply.mode_req_global_position, nav_mode_id, replaces_nav_state,
reporter.failsafeFlags().mode_req_global_position);
setOrClearRequirementBits(reply.mode_req_global_position_relaxed, nav_mode_id, replaces_nav_state,
reporter.failsafeFlags().mode_req_global_position_relaxed);
setOrClearRequirementBits(reply.mode_req_mission, nav_mode_id, replaces_nav_state,
reporter.failsafeFlags().mode_req_mission);
setOrClearRequirementBits(reply.mode_req_home_position, nav_mode_id, replaces_nav_state,
@@ -86,16 +86,27 @@ void ModeChecks::checkAndReport(const Context &context, Report &reporter)
reporter.clearCanRunBits(local_position_modes);
}
NavModes global_position_modes = NavModes::None;
if (reporter.failsafeFlags().global_position_invalid && reporter.failsafeFlags().mode_req_global_position != 0) {
global_position_modes = (NavModes)reporter.failsafeFlags().mode_req_global_position;
}
if (reporter.failsafeFlags().global_position_invalid_relaxed
&& reporter.failsafeFlags().mode_req_global_position_relaxed != 0) {
global_position_modes = global_position_modes | (NavModes)reporter.failsafeFlags().mode_req_global_position_relaxed;
}
if (global_position_modes != NavModes::None) {
/* EVENT
* @description
* The available positioning data is not sufficient to execute the selected mode.
*/
reporter.armingCheckFailure((NavModes)reporter.failsafeFlags().mode_req_global_position,
reporter.armingCheckFailure(global_position_modes,
health_component_t::global_position_estimate,
events::ID("check_modes_global_pos"),
events::Log::Error, "Navigation error: No valid global position estimate");
reporter.clearCanRunBits((NavModes)reporter.failsafeFlags().mode_req_global_position);
reporter.clearCanRunBits(global_position_modes);
}
if (reporter.failsafeFlags().local_altitude_invalid && reporter.failsafeFlags().mode_req_local_alt != 0) {
@@ -50,6 +50,7 @@ void getModeRequirements(uint8_t vehicle_type, failsafe_flags_s &flags)
flags.mode_req_local_position = 0;
flags.mode_req_local_position_relaxed = 0;
flags.mode_req_global_position = 0;
flags.mode_req_global_position_relaxed = 0;
flags.mode_req_local_alt = 0;
flags.mode_req_mission = 0;
flags.mode_req_offboard_signal = 0;
@@ -85,8 +86,16 @@ void getModeRequirements(uint8_t vehicle_type, failsafe_flags_s &flags)
// NAVIGATION_STATE_AUTO_MISSION
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_angular_velocity);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_attitude);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_local_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_global_position);
if (vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_global_position_relaxed);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_local_position_relaxed);
} else {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_global_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_local_position);
}
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_local_alt);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_mission);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION, flags.mode_req_wind_and_flight_time_compliance);
@@ -94,16 +103,32 @@ void getModeRequirements(uint8_t vehicle_type, failsafe_flags_s &flags)
// NAVIGATION_STATE_AUTO_LOITER
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_angular_velocity);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_attitude);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_local_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_global_position);
if (vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_global_position_relaxed);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_local_position_relaxed);
} else {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_global_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_local_position);
}
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_local_alt);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER, flags.mode_req_wind_and_flight_time_compliance);
// NAVIGATION_STATE_AUTO_RTL
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_angular_velocity);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_attitude);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_local_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_global_position);
if (vehicle_type == vehicle_status_s::VEHICLE_TYPE_FIXED_WING) {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_global_position_relaxed);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_local_position_relaxed);
} else {
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_global_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_local_position);
}
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_local_alt);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_home_position);
setRequirement(vehicle_status_s::NAVIGATION_STATE_AUTO_RTL, flags.mode_req_prevent_arming);
+3 -2
View File
@@ -513,12 +513,13 @@ PARAM_DEFINE_INT32(COM_ARM_AUTH_MET, 0);
PARAM_DEFINE_FLOAT(COM_ARM_AUTH_TO, 1);
/**
* Horizontal position error threshold.
* Horizontal position error threshold for hovering systems
*
* This is the horizontal position error (EPH) threshold that will trigger a failsafe.
* The default is appropriate for a multicopter. Can be increased for a fixed-wing.
* If the previous position error was below this threshold, there is an additional
* factor of 2.5 applied (threshold for invalidation 2.5 times the one for validation).
* Only used for multicopters and VTOLs in hover mode.
* Independent from estimator positioning data timeout threshold (see EKF2_NOAID_TOUT).
*
* Set to -1 to disable.
*
+1 -1
View File
@@ -532,7 +532,7 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
// trigger Low Position Accuracy Failsafe (only in auto mission and auto loiter)
if (state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION ||
state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER) {
CHECK_FAILSAFE(status_flags, local_position_accuracy_low, fromPosLowActParam(_param_com_pos_low_act.get()));
CHECK_FAILSAFE(status_flags, position_accuracy_low, fromPosLowActParam(_param_com_pos_low_act.get()));
}
if (state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF ||
@@ -697,6 +697,7 @@ bool FailsafeBase::modeCanRun(const failsafe_flags_s &status_flags, uint8_t mode
(!status_flags.local_position_invalid || ((status_flags.mode_req_local_position & mode_mask) == 0)) &&
(!status_flags.local_position_invalid_relaxed || ((status_flags.mode_req_local_position_relaxed & mode_mask) == 0)) &&
(!status_flags.global_position_invalid || ((status_flags.mode_req_global_position & mode_mask) == 0)) &&
(!status_flags.global_position_invalid_relaxed || ((status_flags.mode_req_global_position_relaxed & mode_mask) == 0)) &&
(!status_flags.local_altitude_invalid || ((status_flags.mode_req_local_alt & mode_mask) == 0)) &&
(!status_flags.auto_mission_missing || ((status_flags.mode_req_mission & mode_mask) == 0)) &&
(!status_flags.offboard_control_signal_lost || ((status_flags.mode_req_offboard_signal & mode_mask) == 0)) &&