Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/libraries/AC_AttitudeControl/AC_WeatherVane.cpp
Views: 1798
/*1* Aircraft Weathervane options common to vtol plane and copters2*/3#include <AP_Vehicle/AP_Vehicle_Type.h>4#include "AC_WeatherVane.h"5#include <GCS_MAVLink/GCS.h>6#include <AP_AHRS/AP_AHRS.h>78#if APM_BUILD_TYPE(APM_BUILD_ArduPlane)9#define WVANE_PARAM_ENABLED 110#define WVANE_PARAM_SPD_MAX_DEFAULT 011#define WVANE_PARAM_VELZ_MAX_DEFAULT 012#define WVANE_PARAM_GAIN_DEFAULT 013#else14#define WVANE_PARAM_ENABLED 015#define WVANE_PARAM_SPD_MAX_DEFAULT 216#define WVANE_PARAM_VELZ_MAX_DEFAULT 117#define WVANE_PARAM_GAIN_DEFAULT 118#endif192021const AP_Param::GroupInfo AC_WeatherVane::var_info[] = {2223// @Param: ENABLE24// @DisplayName: Enable25// @Description: Enable weather vaning. When active, the aircraft will automatically yaw into wind when in a VTOL position controlled mode. Pilot yaw commands override the weathervaning action.26// @Values: -1:Only use during takeoffs or landing see weathervane takeoff and land override parameters,0:Disabled,1:Nose into wind,2:Nose or tail into wind,3:Side into wind,4:tail into wind27// @User: Standard28AP_GROUPINFO_FLAGS("ENABLE", 1, AC_WeatherVane, _direction, WVANE_PARAM_ENABLED, AP_PARAM_FLAG_ENABLE),2930// @Param: GAIN31// @DisplayName: Weathervaning gain32// @Description: This converts the target roll/pitch angle of the aircraft into the correcting (into wind) yaw rate. e.g. Gain = 2, roll = 30 deg, pitch = 0 deg, yaw rate = 60 deg/s.33// @Range: 0.5 434// @Increment: 0.135// @User: Standard36AP_GROUPINFO("GAIN", 2, AC_WeatherVane, _gain, WVANE_PARAM_GAIN_DEFAULT),3738// @Param: ANG_MIN39// @DisplayName: Weathervaning min angle40// @Description: The minimum target roll/pitch angle before active weathervaning will start. This provides a dead zone that is particularly useful for poorly trimmed quadplanes.41// @Units: deg42// @Range: 0 1043// @Increment: 0.144// @User: Standard45AP_GROUPINFO("ANG_MIN", 3, AC_WeatherVane, _min_dz_ang_deg, 1.0),4647// @Param: HGT_MIN48// @DisplayName: Weathervaning min height49// @Description: Above this height weathervaning is permitted. If a range finder is fitted or if terrain is enabled, this parameter sets height AGL. Otherwise, this parameter sets height above home. Set zero to ignore minimum height requirement to activate weathervaning.50// @Description{Plane}: Above this height weathervaning is permitted. If RNGFND_LANDING is enabled or terrain is enabled then this parameter sets height AGL. Otherwise this parameter sets height above home. Set zero to ignore minimum height requirement to activate weathervaning51// @Units: m52// @Range: 0 5053// @Increment: 154// @User: Standard55AP_GROUPINFO("HGT_MIN", 4, AC_WeatherVane, _min_height, 0.0),5657// @Param: SPD_MAX58// @DisplayName: Weathervaning max ground speed59// @Description: Below this ground speed weathervaning is permitted. Set to 0 to ignore this condition when checking if vehicle should weathervane.60// @Units: m/s61// @Range: 0 5062// @Increment: 0.163// @User: Standard64AP_GROUPINFO("SPD_MAX", 5, AC_WeatherVane, _max_vel_xy, WVANE_PARAM_SPD_MAX_DEFAULT),6566// @Param: VELZ_MAX67// @DisplayName: Weathervaning max vertical speed68// @Description: The maximum climb or descent speed that the vehicle will still attempt to weathervane. Set to 0 to ignore this condition to get the aircraft to weathervane at any climb/descent rate. This is particularly useful for aircraft with low disc loading that struggle with yaw control in decent.69// @Units: m/s70// @Range: 0 571// @Increment: 0.172// @User: Standard73AP_GROUPINFO("VELZ_MAX", 6, AC_WeatherVane, _max_vel_z, WVANE_PARAM_VELZ_MAX_DEFAULT),7475// @Param: TAKEOFF76// @DisplayName: Takeoff override77// @Description: Override the weather vaning behaviour when in takeoffs78// @Values: -1:No override,0:Disabled,1:Nose into wind,2:Nose or tail into wind,3:Side into wind,4:tail into wind79// @User: Standard80AP_GROUPINFO("TAKEOFF", 7, AC_WeatherVane, _takeoff_direction, -1),8182// @Param: LAND83// @DisplayName: Landing override84// @Description: Override the weather vaning behaviour when in landing85// @Values: -1:No override,0:Disabled,1:Nose into wind,2:Nose or tail into wind,3:Side into wind,4:tail into wind86// @User: Standard87AP_GROUPINFO("LAND", 8, AC_WeatherVane, _landing_direction, -1),8889// @Param: OPTIONS90// @DisplayName: Weathervaning options91// @Description: Options impacting weathervaning behaviour92// @Bitmask: 0:Use pitch when nose or tail-in for faster weathervaning93// @User: Standard94AP_GROUPINFO("OPTIONS", 9, AC_WeatherVane, _options, 0),9596AP_GROUPEND97};9899100// Constructor101AC_WeatherVane::AC_WeatherVane(void)102{103AP_Param::setup_object_defaults(this, var_info);104}105106bool AC_WeatherVane::get_yaw_out(float &yaw_output, const int16_t pilot_yaw, const float hgt, const float roll_cdeg, const float pitch_cdeg, const bool is_takeoff, const bool is_landing)107{108Direction dir = (Direction)_direction.get();109if ((dir == Direction::OFF) || !allowed || (pilot_yaw != 0) || !is_positive(_gain)) {110// parameter disabled, or 0 gain111// disabled temporarily112// dont't override pilot113reset();114return false;115}116117// override direction when in takeoff for landing118if (is_takeoff && (_takeoff_direction >= 0)) {119dir = (Direction)_takeoff_direction.get();120}121if (is_landing && (_landing_direction >= 0)) {122dir = (Direction)_landing_direction.get();123}124if (dir == Direction::OFF || (dir == Direction::TAKEOFF_OR_LAND_ONLY)) {125// Disabled for takeoff or landing126// Disabled if in flight and dir = -1127reset();128return false;129}130131// Check if we are above the minimum height to weather vane132if (is_positive(_min_height) && (hgt <= _min_height)) {133reset();134return false;135}136137// Check if we meet the velocity thresholds to allow weathervaning138if (is_positive(_max_vel_xy) || is_positive(_max_vel_z)) {139Vector3f vel_ned;140if (!AP::ahrs().get_velocity_NED(vel_ned) || // need speed estimate141(is_positive(_max_vel_xy) && (vel_ned.xy().length_squared() > (_max_vel_xy*_max_vel_xy))) || // check xy speed142(is_positive(_max_vel_z) && (fabsf(vel_ned.z) > _max_vel_z))) { // check z speed143reset();144return false;145}146}147148const uint32_t now = AP_HAL::millis();149if (now - last_check_ms > 250) {150// not run this function or reset recently151reset();152}153last_check_ms = now;154155/*156Use a 2 second buffer to ensure weathervaning occurs once the vehicle has157clearly achieved an acceptable condition.158*/159if (first_activate_ms == 0) {160first_activate_ms = now;161}162if (now - first_activate_ms < 2000) {163return false;164}165166const float deadzone_cdeg = _min_dz_ang_deg*100.0;167float output = 0.0;168const char* dir_string = "";169170// should we enable pitch input for nose-in and tail-in?171const bool pitch_enable = (uint8_t(_options.get()) & uint8_t(Options::PITCH_ENABLE)) != 0;172173switch (dir) {174case Direction::OFF:175case Direction::TAKEOFF_OR_LAND_ONLY:176reset();177return false;178179case Direction::NOSE_IN:180if (pitch_enable && is_positive(pitch_cdeg - deadzone_cdeg)) {181output = fabsf(roll_cdeg) + (pitch_cdeg - deadzone_cdeg);182} else {183output = MAX(fabsf(roll_cdeg) - deadzone_cdeg, 0.0);184}185if (is_negative(roll_cdeg)) {186output *= -1.0;187}188dir_string = "nose in";189break;190191case Direction::NOSE_OR_TAIL_IN:192output = MAX(fabsf(roll_cdeg) - deadzone_cdeg, 0.0);193if (is_negative(roll_cdeg) != is_positive(pitch_cdeg)) {194output *= -1.0;195}196dir_string = "nose or tail in";197break;198199case Direction::SIDE_IN:200output = MAX(fabsf(pitch_cdeg) - deadzone_cdeg, 0.0);201if (is_positive(pitch_cdeg) != is_positive(roll_cdeg)) {202output *= -1.0;203}204dir_string = "side in";205break;206207case Direction::TAIL_IN:208if (pitch_enable && is_negative(pitch_cdeg + deadzone_cdeg)) {209output = fabsf(roll_cdeg) - (pitch_cdeg + deadzone_cdeg);210} else {211output = MAX(fabsf(roll_cdeg) - deadzone_cdeg, 0.0);212}213if (is_positive(roll_cdeg)) {214output *= -1.0;215}216dir_string = "tail in";217break;218}219220if (!active_msg_sent) {221GCS_SEND_TEXT(MAV_SEVERITY_INFO, "Weathervane Active: %s", dir_string);222(void)dir_string; // in case GCS is disabled223active_msg_sent = true;224}225226// Slew output and apply gain227last_output = 0.98 * last_output + 0.02 * output * _gain;228yaw_output = last_output;229return true;230}231232// Reset the weathervane controller233void AC_WeatherVane::reset(void)234{235last_output = 0;236active_msg_sent = false;237first_activate_ms = 0;238last_check_ms = AP_HAL::millis();239}240241242243