Files
ardupilot/libraries/APM_Control/AP_PitchController.cpp
T
Peter Barker da9ecf550a APM_Control: remove convert_pid()
AP_RollController::convert_pid() and AP_PitchController::convert_pid()
converted the old RLL2SRV_/PTCH2SRV_ gains into the AC_PID form.  Added
Apr-2021 and described in the code as "a temporary conversion function
during development"; present in the 4.3.0 release, so anybody running
4.3.0 or later has already had it applied.
2026-09-01 20:49:36 +10:00

306 lines
11 KiB
C++

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Initial Code by Jon Challinger
// Modified by Paul Riseborough
#include <AP_HAL/AP_HAL.h>
#include "AP_PitchController.h"
#include <AP_AHRS/AP_AHRS.h>
#include <AP_Scheduler/AP_Scheduler.h>
extern const AP_HAL::HAL& hal;
const AP_Param::GroupInfo AP_PitchController::var_info[] = {
// @Param: 2SRV_TCONST
// @DisplayName: Pitch Time Constant
// @Description: Time constant in seconds from demanded to achieved pitch angle. Most models respond well to 0.5. May be reduced for faster responses, but setting lower than a model can achieve will not help.
// @Range: 0.4 1.0
// @Units: s
// @Increment: 0.1
// @User: Advanced
AP_GROUPINFO("2SRV_TCONST", 0, AP_PitchController, gains.tau, 0.5f),
// index 1 to 3 reserved for old PID values
// @Param: 2SRV_RMAX_UP
// @DisplayName: Pitch up max rate
// @Description: This sets the maximum nose up pitch rate that the attitude controller will demand (degrees/sec) in angle stabilized modes. Setting it to zero disables the limit.
// @Range: 0 100
// @Units: deg/s
// @Increment: 1
// @User: Advanced
AP_GROUPINFO("2SRV_RMAX_UP", 4, AP_PitchController, gains.rmax_pos, 0.0f),
// @Param: 2SRV_RMAX_DN
// @DisplayName: Pitch down max rate
// @Description: This sets the maximum nose down pitch rate that the attitude controller will demand (degrees/sec) in angle stabilized modes. Setting it to zero disables the limit.
// @Range: 0 100
// @Units: deg/s
// @Increment: 1
// @User: Advanced
AP_GROUPINFO("2SRV_RMAX_DN", 5, AP_PitchController, gains.rmax_neg, 0.0f),
// @Param: 2SRV_RLL
// @DisplayName: Roll compensation
// @Description: Gain added to pitch to keep aircraft from descending or ascending in turns. Increase in increments of 0.05 to reduce altitude loss. Decrease for altitude gain.
// @Range: 0.7 1.5
// @Increment: 0.05
// @User: Standard
AP_GROUPINFO("2SRV_RLL", 6, AP_PitchController, _roll_ff, 1.0f),
// index 7, 8 reserved for old IMAX, FF
// @Param: _RATE_P
// @DisplayName: Pitch axis rate controller P gain
// @Description: Pitch axis rate controller P gain. Corrects in proportion to the difference between the desired pitch rate vs actual pitch rate
// @Range: 0.08 0.35
// @Increment: 0.005
// @User: Standard
// @Param: _RATE_I
// @DisplayName: Pitch axis rate controller I gain
// @Description: Pitch axis rate controller I gain. Corrects long-term difference in desired pitch rate vs actual pitch rate
// @Range: 0.01 0.6
// @Increment: 0.01
// @User: Standard
// @Param: _RATE_IMAX
// @DisplayName: Pitch axis rate controller I gain maximum
// @Description: Pitch axis rate controller I gain maximum. Constrains the maximum that the I term will output
// @Range: 0 1
// @Increment: 0.01
// @User: Standard
// @Param: _RATE_D
// @DisplayName: Pitch axis rate controller D gain
// @Description: Pitch axis rate controller D gain. Compensates for short-term change in desired pitch rate vs actual pitch rate
// @Range: 0.001 0.03
// @Increment: 0.001
// @User: Standard
// @Param: _RATE_FF
// @DisplayName: Pitch axis rate controller feed forward
// @Description: Pitch axis rate controller feed forward
// @Range: 0 3.0
// @Increment: 0.001
// @User: Standard
// @Param: _RATE_FLTT
// @DisplayName: Pitch axis rate controller target frequency in Hz
// @Description: Pitch axis rate controller target frequency in Hz
// @Range: 2 50
// @Increment: 1
// @Units: Hz
// @User: Standard
// @Param: _RATE_FLTE
// @DisplayName: Pitch axis rate controller error frequency in Hz
// @Description: Pitch axis rate controller error frequency in Hz
// @Range: 2 50
// @Increment: 1
// @Units: Hz
// @User: Standard
// @Param: _RATE_FLTD
// @DisplayName: Pitch axis rate controller derivative frequency in Hz
// @Description: Pitch axis rate controller derivative frequency in Hz
// @Range: 0 50
// @Increment: 1
// @Units: Hz
// @User: Standard
// @Param: _RATE_SMAX
// @DisplayName: Pitch slew rate limit
// @Description: Sets an upper limit on the slew rate produced by the combined P and D gains. If the amplitude of the control action produced by the rate feedback exceeds this value, then the D+P gain is reduced to respect the limit. This limits the amplitude of high frequency oscillations caused by an excessive gain. The limit should be set to no more than 25% of the actuators maximum slew rate to allow for load effects. Note: The gain will not be reduced to less than 10% of the nominal value. A value of zero will disable this feature.
// @Range: 0 200
// @Increment: 0.5
// @User: Advanced
// @Param: _RATE_PDMX
// @DisplayName: Pitch axis rate controller PD sum maximum
// @Description: Pitch axis rate controller PD sum maximum. The maximum/minimum value that the sum of the P and D term can output
// @Range: 0 1
// @Increment: 0.01
// @Param: _RATE_D_FF
// @DisplayName: Pitch Derivative FeedForward Gain
// @Description: FF D Gain which produces an output that is proportional to the rate of change of the target
// @Range: 0 0.03
// @Increment: 0.001
// @User: Advanced
// @Param: _RATE_NTF
// @DisplayName: Pitch Target notch filter index
// @Description: Pitch Target notch filter index, zero disables
// @Range: 0 8
// @User: Advanced
// @Param: _RATE_NEF
// @DisplayName: Pitch Error notch filter index
// @Description: Pitch Error notch filter index, zero disables
// @Range: 0 8
// @User: Advanced
AP_SUBGROUPINFO(rate_pid, "_RATE_", 11, AP_PitchController, AC_PID),
// @Param: 2SRV_ACCEL
// @DisplayName: Pitch max acceleration
// @Description: Pitch acceleration limit. Setting to zero disables input shaping.
// @Range: 0 2500
// @Units: deg/s/s
// @Increment: 1
// @User: Advanced
AP_GROUPINFO("2SRV_ACCEL", 12, AP_PitchController, accel_limit, 500),
// @Param: _ANGLE_P
// @DisplayName: Pitch angle P gain
// @Description: Pitch angle P gain. If zero a gain of (1 / PTCH2SRV_TCONST) will be used.
// @Range: 0.000 12.000
// @Increment: 0.01
// @User: Advanced
AP_GROUPINFO("_ANGLE_P", 13, AP_PitchController, angle_p, 0.0),
AP_GROUPEND
};
AP_PitchController::AP_PitchController(const AP_FixedWing &parms)
: AP_FW_Controller(parms,
AC_PID::Defaults{
.p = 0.04,
.i = 0.15,
.d = 0.0,
.ff = 0.345,
.imax = 0.666,
.filt_T_hz = 3.0,
.filt_E_hz = 0.0,
.filt_D_hz = 12.0,
.srmax = 150.0,
.srtau = 1.0
},
AP_AutoTune::ATType::AUTOTUNE_PITCH)
{
AP_Param::setup_object_defaults(this, var_info);
}
// Return the measured pitch angle in degrees
float AP_PitchController::get_measured_angle_deg() const
{
return AP::ahrs().get_pitch_deg();
}
// Return the measured pitch rate in radians per second
float AP_PitchController::get_measured_rate_rads() const
{
return AP::ahrs().get_gyro().y;
}
// Return true if the airspeed should be considered as under speed
bool AP_PitchController::is_underspeed() const
{
return get_airspeed() <= 0.5*float(aparm.airspeed_min);
}
// Return true if the vehicle is inverted
bool AP_PitchController::is_inverted() const
{
return fabsf(AP::ahrs().get_roll_deg()) >= 90.0;
}
// Return positive rate limit in deg per second, zero if disabled
float AP_PitchController::get_positive_rate_limit_degs() const
{
return MAX(gains.rmax_pos.get(), 0.0);
}
// Return negative rate limit in deg per second (as a positive number) zero if disabled
float AP_PitchController::get_negative_rate_limit_degs() const
{
return MAX(gains.rmax_neg.get(), 0.0);
}
// Return true if rate limits should be applied
bool AP_PitchController::should_apply_rate_limits() const
{
return !is_inverted();
}
// get the rate offset in degrees/second needed for pitch in body frame to maintain height in a coordinated turn.
float AP_PitchController::get_rate_target_offset_degs() const
{
const AP_AHRS &_ahrs = AP::ahrs();
float bank_angle = _ahrs.get_roll_rad();
// limit bank angle between +- 80 deg if right way up and between 100 and 260 if inverted
if (!is_inverted()) {
bank_angle = constrain_float(bank_angle,-radians(80),radians(80));
} else {
// Note that the wrap means we have a different range here, we could wrap it back but its only used in trigonometric functions so we don't need to.
bank_angle = constrain_float(wrap_2PI(bank_angle), radians(100), radians(260));
}
if (abs(_ahrs.pitch_sensor) > 7000) {
// don't do turn coordination handling when at very high pitch angles
return 0.0;
}
// Assume true airspeed is at least min airspeed, protect against zeros.
const float true_airspeed = MAX((get_airspeed() * _ahrs.get_EAS2TAS()), MAX(aparm.airspeed_min, 1));
// Lateral acceleration
const float lateral_accel = tanf(bank_angle) * GRAVITY_MSS * cosf(_ahrs.get_pitch_rad());
// Resultant turn rate in the pitch axis
const float turn_rate = (lateral_accel / true_airspeed) * sinf(bank_angle);
// Apply gain
float rate_offset = fabsf(degrees(turn_rate)) * _roll_ff;
return rate_offset;
}
// Function returns an equivalent elevator deflection in centi-degrees in the range from -4500 to 4500
// A positive demand is up
float AP_PitchController::run_axis_rate_control(float desired_rate_degs, float scaler, bool disable_integrator, bool ground_mode)
{
// Invert desired if vehicle is inverted.
if (is_inverted()) {
desired_rate_degs *= -1.0;
}
/*
when we are past the users defined roll limit for the aircraft
our priority should be to bring the aircraft back within the
roll limit. Using elevator for pitch control at large roll
angles is ineffective, and can be counter productive as it
induces earth-frame yaw which can reduce the ability to roll. We
linearly reduce pitch demanded rate when beyond the configured
roll limit, reducing to zero at 90 degrees
*/
const AP_AHRS &_ahrs = AP::ahrs();
float roll_wrapped = labs(_ahrs.roll_sensor);
if (roll_wrapped > 9000) {
roll_wrapped = 18000 - roll_wrapped;
}
const float roll_limit_margin = MIN(aparm.roll_limit*100 + 500.0, 8500.0);
if (roll_wrapped > roll_limit_margin && labs(_ahrs.pitch_sensor) < 7000) {
float roll_prop = (roll_wrapped - roll_limit_margin) / (float)(9000 - roll_limit_margin);
desired_rate_degs *= (1 - roll_prop);
}
return run_rate_control(desired_rate_degs, scaler, disable_integrator, ground_mode);
}