Plane: added support for NAV_PACKAGE_PLACE mission item

this works in conjunction with a lua script to allow for a wide
variety of package place options
This commit is contained in:
Andrew Tridgell 2023-01-17 17:47:03 +11:00
parent 510d979b79
commit 2989e2deba
7 changed files with 157 additions and 19 deletions

View File

@ -413,7 +413,7 @@ bool AP_Arming_Plane::mission_checks(bool report)
if (!plane.mission.read_cmd_from_storage(i, cmd)) { if (!plane.mission.read_cmd_from_storage(i, cmd)) {
break; break;
} }
if ((cmd.id == MAV_CMD_NAV_VTOL_LAND || cmd.id == MAV_CMD_NAV_LAND) && if (plane.is_land_command(cmd.id) &&
prev_cmd.id == MAV_CMD_NAV_WAYPOINT) { prev_cmd.id == MAV_CMD_NAV_WAYPOINT) {
const float dist = cmd.content.location.get_distance(prev_cmd.content.location); const float dist = cmd.content.location.get_distance(prev_cmd.content.location);
const float tecs_land_speed = plane.TECS_controller.get_land_airspeed(); const float tecs_land_speed = plane.TECS_controller.get_land_airspeed();

View File

@ -801,6 +801,19 @@ bool Plane::set_velocity_match(const Vector2f &velocity)
return false; return false;
} }
// allow for override of land descent rate
bool Plane::set_land_descent_rate(float descent_rate)
{
#if HAL_QUADPLANE_ENABLED
if (quadplane.in_vtol_land_descent()) {
quadplane.poscontrol.override_descent_rate = descent_rate;
quadplane.poscontrol.last_override_descent_ms = AP_HAL::millis();
return true;
}
#endif
return false;
}
#endif // AP_SCRIPTING_ENABLED #endif // AP_SCRIPTING_ENABLED
// correct AHRS pitch for TRIM_PITCH_CD in non-VTOL modes, and return VTOL view in VTOL // correct AHRS pitch for TRIM_PITCH_CD in non-VTOL modes, and return VTOL view in VTOL

View File

