2020-09-10 03:31:18 -03:00
|
|
|
#include "Plane.h"
|
|
|
|
|
|
|
|
// Code to integrate AC_Fence library with main ArduPlane code
|
|
|
|
|
2022-07-19 08:33:13 -03:00
|
|
|
#if AP_FENCE_ENABLED
|
2020-09-10 03:31:18 -03:00
|
|
|
|
|
|
|
// fence_check - ask fence library to check for breaches and initiate the response
|
|
|
|
void Plane::fence_check()
|
|
|
|
{
|
|
|
|
const uint8_t orig_breaches = fence.get_breaches();
|
|
|
|
|
2024-05-31 10:13:32 -03:00
|
|
|
uint16_t mission_id = plane.mission.get_current_nav_cmd().id;
|
|
|
|
bool is_in_landing = plane.flight_stage == AP_FixedWing::FlightStage::LAND
|
|
|
|
#if HAL_QUADPLANE_ENABLED
|
|
|
|
|| control_mode->mode_number() == Mode::Number::QLAND
|
2024-06-25 13:07:13 -03:00
|
|
|
|| quadplane.in_vtol_land_descent()
|
2024-05-31 10:13:32 -03:00
|
|
|
#endif
|
|
|
|
|| (plane.is_land_command(mission_id) && plane.mission.state() == AP_Mission::MISSION_RUNNING);
|
|
|
|
|
2020-09-10 03:31:18 -03:00
|
|
|
// check for new breaches; new_breaches is bitmask of fence types breached
|
2024-05-31 10:13:32 -03:00
|
|
|
const uint8_t new_breaches = fence.check(is_in_landing);
|
2020-09-10 03:31:18 -03:00
|
|
|
|
|
|
|
if (!fence.enabled()) {
|
|
|
|
// Switch back to the chosen control mode if still in
|
|
|
|
// GUIDED to the return point
|
|
|
|
switch(fence.get_action()) {
|
|
|
|
case AC_FENCE_ACTION_GUIDED:
|
|
|
|
case AC_FENCE_ACTION_GUIDED_THROTTLE_PASS:
|
|
|
|
case AC_FENCE_ACTION_RTL_AND_LAND:
|
|
|
|
if (plane.control_mode_reason == ModeReason::FENCE_BREACHED &&
|
2020-09-10 05:05:24 -03:00
|
|
|
control_mode->is_guided_mode()) {
|
2020-09-10 03:31:18 -03:00
|
|
|
set_mode(*previous_mode, ModeReason::FENCE_RETURN_PREVIOUS_MODE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// No returning to a previous mode, unless our action allows it
|
|
|
|
break;
|
|
|
|
}
|
2021-03-03 09:59:02 -04:00
|
|
|
return;
|
2020-09-10 03:31:18 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
// we still don't do anything when disarmed, but we do check for fence breaches.
|
|
|
|
// fence pre-arm check actually checks if any fence has been breached
|
|
|
|
// that's not ever going to be true if we don't call check on AP_Fence while disarmed
|
|
|
|
if (!arming.is_armed()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Never trigger a fence breach in the final stage of landing
|
|
|
|
if (landing.is_expecting_impact()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-12 16:34:31 -03:00
|
|
|
if (in_fence_recovery()) {
|
2021-03-03 07:49:04 -04:00
|
|
|
// we have already triggered, don't trigger again until the
|
|
|
|
// user disables/re-enables using the fence channel switch
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-06 17:44:31 -03:00
|
|
|
if (new_breaches) {
|
2024-01-19 16:43:45 -04:00
|
|
|
fence.print_fence_message("breached", new_breaches);
|
2022-08-06 17:44:31 -03:00
|
|
|
|
2020-09-10 03:31:18 -03:00
|
|
|
// if the user wants some kind of response and motors are armed
|
|
|
|
const uint8_t fence_act = fence.get_action();
|
|
|
|
switch (fence_act) {
|
|
|
|
case AC_FENCE_ACTION_REPORT_ONLY:
|
|
|
|
break;
|
|
|
|
case AC_FENCE_ACTION_GUIDED:
|
|
|
|
case AC_FENCE_ACTION_GUIDED_THROTTLE_PASS:
|
|
|
|
case AC_FENCE_ACTION_RTL_AND_LAND:
|
|
|
|
if (fence_act == AC_FENCE_ACTION_RTL_AND_LAND) {
|
2022-03-22 22:55:09 -03:00
|
|
|
if (control_mode == &mode_auto &&
|
|
|
|
mission.get_in_landing_sequence_flag() &&
|
2022-03-23 00:34:22 -03:00
|
|
|
(g.rtl_autoland == RtlAutoland::RTL_THEN_DO_LAND_START ||
|
|
|
|
g.rtl_autoland == RtlAutoland::RTL_IMMEDIATE_DO_LAND_START)) {
|
2022-03-22 22:55:09 -03:00
|
|
|
// already landing
|
|
|
|
return;
|
|
|
|
}
|
2020-09-10 03:31:18 -03:00
|
|
|
set_mode(mode_rtl, ModeReason::FENCE_BREACHED);
|
|
|
|
} else {
|
|
|
|
set_mode(mode_guided, ModeReason::FENCE_BREACHED);
|
|
|
|
}
|
|
|
|
|
2022-02-09 19:44:58 -04:00
|
|
|
Location loc;
|
2020-09-10 03:31:18 -03:00
|
|
|
if (fence.get_return_rally() != 0 || fence_act == AC_FENCE_ACTION_RTL_AND_LAND) {
|
2023-04-07 05:25:34 -03:00
|
|
|
loc = calc_best_rally_or_home_location(current_loc, get_RTL_altitude_cm());
|
2020-09-10 03:31:18 -03:00
|
|
|
} else {
|
|
|
|
//return to fence return point, not a rally point
|
|
|
|
if (fence.get_return_altitude() > 0) {
|
|
|
|
// fly to the return point using _retalt
|
2022-02-09 19:44:58 -04:00
|
|
|
loc.alt = home.alt + 100.0f * fence.get_return_altitude();
|
2020-09-10 03:31:18 -03:00
|
|
|
} else if (fence.get_safe_alt_min() >= fence.get_safe_alt_max()) {
|
|
|
|
// invalid min/max, use RTL_altitude
|
2024-01-18 01:58:09 -04:00
|
|
|
loc.alt = home.alt + g.RTL_altitude*100;
|
2020-09-10 03:31:18 -03:00
|
|
|
} else {
|
|
|
|
// fly to the return point, with an altitude half way between
|
|
|
|
// min and max
|
2022-02-09 19:44:58 -04:00
|
|
|
loc.alt = home.alt + 100.0f * (fence.get_safe_alt_min() + fence.get_safe_alt_max()) / 2;
|
2020-09-10 03:31:18 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector2l return_point;
|
|
|
|
if(fence.polyfence().get_return_point(return_point)) {
|
2022-02-09 19:44:58 -04:00
|
|
|
loc.lat = return_point[0];
|
|
|
|
loc.lng = return_point[1];
|
2020-09-10 03:31:18 -03:00
|
|
|
} else {
|
2021-04-29 06:24:16 -03:00
|
|
|
// When no fence return point is found (ie. no inclusion fence uploaded, but exclusion is)
|
|
|
|
// we fail to obtain a valid fence return point. In this case, home is considered a safe
|
|
|
|
// return point.
|
2022-02-09 19:44:58 -04:00
|
|
|
loc.lat = home.lat;
|
|
|
|
loc.lng = home.lng;
|
2020-09-10 03:31:18 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fence.get_action() != AC_FENCE_ACTION_RTL_AND_LAND) {
|
2022-02-09 19:44:58 -04:00
|
|
|
setup_terrain_target_alt(loc);
|
|
|
|
set_guided_WP(loc);
|
2020-09-10 03:31:18 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fence.get_action() == AC_FENCE_ACTION_GUIDED_THROTTLE_PASS) {
|
|
|
|
guided_throttle_passthru = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-07-13 21:58:09 -03:00
|
|
|
LOGGER_WRITE_ERROR(LogErrorSubsystem::FAILSAFE_FENCE, LogErrorCode(new_breaches));
|
2024-02-08 10:46:01 -04:00
|
|
|
} else if (orig_breaches && fence.get_breaches() == 0) {
|
|
|
|
GCS_SEND_TEXT(MAV_SEVERITY_NOTICE, "Fence breach cleared");
|
2020-09-10 03:31:18 -03:00
|
|
|
// record clearing of breach
|
2023-07-13 21:58:09 -03:00
|
|
|
LOGGER_WRITE_ERROR(LogErrorSubsystem::FAILSAFE_FENCE, LogErrorCode::ERROR_RESOLVED);
|
2020-09-10 03:31:18 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Plane::fence_stickmixing(void) const
|
|
|
|
{
|
|
|
|
if (fence.enabled() &&
|
|
|
|
fence.get_breaches() &&
|
2022-08-12 16:34:31 -03:00
|
|
|
in_fence_recovery())
|
2020-09-10 03:31:18 -03:00
|
|
|
{
|
|
|
|
// don't mix in user input
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// normal mixing rules
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-14 08:48:57 -04:00
|
|
|
|
2022-08-12 16:34:31 -03:00
|
|
|
bool Plane::in_fence_recovery() const
|
|
|
|
{
|
|
|
|
const bool current_mode_breach = plane.control_mode_reason == ModeReason::FENCE_BREACHED;
|
|
|
|
const bool previous_mode_breach = plane.previous_mode_reason == ModeReason::FENCE_BREACHED;
|
|
|
|
const bool previous_mode_complete = (plane.control_mode_reason == ModeReason::RTL_COMPLETE_SWITCHING_TO_VTOL_LAND_RTL) ||
|
|
|
|
(plane.control_mode_reason == ModeReason::RTL_COMPLETE_SWITCHING_TO_FIXEDWING_AUTOLAND) ||
|
|
|
|
(plane.control_mode_reason == ModeReason::QRTL_INSTEAD_OF_RTL) ||
|
|
|
|
(plane.control_mode_reason == ModeReason::QLAND_INSTEAD_OF_RTL);
|
|
|
|
|
|
|
|
return current_mode_breach || (previous_mode_breach && previous_mode_complete);
|
|
|
|
}
|
|
|
|
|
2021-06-01 03:03:52 -03:00
|
|
|
#endif
|