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_Autorotation/AC_Autorotation.cpp
Views: 1798
#include "AC_Autorotation.h"1#include <AP_Logger/AP_Logger.h>2#include <AP_RPM/AP_RPM.h>3#include <AP_AHRS/AP_AHRS.h>45// Autorotation controller defaults6// Head Speed (HS) controller specific default definitions7#define HS_CONTROLLER_COLLECTIVE_CUTOFF_FREQ 2.0f // low-pass filter on accel error (unit: hz)8#define HS_CONTROLLER_HEADSPEED_P 0.7f // Default P gain for head speed controller (unit: -)9#define HS_CONTROLLER_ENTRY_COL_FILTER 0.7f // Default low pass filter frequency during the entry phase (unit: Hz)10#define HS_CONTROLLER_GLIDE_COL_FILTER 0.1f // Default low pass filter frequency during the glide phase (unit: Hz)1112// Speed Height controller specific default definitions for autorotation use13#define FWD_SPD_CONTROLLER_GND_SPEED_TARGET 1100 // Default target ground speed for speed height controller (unit: cm/s)14#define FWD_SPD_CONTROLLER_MAX_ACCEL 60 // Default acceleration limit for speed height controller (unit: cm/s/s)15#define AP_FW_VEL_P 0.9f16#define AP_FW_VEL_FF 0.15f171819const AP_Param::GroupInfo AC_Autorotation::var_info[] = {2021// @Param: ENABLE22// @DisplayName: Enable settings for RSC Setpoint23// @Description: Allows you to enable (1) or disable (0) the autonomous autorotation capability.24// @Values: 0:Disabled,1:Enabled25// @User: Advanced26AP_GROUPINFO_FLAGS("ENABLE", 1, AC_Autorotation, _param_enable, 0, AP_PARAM_FLAG_ENABLE),2728// @Param: HS_P29// @DisplayName: P gain for head speed controller30// @Description: Increase value to increase sensitivity of head speed controller during autonomous autorotation.31// @Range: 0.3 132// @Increment: 0.0133// @User: Advanced34AP_SUBGROUPINFO(_p_hs, "HS_", 2, AC_Autorotation, AC_P),3536// @Param: HS_SET_PT37// @DisplayName: Target Head Speed38// @Description: The target head speed in RPM during autorotation. Start by setting to desired hover speed and tune from there as necessary.39// @Units: RPM40// @Range: 1000 280041// @Increment: 142// @User: Advanced43AP_GROUPINFO("HS_SET_PT", 3, AC_Autorotation, _param_head_speed_set_point, 1500),4445// @Param: TARG_SP46// @DisplayName: Target Glide Ground Speed47// @Description: Target ground speed in cm/s for the autorotation controller to try and achieve/ maintain during the glide phase.48// @Units: cm/s49// @Range: 800 200050// @Increment: 5051// @User: Advanced52AP_GROUPINFO("TARG_SP", 4, AC_Autorotation, _param_target_speed, FWD_SPD_CONTROLLER_GND_SPEED_TARGET),5354// @Param: COL_FILT_E55// @DisplayName: Entry Phase Collective Filter56// @Description: Cut-off frequency for collective low pass filter. For the entry phase. Acts as a following trim. Must be higher than AROT_COL_FILT_G.57// @Units: Hz58// @Range: 0.2 0.559// @Increment: 0.0160// @User: Advanced61AP_GROUPINFO("COL_FILT_E", 5, AC_Autorotation, _param_col_entry_cutoff_freq, HS_CONTROLLER_ENTRY_COL_FILTER),6263// @Param: COL_FILT_G64// @DisplayName: Glide Phase Collective Filter65// @Description: Cut-off frequency for collective low pass filter. For the glide phase. Acts as a following trim. Must be lower than AROT_COL_FILT_E.66// @Units: Hz67// @Range: 0.03 0.1568// @Increment: 0.0169// @User: Advanced70AP_GROUPINFO("COL_FILT_G", 6, AC_Autorotation, _param_col_glide_cutoff_freq, HS_CONTROLLER_GLIDE_COL_FILTER),7172// @Param: AS_ACC_MAX73// @DisplayName: Forward Acceleration Limit74// @Description: Maximum forward acceleration to apply in speed controller.75// @Units: cm/s/s76// @Range: 30 6077// @Increment: 1078// @User: Advanced79AP_GROUPINFO("AS_ACC_MAX", 7, AC_Autorotation, _param_accel_max, FWD_SPD_CONTROLLER_MAX_ACCEL),8081// @Param: HS_SENSOR82// @DisplayName: Main Rotor RPM Sensor83// @Description: Allocate the RPM sensor instance to use for measuring head speed. RPM1 = 0. RPM2 = 1.84// @Units: s85// @Range: 0.5 386// @Increment: 0.187// @User: Advanced88AP_GROUPINFO("HS_SENSOR", 8, AC_Autorotation, _param_rpm_instance, 0),8990// @Param: FW_V_P91// @DisplayName: Velocity (horizontal) P gain92// @Description: Velocity (horizontal) P gain. Determines the proportion of the target acceleration based on the velocity error.93// @Range: 0.1 6.094// @Increment: 0.195// @User: Advanced96AP_SUBGROUPINFO(_p_fw_vel, "FW_V_", 9, AC_Autorotation, AC_P),9798// @Param: FW_V_FF99// @DisplayName: Velocity (horizontal) feed forward100// @Description: Velocity (horizontal) input filter. Corrects the target acceleration proportionally to the desired velocity.101// @Range: 0 1102// @Increment: 0.01103// @User: Advanced104AP_GROUPINFO("FW_V_FF", 10, AC_Autorotation, _param_fwd_k_ff, AP_FW_VEL_FF),105106AP_GROUPEND107};108109// Constructor110AC_Autorotation::AC_Autorotation() :111_p_hs(HS_CONTROLLER_HEADSPEED_P),112_p_fw_vel(AP_FW_VEL_P)113{114AP_Param::setup_object_defaults(this, var_info);115}116117// Initialisation of head speed controller118void AC_Autorotation::init_hs_controller()119{120// Set initial collective position to be the collective position on initialisation121_collective_out = 0.4f;122123// Reset feed forward filter124col_trim_lpf.reset(_collective_out);125126// Reset flags127_flags.bad_rpm = false;128129// Reset RPM health monitoring130_unhealthy_rpm_counter = 0;131_healthy_rpm_counter = 0;132133// Protect against divide by zero134_param_head_speed_set_point.set(MAX(_param_head_speed_set_point,500));135}136137138bool AC_Autorotation::update_hs_glide_controller(float dt)139{140// Reset rpm health flag141_flags.bad_rpm = false;142_flags.bad_rpm_warning = false;143144// Get current rpm and update healthy signal counters145_current_rpm = get_rpm(true);146147if (_unhealthy_rpm_counter <=30) {148// Normalised head speed149float head_speed_norm = _current_rpm / _param_head_speed_set_point;150151// Set collective trim low pass filter cut off frequency152col_trim_lpf.set_cutoff_frequency(_col_cutoff_freq);153154// Calculate the head speed error. Current rpm is normalised by the set point head speed.155// Target head speed is defined as a percentage of the set point.156_head_speed_error = head_speed_norm - _target_head_speed;157158_p_term_hs = _p_hs.get_p(_head_speed_error);159160// Adjusting collective trim using feed forward (not yet been updated, so this value is the previous time steps collective position)161_ff_term_hs = col_trim_lpf.apply(_collective_out, dt);162163// Calculate collective position to be set164_collective_out = _p_term_hs + _ff_term_hs;165166} else {167// RPM sensor is bad set collective to minimum168_collective_out = -1.0f;169170_flags.bad_rpm_warning = true;171}172173// Send collective to setting to motors output library174set_collective(HS_CONTROLLER_COLLECTIVE_CUTOFF_FREQ);175176return _flags.bad_rpm_warning;177}178179180// Function to set collective and collective filter in motor library181void AC_Autorotation::set_collective(float collective_filter_cutoff) const182{183AP_Motors *motors = AP::motors();184if (motors) {185motors->set_throttle_filter_cutoff(collective_filter_cutoff);186motors->set_throttle(_collective_out);187}188}189190191//function that gets rpm and does rpm signal checking to ensure signal is reliable192//before using it in the controller193float AC_Autorotation::get_rpm(bool update_counter)194{195float current_rpm = 0.0f;196197#if AP_RPM_ENABLED198// Get singleton for RPM library199const AP_RPM *rpm = AP_RPM::get_singleton();200201//Get current rpm, checking to ensure no nullptr202if (rpm != nullptr) {203//Check requested rpm instance to ensure either 0 or 1. Always defaults to 0.204if ((_param_rpm_instance > 1) || (_param_rpm_instance < 0)) {205_param_rpm_instance.set(0);206}207208//Get RPM value209uint8_t instance = _param_rpm_instance;210211//Check RPM sensor is returning a healthy status212if (!rpm->get_rpm(instance, current_rpm) || current_rpm <= -1) {213//unhealthy, rpm unreliable214_flags.bad_rpm = true;215}216217} else {218_flags.bad_rpm = true;219}220#else221_flags.bad_rpm = true;222#endif223224if (_flags.bad_rpm) {225//count unhealthy rpm updates and reset healthy rpm counter226_unhealthy_rpm_counter++;227_healthy_rpm_counter = 0;228229} else if (!_flags.bad_rpm && _unhealthy_rpm_counter > 0) {230//poor rpm reading may have cleared. Wait 10 update cycles to clear.231_healthy_rpm_counter++;232233if (_healthy_rpm_counter >= 10) {234//poor rpm health has cleared, reset counters235_unhealthy_rpm_counter = 0;236_healthy_rpm_counter = 0;237}238}239return current_rpm;240}241242243#if HAL_LOGGING_ENABLED244void AC_Autorotation::Log_Write_Autorotation(void) const245{246// @LoggerMessage: AROT247// @Vehicles: Copter248// @Description: Helicopter AutoRotation information249// @Field: TimeUS: Time since system startup250// @Field: P: P-term for headspeed controller response251// @Field: hserr: head speed error; difference between current and desired head speed252// @Field: ColOut: Collective Out253// @Field: FFCol: FF-term for headspeed controller response254// @Field: CRPM: current headspeed RPM255// @Field: SpdF: current forward speed256// @Field: CmdV: desired forward speed257// @Field: p: p-term of velocity response258// @Field: ff: ff-term of velocity response259// @Field: AccO: forward acceleration output260// @Field: AccT: forward acceleration target261// @Field: PitT: pitch target262263//Write to data flash log264AP::logger().WriteStreaming("AROT",265"TimeUS,P,hserr,ColOut,FFCol,CRPM,SpdF,CmdV,p,ff,AccO,AccT,PitT",266"Qffffffffffff",267AP_HAL::micros64(),268(double)_p_term_hs,269(double)_head_speed_error,270(double)_collective_out,271(double)_ff_term_hs,272(double)_current_rpm,273(double)_speed_forward,274(double)_cmd_vel,275(double)_vel_p,276(double)_vel_ff,277(double)_accel_out,278(double)_accel_target,279(double)_pitch_target);280}281#endif // HAL_LOGGING_ENABLED282283// Initialise forward speed controller284void AC_Autorotation::init_fwd_spd_controller(void)285{286// Reset I term and acceleration target287_accel_target = 0.0f;288289// Ensure parameter acceleration doesn't exceed hard-coded limit290_accel_max = MIN(_param_accel_max, 60.0f);291292// Reset cmd vel and last accel to sensible values293_cmd_vel = calc_speed_forward(); //(cm/s)294_accel_out_last = _cmd_vel*_param_fwd_k_ff;295}296297298// set_dt - sets time delta in seconds for all controllers299void AC_Autorotation::set_dt(float delta_sec)300{301_dt = delta_sec;302}303304305// update speed controller306void AC_Autorotation::update_forward_speed_controller(void)307{308// Specify forward velocity component and determine delta velocity with respect to time309_speed_forward = calc_speed_forward(); //(cm/s)310311_delta_speed_fwd = _speed_forward - _speed_forward_last; //(cm/s)312_speed_forward_last = _speed_forward; //(cm/s)313314// Limiting the target velocity based on the max acceleration limit315if (_cmd_vel < _vel_target) {316_cmd_vel += _accel_max * _dt;317if (_cmd_vel > _vel_target) {318_cmd_vel = _vel_target;319}320} else {321_cmd_vel -= _accel_max * _dt;322if (_cmd_vel < _vel_target) {323_cmd_vel = _vel_target;324}325}326327// get p328_vel_p = _p_fw_vel.get_p(_cmd_vel-_speed_forward);329330// get ff331_vel_ff = _cmd_vel*_param_fwd_k_ff;332333//calculate acceleration target based on PI controller334_accel_target = _vel_ff + _vel_p;335336// filter correction acceleration337_accel_target_filter.set_cutoff_frequency(10.0f);338_accel_target_filter.apply(_accel_target, _dt);339340//Limits the maximum change in pitch attitude based on acceleration341if (_accel_target > _accel_out_last + _accel_max) {342_accel_target = _accel_out_last + _accel_max;343} else if (_accel_target < _accel_out_last - _accel_max) {344_accel_target = _accel_out_last - _accel_max;345}346347//Limiting acceleration based on velocity gained during the previous time step348if (fabsf(_delta_speed_fwd) > _accel_max * _dt) {349_flag_limit_accel = true;350} else {351_flag_limit_accel = false;352}353354if ((_flag_limit_accel && fabsf(_accel_target) < fabsf(_accel_out_last)) || !_flag_limit_accel) {355_accel_out = _accel_target;356} else {357_accel_out = _accel_out_last;358}359_accel_out_last = _accel_out;360361// update angle targets that will be passed to stabilize controller362_pitch_target = accel_to_angle(-_accel_out*0.01) * 100;363364}365366367// Determine the forward ground speed component from measured components368float AC_Autorotation::calc_speed_forward(void)369{370auto &ahrs = AP::ahrs();371Vector2f groundspeed_vector = ahrs.groundspeed_vector();372float speed_forward = (groundspeed_vector.x*ahrs.cos_yaw() + groundspeed_vector.y*ahrs.sin_yaw())* 100; //(c/s)373return speed_forward;374}375376377378