This commit is contained in:
Alessandro Simovic
2023-03-29 16:14:33 +02:00
parent 370af7c30f
commit 4435a57e68
4 changed files with 205 additions and 492 deletions
+1 -1
View File
@@ -6,4 +6,4 @@ uint8 PRECLAND_STATE_TOUCHING_DOWN = 4 # Same as descend, but if sight o
uint8 PRECLAND_STATE_FALLBACK = 5 # Fallback to conventional landing, either because of opportunistic precision landing or because maximum number of precland attempts were reached
uint64 timestamp # time since system start (microseconds)
uint8 precland_state # this flight-task's internal state
uint8 state # this flight-task's internal state
@@ -180,6 +180,7 @@ void FlightModeManager::start_flight_task()
should_disable_task = false;
if (switchTask(FlightTaskIndex::AutoPrecisionLanding) != FlightTaskError::NoError) {
PX4_INFO("Switching to precland flight task");
task_failure = true;
}
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2017-2023 PX4 Development Team. All rights reserved.
* Copyright (c) 2023 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,450 +30,201 @@
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file FlightTaskAutoPrecisionLanding.cpp
*
* @author Nicolas de Palezieux (Sunflower Labs) <ndepal@gmail.com>
*/
#include "FlightTaskAutoPrecisionLanding.hpp"
#include <mathlib/mathlib.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <fcntl.h>
static constexpr const char *LOST_TARGET_ERROR_MESSAGE = "Lost landing target while landing";
using namespace matrix;
bool FlightTaskAutoPrecisionLanding::activate(const trajectory_setpoint_s &last_setpoint)
{
bool ret = FlightTask::activate(last_setpoint);
PX4_INFO("precland activated");
_search_cnt = 0;
_last_slewrate_time = 0;
_position_setpoint = _position;
_search_count = 0;
try_switch_to_state_auto_rtl();
// TODO: Use target orientation instead
_yaw_setpoint = _yaw;
return ret;
}
void FlightTaskAutoPrecisionLanding::do_state_transition(PRECLAND_STATE new_state)
{
_precland_state = new_state;
_state_start_time = hrt_absolute_time();
}
bool FlightTaskAutoPrecisionLanding::inside_acceptance_radius()
{
return Vector3f(_position_setpoint - _position).norm() <= _param_pld_hacc_rad.get();
}
bool FlightTaskAutoPrecisionLanding::update()
{
bool ret = FlightTaskAuto::update();
// printf("state: %u\n", _precland_state);
// Fetch uorb
if (_landing_target_pose_sub.updated()) {
_landing_target_pose_sub.copy(&_landing_target_pose);
_precision_target_ned(0) = _landing_target_pose.x_rel;
_precision_target_ned(1) = _landing_target_pose.y_rel;
_precision_target_ned(2) = _landing_target_pose.z_rel;
}
// target pose can become invalid when the message timed out
_landing_target_pose_valid = (hrt_elapsed_time(&_landing_target_pose.timestamp) / 1e6f) <= _param_pld_btout.get();
// Initialize precision target coordinates with home position if marker has not been spotted yet
if (_landing_target_pose.timestamp == 0) {
if (_sub_home_position.get().valid_lpos && _sub_home_position.get().valid_alt) {
_precision_target_ned(0) = _sub_home_position.get().x;
_precision_target_ned(1) = _sub_home_position.get().y;
_precision_target_ned(2) = _sub_home_position.get().z; // TODO: I think this is NAN
} else {
// Nothing to do without valid home location or target position
return ret;
}
switch (_state) {
case PrecLandState::AutoRTL:
run_state_auto_rtl();
break;
case PrecLandState::MoveAboveTarget:
run_state_move_above_target();
break;
case PrecLandState::DescendAboveTarget:
run_state_descend_above_target();
break;
case PrecLandState::TouchingDown:
run_state_touching_down();
break;
case PrecLandState::Search:
run_state_search();
break;
case PrecLandState::Fallback:
run_state_fallback();
break;
default:
// unknown state
break;
}
// Publish status message for debugging
precision_landing_status_s precision_landing_status{};
precision_landing_status.timestamp = hrt_absolute_time();
precision_landing_status.precland_state = (uint8_t) _state;
_precision_landing_status_pub.publish(precision_landing_status);
_constraints.want_takeoff = _checkTakeoff();
// Fetch runtime parameters
const float max_search_duration = _param_pld_srch_tout.get();
const float search_rel_altitude = _param_pld_srch_alt.get();
switch (_precland_state) {
case PRECLAND_STATE::AUTORTL_CLIMB:
PX4_INFO("AUTORTL_CLIMB");
_position_setpoint = _position;
_position_setpoint(2) = _precision_target_ned(2) - search_rel_altitude;
_velocity_setpoint(0) = _velocity_setpoint(1) = _velocity_setpoint(2) = NAN;
// transition condition
// Wait for drone to reach z position setpoint
if (abs(_position(2) - _position_setpoint(2)) <= _param_pld_hacc_rad.get()) {
mavlink_log_info(&_mavlink_log_pub, "Moving above target");
do_state_transition(PRECLAND_STATE::AUTORTL_APPROACH);
}
break;
case PRECLAND_STATE::AUTORTL_APPROACH:
PX4_INFO("AUTORTL_APPROACH");
_position_setpoint = _precision_target_ned;
_position_setpoint(2) -= search_rel_altitude;
_velocity_setpoint(0) = _velocity_setpoint(1) = _velocity_setpoint(2) = NAN;
// transition condition
// Wait for drone to reach position setpoint
if (inside_acceptance_radius()) {
mavlink_log_info(&_mavlink_log_pub, "Moving to search center");
do_state_transition(PRECLAND_STATE::MOVE_TO_SEARCH_ALTITUDE);
}
break;
case PRECLAND_STATE::MOVE_TO_SEARCH_ALTITUDE:
PX4_INFO("MOVE_TO_SEARCH_ALTITUDE");
// Ascend/Descend to search altitude
_position_setpoint = _precision_target_ned;
_position_setpoint(2) -= search_rel_altitude;
_velocity_setpoint(0) = _velocity_setpoint(1) = _velocity_setpoint(2) = NAN;
_acceleration_setpoint(0) = _acceleration_setpoint(1) = _acceleration_setpoint(2) = NAN;
// transition condition
if (inside_acceptance_radius()) {
mavlink_log_info(&_mavlink_log_pub, "Starting search");
do_state_transition(PRECLAND_STATE::SEARCHING_TARGET);
}
break;
case PRECLAND_STATE::SEARCHING_TARGET:
PX4_INFO("SEARCHING_TARGET");
// Currently no search pattern is implemented. Just wait for target...
// Workaround for Orion app making unwanted changes to my parameters
if ((hrt_absolute_time() - _state_start_time) > max_search_duration * SEC2USEC) {
mavlink_log_info(&_mavlink_log_pub, "Search timed out");
if (++_search_count >= _param_pld_max_srch.get()) {
mavlink_log_info(&_mavlink_log_pub, "Abandonning search and landing immediately");
do_state_transition(PRECLAND_STATE::LANDING);
} else {
mavlink_log_info(&_mavlink_log_pub, "Moving to search center");
do_state_transition(PRECLAND_STATE::MOVE_TO_SEARCH_ALTITUDE);
}
}
// transition condition
if (hrt_absolute_time() - _landing_target_pose.timestamp <= _param_pld_btout.get()*SEC2USEC) {
mavlink_log_info(&_mavlink_log_pub, "Moving above target");
do_state_transition(PRECLAND_STATE::MOVING_ABOVE_TARGET);
}
break;
case PRECLAND_STATE::MOVING_ABOVE_TARGET:
PX4_INFO("MOVING_ABOVE_TARGET");
_position_setpoint(0) = _landing_target_pose.x_abs;
_position_setpoint(1) = _landing_target_pose.y_abs;
_position_setpoint(2) = _precision_target_ned(2) - search_rel_altitude;
_velocity_setpoint(0) = NAN;
_velocity_setpoint(1) = NAN;
_velocity_setpoint(2) = 0;
// Transition condition
// - Check acceptance radius and
// - wait long enough to observe if the landing_target_pose timed out before proceeding
if (abs(_position(0) - _position_setpoint(0)) <= _param_pld_hacc_rad.get()
&& abs(_position(1) - _position_setpoint(1)) <= _param_pld_hacc_rad.get()
&& _velocity.norm() <= HOVER_SPEED_THRESHOLD
&& (hrt_absolute_time() - _state_start_time) > _param_pld_btout.get() * SEC2USEC) {
if (hrt_absolute_time() - _landing_target_pose.timestamp < _param_pld_btout.get() * SEC2USEC) {
mavlink_log_info(&_mavlink_log_pub, "Landing on target...");
do_state_transition(PRECLAND_STATE::LANDING);
} else {
mavlink_log_info(&_mavlink_log_pub, "Lost target, back to searching");
do_state_transition(PRECLAND_STATE::SEARCHING_TARGET);
}
}
break;
case PRECLAND_STATE::LANDING:
PX4_INFO("LANDING");
// Control XY position and Z velocity
_position_setpoint(0) = _landing_target_pose.x_abs;
_position_setpoint(1) = _landing_target_pose.y_abs;
_position_setpoint(2) = NAN;
_velocity_setpoint(0) = 0;
_velocity_setpoint(1) = 0;
_velocity_setpoint(2) = _param_mpc_land_speed.get();
_acceleration_setpoint(2) = NAN;
break;
}
precision_landing_status.timestamp = hrt_absolute_time();
precision_landing_status.state = _precland_state;
_precision_landing_status_pub.publish(precision_landing_status);
return ret;
}
void
FlightTaskAutoPrecisionLanding::run_state_auto_rtl()
{
// In this state simply track the navigator setpoint triplet
// This ensures that the behaviour for precision landing during RTL / LAND
// is the same as without precision landing.
// This flight task will generate independent setpoints once the vehicle
// is in the vertical landing phase.
_position_setpoint = _target;
if (try_switch_to_state_move_above_target()) {
// If target visible and go to horizontal approach directly
return;
} else if ((PrecLandMode)_param_rtl_pld_md.get() == PrecLandMode::Opportunistic) {
// could not see the target immediately, so just fall back to normal landing
try_switch_to_state_fallback();
} else if (_type == WaypointType::land) {
// Navigator already entered land stage. Take over with precision landing
// This is where the vehicle starts to behave differently than in regular land!
try_switch_to_state_search();
}
}
void
FlightTaskAutoPrecisionLanding::run_state_move_above_target()
{
float x = _landing_target_pose.x_abs;
float y = _landing_target_pose.y_abs;
slewrate(x, y); // TODO: Replace this with PX4's AlphaFilter
// Fly to target XY position, but keep navigator's altitude setpoint
_position_setpoint(0) = x;
_position_setpoint(1) = y;
_position_setpoint(2) = _target(2);
_velocity_setpoint(0) = _velocity_setpoint(1) = NAN;
// If altitude setpoint is NAN, we stay at the current altitude
if (!PX4_ISFINITE(_position_setpoint(2))) {
_velocity_setpoint(2) = 0.0f;
}
// check if target visible, if not go to start
if (!check_state_conditions(PrecLandState::MoveAboveTarget)) {
PX4_WARN("%s, state: %i", LOST_TARGET_ERROR_MESSAGE, (int) _state);
// Stay at current position for searching for the landing target
// TODO: This is not going to work after conversion to flight task, because
// the position_setpoint will be overwritten at the next iteration!
// Solution: An additional wait state
_position_setpoint = _position;
_velocity_setpoint(0) = _velocity_setpoint(1) = _velocity_setpoint(2) = NAN;
if (!try_switch_to_state_auto_rtl()) {
try_switch_to_state_fallback();
}
return;
}
if (check_state_conditions(PrecLandState::DescendAboveTarget)) {
if (!_point_reached_time) {
_point_reached_time = hrt_absolute_time();
}
if (hrt_absolute_time() - _point_reached_time > 2000000) {
// if close enough for descent above target go to descend above target
if (try_switch_to_state_descend_above_target()) {
return;
}
}
}
}
void
FlightTaskAutoPrecisionLanding::run_state_descend_above_target()
{
// Overwrite Auto setpoints in order to descend above target
_position_setpoint(0) = _landing_target_pose.x_abs;
_position_setpoint(1) = _landing_target_pose.y_abs;
_position_setpoint(2) = NAN;
_velocity_setpoint(0) = 0;
_velocity_setpoint(1) = 0;
_velocity_setpoint(2) = _param_mpc_land_speed.get();
// check if target visible
if (!check_state_conditions(PrecLandState::DescendAboveTarget)) {
if (!try_switch_to_state_touching_down()) {
PX4_WARN("%s, state: %i", LOST_TARGET_ERROR_MESSAGE, (int) _state);
// Stay at current position for searching for the target
_position_setpoint = _position;
if (!try_switch_to_state_auto_rtl()) {
try_switch_to_state_fallback();
}
}
return;
}
}
void
FlightTaskAutoPrecisionLanding::run_state_touching_down()
{
// Overwrite Auto setpoints in order to land at target's last known location
_position_setpoint(0) = _landing_target_pose.x_abs;
_position_setpoint(1) = _landing_target_pose.y_abs;
_position_setpoint(2) = NAN;
_velocity_setpoint(0) = 0;
_velocity_setpoint(1) = 0;
_velocity_setpoint(2) = _param_mpc_land_speed.get();
}
void
FlightTaskAutoPrecisionLanding::run_state_search()
{
// Overwrite Auto setpoints in order to hover at search altitude
_position_setpoint = _target;
_position_setpoint(2) = _sub_home_position.get().z - _param_pld_srch_alt.get();
_velocity_setpoint(0) = _velocity_setpoint(1) = _velocity_setpoint(2) = NAN;
// check if we can see the target
if (check_state_conditions(PrecLandState::MoveAboveTarget)) {
if (!_target_acquired_time) {
// target just became visible. Stop climbing, but give it some margin so we don't stop too apruptly
_target_acquired_time = hrt_absolute_time();
_position_setpoint = _position;
_position_setpoint(2) += 1.0f;
}
}
// stay at that height for a second to allow the vehicle to settle
if (_target_acquired_time && (hrt_absolute_time() - _target_acquired_time) > 1000000) {
// try to switch to horizontal approach
if (try_switch_to_state_move_above_target()) {
return;
}
} else if (hrt_absolute_time() - _state_start_time > _param_pld_srch_tout.get()*SEC2USEC) {
// Search timed out and go to fallback
PX4_WARN("Search timed out");
try_switch_to_state_fallback();
}
}
void
FlightTaskAutoPrecisionLanding::run_state_fallback()
{
// Try switching to horizontal approach. This works if the
// target meanwhile became visible
try_switch_to_state_move_above_target();
// Otherwise there is nothing to do, except for listening to navigator
_position_setpoint = _target;
}
bool
FlightTaskAutoPrecisionLanding::try_switch_to_state_auto_rtl()
{
if (check_state_conditions(PrecLandState::AutoRTL)) {
_search_cnt++;
_point_reached_time = 0;
_state = PrecLandState::AutoRTL;
_state_start_time = hrt_absolute_time();
return true;
}
return false;
}
bool
FlightTaskAutoPrecisionLanding::try_switch_to_state_move_above_target()
{
if (check_state_conditions(PrecLandState::MoveAboveTarget)) {
print_state_switch_message("horizontal approach");
_point_reached_time = 0;
_state = PrecLandState::MoveAboveTarget;
_state_start_time = hrt_absolute_time();
return true;
}
return false;
}
bool
FlightTaskAutoPrecisionLanding::try_switch_to_state_descend_above_target()
{
if (check_state_conditions(PrecLandState::DescendAboveTarget)) {
print_state_switch_message("descend");
_state = PrecLandState::DescendAboveTarget;
_state_start_time = hrt_absolute_time();
return true;
}
return false;
}
bool
FlightTaskAutoPrecisionLanding::try_switch_to_state_touching_down()
{
if (check_state_conditions(PrecLandState::TouchingDown)) {
print_state_switch_message("final approach");
_state = PrecLandState::TouchingDown;
_state_start_time = hrt_absolute_time();
return true;
}
return false;
}
void
FlightTaskAutoPrecisionLanding::try_switch_to_state_search()
{
PX4_INFO("Climbing to search altitude");
_target_acquired_time = 0;
_state = PrecLandState::Search;
_state_start_time = hrt_absolute_time();
}
void
FlightTaskAutoPrecisionLanding::try_switch_to_state_fallback()
{
print_state_switch_message("fallback");
_state = PrecLandState::Fallback;
_state_start_time = hrt_absolute_time();
}
void FlightTaskAutoPrecisionLanding::print_state_switch_message(const char *state_name)
{
PX4_INFO("Precland: switching to %s", state_name);
}
bool FlightTaskAutoPrecisionLanding::check_state_conditions(PrecLandState state)
{
switch (state) {
case PrecLandState::AutoRTL:
return _search_cnt <= _param_pld_max_srch.get();
case PrecLandState::MoveAboveTarget:
// if we're already in this state, only want to make it invalid if we reached the target but can't see it anymore
if (_state == PrecLandState::MoveAboveTarget) {
if (hor_acc_radius_check()) {
// we've reached the position where we last saw the target. If we don't see it now, we need to do something
return _landing_target_pose_valid && _landing_target_pose.abs_pos_valid;
} else {
// We've seen the target sometime during horizontal approach.
// Even if we don't see it as we're moving towards it, continue approaching last known location
return true;
}
}
// If we're trying to switch to this state, the target needs to be visible
return _landing_target_pose_valid && _landing_target_pose.abs_pos_valid;
case PrecLandState::DescendAboveTarget:
// if we're already in this state, only leave it if target becomes unusable, don't care about horizontal offset to target
if (_state == PrecLandState::DescendAboveTarget) {
// if we're close to the ground, we're more critical of target timeouts so we quickly go into descend
if (check_state_conditions(PrecLandState::TouchingDown)) {
return hrt_absolute_time() - _landing_target_pose.timestamp < 500000; // 0.5s // TODO: Magic number!
} else {
return _landing_target_pose_valid && _landing_target_pose.abs_pos_valid;
}
} else {
// if not already in this state, need to be above target to enter it
return _landing_target_pose.abs_pos_valid && hor_acc_radius_check();
}
case PrecLandState::TouchingDown:
return _landing_target_pose_valid && _landing_target_pose.abs_pos_valid
&& (_landing_target_pose.z_abs - _position(2)) < _param_pld_fappr_alt.get();
case PrecLandState::Search:
return true;
case PrecLandState::Fallback:
return true;
default:
return false;
}
}
bool FlightTaskAutoPrecisionLanding::hor_acc_radius_check()
{
return Vector2f(Vector2f(_landing_target_pose.x_abs,
_landing_target_pose.y_abs) - _position.xy()).norm() <= _param_pld_hacc_rad.get();
}
void FlightTaskAutoPrecisionLanding::slewrate(float &sp_x, float &sp_y)
{
matrix::Vector2f sp_curr(sp_x, sp_y);
uint64_t now = hrt_absolute_time();
float dt = (now - _last_slewrate_time);
if (dt < 1) {
// bad dt, can't divide by it
return;
}
dt /= SEC2USEC;
if (_last_slewrate_time == 0) {
// running the first time since switching to precland
_sp_pev_prev(0) = sp_x;
_sp_pev_prev(1) = sp_y;
_sp_pev(0) = sp_x;
_sp_pev(1) = sp_y;
}
_last_slewrate_time = now;
// limit the setpoint speed to the maximum cruise speed
matrix::Vector2f sp_vel = (sp_curr - _sp_pev) / dt; // velocity of the setpoints
if (sp_vel.length() > _param_xy_vel_cruise.get()) {
sp_vel = sp_vel.normalized() * _param_xy_vel_cruise.get();
sp_curr = _sp_pev + sp_vel * dt;
}
// limit the setpoint acceleration to the maximum acceleration
matrix::Vector2f sp_acc = (sp_curr - _sp_pev * 2 + _sp_pev_prev) / (dt * dt); // acceleration of the setpoints
if (sp_acc.length() > _param_acceleration_hor.get()) {
sp_acc = sp_acc.normalized() * _param_acceleration_hor.get();
sp_curr = _sp_pev * 2 - _sp_pev_prev + sp_acc * (dt * dt);
}
// limit the setpoint speed such that we can stop at the setpoint given the maximum acceleration/deceleration
float max_spd = sqrtf(_param_acceleration_hor.get() * ((matrix::Vector2f)(_sp_pev - matrix::Vector2f(sp_x,
sp_y))).length());
sp_vel = (sp_curr - _sp_pev) / dt; // velocity of the setpoints
if (sp_vel.length() > max_spd) {
sp_vel = sp_vel.normalized() * max_spd;
sp_curr = _sp_pev + sp_vel * dt;
}
_sp_pev_prev = _sp_pev;
_sp_pev = sp_curr;
sp_x = sp_curr(0);
sp_y = sp_curr(1);
}
@@ -1,6 +1,6 @@
/****************************************************************************
*
* Copyright (c) 2017-2023 PX4 Development Team. All rights reserved.
* Copyright (c) 2023 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,41 +35,23 @@
* @file FlightTaskAutoPrecisionLanding.hpp
*
* Flight task for better precision landing
*
* @author Nicolas de Palezieux (Sunflower Labs) <ndepal@gmail.com>
*/
#pragma once
#include "FlightTaskAuto.hpp"
#include <matrix/math.hpp>
#include <mathlib/mathlib.h>
#include <lib/geo/geo.h>
#include <px4_platform_common/module_params.h>
#include <uORB/Subscription.hpp>
#include <uORB/PublicationMulti.hpp>
#include <uORB/topics/landing_target_pose.h>
#include <uORB/topics/precision_landing_status.h>
// #include <uORB/topics/vehicle_local_position_setpoint.h>
#include <systemlib/mavlink_log.h>
#include <uORB/topics/follow_target_estimator.h>
// #include <lib/ecl/geo/geo.h>
#include <mathlib/mathlib.h>
#define SEC2USEC 1000000.0f // TODO: Get the correct define from some header
#define STATE_TIMEOUT 10000000 // [us] Maximum time to spend in any state
#define ACCEPTANCE_RADIUS 0.20f // Horizontal acceptance radius for the navigation to the landing target
// TODO: Get ACCEPTANCE_RADIUS from NAV_ACC_RAD
enum class PrecLandState {
AutoRTL, // Starting state
Search, // Search for landing target
MoveAboveTarget, // Positioning over landing target while maintaining altitude
DescendAboveTarget, // Stay over landing target while descending
TouchingDown, // Final landing approach, even without landing target
Fallback // Fallback landing method
};
enum class PrecLandMode {
Opportunistic = 1, // only do precision landing if landing target visible at the beginning
Required = 2 // try to find landing target if not visible at the beginning
};
// TODO: Get the correct define from some header
#define SEC2USEC 1000000.0f
#define HOVER_SPEED_THRESHOLD 0.20f // If drone has speed under this value it is considered to be hovering in place
class FlightTaskAutoPrecisionLanding : public FlightTaskAuto
{
@@ -82,60 +64,39 @@ public:
bool update() override;
private:
// run the control loop for each state
void run_state_auto_rtl();
void run_state_search();
void run_state_move_above_target();
void run_state_descend_above_target();
void run_state_touching_down();
void run_state_fallback();
// attempt to switch to a different state. Returns true if state change was successful, false otherwise
bool try_switch_to_state_auto_rtl();
void try_switch_to_state_search();
bool try_switch_to_state_move_above_target();
bool try_switch_to_state_descend_above_target();
bool try_switch_to_state_touching_down();
void try_switch_to_state_fallback();
void print_state_switch_message(const char *state_name);
// check if a given state could be changed into. Return true if possible to transition to state, false otherwise
bool check_state_conditions(PrecLandState state);
void slewrate(float &sp_x, float &sp_y);
bool hor_acc_radius_check();
landing_target_pose_s _landing_target_pose{}; /**< precision landing target position */
uORB::Subscription _landing_target_pose_sub{ORB_ID(landing_target_pose)};
uORB::PublicationMulti<precision_landing_status_s> _precision_landing_status_pub{ORB_ID(precision_landing_status)};
bool _landing_target_pose_valid{false}; /**< whether we have received a landing target position message */
uint64_t _state_start_time{0}; /**< time when we entered current state */
uint64_t _last_slewrate_time{0}; /**< time when we last limited setpoint changes */
uint64_t _target_acquired_time{0}; /**< time when we first saw the landing target during search */
uint64_t _point_reached_time{0}; /**< time when we reached a setpoint */
int _search_cnt{0}; /**< counter of how many times we had to search for the landing target */
matrix::Vector2f _sp_pev;
matrix::Vector2f _sp_pev_prev;
PrecLandState _state{PrecLandState::AutoRTL};
DEFINE_PARAMETERS_CUSTOM_PARENT(FlightTask,
(ParamFloat<px4::params::MPC_LAND_SPEED>) _param_mpc_land_speed, ///< velocity for controlled descend
(ParamFloat<px4::params::MPC_ACC_HOR>) _param_acceleration_hor,
(ParamFloat<px4::params::MPC_XY_CRUISE>) _param_xy_vel_cruise,
(ParamFloat<px4::params::PLD_BTOUT>) _param_pld_btout,
(ParamFloat<px4::params::PLD_HACC_RAD>) _param_pld_hacc_rad,
(ParamFloat<px4::params::PLD_FAPPR_ALT>) _param_pld_fappr_alt,
(ParamFloat<px4::params::PLD_SRCH_ALT>) _param_pld_srch_alt,
(ParamFloat<px4::params::PLD_SRCH_TOUT>) _param_pld_srch_tout,
(ParamInt<px4::params::PLD_MAX_SRCH>) _param_pld_max_srch,
(ParamInt<px4::params::RTL_PLD_MD>) _param_rtl_pld_md
(ParamFloat<px4::params::PLD_HACC_RAD>) _param_pld_hacc_rad,
(ParamFloat<px4::params::PLD_BTOUT>) _param_pld_btout
)
enum PRECLAND_STATE {
AUTORTL_CLIMB,
AUTORTL_APPROACH,
MOVE_TO_SEARCH_ALTITUDE,
SEARCHING_TARGET,
MOVING_ABOVE_TARGET,
LANDING
};
void do_state_transition(PRECLAND_STATE new_state);
bool inside_acceptance_radius();
PRECLAND_STATE _precland_state = PRECLAND_STATE::AUTORTL_CLIMB;
uORB::Subscription _landing_target_pose_sub{ORB_ID(landing_target_pose)};
landing_target_pose_s _landing_target_pose{}; /**< precision landing target position */
uORB::PublicationMulti<precision_landing_status_s> _precision_landing_status_pub{ORB_ID(precision_landing_status)};
uint64_t _state_start_time{0}; /**< time when entering search state */
int _search_count = 0;
orb_advert_t _mavlink_log_pub{nullptr};
matrix::Vector3f _precision_target_ned = {NAN, NAN, NAN};
};