2013-05-29 20:53:02 -03:00
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2013-08-29 02:34:34 -03:00
/*
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/>.
*/
2012-08-21 23:08:14 -03:00
// Code by Jon Challinger
2013-04-23 08:02:18 -03:00
// Modified by Paul Riseborough
2012-08-21 23:08:14 -03:00
//
2013-01-10 15:22:37 -04:00
# include <AP_Math.h>
2012-10-12 14:53:42 -03:00
# include <AP_HAL.h>
2012-08-21 23:08:14 -03:00
# include "AP_RollController.h"
2012-10-12 14:53:42 -03:00
extern const AP_HAL : : HAL & hal ;
2012-08-21 23:08:14 -03:00
const AP_Param : : GroupInfo AP_RollController : : var_info [ ] PROGMEM = {
2014-01-09 15:34:58 -04:00
// @Param: TCONST
2013-09-08 21:17:21 -03:00
// @DisplayName: Roll Time Constant
2013-05-31 04:21:20 -03:00
// @Description: This controls the time constant in seconds from demanded to achieved bank angle. A value of 0.5 is a good default and will work with nearly all models. Advanced users may want to reduce this time to obtain a faster response but there is no point setting a time less than the aircraft can achieve.
2013-05-13 08:10:55 -03:00
// @Range: 0.4 1.0
// @Units: seconds
2013-05-05 03:25:17 -03:00
// @Increment: 0.1
// @User: Advanced
2014-04-12 01:11:33 -03:00
AP_GROUPINFO ( " TCONST " , 0 , AP_RollController , gains . tau , 0.5f ) ,
2013-05-05 03:25:17 -03:00
2013-05-31 02:31:25 -03:00
// @Param: P
2013-05-13 08:10:55 -03:00
// @DisplayName: Proportional Gain
2013-05-30 08:46:45 -03:00
// @Description: This is the gain from bank angle to aileron. This gain works the same way as the P term in the old PID (RLL2SRV_P) and can be set to the same value.
2014-08-16 05:07:13 -03:00
// @Range: 0.1 4.0
2013-05-05 03:25:17 -03:00
// @Increment: 0.1
// @User: User
2014-04-12 01:11:33 -03:00
AP_GROUPINFO ( " P " , 1 , AP_RollController , gains . P , 0.4f ) ,
2013-05-05 03:25:17 -03:00
2013-05-31 02:31:25 -03:00
// @Param: D
2013-05-13 08:10:55 -03:00
// @DisplayName: Damping Gain
2013-09-08 21:17:21 -03:00
// @Description: This is the gain from roll rate to aileron. This adjusts the damping of the roll control loop. It has the same effect as RLL2SRV_D in the old PID controller but without the spikes in servo demands. This gain helps to reduce rolling in turbulence. It should be increased in 0.01 increments as too high a value can lead to a high frequency roll oscillation that could overstress the airframe.
2013-05-05 03:25:17 -03:00
// @Range: 0 0.1
// @Increment: 0.01
// @User: User
2014-04-12 01:11:33 -03:00
AP_GROUPINFO ( " D " , 2 , AP_RollController , gains . D , 0.02f ) ,
2013-05-05 03:25:17 -03:00
2013-05-31 02:31:25 -03:00
// @Param: I
2013-05-13 08:10:55 -03:00
// @DisplayName: Integrator Gain
2013-05-30 08:46:45 -03:00
// @Description: This is the gain from the integral of bank angle to aileron. It has the same effect as RLL2SRV_I in the old PID controller. Increasing this gain causes the controller to trim out steady offsets due to an out of trim aircraft.
2013-05-13 08:10:55 -03:00
// @Range: 0 1.0
// @Increment: 0.05
2013-05-05 03:25:17 -03:00
// @User: User
2014-11-13 07:13:25 -04:00
AP_GROUPINFO ( " I " , 3 , AP_RollController , gains . I , 0.04f ) ,
2013-05-05 03:25:17 -03:00
// @Param: RMAX
2013-05-13 08:10:55 -03:00
// @DisplayName: Maximum Roll Rate
2013-05-05 03:25:17 -03:00
// @Description: This sets the maximum roll rate that the controller will demand (degrees/sec). Setting it to zero disables the limit. If this value is set too low, then the roll can't keep up with the navigation demands and the plane will start weaving. If it is set too high (or disabled by setting to zero) then ailerons will get large inputs at the start of turns. A limit of 60 degrees/sec is a good default.
// @Range: 0 180
// @Units: degrees/second
// @Increment: 1
2013-05-13 08:10:55 -03:00
// @User: Advanced
2014-04-12 01:11:33 -03:00
AP_GROUPINFO ( " RMAX " , 4 , AP_RollController , gains . rmax , 0 ) ,
2013-05-05 03:25:17 -03:00
2013-06-11 05:35:31 -03:00
// @Param: IMAX
// @DisplayName: Integrator limit
2015-02-19 01:15:33 -04:00
// @Description: This limits the number of degrees of aileron in centi-degrees over which the integrator will operate. At the default setting of 3000 centi-degrees, the integrator will be limited to +- 30 degrees of servo travel. The maximum servo deflection is +- 45 centi-degrees, so the default value represents a 2/3rd of the total control throw which is adequate unless the aircraft is severely out of trim.
2013-06-11 05:35:31 -03:00
// @Range: 0 4500
// @Increment: 1
// @User: Advanced
2015-02-19 01:15:33 -04:00
AP_GROUPINFO ( " IMAX " , 5 , AP_RollController , gains . imax , 3000 ) ,
2013-06-11 05:35:31 -03:00
2012-08-21 23:08:14 -03:00
AP_GROUPEND
} ;
2013-07-10 10:25:06 -03:00
/*
internal rate controller , called by attitude and rate controller
public functions
*/
2013-08-02 08:54:48 -03:00
int32_t AP_RollController : : _get_rate_out ( float desired_rate , float scaler , bool disable_integrator )
2012-08-21 23:08:14 -03:00
{
2012-10-12 14:53:42 -03:00
uint32_t tnow = hal . scheduler - > millis ( ) ;
2012-08-21 23:08:14 -03:00
uint32_t dt = tnow - _last_t ;
if ( _last_t = = 0 | | dt > 1000 ) {
dt = 0 ;
}
_last_t = tnow ;
2013-07-20 01:37:05 -03:00
// Calculate equivalent gains so that values for K_P and K_I can be taken across from the old PID law
// No conversion is required for K_D
2014-04-12 01:11:33 -03:00
float ki_rate = gains . I * gains . tau ;
float kp_ff = max ( ( gains . P - gains . I * gains . tau ) * gains . tau - gains . D , 0 ) / _ahrs . get_EAS2TAS ( ) ;
2013-05-31 04:21:20 -03:00
float delta_time = ( float ) dt * 0.001f ;
2012-08-21 23:08:14 -03:00
2013-04-23 08:02:18 -03:00
// Limit the demanded roll rate
2014-04-12 01:11:33 -03:00
if ( gains . rmax & & desired_rate < - gains . rmax ) {
desired_rate = - gains . rmax ;
} else if ( gains . rmax & & desired_rate > gains . rmax ) {
desired_rate = gains . rmax ;
2013-05-31 04:21:20 -03:00
}
2012-08-21 23:08:14 -03:00
2013-04-23 16:22:17 -03:00
// Get body rate vector (radians/sec)
2013-08-14 01:56:18 -03:00
float omega_x = _ahrs . get_gyro ( ) . x ;
2013-04-23 16:22:17 -03:00
// Calculate the roll rate error (deg/sec) and apply gain scaler
2014-04-12 01:11:33 -03:00
float achieved_rate = ToDeg ( omega_x ) ;
float rate_error = ( desired_rate - achieved_rate ) * scaler ;
2012-08-21 23:08:14 -03:00
2013-04-23 08:02:18 -03:00
// Get an airspeed estimate - default to zero if none available
float aspeed ;
2013-08-14 01:56:18 -03:00
if ( ! _ahrs . airspeed_estimate ( & aspeed ) ) {
2013-05-31 04:21:20 -03:00
aspeed = 0.0f ;
}
2013-04-23 08:02:18 -03:00
2013-10-21 03:58:46 -03:00
// Multiply roll rate error by _ki_rate, apply scaler and integrate
// Scaler is applied before integrator so that integrator state relates directly to aileron deflection
// This means aileron trim offset doesn't change as the value of scaler changes with airspeed
2013-04-23 08:02:18 -03:00
// Don't integrate if in stabilise mode as the integrator will wind up against the pilots inputs
2013-08-02 08:54:48 -03:00
if ( ! disable_integrator & & ki_rate > 0 ) {
2013-04-23 08:02:18 -03:00
//only integrate if gain and time step are positive and airspeed above min value.
2013-07-17 22:57:11 -03:00
if ( dt > 0 & & aspeed > float ( aparm . airspeed_min ) ) {
2013-10-21 03:58:46 -03:00
float integrator_delta = rate_error * ki_rate * delta_time * scaler ;
2013-04-23 08:02:18 -03:00
// prevent the integrator from increasing if surface defln demand is above the upper limit
2013-05-31 04:21:20 -03:00
if ( _last_out < - 45 ) {
integrator_delta = max ( integrator_delta , 0 ) ;
} else if ( _last_out > 45 ) {
// prevent the integrator from decreasing if surface defln demand is below the lower limit
integrator_delta = min ( integrator_delta , 0 ) ;
}
2013-04-23 08:02:18 -03:00
_integrator + = integrator_delta ;
2012-08-21 23:08:14 -03:00
}
} else {
_integrator = 0 ;
}
2013-04-23 08:02:18 -03:00
2013-06-11 05:35:31 -03:00
// Scale the integration limit
2014-04-12 01:11:33 -03:00
float intLimScaled = gains . imax * 0.01f ;
2013-06-11 05:35:31 -03:00
// Constrain the integrator state
_integrator = constrain_float ( _integrator , - intLimScaled , intLimScaled ) ;
2013-04-23 08:02:18 -03:00
// Calculate the demanded control surface deflection
// Note the scaler is applied again. We want a 1/speed scaler applied to the feed-forward
// path, but want a 1/speed^2 scaler applied to the rate error path.
// This is because acceleration scales with speed^2, but rate scales with speed.
2014-04-12 01:11:33 -03:00
_last_out = ( ( rate_error * gains . D ) + ( desired_rate * kp_ff ) ) * scaler ;
if ( autotune . running & & aspeed > aparm . airspeed_min ) {
// let autotune have a go at the values
// Note that we don't pass the integrator component so we get
// a better idea of how much the base PD controller
// contributed
autotune . update ( desired_rate , achieved_rate , _last_out ) ;
}
_last_out + = _integrator ;
2013-04-23 08:02:18 -03:00
// Convert to centi-degrees and constrain
2013-05-05 01:34:33 -03:00
return constrain_float ( _last_out * 100 , - 4500 , 4500 ) ;
2012-08-21 23:08:14 -03:00
}
2013-07-10 10:25:06 -03:00
/*
Function returns an equivalent elevator deflection in centi - degrees in the range from - 4500 to 4500
A positive demand is up
Inputs are :
1 ) desired roll rate in degrees / sec
2 ) control gain scaler = scaling_speed / aspeed
*/
int32_t AP_RollController : : get_rate_out ( float desired_rate , float scaler )
{
2013-10-04 09:16:24 -03:00
return _get_rate_out ( desired_rate , scaler , false ) ;
2013-07-10 10:25:06 -03:00
}
/*
Function returns an equivalent elevator deflection in centi - degrees in the range from - 4500 to 4500
A positive demand is up
Inputs are :
1 ) demanded bank angle in centi - degrees
2 ) control gain scaler = scaling_speed / aspeed
3 ) boolean which is true when stabilise mode is active
4 ) minimum FBW airspeed ( metres / sec )
*/
2013-08-02 08:54:48 -03:00
int32_t AP_RollController : : get_servo_out ( int32_t angle_err , float scaler , bool disable_integrator )
2013-07-10 10:25:06 -03:00
{
2014-07-08 07:26:20 -03:00
if ( gains . tau < 0.1f ) {
2014-04-12 01:11:33 -03:00
gains . tau . set ( 0.1f ) ;
2013-07-10 10:25:06 -03:00
}
// Calculate the desired roll rate (deg/sec) from the angle error
2014-04-12 01:11:33 -03:00
float desired_rate = angle_err * 0.01f / gains . tau ;
2013-07-10 10:25:06 -03:00
2013-08-02 08:54:48 -03:00
return _get_rate_out ( desired_rate , scaler , disable_integrator ) ;
2013-07-10 10:25:06 -03:00
}
2012-08-21 23:08:14 -03:00
void AP_RollController : : reset_I ( )
{
_integrator = 0 ;
}