#pragma once
#include <AP_Param/AP_Param.h>
#include <AP_Common/Location.h>
#include <stdint.h>
#include <AP_Soaring/AP_Soaring.h>
#include <AP_ADSB/AP_ADSB.h>
#include <AP_Vehicle/ModeReason.h>
#include "quadplane.h"
#include <AP_AHRS/AP_AHRS.h>
#include <AP_Mission/AP_Mission.h>
#include "config.h"
#include "pullup.h"
#include "systemid.h"
#ifndef AP_QUICKTUNE_ENABLED
#define AP_QUICKTUNE_ENABLED HAL_QUADPLANE_ENABLED
#endif
#ifndef MODE_AUTOLAND_ENABLED
#define MODE_AUTOLAND_ENABLED 1
#endif
#include <AP_Quicktune/AP_Quicktune.h>
class AC_PosControl;
class AC_AttitudeControl_Multi;
class AC_Loiter;
class Mode
{
public:
CLASS_NO_COPY(Mode);
enum Number : uint8_t {
MANUAL = 0,
CIRCLE = 1,
STABILIZE = 2,
TRAINING = 3,
ACRO = 4,
FLY_BY_WIRE_A = 5,
FLY_BY_WIRE_B = 6,
CRUISE = 7,
AUTOTUNE = 8,
AUTO = 10,
RTL = 11,
LOITER = 12,
TAKEOFF = 13,
AVOID_ADSB = 14,
GUIDED = 15,
INITIALISING = 16,
#if HAL_QUADPLANE_ENABLED
QSTABILIZE = 17,
QHOVER = 18,
QLOITER = 19,
QLAND = 20,
QRTL = 21,
#if QAUTOTUNE_ENABLED
QAUTOTUNE = 22,
#endif
QACRO = 23,
#endif
THERMAL = 24,
#if HAL_QUADPLANE_ENABLED
LOITER_ALT_QLAND = 25,
#endif
#if MODE_AUTOLAND_ENABLED
AUTOLAND = 26,
#endif
};
Mode();
bool enter();
void exit();
virtual void run();
virtual Number mode_number() const = 0;
virtual const char *name() const = 0;
virtual const char *name4() const = 0;
bool pre_arm_checks(size_t buflen, char *buffer) const;
void reset_controllers();
virtual void update() = 0;
virtual bool is_vtol_mode() const { return false; }
virtual bool is_vtol_man_throttle() const;
virtual bool is_vtol_man_mode() const { return false; }
virtual bool is_guided_mode() const { return false; }
virtual bool allows_terrain_disable() const { return false; }
virtual bool does_automatic_thermal_switch() const {return false; }
virtual void navigate() { return; }
virtual bool allows_throttle_nudging() const { return false; }
virtual bool does_auto_navigation() const { return false; }
virtual bool does_auto_throttle() const { return false; }
virtual bool mode_allows_autotuning() const { return false; }
virtual void update_target_altitude();
virtual bool handle_guided_request(Location target_loc) { return false; }
virtual bool is_landing() const { return false; }
virtual bool is_taking_off() const;
virtual bool use_throttle_limits() const;
virtual bool use_battery_compensation() const;
#if MODE_AUTOLAND_ENABLED
virtual bool allows_autoland_direction_capture() const { return false; }
#endif
#if AP_QUICKTUNE_ENABLED
virtual bool supports_quicktune() const { return false; }
#endif
#if AP_PLANE_SYSTEMID_ENABLED
virtual bool supports_vtol_systemid() const { return false; }
virtual bool supports_fw_systemid() const { return false; }
bool allow_fw_systemid() const;
#endif
protected:
virtual bool _enter() { return true; }
virtual void _exit() { return; }
virtual bool _pre_arm_checks(size_t buflen, char *buffer) const;
void output_rudder_and_steering(float val);
void output_pilot_throttle();
uint8_t unused_integer;
#if HAL_QUADPLANE_ENABLED
AC_PosControl*& pos_control;
AC_AttitudeControl_Multi*& attitude_control;
AC_Loiter*& loiter_nav;
QuadPlane& quadplane;
QuadPlane::PosControlState &poscontrol;
#endif
AP_AHRS& ahrs;
};
class ModeAcro : public Mode
{
friend class ModeQAcro;
public:
Mode::Number mode_number() const override { return Mode::Number::ACRO; }
const char *name() const override { return "Acro"; }
const char *name4() const override { return "ACRO"; }
void update() override;
void run() override;
void stabilize();
void stabilize_quaternion();
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
protected:
struct {
bool locked_roll;
bool locked_pitch;
float locked_roll_err;
int32_t locked_pitch_cd;
Quaternion q;
bool roll_active_last;
bool pitch_active_last;
bool yaw_active_last;
} acro_state;
bool _enter() override;
};
class ModeAuto : public Mode
{
public:
friend class Plane;
Number mode_number() const override { return Number::AUTO; }
const char *name() const override { return "Auto"; }
const char *name4() const override { return "AUTO"; }
bool does_automatic_thermal_switch() const override { return true; }
void update() override;
void navigate() override;
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override;
bool does_auto_throttle() const override;
bool mode_allows_autotuning() const override { return true; }
bool is_landing() const override;
void do_nav_delay(const AP_Mission::Mission_Command& cmd);
bool verify_nav_delay(const AP_Mission::Mission_Command& cmd);
bool verify_altitude_wait(const AP_Mission::Mission_Command& cmd);
void run() override;
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
#if AP_PLANE_GLIDER_PULLUP_ENABLED
bool in_pullup() const { return pullup.in_pullup(); }
#endif
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
void _exit() override;
bool _pre_arm_checks(size_t buflen, char *buffer) const override;
private:
struct {
uint32_t time_max_ms;
uint32_t time_start_ms;
} nav_delay;
void wiggle_servos();
struct {
uint8_t stage;
uint32_t last_ms;
} wiggle;
#if AP_PLANE_GLIDER_PULLUP_ENABLED
GliderPullup pullup;
#endif
};
class ModeAutoTune : public Mode
{
public:
Number mode_number() const override { return Number::AUTOTUNE; }
const char *name() const override { return "Autotune"; }
const char *name4() const override { return "ATUN"; }
void update() override;
bool mode_allows_autotuning() const override { return true; }
void run() override;
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
protected:
bool _enter() override;
};
class ModeGuided : public Mode
{
public:
Number mode_number() const override { return Number::GUIDED; }
const char *name() const override { return "Guided"; }
const char *name4() const override { return "GUID"; }
void update() override;
void navigate() override;
virtual bool is_guided_mode() const override { return true; }
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
bool handle_guided_request(Location target_loc) override;
#if AP_PLANE_OFFBOARD_GUIDED_SLEW_ENABLED
bool handle_change_airspeed(const float airspeed, const float acceleration);
#endif
void set_radius_and_direction(const float radius, const bool direction_is_ccw);
void update_target_altitude() override;
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
bool _pre_arm_checks(size_t buflen, char *buffer) const override { return true; }
#if AP_QUICKTUNE_ENABLED
bool supports_quicktune() const override { return true; }
#endif
private:
float active_radius_m;
};
class ModeCircle: public Mode
{
public:
Number mode_number() const override { return Number::CIRCLE; }
const char *name() const override { return "Circle"; }
const char *name4() const override { return "CIRC"; }
void update() override;
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
};
class ModeLoiter : public Mode
{
public:
Number mode_number() const override { return Number::LOITER; }
const char *name() const override { return "Loiter"; }
const char *name4() const override { return "LOIT"; }
void update() override;
void navigate() override;
bool isHeadingLinedUp(const Location loiterCenterLoc, const Location targetLoc);
bool isHeadingLinedUp_cd(const int32_t bearing_cd, const int32_t heading_cd);
bool isHeadingLinedUp_cd(const int32_t bearing_cd);
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
bool allows_terrain_disable() const override { return true; }
void update_target_altitude() override;
bool mode_allows_autotuning() const override { return true; }
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
};
#if HAL_QUADPLANE_ENABLED
class ModeLoiterAltQLand : public ModeLoiter
{
public:
Number mode_number() const override { return Number::LOITER_ALT_QLAND; }
const char *name() const override { return "Loiter to QLand"; }
const char *name4() const override { return "L2QL"; }
bool handle_guided_request(Location target_loc) override;
protected:
bool _enter() override;
void navigate() override;
private:
void switch_qland();
};
#endif
class ModeManual : public Mode
{
public:
Number mode_number() const override { return Number::MANUAL; }
const char *name() const override { return "Manual"; }
const char *name4() const override { return "MANU"; }
void update() override;
void run() override;
bool use_throttle_limits() const override;
bool use_battery_compensation() const override { return false; }
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
};
class ModeRTL : public Mode
{
public:
Number mode_number() const override { return Number::RTL; }
const char *name() const override { return "RTL"; }
const char *name4() const override { return "RTL "; }
void update() override;
void navigate() override;
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
protected:
bool _enter() override;
bool _pre_arm_checks(size_t buflen, char *buffer) const override { return false; }
private:
bool switch_QRTL();
};
class ModeStabilize : public Mode
{
public:
Number mode_number() const override { return Number::STABILIZE; }
const char *name() const override { return "Stabilize"; }
const char *name4() const override { return "STAB"; }
void update() override;
void run() override;
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
private:
void stabilize_stick_mixing_direct();
};
class ModeTraining : public Mode
{
public:
Number mode_number() const override { return Number::TRAINING; }
const char *name() const override { return "Training"; }
const char *name4() const override { return "TRAN"; }
void update() override;
void run() override;
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
};
class ModeInitializing : public Mode
{
public:
Number mode_number() const override { return Number::INITIALISING; }
const char *name() const override { return "Initialising"; }
const char *name4() const override { return "INIT"; }
bool _enter() override { return false; }
void update() override { }
bool allows_throttle_nudging() const override { return true; }
bool does_auto_throttle() const override { return true; }
protected:
bool _pre_arm_checks(size_t buflen, char *buffer) const override { return false; }
};
class ModeFBWA : public Mode
{
public:
Number mode_number() const override { return Number::FLY_BY_WIRE_A; }
const char *name() const override { return "FBWA"; }
const char *name4() const override { return "FBWA"; }
void update() override;
bool mode_allows_autotuning() const override { return true; }
void run() override;
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
};
class ModeFBWB : public Mode
{
public:
Number mode_number() const override { return Number::FLY_BY_WIRE_B; }
const char *name() const override { return "FBWB"; }
const char *name4() const override { return "FBWB"; }
bool allows_terrain_disable() const override { return true; }
bool does_automatic_thermal_switch() const override { return true; }
void update() override;
bool does_auto_throttle() const override { return true; }
bool mode_allows_autotuning() const override { return true; }
void update_target_altitude() override {};
protected:
bool _enter() override;
};
class ModeCruise : public Mode
{
public:
Number mode_number() const override { return Number::CRUISE; }
const char *name() const override { return "Cruise"; }
const char *name4() const override { return "CRUS"; }
bool allows_terrain_disable() const override { return true; }
bool does_automatic_thermal_switch() const override { return true; }
void update() override;
void navigate() override;
bool get_target_heading_cd(int32_t &target_heading) const;
bool does_auto_throttle() const override { return true; }
void update_target_altitude() override {};
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_fw_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
bool locked_heading;
int32_t locked_heading_cd;
uint32_t lock_timer_ms;
};
#if HAL_ADSB_ENABLED
class ModeAvoidADSB : public Mode
{
public:
Number mode_number() const override { return Number::AVOID_ADSB; }
const char *name() const override { return "Avoid ADSB"; }
const char *name4() const override { return "AVOI"; }
void update() override;
void navigate() override;
virtual bool is_guided_mode() const override { return true; }
bool does_auto_throttle() const override { return true; }
protected:
bool _enter() override;
};
#endif
#if HAL_QUADPLANE_ENABLED
class ModeQStabilize : public Mode
{
public:
Number mode_number() const override { return Number::QSTABILIZE; }
const char *name() const override { return "QStabilize"; }
const char *name4() const override { return "QSTB"; }
bool is_vtol_mode() const override { return true; }
bool is_vtol_man_throttle() const override { return true; }
virtual bool is_vtol_man_mode() const override { return true; }
bool allows_throttle_nudging() const override { return true; }
void update() override;
bool _enter() override;
void run() override;
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_vtol_systemid() const override { return true; }
#endif
protected:
private:
void set_tailsitter_roll_pitch(const float roll_input, const float pitch_input);
void set_limited_roll_pitch(const float roll_input, const float pitch_input);
};
class ModeQHover : public Mode
{
public:
Number mode_number() const override { return Number::QHOVER; }
const char *name() const override { return "QHover"; }
const char *name4() const override { return "QHOV"; }
bool is_vtol_mode() const override { return true; }
virtual bool is_vtol_man_mode() const override { return true; }
void update() override;
void run() override;
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_vtol_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
#if AP_QUICKTUNE_ENABLED
bool supports_quicktune() const override { return true; }
#endif
};
class ModeQLoiter : public Mode
{
friend class QuadPlane;
friend class ModeQLand;
friend class Plane;
public:
Number mode_number() const override { return Number::QLOITER; }
const char *name() const override { return "QLoiter"; }
const char *name4() const override { return "QLOT"; }
bool is_vtol_mode() const override { return true; }
virtual bool is_vtol_man_mode() const override { return true; }
void update() override;
void run() override;
#if AP_PLANE_SYSTEMID_ENABLED
bool supports_vtol_systemid() const override { return true; }
#endif
protected:
bool _enter() override;
uint32_t last_target_loc_set_ms;
#if AP_QUICKTUNE_ENABLED
bool supports_quicktune() const override { return true; }
#endif
};
class ModeQLand : public Mode
{
public:
Number mode_number() const override { return Number::QLAND; }
const char *name() const override { return "QLand"; }
const char *name4() const override { return "QLND"; }
bool is_vtol_mode() const override { return true; }
void update() override;
void run() override;
protected:
bool _enter() override;
bool _pre_arm_checks(size_t buflen, char *buffer) const override { return false; }
};
class ModeQRTL : public Mode
{
public:
Number mode_number() const override { return Number::QRTL; }
const char *name() const override { return "QRTL"; }
const char *name4() const override { return "QRTL"; }
bool is_vtol_mode() const override { return true; }
void update() override;
void run() override;
bool does_auto_throttle() const override { return true; }
void update_target_altitude() override;
bool allows_throttle_nudging() const override;
float get_VTOL_return_radius() const;
protected:
bool _enter() override;
bool _pre_arm_checks(size_t buflen, char *buffer) const override { return false; }
private:
enum class SubMode {
climb,
RTL,
} submode;
};
class ModeQAcro : public Mode
{
public:
Number mode_number() const override { return Number::QACRO; }
const char *name() const override { return "QAcro"; }
const char *name4() const override { return "QACO"; }
bool is_vtol_mode() const override { return true; }
bool is_vtol_man_throttle() const override { return true; }
virtual bool is_vtol_man_mode() const override { return true; }
void update() override;
void run() override;
protected:
bool _enter() override;
};
#if QAUTOTUNE_ENABLED
class ModeQAutotune : public Mode
{
public:
Number mode_number() const override { return Number::QAUTOTUNE; }
const char *name() const override { return "QAutotune"; }
const char *name4() const override { return "QATN"; }
bool is_vtol_mode() const override { return true; }
virtual bool is_vtol_man_mode() const override { return true; }
void run() override;
void update() override;
protected:
bool _enter() override;
void _exit() override;
};
#endif
#endif
class ModeTakeoff: public Mode
{
public:
ModeTakeoff();
Number mode_number() const override { return Number::TAKEOFF; }
const char *name() const override { return "Takeoff"; }
const char *name4() const override { return "TKOF"; }
void update() override;
void navigate() override;
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
#if MODE_AUTOLAND_ENABLED
bool allows_autoland_direction_capture() const override { return true; }
#endif
static const struct AP_Param::GroupInfo var_info[];
AP_Int16 target_alt;
AP_Int16 level_alt;
AP_Float ground_pitch;
protected:
AP_Int16 target_dist;
AP_Int8 level_pitch;
bool takeoff_mode_setup;
Location start_loc;
bool _enter() override;
private:
bool have_autoenabled_fences;
};
#if MODE_AUTOLAND_ENABLED
class ModeAutoLand: public Mode
{
public:
ModeAutoLand();
Number mode_number() const override { return Number::AUTOLAND; }
const char *name() const override { return "Autoland"; }
const char *name4() const override { return "ALND"; }
void update() override;
void navigate() override;
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
bool is_landing() const override;
void check_takeoff_direction(void);
bool landing_lined_up(void);
void arm_check(void);
static const struct AP_Param::GroupInfo var_info[];
AP_Int16 final_wp_alt;
AP_Int16 final_wp_dist;
AP_Int16 landing_dir_off;
AP_Int8 options;
AP_Int16 terrain_alt_min;
enum class AutoLandOption {
AUTOLAND_DIR_ON_ARM = (1U << 0),
};
enum class AutoLandStage {
CLIMB,
LOITER,
LANDING
};
bool autoland_option_is_set(AutoLandOption option) const {
return (options & int8_t(option)) != 0;
}
protected:
bool _enter() override;
AP_Mission::Mission_Command cmd_climb;
AP_Mission::Mission_Command cmd_loiter;
AP_Mission::Mission_Command cmd_land;
Location land_start;
AutoLandStage stage;
void set_autoland_direction(const float heading);
};
#endif
#if HAL_SOARING_ENABLED
class ModeThermal: public Mode
{
public:
Number mode_number() const override { return Number::THERMAL; }
const char *name() const override { return "Thermal"; }
const char *name4() const override { return "THML"; }
void update() override;
void update_soaring();
void navigate() override;
bool allows_throttle_nudging() const override { return true; }
bool does_auto_navigation() const override { return true; }
bool does_auto_throttle() const override { return true; }
protected:
bool exit_heading_aligned() const;
void restore_mode(const char *reason, ModeReason modereason);
bool _enter() override;
};
#endif