mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 06:28:27 -04:00
5824a12b2e
This variable updated unpredictably, and it was easy to introduce bugs. It was not used in many places and is clearer to calculate the error directly when needed.
157 lines
6.0 KiB
C++
157 lines
6.0 KiB
C++
#include "mode.h"
|
|
#include "Plane.h"
|
|
|
|
bool ModeRTL::_enter()
|
|
{
|
|
plane.prev_WP_loc = plane.current_loc;
|
|
plane.do_RTL(plane.get_RTL_altitude_cm());
|
|
plane.rtl.done_climb = false;
|
|
#if HAL_QUADPLANE_ENABLED
|
|
plane.vtol_approach_s.approach_stage = Plane::Landing_ApproachStage::RTL;
|
|
|
|
// Quadplane specific checks
|
|
if (plane.quadplane.available()) {
|
|
// treat RTL as QLAND if we are in guided wait takeoff state, to cope
|
|
// with failsafes during GUIDED->AUTO takeoff sequence
|
|
if (plane.quadplane.guided_wait_takeoff_on_mode_enter) {
|
|
plane.set_mode(plane.mode_qland, ModeReason::QLAND_INSTEAD_OF_RTL);
|
|
return true;
|
|
}
|
|
|
|
// if Q_RTL_MODE is QRTL always, immediately switch to QRTL mode
|
|
if (plane.quadplane.rtl_mode == QuadPlane::RTL_MODE::QRTL_ALWAYS) {
|
|
plane.set_mode(plane.mode_qrtl, ModeReason::QRTL_INSTEAD_OF_RTL);
|
|
return true;
|
|
}
|
|
|
|
// if VTOL landing is expected and quadplane motors are active and within QRTL radius and under QRTL altitude then switch to QRTL
|
|
const bool vtol_landing = (plane.quadplane.rtl_mode == QuadPlane::RTL_MODE::SWITCH_QRTL) || (plane.quadplane.rtl_mode == QuadPlane::RTL_MODE::VTOL_APPROACH_QRTL);
|
|
if (vtol_landing && (quadplane.motors->get_desired_spool_state() == AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED)) {
|
|
int32_t alt_cm;
|
|
if ((plane.current_loc.get_distance(plane.next_WP_loc) < plane.mode_qrtl.get_VTOL_return_radius()) &&
|
|
plane.current_loc.get_alt_cm(Location::AltFrame::ABOVE_HOME, alt_cm) && (alt_cm < plane.quadplane.qrtl_alt*100)) {
|
|
plane.set_mode(plane.mode_qrtl, ModeReason::QRTL_INSTEAD_OF_RTL);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
void ModeRTL::update()
|
|
{
|
|
plane.calc_nav_roll();
|
|
plane.calc_nav_pitch();
|
|
plane.calc_throttle();
|
|
|
|
bool alt_threshold_reached = false;
|
|
if (plane.flight_option_enabled(FlightOptions::CLIMB_BEFORE_TURN)) {
|
|
// Climb to RTL_ALTITUDE before turning. This overrides RTL_CLIMB_MIN.
|
|
alt_threshold_reached = plane.current_loc.alt > plane.next_WP_loc.alt;
|
|
} else if (plane.g2.rtl_climb_min > 0) {
|
|
/*
|
|
when RTL first starts limit bank angle to LEVEL_ROLL_LIMIT
|
|
until we have climbed by RTL_CLIMB_MIN meters
|
|
*/
|
|
alt_threshold_reached = (plane.current_loc.alt - plane.prev_WP_loc.alt)*0.01 > plane.g2.rtl_climb_min;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
if (!plane.rtl.done_climb && alt_threshold_reached) {
|
|
plane.prev_WP_loc = plane.current_loc;
|
|
plane.setup_glide_slope();
|
|
plane.rtl.done_climb = true;
|
|
}
|
|
if (!plane.rtl.done_climb) {
|
|
// Constrain the roll limit as a failsafe, that way if something goes wrong the plane will
|
|
// eventually turn back and go to RTL instead of going perfectly straight. This also leaves
|
|
// some leeway for fighting wind.
|
|
plane.roll_limit_cd = MIN(plane.roll_limit_cd, plane.g.level_roll_limit*100);
|
|
plane.nav_roll_cd = constrain_int32(plane.nav_roll_cd, -plane.roll_limit_cd, plane.roll_limit_cd);
|
|
}
|
|
}
|
|
|
|
void ModeRTL::navigate()
|
|
{
|
|
#if HAL_QUADPLANE_ENABLED
|
|
if (plane.quadplane.available()) {
|
|
if (plane.quadplane.rtl_mode == QuadPlane::RTL_MODE::VTOL_APPROACH_QRTL) {
|
|
// VTOL approach landing
|
|
AP_Mission::Mission_Command cmd;
|
|
cmd.content.location = plane.next_WP_loc;
|
|
plane.verify_landing_vtol_approach(cmd);
|
|
if (plane.vtol_approach_s.approach_stage == Plane::Landing_ApproachStage::VTOL_LANDING) {
|
|
plane.set_mode(plane.mode_qrtl, ModeReason::RTL_COMPLETE_SWITCHING_TO_VTOL_LAND_RTL);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ((AP_HAL::millis() - plane.last_mode_change_ms > 1000) && switch_QRTL()) {
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
uint16_t radius = abs(plane.g.rtl_radius);
|
|
if (radius > 0) {
|
|
plane.loiter.direction = (plane.g.rtl_radius < 0) ? -1 : 1;
|
|
}
|
|
|
|
plane.update_loiter(radius);
|
|
|
|
if (!plane.auto_state.checked_for_autoland) {
|
|
if ((plane.g.rtl_autoland == RtlAutoland::RTL_IMMEDIATE_DO_LAND_START) ||
|
|
(plane.g.rtl_autoland == RtlAutoland::RTL_THEN_DO_LAND_START &&
|
|
plane.reached_loiter_target() &&
|
|
labs(plane.calc_altitude_error_cm()) < 1000))
|
|
{
|
|
// we've reached the RTL point, see if we have a landing sequence
|
|
if (plane.have_position && plane.mission.jump_to_landing_sequence(plane.current_loc)) {
|
|
// switch from RTL -> AUTO
|
|
plane.mission.set_force_resume(true);
|
|
if (plane.set_mode(plane.mode_auto, ModeReason::RTL_COMPLETE_SWITCHING_TO_FIXEDWING_AUTOLAND)) {
|
|
// return here so we don't change the radius and don't run the rtl update_loiter()
|
|
return;
|
|
}
|
|
}
|
|
|
|
// prevent running the expensive jump_to_landing_sequence
|
|
// on every loop
|
|
plane.auto_state.checked_for_autoland = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if HAL_QUADPLANE_ENABLED
|
|
// Switch to QRTL if enabled and within radius
|
|
bool ModeRTL::switch_QRTL()
|
|
{
|
|
if (plane.quadplane.rtl_mode != QuadPlane::RTL_MODE::SWITCH_QRTL) {
|
|
return false;
|
|
}
|
|
|
|
uint16_t qrtl_radius = abs(plane.g.rtl_radius);
|
|
if (qrtl_radius == 0) {
|
|
qrtl_radius = abs(plane.aparm.loiter_radius);
|
|
}
|
|
|
|
if (plane.nav_controller->reached_loiter_target() ||
|
|
plane.current_loc.past_interval_finish_line(plane.prev_WP_loc, plane.next_WP_loc) ||
|
|
plane.auto_state.wp_distance < MAX(qrtl_radius, plane.quadplane.stopping_distance())) {
|
|
/*
|
|
for a quadplane in RTL mode we switch to QRTL when we
|
|
are within the maximum of the stopping distance and the
|
|
RTL_RADIUS
|
|
*/
|
|
plane.set_mode(plane.mode_qrtl, ModeReason::RTL_COMPLETE_SWITCHING_TO_VTOL_LAND_RTL);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#endif // HAL_QUADPLANE_ENABLED
|