@ -1039,8 +1039,7 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_long_packet(const mavlink_command_l
{ {
uint16_t mission_id = plane.mission.get_current_nav_cmd().id; uint16_t mission_id = plane.mission.get_current_nav_cmd().id;
bool is_in_landing = (plane.flight_stage == AP_FixedWing::FlightStage::LAND) || bool is_in_landing = (plane.flight_stage == AP_FixedWing::FlightStage::LAND) ||
(mission_id == MAV_CMD_NAV_LAND) || plane.is_land_command(mission_id);
(mission_id == MAV_CMD_NAV_VTOL_LAND);
if (is_in_landing) { if (is_in_landing) {
// fly a user planned abort pattern if available // fly a user planned abort pattern if available
if (plane.mission.jump_to_abort_landing_sequence()) { if (plane.mission.jump_to_abort_landing_sequence()) {

View File

@ -938,6 +938,13 @@ private:
void do_nav_delay(const AP_Mission::Mission_Command& cmd); void do_nav_delay(const AP_Mission::Mission_Command& cmd);
bool verify_nav_delay(const AP_Mission::Mission_Command& cmd); bool verify_nav_delay(const AP_Mission::Mission_Command& cmd);
bool is_land_command(uint16_t cmd) const;
/*
return true if in a specific AUTO mission command
*/
bool in_auto_mission_id(uint16_t command) const;
// Delay the next navigation command // Delay the next navigation command
struct { struct {
uint32_t time_max_ms; uint32_t time_max_ms;
@ -956,12 +963,6 @@ private:
// set home location and store it persistently: // set home location and store it persistently:
bool set_home_persistently(const Location &loc) WARN_IF_UNUSED; bool set_home_persistently(const Location &loc) WARN_IF_UNUSED;
// quadplane.cpp
#if HAL_QUADPLANE_ENABLED
bool verify_vtol_takeoff(const AP_Mission::Mission_Command &cmd);
bool verify_vtol_land(const AP_Mission::Mission_Command &cmd);
#endif
// control_modes.cpp // control_modes.cpp
void read_control_switch(); void read_control_switch();
uint8_t readSwitch(void) const; uint8_t readSwitch(void) const;
@ -1229,6 +1230,9 @@ public:
bool get_target_location(Location& target_loc) override; bool get_target_location(Location& target_loc) override;
bool update_target_location(const Location &old_loc, const Location &new_loc) override; bool update_target_location(const Location &old_loc, const Location &new_loc) override;
bool set_velocity_match(const Vector2f &velocity) override; bool set_velocity_match(const Vector2f &velocity) override;
// allow for landing descent rate to be overridden by a script, may be -ve to climb
bool set_land_descent_rate(float descent_rate) override;
#endif // AP_SCRIPTING_ENABLED #endif // AP_SCRIPTING_ENABLED
}; };

View File

@ -98,6 +98,7 @@ bool Plane::start_command(const AP_Mission::Mission_Command& cmd)
return quadplane.do_vtol_takeoff(cmd); return quadplane.do_vtol_takeoff(cmd);
case MAV_CMD_NAV_VTOL_LAND: case MAV_CMD_NAV_VTOL_LAND:
case MAV_CMD_NAV_PAYLOAD_PLACE:
if (quadplane.landing_with_fixed_wing_spiral_approach()) { if (quadplane.landing_with_fixed_wing_spiral_approach()) {
// the user wants to approach the landing in a fixed wing flight mode // the user wants to approach the landing in a fixed wing flight mode
// the waypoint will be used as a loiter_to_alt // the waypoint will be used as a loiter_to_alt
@ -243,7 +244,7 @@ bool Plane::verify_command(const AP_Mission::Mission_Command& cmd) // Ret
case MAV_CMD_NAV_LAND: case MAV_CMD_NAV_LAND:
#if HAL_QUADPLANE_ENABLED #if HAL_QUADPLANE_ENABLED
if (quadplane.is_vtol_land(cmd.id)) { if (quadplane.is_vtol_land(cmd.id)) {
return quadplane.verify_vtol_land(); return quadplane.verify_vtol_land();
} }
#endif #endif
if (flight_stage == AP_FixedWing::FlightStage::ABORT_LANDING) { if (flight_stage == AP_FixedWing::FlightStage::ABORT_LANDING) {
@ -286,6 +287,7 @@ bool Plane::verify_command(const AP_Mission::Mission_Command& cmd) // Ret
case MAV_CMD_NAV_VTOL_TAKEOFF: case MAV_CMD_NAV_VTOL_TAKEOFF:
return quadplane.verify_vtol_takeoff(cmd); return quadplane.verify_vtol_takeoff(cmd);
case MAV_CMD_NAV_VTOL_LAND: case MAV_CMD_NAV_VTOL_LAND:
case MAV_CMD_NAV_PAYLOAD_PLACE:
if (quadplane.landing_with_fixed_wing_spiral_approach() && !verify_landing_vtol_approach(cmd)) { if (quadplane.landing_with_fixed_wing_spiral_approach() && !verify_landing_vtol_approach(cmd)) {
// verify_landing_vtol_approach will return true once we have completed the approach, // verify_landing_vtol_approach will return true once we have completed the approach,
// in which case we fall over to normal vtol landing code // in which case we fall over to normal vtol landing code
@ -1276,3 +1278,24 @@ bool Plane::nav_scripting_enable(uint8_t mode)
return nav_scripting.enabled; return nav_scripting.enabled;
} }
#endif // AP_SCRIPTING_ENABLED #endif // AP_SCRIPTING_ENABLED
/*
return true if this is a LAND command
note that we consider a PAYLOAD_PLACE to be a land command as it
follows the landing logic for quadplanes
*/
bool Plane::is_land_command(uint16_t command) const
{
return
command == MAV_CMD_NAV_VTOL_LAND ||
command == MAV_CMD_NAV_LAND ||
command == MAV_CMD_NAV_PAYLOAD_PLACE;
}
/*
return true if in a specific AUTO mission command
*/
bool Plane::in_auto_mission_id(uint16_t command) const
{
return control_mode == &mode_auto && mission.get_current_nav_id() == command;
}

View File

@ -1209,6 +1209,13 @@ bool QuadPlane::is_flying_vtol(void) const
*/ */
float QuadPlane::landing_descent_rate_cms(float height_above_ground) float QuadPlane::landing_descent_rate_cms(float height_above_ground)
{ {
if (poscontrol.last_override_descent_ms != 0) {
const uint32_t now = AP_HAL::millis();
if (now - poscontrol.last_override_descent_ms < 1000) {
return poscontrol.override_descent_rate*100;
}
}
if (poscontrol.get_state() == QPOS_LAND_FINAL) { if (poscontrol.get_state() == QPOS_LAND_FINAL) {
// when in final use descent rate for final even if alt has climbed again // when in final use descent rate for final even if alt has climbed again
height_above_ground = MIN(height_above_ground, land_final_alt); height_above_ground = MIN(height_above_ground, land_final_alt);
@ -2099,6 +2106,7 @@ bool QuadPlane::in_vtol_auto(void) const
return is_vtol_takeoff(id); return is_vtol_takeoff(id);
case MAV_CMD_NAV_VTOL_LAND: case MAV_CMD_NAV_VTOL_LAND:
case MAV_CMD_NAV_LAND: case MAV_CMD_NAV_LAND:
case MAV_CMD_NAV_PAYLOAD_PLACE:
return is_vtol_land(id); return is_vtol_land(id);
default: default:
return false; return false;
@ -2285,6 +2293,11 @@ void QuadPlane::PosControlState::set_state(enum position_control_state s)
} else if (s == QPOS_LAND_DESCEND) { } else if (s == QPOS_LAND_DESCEND) {
// reset throttle descent control // reset throttle descent control
qp.thr_ctrl_land = false; qp.thr_ctrl_land = false;
qp.land_descend_start_alt = plane.current_loc.alt*0.01;
last_override_descent_ms = 0;
} else if (s == QPOS_LAND_ABORT) {
// reset throttle descent control
qp.thr_ctrl_land = false;
} else if (s == QPOS_LAND_FINAL) { } else if (s == QPOS_LAND_FINAL) {
// remember last pos reset to handle GPS glitch in LAND_FINAL // remember last pos reset to handle GPS glitch in LAND_FINAL
Vector2f rpos; Vector2f rpos;
@ -2674,6 +2687,7 @@ void QuadPlane::vtol_position_controller(void)
} }
case QPOS_POSITION2: case QPOS_POSITION2:
case QPOS_LAND_ABORT:
case QPOS_LAND_DESCEND: { case QPOS_LAND_DESCEND: {
setup_target_position(); setup_target_position();
/* /*
@ -2825,6 +2839,7 @@ void QuadPlane::vtol_position_controller(void)
} }
case QPOS_LAND_DESCEND: case QPOS_LAND_DESCEND:
case QPOS_LAND_ABORT:
case QPOS_LAND_FINAL: { case QPOS_LAND_FINAL: {
float height_above_ground = plane.relative_ground_altitude(plane.g.rangefinder_landing); float height_above_ground = plane.relative_ground_altitude(plane.g.rangefinder_landing);
if (poscontrol.get_state() == QPOS_LAND_FINAL) { if (poscontrol.get_state() == QPOS_LAND_FINAL) {
@ -2832,6 +2847,10 @@ void QuadPlane::vtol_position_controller(void)
ahrs.set_touchdown_expected(true); ahrs.set_touchdown_expected(true);
} }
} }
if (poscontrol.get_state() == QPOS_LAND_ABORT) {
set_climb_rate_cms(wp_nav->get_default_speed_up());
break;
}
const float descent_rate_cms = landing_descent_rate_cms(height_above_ground); const float descent_rate_cms = landing_descent_rate_cms(height_above_ground);
pos_control->land_at_climb_rate_cm(-descent_rate_cms, descent_rate_cms>0); pos_control->land_at_climb_rate_cm(-descent_rate_cms, descent_rate_cms>0);
break; break;
@ -3044,7 +3063,21 @@ void QuadPlane::control_auto(void)
} }
if (poscontrol.get_state() > QPOS_APPROACH) { if (poscontrol.get_state() > QPOS_APPROACH) {
if (!plane.arming.get_delay_arming()) { bool should_run_motors = false;
// don't run the motors if in an arming delay
if (plane.arming.get_delay_arming()) {
should_run_motors = false;
}
// don't run motors if we are in the wait state for payload place
if (motors->get_desired_spool_state() == AP_Motors::DesiredSpoolState::SHUT_DOWN &&
plane.in_auto_mission_id(MAV_CMD_NAV_PAYLOAD_PLACE) &&
poscontrol.get_state() == QPOS_LAND_COMPLETE) {
should_run_motors = false;
}
if (should_run_motors) {
set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED); set_desired_spool_state(AP_Motors::DesiredSpoolState::THROTTLE_UNLIMITED);
} }
} }
@ -3058,6 +3091,7 @@ void QuadPlane::control_auto(void)
} }
break; break;
case MAV_CMD_NAV_VTOL_LAND: case MAV_CMD_NAV_VTOL_LAND:
case MAV_CMD_NAV_PAYLOAD_PLACE:
case MAV_CMD_NAV_LAND: case MAV_CMD_NAV_LAND:
if (is_vtol_land(id)) { if (is_vtol_land(id)) {
vtol_position_controller(); vtol_position_controller();
@ -3283,6 +3317,15 @@ bool QuadPlane::check_land_complete(void)
if (land_detector(4000)) { if (land_detector(4000)) {
poscontrol.set_state(QPOS_LAND_COMPLETE); poscontrol.set_state(QPOS_LAND_COMPLETE);
gcs().send_text(MAV_SEVERITY_INFO,"Land complete"); gcs().send_text(MAV_SEVERITY_INFO,"Land complete");
if (plane.in_auto_mission_id(MAV_CMD_NAV_PAYLOAD_PLACE)) {
// for payload place with full landing we shutdown motors
// and wait for the lua script to trigger a climb (using
// landing abort) or disarm
set_desired_spool_state(AP_Motors::DesiredSpoolState::SHUT_DOWN);
return false;
}
if (plane.control_mode != &plane.mode_auto || if (plane.control_mode != &plane.mode_auto ||
!plane.mission.continue_after_land()) { !plane.mission.continue_after_land()) {
// disarm on land unless we have MIS_OPTIONS setup to // disarm on land unless we have MIS_OPTIONS setup to
@ -3384,6 +3427,23 @@ bool QuadPlane::verify_vtol_land(void)
gcs().send_text(MAV_SEVERITY_INFO,"Land final started"); gcs().send_text(MAV_SEVERITY_INFO,"Land final started");
} }
// at land_final_alt begin final landing
if (poscontrol.get_state() == QPOS_LAND_ABORT &&
plane.current_loc.alt*0.01 >= land_descend_start_alt) {
// continue to next WP, if there is one
return true;
}
if (plane.in_auto_mission_id(MAV_CMD_NAV_PAYLOAD_PLACE) &&
(poscontrol.get_state() == QPOS_LAND_DESCEND ||
poscontrol.get_state() == QPOS_LAND_FINAL)) {
const auto &cmd = plane.mission.get_current_nav_cmd();
if (cmd.p1 > 0 && plane.current_loc.alt*0.01 < land_descend_start_alt - cmd.p1*0.01) {
gcs().send_text(MAV_SEVERITY_INFO,"Payload place aborted");
poscontrol.set_state(QPOS_LAND_ABORT);
}
}
if (check_land_complete() && plane.mission.continue_after_land()) { if (check_land_complete() && plane.mission.continue_after_land()) {
gcs().send_text(MAV_SEVERITY_INFO,"Mission continue"); gcs().send_text(MAV_SEVERITY_INFO,"Mission continue");
return true; return true;
@ -3730,7 +3790,7 @@ bool QuadPlane::is_vtol_takeoff(uint16_t id) const
*/ */
bool QuadPlane::is_vtol_land(uint16_t id) const bool QuadPlane::is_vtol_land(uint16_t id) const
{ {
if (id == MAV_CMD_NAV_VTOL_LAND) { if (id == MAV_CMD_NAV_VTOL_LAND || id == MAV_CMD_NAV_PAYLOAD_PLACE) {
if (landing_with_fixed_wing_spiral_approach()) { if (landing_with_fixed_wing_spiral_approach()) {
return plane.vtol_approach_s.approach_stage == Plane::Landing_ApproachStage::VTOL_LANDING; return plane.vtol_approach_s.approach_stage == Plane::Landing_ApproachStage::VTOL_LANDING;
} else { } else {
@ -3879,12 +3939,13 @@ bool QuadPlane::in_vtol_land_approach(void) const
*/ */
bool QuadPlane::in_vtol_land_descent(void) const bool QuadPlane::in_vtol_land_descent(void) const
{ {
const auto state = poscontrol.get_state();
if (plane.control_mode == &plane.mode_qrtl && if (plane.control_mode == &plane.mode_qrtl &&
(poscontrol.get_state() == QPOS_LAND_DESCEND || poscontrol.get_state() == QPOS_LAND_FINAL)) { (state == QPOS_LAND_DESCEND || state == QPOS_LAND_FINAL || state == QPOS_LAND_ABORT)) {
return true; return true;
} }
if (in_vtol_auto() && is_vtol_land(plane.mission.get_current_nav_cmd().id) && if (in_vtol_auto() && is_vtol_land(plane.mission.get_current_nav_cmd().id) &&
(poscontrol.get_state() == QPOS_LAND_DESCEND || poscontrol.get_state() == QPOS_LAND_FINAL)) { (state == QPOS_LAND_DESCEND || state == QPOS_LAND_FINAL || state == QPOS_LAND_ABORT)) {
return true; return true;
} }
return false; return false;
@ -4367,6 +4428,11 @@ bool QuadPlane::landing_with_fixed_wing_spiral_approach(void) const
{ {
const AP_Mission::Mission_Command cmd = plane.mission.get_current_nav_cmd(); const AP_Mission::Mission_Command cmd = plane.mission.get_current_nav_cmd();
if (cmd.id == MAV_CMD_NAV_PAYLOAD_PLACE &&
option_is_set(QuadPlane::OPTION::MISSION_LAND_FW_APPROACH)) {
return true;
}
return ((cmd.id == MAV_CMD_NAV_VTOL_LAND) && return ((cmd.id == MAV_CMD_NAV_VTOL_LAND) &&
(option_is_set(QuadPlane::OPTION::MISSION_LAND_FW_APPROACH) || (option_is_set(QuadPlane::OPTION::MISSION_LAND_FW_APPROACH) ||
cmd.p1 == NAV_VTOL_LAND_OPTIONS_FW_SPIRAL_APPROACH)); cmd.p1 == NAV_VTOL_LAND_OPTIONS_FW_SPIRAL_APPROACH));
@ -4413,4 +4479,27 @@ void QuadPlane::setup_rp_fw_angle_gains(void)
attitude_control->set_angle_P_scale(gain_scale); attitude_control->set_angle_P_scale(gain_scale);
} }
/*
abort landing, used by scripting for payload place and ship landing abort
will return false if not in a landing descent
*/
bool QuadPlane::abort_landing(void)
{
if (poscontrol.get_state() == QPOS_LAND_ABORT) {
// already aborted?
return false;
}
// special case for payload place with full landing
const bool payload_place_landed =
plane.in_auto_mission_id(MAV_CMD_NAV_PAYLOAD_PLACE) &&
poscontrol.get_state() == QPOS_LAND_COMPLETE;
if (!payload_place_landed && !in_vtol_land_descent()) {
return false;
}
poscontrol.set_state(QuadPlane::QPOS_LAND_ABORT);
return true;
}
#endif // HAL_QUADPLANE_ENABLED #endif // HAL_QUADPLANE_ENABLED

View File

@ -97,6 +97,9 @@ public:
return available() && assisted_flight; return available() && assisted_flight;
} }
// abort landing, only valid when in a VTOL landing descent
bool abort_landing(void);
/* /*
return true if we are in a transition to fwd flight from hover return true if we are in a transition to fwd flight from hover
*/ */
@ -172,6 +175,11 @@ public:
// Check if servo auto trim is allowed // Check if servo auto trim is allowed
bool allow_servo_auto_trim(); bool allow_servo_auto_trim();
/*
are we in the descent phase of a VTOL landing?
*/
bool in_vtol_land_descent(void) const;
private: private:
AP_AHRS &ahrs; AP_AHRS &ahrs;
@ -461,6 +469,7 @@ private:
QPOS_POSITION1, QPOS_POSITION1,
QPOS_POSITION2, QPOS_POSITION2,
QPOS_LAND_DESCEND, QPOS_LAND_DESCEND,
QPOS_LAND_ABORT,
QPOS_LAND_FINAL, QPOS_LAND_FINAL,
QPOS_LAND_COMPLETE QPOS_LAND_COMPLETE
}; };
@ -491,6 +500,9 @@ private:
float target_accel; float target_accel;
uint32_t last_pos_reset_ms; uint32_t last_pos_reset_ms;
bool overshoot; bool overshoot;
float override_descent_rate;
uint32_t last_override_descent_ms;
private: private:
uint32_t last_state_change_ms; uint32_t last_state_change_ms;
enum position_control_state state; enum position_control_state state;
@ -574,6 +586,9 @@ private:
float last_land_final_agl; float last_land_final_agl;
// AHRS alt for land abort and package place, meters
float land_descend_start_alt;
// min alt for navigation in takeoff // min alt for navigation in takeoff
AP_Float takeoff_navalt_min; AP_Float takeoff_navalt_min;
uint32_t takeoff_last_run_ms; uint32_t takeoff_last_run_ms;
@ -603,11 +618,6 @@ private:
*/ */
bool in_vtol_land_approach(void) const; bool in_vtol_land_approach(void) const;
/*
are we in the descent phase of a VTOL landing?
*/
bool in_vtol_land_descent(void) const;
/* /*
are we in the final landing phase of a VTOL landing? are we in the final landing phase of a VTOL landing?
*/ */