mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-11-05 00:21:35 +08:00
commander failsafe: add API to defer failsafes
This commit is contained in:
@@ -167,7 +167,7 @@ void set_param_value_float(const std::string &name, float value)
|
|||||||
|
|
||||||
int failsafe_update(bool armed, bool vtol_in_transition_mode, bool mission_finished,
|
int failsafe_update(bool armed, bool vtol_in_transition_mode, bool mission_finished,
|
||||||
bool user_override, uint8_t user_intended_mode, uint8_t vehicle_type,
|
bool user_override, uint8_t user_intended_mode, uint8_t vehicle_type,
|
||||||
failsafe_flags_s status_flags)
|
failsafe_flags_s status_flags, bool defer_failsafes)
|
||||||
{
|
{
|
||||||
uint64_t time_ms = emscripten_date_now();
|
uint64_t time_ms = emscripten_date_now();
|
||||||
FailsafeBase::State state{};
|
FailsafeBase::State state{};
|
||||||
@@ -177,6 +177,7 @@ int failsafe_update(bool armed, bool vtol_in_transition_mode, bool mission_finis
|
|||||||
state.user_intended_mode = user_intended_mode;
|
state.user_intended_mode = user_intended_mode;
|
||||||
state.vehicle_type = vehicle_type;
|
state.vehicle_type = vehicle_type;
|
||||||
mode_util::getModeRequirements(vehicle_type, status_flags);
|
mode_util::getModeRequirements(vehicle_type, status_flags);
|
||||||
|
failsafe_instance.current().deferFailsafes(defer_failsafes, 0);
|
||||||
return failsafe_instance.current().update(time_ms * 1000, state, false, user_override, status_flags);
|
return failsafe_instance.current().update(time_ms * 1000, state, false, user_override, status_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,6 +206,11 @@
|
|||||||
<button onclick="moveRCSticks()">Move RC Sticks (user takeover request)</button>
|
<button onclick="moveRCSticks()">Move RC Sticks (user takeover request)</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr style="display:none;"> <!-- hide this by default -->
|
||||||
|
<td><label for="defer_failsafes">Defer Failsafes:</label></td>
|
||||||
|
<td><input type="checkbox" id="defer_failsafes" name="defer_failsafes"></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="box"><h3>Parameters</h3>
|
<div class="box"><h3>Parameters</h3>
|
||||||
@@ -322,8 +327,9 @@
|
|||||||
var mission_finished = document.querySelector('input[id="mission_finished"]').checked;
|
var mission_finished = document.querySelector('input[id="mission_finished"]').checked;
|
||||||
var intended_nav_state = document.querySelector('select[id="intended_nav_state"]').value;
|
var intended_nav_state = document.querySelector('select[id="intended_nav_state"]').value;
|
||||||
var vehicle_type = document.querySelector('select[id="vehicle_type"]').value;
|
var vehicle_type = document.querySelector('select[id="vehicle_type"]').value;
|
||||||
|
var defer_failsafes = document.querySelector('input[id="defer_failsafes"]').checked;
|
||||||
var updated_user_intended_mode = Module.failsafe_update(armed, vtol_in_transition_mode, mission_finished, user_override_requested, parseInt(intended_nav_state),
|
var updated_user_intended_mode = Module.failsafe_update(armed, vtol_in_transition_mode, mission_finished, user_override_requested, parseInt(intended_nav_state),
|
||||||
parseInt(vehicle_type), state);
|
parseInt(vehicle_type), state, defer_failsafes);
|
||||||
user_override_requested = false;
|
user_override_requested = false;
|
||||||
var action = Module.selected_action();
|
var action = Module.selected_action();
|
||||||
action_str = Module.action_str(action);
|
action_str = Module.action_str(action);
|
||||||
|
|||||||
@@ -392,8 +392,8 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
|||||||
|
|
||||||
|
|
||||||
CHECK_FAILSAFE(status_flags, wind_limit_exceeded,
|
CHECK_FAILSAFE(status_flags, wind_limit_exceeded,
|
||||||
ActionOptions(Action::RTL).clearOn(ClearCondition::OnModeChangeOrDisarm));
|
ActionOptions(Action::RTL).clearOn(ClearCondition::OnModeChangeOrDisarm).cannotBeDeferred());
|
||||||
CHECK_FAILSAFE(status_flags, flight_time_limit_exceeded, ActionOptions(Action::RTL));
|
CHECK_FAILSAFE(status_flags, flight_time_limit_exceeded, ActionOptions(Action::RTL).cannotBeDeferred());
|
||||||
|
|
||||||
// trigger RTL if low position accurancy is detected
|
// trigger RTL if low position accurancy is detected
|
||||||
if (state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION ||
|
if (state.user_intended_mode == vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION ||
|
||||||
@@ -401,7 +401,7 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
|||||||
CHECK_FAILSAFE(status_flags, local_position_accuracy_low, ActionOptions(Action::RTL));
|
CHECK_FAILSAFE(status_flags, local_position_accuracy_low, ActionOptions(Action::RTL));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_FAILSAFE(status_flags, primary_geofence_breached, fromGfActParam(_param_gf_action.get()));
|
CHECK_FAILSAFE(status_flags, primary_geofence_breached, fromGfActParam(_param_gf_action.get()).cannotBeDeferred());
|
||||||
|
|
||||||
// Battery
|
// Battery
|
||||||
CHECK_FAILSAFE(status_flags, battery_low_remaining_time, ActionOptions(Action::RTL).causedBy(Cause::BatteryLow));
|
CHECK_FAILSAFE(status_flags, battery_low_remaining_time, ActionOptions(Action::RTL).causedBy(Cause::BatteryLow));
|
||||||
@@ -434,7 +434,7 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
|||||||
if ((_armed_time != 0)
|
if ((_armed_time != 0)
|
||||||
&& (time_us < _armed_time + static_cast<hrt_abstime>(_param_com_spoolup_time.get() * 1_s))
|
&& (time_us < _armed_time + static_cast<hrt_abstime>(_param_com_spoolup_time.get() * 1_s))
|
||||||
) {
|
) {
|
||||||
CHECK_FAILSAFE(status_flags, fd_esc_arming_failure, Action::Disarm);
|
CHECK_FAILSAFE(status_flags, fd_esc_arming_failure, ActionOptions(Action::Disarm).cannotBeDeferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_armed_time != 0)
|
if ((_armed_time != 0)
|
||||||
@@ -442,10 +442,10 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
|||||||
+ static_cast<hrt_abstime>((_param_com_lkdown_tko.get() + _param_com_spoolup_time.get()) * 1_s))
|
+ static_cast<hrt_abstime>((_param_com_lkdown_tko.get() + _param_com_spoolup_time.get()) * 1_s))
|
||||||
) {
|
) {
|
||||||
// This handles the case where something fails during the early takeoff phase
|
// This handles the case where something fails during the early takeoff phase
|
||||||
CHECK_FAILSAFE(status_flags, fd_critical_failure, Action::Disarm);
|
CHECK_FAILSAFE(status_flags, fd_critical_failure, ActionOptions(Action::Disarm).cannotBeDeferred());
|
||||||
|
|
||||||
} else if (!circuit_breaker_enabled_by_val(_param_cbrk_flightterm.get(), CBRK_FLIGHTTERM_KEY)) {
|
} else if (!circuit_breaker_enabled_by_val(_param_cbrk_flightterm.get(), CBRK_FLIGHTTERM_KEY)) {
|
||||||
CHECK_FAILSAFE(status_flags, fd_critical_failure, Action::Terminate);
|
CHECK_FAILSAFE(status_flags, fd_critical_failure, ActionOptions(Action::Terminate).cannotBeDeferred());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
CHECK_FAILSAFE(status_flags, fd_critical_failure, Action::Warn);
|
CHECK_FAILSAFE(status_flags, fd_critical_failure, Action::Warn);
|
||||||
@@ -460,7 +460,7 @@ void Failsafe::checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
|||||||
Action mode_fallback_action = checkModeFallback(status_flags, state.user_intended_mode);
|
Action mode_fallback_action = checkModeFallback(status_flags, state.user_intended_mode);
|
||||||
_last_state_mode_fallback = checkFailsafe(_caller_id_mode_fallback, _last_state_mode_fallback,
|
_last_state_mode_fallback = checkFailsafe(_caller_id_mode_fallback, _last_state_mode_fallback,
|
||||||
mode_fallback_action != Action::None,
|
mode_fallback_action != Action::None,
|
||||||
ActionOptions(mode_fallback_action).allowUserTakeover(UserTakeoverAllowed::Always));
|
ActionOptions(mode_fallback_action).allowUserTakeover(UserTakeoverAllowed::Always).cannotBeDeferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Failsafe::updateArmingState(const hrt_abstime &time_us, bool armed, const failsafe_flags_s &status_flags)
|
void Failsafe::updateArmingState(const hrt_abstime &time_us, bool armed, const failsafe_flags_s &status_flags)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ protected:
|
|||||||
ActionOptions(Action::RTL).allowUserTakeover(UserTakeoverAllowed::Never));
|
ActionOptions(Action::RTL).allowUserTakeover(UserTakeoverAllowed::Never));
|
||||||
|
|
||||||
_last_state_test = checkFailsafe(_caller_id_test, _last_state_test, status_flags.fd_motor_failure
|
_last_state_test = checkFailsafe(_caller_id_test, _last_state_test, status_flags.fd_motor_failure
|
||||||
&& status_flags.fd_critical_failure, Action::Terminate);
|
&& status_flags.fd_critical_failure, ActionOptions(Action::Terminate).cannotBeDeferred());
|
||||||
}
|
}
|
||||||
|
|
||||||
Action checkModeFallback(const failsafe_flags_s &status_flags, uint8_t user_intended_mode) const override
|
Action checkModeFallback(const failsafe_flags_s &status_flags, uint8_t user_intended_mode) const override
|
||||||
@@ -258,3 +258,114 @@ TEST_F(FailsafeTest, takeover_denied)
|
|||||||
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Terminate);
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Terminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FailsafeTest, defer)
|
||||||
|
{
|
||||||
|
FailsafeTester failsafe(nullptr);
|
||||||
|
|
||||||
|
failsafe_flags_s failsafe_flags{};
|
||||||
|
FailsafeBase::State state{};
|
||||||
|
state.armed = true;
|
||||||
|
state.user_intended_mode = vehicle_status_s::NAVIGATION_STATE_POSCTL;
|
||||||
|
state.vehicle_type = vehicle_status_s::VEHICLE_TYPE_ROTARY_WING;
|
||||||
|
hrt_abstime time = 3847124342;
|
||||||
|
|
||||||
|
uint8_t updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
|
||||||
|
const int defer_timeout_s = 10;
|
||||||
|
failsafe.deferFailsafes(true, defer_timeout_s);
|
||||||
|
ASSERT_TRUE(failsafe.getDeferFailsafes());
|
||||||
|
ASSERT_FALSE(failsafe.failsafeDeferred());
|
||||||
|
// GCS connection lost -> deferred
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.gcs_connection_lost = true;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_TRUE(failsafe.getDeferFailsafes());
|
||||||
|
ASSERT_TRUE(failsafe.failsafeDeferred());
|
||||||
|
|
||||||
|
// Wait a bit, still deferred
|
||||||
|
time += 5_s;
|
||||||
|
state.user_intended_mode = vehicle_status_s::NAVIGATION_STATE_STAB;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(updated_user_intented_mode, state.user_intended_mode);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_TRUE(failsafe.getDeferFailsafes());
|
||||||
|
ASSERT_TRUE(failsafe.failsafeDeferred());
|
||||||
|
|
||||||
|
// Wait a bit, don't defer anymore -> failsafe triggered (hold)
|
||||||
|
time += 1_s;
|
||||||
|
failsafe.deferFailsafes(false, 0);
|
||||||
|
ASSERT_FALSE(failsafe.getDeferFailsafes());
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(updated_user_intented_mode, state.user_intended_mode);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Hold);
|
||||||
|
ASSERT_FALSE(failsafe.getDeferFailsafes());
|
||||||
|
ASSERT_FALSE(failsafe.failsafeDeferred());
|
||||||
|
|
||||||
|
// Cannot enable while in failsafe
|
||||||
|
ASSERT_FALSE(failsafe.deferFailsafes(true, 0));
|
||||||
|
|
||||||
|
// Still in hold
|
||||||
|
time += 4_s;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Hold);
|
||||||
|
|
||||||
|
// Now changed to descend
|
||||||
|
time += 4_s;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Descend);
|
||||||
|
|
||||||
|
// Clear failsafe
|
||||||
|
failsafe_flags.gcs_connection_lost = false;
|
||||||
|
time += 10_ms;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
|
||||||
|
|
||||||
|
// Defer and trigger timeout
|
||||||
|
failsafe.deferFailsafes(true, defer_timeout_s);
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.wind_limit_exceeded = true;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_TRUE(failsafe.failsafeDeferred());
|
||||||
|
time += 1_s * defer_timeout_s + 10_ms;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::RTL);
|
||||||
|
ASSERT_FALSE(failsafe.failsafeDeferred());
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.wind_limit_exceeded = false;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
|
||||||
|
// Defer and clear failsafe -> no action
|
||||||
|
failsafe.deferFailsafes(true, defer_timeout_s);
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.wind_limit_exceeded = true;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_TRUE(failsafe.failsafeDeferred());
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.wind_limit_exceeded = false;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_FALSE(failsafe.failsafeDeferred());
|
||||||
|
failsafe.deferFailsafes(false, defer_timeout_s);
|
||||||
|
time += 10_ms;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
|
||||||
|
// Defer and trigger non-deferrable failsafe
|
||||||
|
failsafe.deferFailsafes(true, defer_timeout_s);
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.wind_limit_exceeded = true;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::None);
|
||||||
|
ASSERT_TRUE(failsafe.failsafeDeferred());
|
||||||
|
time += 10_ms;
|
||||||
|
failsafe_flags.fd_motor_failure = true;
|
||||||
|
failsafe_flags.fd_critical_failure = true;
|
||||||
|
updated_user_intented_mode = failsafe.update(time, state, false, false, failsafe_flags);
|
||||||
|
ASSERT_EQ(failsafe.selectedAction(), FailsafeBase::Action::Terminate);
|
||||||
|
ASSERT_FALSE(failsafe.failsafeDeferred());
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,7 +70,14 @@ uint8_t FailsafeBase::update(const hrt_abstime &time_us, const State &state, boo
|
|||||||
removeActions(ClearCondition::OnModeChangeOrDisarm);
|
removeActions(ClearCondition::OnModeChangeOrDisarm);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDelay(time_us - _last_update);
|
if (_defer_failsafes && _failsafe_defer_started != 0 && _defer_timeout > 0
|
||||||
|
&& time_us > _failsafe_defer_started + _defer_timeout) {
|
||||||
|
_defer_failsafes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_failsafe_defer_started == 0) {
|
||||||
|
updateDelay(time_us - _last_update);
|
||||||
|
}
|
||||||
|
|
||||||
checkStateAndMode(time_us, state, status_flags);
|
checkStateAndMode(time_us, state, status_flags);
|
||||||
removeNonActivatedActions();
|
removeNonActivatedActions();
|
||||||
@@ -79,7 +86,8 @@ uint8_t FailsafeBase::update(const hrt_abstime &time_us, const State &state, boo
|
|||||||
SelectedActionState action_state{};
|
SelectedActionState action_state{};
|
||||||
getSelectedAction(state, status_flags, user_intended_mode_updated, rc_sticks_takeover_request, action_state);
|
getSelectedAction(state, status_flags, user_intended_mode_updated, rc_sticks_takeover_request, action_state);
|
||||||
|
|
||||||
updateDelay(time_us - _last_update, action_state.delayed_action != Action::None);
|
updateStartDelay(time_us - _last_update, action_state.delayed_action != Action::None);
|
||||||
|
updateFailsafeDeferState(time_us, action_state.failsafe_deferred);
|
||||||
|
|
||||||
// Notify user if the action is worse than before, or a new action got added
|
// Notify user if the action is worse than before, or a new action got added
|
||||||
if (action_state.action > _selected_action || (action_state.action != Action::None && _notification_required)) {
|
if (action_state.action > _selected_action || (action_state.action != Action::None && _notification_required)) {
|
||||||
@@ -98,7 +106,19 @@ uint8_t FailsafeBase::update(const hrt_abstime &time_us, const State &state, boo
|
|||||||
return _last_user_intended_mode;
|
return _last_user_intended_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FailsafeBase::updateDelay(const hrt_abstime &dt, bool delay_active)
|
void FailsafeBase::updateFailsafeDeferState(const hrt_abstime &time_us, bool defer)
|
||||||
|
{
|
||||||
|
if (defer) {
|
||||||
|
if (_failsafe_defer_started == 0) {
|
||||||
|
_failsafe_defer_started = time_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_failsafe_defer_started = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FailsafeBase::updateStartDelay(const hrt_abstime &dt, bool delay_active)
|
||||||
{
|
{
|
||||||
// Ensure that even with a toggling state the delayed action is executed at some point.
|
// Ensure that even with a toggling state the delayed action is executed at some point.
|
||||||
// This is done by increasing the delay slower than reducing it.
|
// This is done by increasing the delay slower than reducing it.
|
||||||
@@ -411,6 +431,7 @@ void FailsafeBase::getSelectedAction(const State &state, const failsafe_flags_s
|
|||||||
returned_state.action = Action::None;
|
returned_state.action = Action::None;
|
||||||
Action &selected_action = returned_state.action;
|
Action &selected_action = returned_state.action;
|
||||||
UserTakeoverAllowed allow_user_takeover = UserTakeoverAllowed::Always;
|
UserTakeoverAllowed allow_user_takeover = UserTakeoverAllowed::Always;
|
||||||
|
bool allow_failsafe_to_be_deferred{true};
|
||||||
|
|
||||||
// Select the worst action based on the current active actions
|
// Select the worst action based on the current active actions
|
||||||
for (int action_idx = 0; action_idx < max_num_actions; ++action_idx) {
|
for (int action_idx = 0; action_idx < max_num_actions; ++action_idx) {
|
||||||
@@ -426,9 +447,19 @@ void FailsafeBase::getSelectedAction(const State &state, const failsafe_flags_s
|
|||||||
selected_action = cur_action.action;
|
selected_action = cur_action.action;
|
||||||
returned_state.cause = cur_action.cause;
|
returned_state.cause = cur_action.cause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cur_action.can_be_deferred) {
|
||||||
|
allow_failsafe_to_be_deferred = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_defer_failsafes && allow_failsafe_to_be_deferred && selected_action != Action::None) {
|
||||||
|
returned_state.failsafe_deferred = selected_action > Action::Warn;
|
||||||
|
returned_state.action = Action::None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we should enter delayed Hold
|
// Check if we should enter delayed Hold
|
||||||
if (_current_delay > 0 && !_user_takeover_active && allow_user_takeover <= UserTakeoverAllowed::AlwaysModeSwitchOnly
|
if (_current_delay > 0 && !_user_takeover_active && allow_user_takeover <= UserTakeoverAllowed::AlwaysModeSwitchOnly
|
||||||
&& selected_action != Action::Disarm && selected_action != Action::Terminate) {
|
&& selected_action != Action::Disarm && selected_action != Action::Terminate) {
|
||||||
@@ -627,3 +658,23 @@ bool FailsafeBase::modeCanRun(const failsafe_flags_s &status_flags, uint8_t mode
|
|||||||
(!status_flags.home_position_invalid || ((status_flags.mode_req_home_position & mode_mask) == 0)) &&
|
(!status_flags.home_position_invalid || ((status_flags.mode_req_home_position & mode_mask) == 0)) &&
|
||||||
((status_flags.mode_req_other & mode_mask) == 0);
|
((status_flags.mode_req_other & mode_mask) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FailsafeBase::deferFailsafes(bool enabled, int timeout_s)
|
||||||
|
{
|
||||||
|
if (enabled && _selected_action > Action::Warn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout_s == 0) {
|
||||||
|
_defer_timeout = DEFAULT_DEFER_TIMEOUT;
|
||||||
|
|
||||||
|
} else if (timeout_s < 0) {
|
||||||
|
_defer_timeout = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_defer_timeout = timeout_s * 1_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
_defer_failsafes = enabled;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,12 +39,16 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
using namespace time_literals;
|
||||||
|
|
||||||
#define CHECK_FAILSAFE(status_flags, flag_name, options) \
|
#define CHECK_FAILSAFE(status_flags, flag_name, options) \
|
||||||
checkFailsafe((int)offsetof(failsafe_flags_s, flag_name), lastStatusFlags().flag_name, status_flags.flag_name, options)
|
checkFailsafe((int)offsetof(failsafe_flags_s, flag_name), lastStatusFlags().flag_name, status_flags.flag_name, options)
|
||||||
|
|
||||||
class FailsafeBase: public ModuleParams
|
class FailsafeBase: public ModuleParams
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static constexpr hrt_abstime DEFAULT_DEFER_TIMEOUT = 30_s;
|
||||||
|
|
||||||
enum class Action : uint8_t {
|
enum class Action : uint8_t {
|
||||||
// Actions further down take precedence
|
// Actions further down take precedence
|
||||||
None,
|
None,
|
||||||
@@ -149,6 +153,16 @@ public:
|
|||||||
|
|
||||||
bool userTakeoverActive() const { return _user_takeover_active; }
|
bool userTakeoverActive() const { return _user_takeover_active; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defer all failsafes that can be deferred. Can be used to avoid triggering failsafes in critical situations.
|
||||||
|
* @param enabled
|
||||||
|
* @param timeout_s timeout in seconds, if set to 0, DEFAULT_DEFER_TIMEOUT is used, -1=no timeout
|
||||||
|
* @return true on success, false if failsafe already active
|
||||||
|
*/
|
||||||
|
bool deferFailsafes(bool enabled, int timeout_s);
|
||||||
|
bool getDeferFailsafes() const { return _defer_failsafes; }
|
||||||
|
bool failsafeDeferred() const { return _failsafe_defer_started != 0; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class UserTakeoverAllowed {
|
enum class UserTakeoverAllowed {
|
||||||
Always, ///< allow takeover (immediately)
|
Always, ///< allow takeover (immediately)
|
||||||
@@ -162,6 +176,7 @@ protected:
|
|||||||
ActionOptions &allowUserTakeover(UserTakeoverAllowed allow = UserTakeoverAllowed::Auto) { allow_user_takeover = allow; return *this; }
|
ActionOptions &allowUserTakeover(UserTakeoverAllowed allow = UserTakeoverAllowed::Auto) { allow_user_takeover = allow; return *this; }
|
||||||
ActionOptions &clearOn(ClearCondition clear_condition_) { clear_condition = clear_condition_; return *this; }
|
ActionOptions &clearOn(ClearCondition clear_condition_) { clear_condition = clear_condition_; return *this; }
|
||||||
ActionOptions &causedBy(Cause cause_) { cause = cause_; return *this; }
|
ActionOptions &causedBy(Cause cause_) { cause = cause_; return *this; }
|
||||||
|
ActionOptions &cannotBeDeferred() { can_be_deferred = false; return *this; }
|
||||||
|
|
||||||
bool valid() const { return id != -1; }
|
bool valid() const { return id != -1; }
|
||||||
void setInvalid() { id = -1; }
|
void setInvalid() { id = -1; }
|
||||||
@@ -170,6 +185,7 @@ protected:
|
|||||||
ClearCondition clear_condition{ClearCondition::WhenConditionClears};
|
ClearCondition clear_condition{ClearCondition::WhenConditionClears};
|
||||||
Cause cause{Cause::Generic};
|
Cause cause{Cause::Generic};
|
||||||
UserTakeoverAllowed allow_user_takeover{UserTakeoverAllowed::Auto};
|
UserTakeoverAllowed allow_user_takeover{UserTakeoverAllowed::Auto};
|
||||||
|
bool can_be_deferred{true};
|
||||||
|
|
||||||
bool state_failure{false}; ///< used when the clear_condition isn't set to clear immediately
|
bool state_failure{false}; ///< used when the clear_condition isn't set to clear immediately
|
||||||
bool activated{false}; ///< true if checkFailsafe was called during current update
|
bool activated{false}; ///< true if checkFailsafe was called during current update
|
||||||
@@ -182,6 +198,7 @@ protected:
|
|||||||
Cause cause{Cause::Generic};
|
Cause cause{Cause::Generic};
|
||||||
uint8_t updated_user_intended_mode{};
|
uint8_t updated_user_intended_mode{};
|
||||||
bool user_takeover{false};
|
bool user_takeover{false};
|
||||||
|
bool failsafe_deferred{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
virtual void checkStateAndMode(const hrt_abstime &time_us, const State &state,
|
||||||
@@ -232,7 +249,9 @@ private:
|
|||||||
|
|
||||||
bool actionAllowsUserTakeover(Action action) const;
|
bool actionAllowsUserTakeover(Action action) const;
|
||||||
|
|
||||||
void updateDelay(const hrt_abstime &dt, bool delay_active);
|
void updateStartDelay(const hrt_abstime &dt, bool delay_active);
|
||||||
|
|
||||||
|
void updateFailsafeDeferState(const hrt_abstime &time_us, bool defer);
|
||||||
|
|
||||||
static constexpr int max_num_actions{8};
|
static constexpr int max_num_actions{8};
|
||||||
ActionOptions _actions[max_num_actions]; ///< currently active actions
|
ActionOptions _actions[max_num_actions]; ///< currently active actions
|
||||||
@@ -245,6 +264,10 @@ private:
|
|||||||
bool _user_takeover_active{false};
|
bool _user_takeover_active{false};
|
||||||
bool _notification_required{false};
|
bool _notification_required{false};
|
||||||
|
|
||||||
|
bool _defer_failsafes{false};
|
||||||
|
hrt_abstime _defer_timeout{0};
|
||||||
|
hrt_abstime _failsafe_defer_started{0};
|
||||||
|
|
||||||
hrt_abstime _current_start_delay{0}; ///< _current_delay is set to this value when starting the delay
|
hrt_abstime _current_start_delay{0}; ///< _current_delay is set to this value when starting the delay
|
||||||
hrt_abstime _current_delay{0}; ///< If > 0, stay in Hold, and take action once delay reaches 0
|
hrt_abstime _current_delay{0}; ///< If > 0, stay in Hold, and take action once delay reaches 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user