LCOV - code coverage report
Current view: top level - AP_TECS - AP_TECS.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 44 44 100.0 %
Date: 2026-09-09 11:02:08 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /// @file    AP_TECS.h
       2             : /// @brief   Combined Total Energy Speed & Height Control. This is a instance of an
       3             : 
       4             : /*
       5             :  *  Written by Paul Riseborough 2013 to provide:
       6             :  *  - Combined control of speed and height using throttle to control
       7             :  *    total energy and pitch angle to control exchange of energy between
       8             :  *    potential and kinetic.
       9             :  *    Selectable speed or height priority modes when calculating pitch angle
      10             :  *  - Fallback mode when no airspeed measurement is available that
      11             :  *    sets throttle based on height rate demand and switches pitch angle control to
      12             :  *    height priority
      13             :  *  - Underspeed protection that demands maximum throttle switches pitch angle control
      14             :  *    to speed priority mode
      15             :  *  - Relative ease of tuning through use of intuitive time constant, trim rate and damping parameters and the use
      16             :  *    of easy to measure aircraft performance data
      17             :  */
      18             : #pragma once
      19             : 
      20             : #include <AP_Math/AP_Math.h>
      21             : #include <AP_AHRS/AP_AHRS.h>
      22             : #include <AP_Param/AP_Param.h>
      23             : #include <AP_Vehicle/AP_FixedWing.h>
      24             : #include <Filter/AverageFilter.h>
      25             : 
      26             : class AP_Landing;
      27             : class AP_TECS {
      28             : public:
      29         692 :     AP_TECS(AP_AHRS &ahrs, const AP_FixedWing &parms, const AP_Landing &landing, const uint32_t log_bitmask)
      30         692 :         : _ahrs(ahrs)
      31         692 :         , aparm(parms)
      32         692 :         , _landing(landing)
      33         692 :         , _log_bitmask(log_bitmask)
      34             :     {
      35         692 :         AP_Param::setup_object_defaults(this, var_info);
      36         692 :     }
      37             : 
      38             :     /* Do not allow copies */
      39             :     CLASS_NO_COPY(AP_TECS);
      40             : 
      41             :     // Update of the estimated height and height rate internal state
      42             :     // Update of the inertial speed rate internal state
      43             :     // Should be called at 50Hz or greater
      44             :     void update_50hz(void);
      45             : 
      46             :     // Update the control loop calculations
      47             :     // Do not call slower than 10Hz or faster than 500Hz
      48             :     void update_pitch_throttle(int32_t hgt_dem_cm,
      49             :                                int32_t EAS_dem_cm,
      50             :                                enum AP_FixedWing::FlightStage flight_stage,
      51             :                                float distance_beyond_land_wp,
      52             :                                int32_t ptchMinCO_cd,
      53             :                                int16_t throttle_nudge,
      54             :                                float hgt_afe,
      55             :                                float load_factor,
      56             :                                float pitch_trim_deg);
      57             : 
      58             :     // demanded throttle in percentage
      59             :     // should return -100 to 100, usually positive unless reverse thrust is enabled via _THRminf < 0
      60     5077750 :     float get_throttle_demand(void) {
      61     5077750 :         return _throttle_dem * 100.0f;
      62             :     }
      63             : 
      64             :     // demanded pitch angle in centi-degrees
      65             :     // should return between -9000 to +9000
      66     3888434 :     int32_t get_pitch_demand(void) {
      67     3888434 :         return int32_t(_pitch_dem * 5729.5781f);
      68             :     }
      69             : 
      70             :     // Rate of change of velocity along X body axis in m/s^2
      71         383 :     float get_VXdot(void) {
      72         383 :         return _vel_dot;
      73             :     }
      74             : 
      75             :     // return current target airspeed
      76      667518 :     float get_target_airspeed(void) const {
      77      667518 :         return _TAS_dem_adj / _ahrs.get_EAS2TAS();
      78             :     }
      79             : 
      80             :     // return maximum climb rate
      81       60548 :     float get_max_climbrate(void) const {
      82       60548 :         return _maxClimbRate;
      83             :     }
      84             : 
      85             :     // return maximum sink rate (+ve number down)
      86       19436 :     float get_max_sinkrate(void) const {
      87       19436 :         return _maxSinkRate;
      88             :     }
      89             :     
      90             :     // added to let SoaringContoller reset pitch integrator to zero
      91           5 :     void reset_pitch_I(void) {
      92           5 :         _integSEBdot = 0.0f;
      93           5 :         _integKE = 0.0f;
      94           5 :     }
      95             : 
      96             :     // reset throttle integrator
      97       21278 :     void reset_throttle_I(void) {
      98       21278 :         _integTHR_state = 0.0;
      99       21278 :     }
     100             : 
     101             :     // return landing sink rate
     102        6097 :     float get_land_sinkrate(void) const {
     103        6097 :         return _land_sink;
     104             :     }
     105             : 
     106             :     // return landing airspeed
     107      205125 :     float get_land_airspeed(void) const {
     108      205125 :         return _landAirspeed;
     109             :     }
     110             : 
     111             :     // return height rate demand, in m/s
     112             :     float get_height_rate_demand(void) const {
     113             :         return _hgt_rate_dem;
     114             :     }
     115             : 
     116             :     // set path_proportion
     117      515533 :     void set_path_proportion(float path_proportion) {
     118      515533 :         _path_proportion = constrain_float(path_proportion, 0.0f, 1.0f);
     119      515533 :     }
     120             : 
     121             :     // set soaring flag
     122       17049 :     void set_gliding_requested_flag(bool gliding_requested) {
     123       17049 :         _flags.gliding_requested = gliding_requested;
     124       17049 :     }
     125             : 
     126             :     // set propulsion failed flag
     127             :     void set_propulsion_failed_flag(bool propulsion_failed) {
     128             :         _flags.propulsion_failed = propulsion_failed;
     129             :     }
     130             : 
     131             :     // set minimum throttle override, [-1, -1] range
     132             :     // if reset_output is true the output slew limiter will also be reset to respect the lower limit
     133             :     // its decay is controlled by TECS_THR_ERATE
     134             :     void set_throttle_min(const float thr_min, bool reset_output = false);
     135             : 
     136             :     // set maximum throttle override, [0, -1] range
     137             :     // it is applicable for one control cycle only
     138             :     void set_throttle_max(const float thr_max);
     139             : 
     140             :     // set minimum pitch override, in degrees.
     141             :     // it is applicable for one control cycle only
     142             :     void set_pitch_min(const float pitch_min);
     143             : 
     144             :     // set maximum pitch override, in degrees.
     145             :     // it is applicable for one control cycle only
     146             :     void set_pitch_max(const float pitch_max);
     147             : 
     148             :     // force use of synthetic airspeed for one loop
     149      394556 :     void use_synthetic_airspeed(void) {
     150      394556 :         _use_synthetic_airspeed_once = true;
     151      394556 :     }
     152             : 
     153             :     // reset on next loop
     154      813598 :     void reset(void) {
     155      813598 :         _need_reset = true;
     156      813598 :     }
     157             : 
     158             :     // Apply an altitude offset, to compensate for changes in home alt.
     159             :     void offset_altitude(const float alt_offset);
     160             : 
     161             :     // Return true if airspeed should be used
     162             :     bool use_airspeed() const;
     163             : 
     164             :     // this supports the TECS_* user settable parameters
     165             :     static const struct AP_Param::GroupInfo var_info[];
     166             : 
     167             : private:
     168             :     // Last time update_50Hz was called
     169             :     uint64_t _update_50hz_last_usec;
     170             : 
     171             :     // Last time update_pitch_throttle was called
     172             :     uint64_t _update_pitch_throttle_last_usec;
     173             : 
     174             :     // reference to the AHRS object
     175             :     AP_AHRS &_ahrs;
     176             : 
     177             :     const AP_FixedWing &aparm;
     178             : 
     179             :     // reference to const AP_Landing to access it's params
     180             :     const AP_Landing &_landing;
     181             : 
     182             :     // Logging  bitmask
     183             :     const uint32_t _log_bitmask;
     184             : 
     185             :     // TECS tuning parameters
     186             :     AP_Float _hgtCompFiltOmega;
     187             :     AP_Float _spdCompFiltOmega;
     188             :     AP_Float _maxClimbRate;
     189             :     AP_Float _minSinkRate;
     190             :     AP_Float _maxSinkRate;
     191             :     AP_Float _timeConst;
     192             :     AP_Float _landTimeConst;
     193             :     AP_Float _ptchDamp;
     194             :     AP_Float _land_pitch_damp;
     195             :     AP_Float _landDamp;
     196             :     AP_Float _thrDamp;
     197             :     AP_Float _land_throttle_damp;
     198             :     AP_Float _integGain;
     199             :     AP_Float _integGain_takeoff;
     200             :     AP_Float _integGain_land;
     201             :     AP_Float _vertAccLim;
     202             :     AP_Float _rollComp;
     203             :     AP_Float _spdWeight;
     204             :     AP_Float _spdWeightLand;
     205             :     AP_Float _landThrottle;
     206             :     AP_Float _landAirspeed;
     207             :     AP_Float _land_sink;
     208             :     AP_Float _land_sink_rate_change;
     209             :     AP_Int8  _pitch_max;
     210             :     AP_Int8  _pitch_min;
     211             :     AP_Int8  _land_pitch_max;
     212             :     AP_Float _maxSinkRate_approach;
     213             :     AP_Int32 _options;
     214             :     AP_Float _flare_holdoff_hgt;
     215             :     AP_Float _hgt_dem_tconst;
     216             : 
     217             :     enum class Option {
     218             :         GLIDER_ONLY     = (1<<0),
     219             :         DESCENT_SPEEDUP = (1<<1)
     220             :     };
     221             : 
     222      627784 :     bool option_is_set(const Option option) const {
     223      627784 :         return (_options.get() & int32_t(option)) != 0;
     224             :     }
     225             : 
     226             :     AP_Float _pitch_ff_v0;
     227             :     AP_Float _pitch_ff_k;
     228             :     AP_Float _accel_gf;
     229             :     AP_Int8 _thr_min_pct_ext_rate_lim;
     230             : 
     231             :     // current height estimate (above field elevation)
     232             :     float _height;
     233             : 
     234             :     // throttle demand in the range from -1.0 to 1.0, usually positive unless reverse thrust is enabled via _THRminf < 0
     235             :     float _throttle_dem;
     236             : 
     237             :     // pitch angle demand in radians
     238             :     float _pitch_dem;
     239             : 
     240             :     // estimated climb rate (m/s)
     241             :     float _climb_rate;
     242             : 
     243             :     // climb and sink rate limits
     244             :     float _climb_rate_limit;
     245             :     float _sink_rate_limit;
     246             : 
     247             :     /*
     248             :       a filter to estimate climb rate if we don't have it from the EKF
     249             :      */
     250             :     struct {
     251             :         // height filter second derivative
     252             :         float dd_height;
     253             : 
     254             :         // height integration
     255             :         float height;
     256             :     } _height_filter;
     257             : 
     258             :     // Integrator state 4 - airspeed filter first derivative
     259             :     float _integDTAS_state;
     260             : 
     261             :     // Integrator state 5 - true airspeed
     262             :     float _TAS_state;
     263             : 
     264             :     // Integrator state 6 - throttle integrator
     265             :     float _integTHR_state;
     266             : 
     267             :     // energy balance error integral
     268             :     float _integSEBdot;
     269             : 
     270             :     // pitch demand kinetic energy error integral
     271             :     float _integKE;
     272             : 
     273             :     // throttle demand rate limiter state
     274             :     float _last_throttle_dem;
     275             : 
     276             :     // pitch demand rate limiter state
     277             :     float _last_pitch_dem;
     278             : 
     279             :     // Rate of change of speed along X axis
     280             :     float _vel_dot;
     281             :     float _vel_dot_lpf;
     282             : 
     283             :     // True airspeed limits
     284             :     float _TASmax;
     285             :     float _TASmin;
     286             : 
     287             :     // Current true airspeed demand
     288             :     float _TAS_dem;
     289             : 
     290             :     // Equivalent airspeed demand
     291             :     float _EAS_dem;
     292             : 
     293             :     // height demands
     294             :     float _hgt_dem_in_raw;      // height demand input from autopilot before any modification (m)
     295             :     float _hgt_dem_in;          // height demand input from autopilot after unachievable climb or descent limiting (m)
     296             :     float _hgt_dem_in_prev;     // previous value of _hgt_dem_in (m)
     297             :     float _hgt_dem_lpf;         // height demand after application of low pass filtering (m)
     298             :     float _flare_hgt_dem_adj;   // height rate demand during flare adjusted for height tracking offset at flare entry (m)
     299             :     float _flare_hgt_dem_ideal; // height we want to fly at during flare (m)
     300             :     float _hgt_dem;             // height demand sent to control loops (m)
     301             :     float _hgt_dem_prev;        // _hgt_dem from previous frame (m)
     302             : 
     303             :     // height rate demands
     304             :     float _hgt_dem_rate_ltd;    // height demand after application of the rate limiter (m)
     305             :     float _hgt_rate_dem;        // height rate demand sent to control loops
     306             : 
     307             :     // offset applied to height demand post takeoff to compensate for height demand filter lag
     308             :     float _post_TO_hgt_offset;
     309             : 
     310             :     // last lag compensation offset applied to height demand
     311             :     float _lag_comp_hgt_offset;
     312             : 
     313             :     // Speed demand after application of rate limiting
     314             :     // This is the demand tracked by the TECS control loops
     315             :     float _TAS_dem_adj;
     316             : 
     317             :     // Speed rate demand after application of rate limiting
     318             :     // This is the demand tracked by the TECS control loops
     319             :     float _TAS_rate_dem;
     320             :     float _TAS_rate_dem_lpf;
     321             : 
     322             :     // Total energy rate filter state
     323             :     float _STEdotErrLast;
     324             : 
     325             :     struct flags {
     326             :         // Underspeed condition
     327             :         bool underspeed:1;
     328             : 
     329             :         // Bad descent condition caused by unachievable airspeed demand
     330             :         bool badDescent:1;
     331             : 
     332             :         // true when plane is in auto mode and executing a land mission item
     333             :         bool is_doing_auto_land:1;
     334             : 
     335             :         // true when we have reached target speed in takeoff
     336             :         bool reached_speed_takeoff:1;
     337             : 
     338             :         // true if the soaring feature has requested gliding flight
     339             :         bool gliding_requested:1;
     340             : 
     341             :         // true when we are in gliding flight, in one of three situations;
     342             :         //   - THR_MAX=0
     343             :         //   - gliding has been requested e.g. by soaring feature
     344             :         //   - engine failure detected (detection not implemented currently)
     345             :         bool is_gliding:1;
     346             : 
     347             :         // true if a propulsion failure is detected.
     348             :         bool propulsion_failed:1;
     349             : 
     350             :         // true when a reset of airspeed and height states to current is performed on this frame
     351             :         bool reset:1;
     352             : 
     353             :     };
     354             :     union {
     355             :         struct flags _flags;
     356             :         uint8_t _flags_byte;
     357             :     };
     358             : 
     359             :     // time when underspeed started
     360             :     uint32_t _underspeed_start_ms;
     361             : 
     362             :     // auto mode flightstage
     363             :     enum AP_FixedWing::FlightStage _flight_stage;
     364             : 
     365             :     // pitch demand before limiting
     366             :     float _pitch_dem_unc;
     367             : 
     368             :     // Specific total energy rate limits
     369             :     float _STEdot_max;     // Specific total energy rate gain at cruise airspeed & THR_MAX (m/s/s)
     370             :     float _STEdot_min;     // Specific total energy rate loss at cruise airspeed & THR_MIN (m/s/s)
     371             :     float _STEdot_neg_max; // Specific total energy rate loss at max airspeed & THR_MIN (m/s/s)
     372             : 
     373             :     // Maximum and minimum floating point throttle limits
     374             :     float _THRmaxf;
     375             :     float _THRminf;
     376             :     // Maximum and minimum throttle safety limits, set externally, typically by servos.cpp:apply_throttle_limits()
     377             :     float _THRmaxf_ext = 1.0f;
     378             :     float _THRminf_ext = -1.0f;
     379             :     // Maximum and minimum pitch limits, set externally, typically by the takeoff logic.
     380             :     float _PITCHmaxf_ext = 90.0f;
     381             :     float _PITCHminf_ext = -90.0f;
     382             : 
     383             :     // Maximum and minimum floating point pitch limits
     384             :     float _PITCHmaxf;
     385             :     float _PITCHminf;
     386             : 
     387             :     // 1 if throttle is clipping at max value, -1 if clipping at min value, 0 otherwise
     388             :     enum class clipStatus  : int8_t {
     389             :         MIN  = -1,
     390             :         NONE =  0,
     391             :         MAX  =  1,
     392             :     };
     393             :     clipStatus _thr_clip_status;
     394             : 
     395             :     // Specific energy quantities
     396             :     float _SPE_dem;
     397             :     float _SKE_dem;
     398             :     float _SPEdot_dem;
     399             :     float _SKEdot_dem;
     400             :     float _SPE_est;
     401             :     float _SKE_est;
     402             :     float _SPEdot;
     403             :     float _SKEdot;
     404             : 
     405             :     // variables used for precision landing pitch control
     406             :     float _hgt_at_start_of_flare;
     407             :     float _hgt_rate_dem_at_flare_entry;
     408             :     float _hgt_afe;
     409             :     float _pitch_min_at_flare_entry;
     410             : 
     411             :     // used to scale max climb and sink limits to match vehicle ability
     412             :     float _max_climb_scaler;
     413             :     float _max_sink_scaler;
     414             :     float _sink_fraction;
     415             : 
     416             :     // Specific energy error quantities
     417             :     float _STE_error;
     418             : 
     419             :     // 1 when specific energy balance rate demand is clipping in the up direction
     420             :     // -1 when specific energy balance rate demand is clipping in the down direction
     421             :     // 0 when not clipping
     422             :     clipStatus _SEBdot_dem_clip;
     423             : 
     424             :     // Time since last update of main TECS loop (seconds)
     425             :     float _DT;
     426             : 
     427             :     // true when class variables used for flare control have been initialised
     428             :     // on flare entry
     429             :     bool _flare_initialised;
     430             : 
     431             :     // percent traveled along the previous and next waypoints
     432             :     float _path_proportion;
     433             : 
     434             :     float _distance_beyond_land_wp;
     435             : 
     436             :     float _land_pitch_min = -90;
     437             : 
     438             :     // need to reset on next loop
     439             :     bool _need_reset;
     440             :     // Flag if someone else drives throttle externally.
     441             :     bool _flag_throttle_forced;
     442             : 
     443             :     // Checks if we reset at the beginning of takeoff.
     444             :     bool _flag_have_reset_after_takeoff;
     445             : 
     446             :     float _SKE_weighting;
     447             : 
     448             :     AP_Int8 _use_synthetic_airspeed;
     449             :     
     450             :     // use synthetic airspeed for next loop
     451             :     bool _use_synthetic_airspeed_once;
     452             : 
     453             :     // using airspeed in throttle calculation this frame
     454             :     bool _using_airspeed_for_throttle;
     455             : 
     456             :     // low pass filters used for crossover filter that combines demanded and measured pitch
     457             :     // when calculating a pitch to throttle mapping.
     458             :     LowPassFilterFloat _pitch_demand_lpf;
     459             :     LowPassFilterFloat _pitch_measured_lpf;
     460             : 
     461             :     // aerodynamic load factor
     462             :     float _load_factor;
     463             : 
     464             :     // Update the airspeed internal state using a second order complementary filter
     465             :     void _update_speed(float DT);
     466             : 
     467             :     // Update the demanded airspeed
     468             :     void _update_speed_demand(void);
     469             : 
     470             :     // Update the demanded height
     471             :     void _update_height_demand(void);
     472             : 
     473             :     // Detect an underspeed condition
     474             :     void _detect_underspeed(void);
     475             : 
     476             :     // Update Specific Energy Quantities
     477             :     void _update_energies(void);
     478             : 
     479             :     // Update Demanded Throttle
     480             :     void _update_throttle_with_airspeed(void);
     481             : 
     482             :     // Update Demanded Throttle Non-Airspeed
     483             :     void _update_throttle_without_airspeed(int16_t throttle_nudge, float pitch_trim_deg);
     484             : 
     485             :     // Constrain throttle demand and record clipping
     486             :     void constrain_throttle();
     487             : 
     488             :     // get integral gain which is flight_stage dependent
     489             :     float _get_i_gain(void);
     490             : 
     491             :     // Detect Bad Descent
     492             :     void _detect_bad_descent(void);
     493             : 
     494             :     // Update Demanded Pitch Angle
     495             :     void _update_pitch(void);
     496             : 
     497             :     // Initialise states and variables
     498             :     void _initialise_states(float hgt_afe);
     499             : 
     500             :     // Calculate specific total energy rate limits
     501             :     void _update_STE_rate_lim(void);
     502             : 
     503             :     // declares a 5point average filter using floats
     504             :     AverageFilterFloat_Size5 _vdot_filter;
     505             : 
     506             :     // current time constant
     507             :     float timeConstant(void) const;
     508             : 
     509             :     // Update the allowable throttle range.
     510             :     void _update_throttle_limits();
     511             : 
     512             :     // Update the allowable pitch range.
     513             :     void _update_pitch_limits(const int32_t ptchMinCO_cd);
     514             : };

Generated by: LCOV version 1.14