2024-07-27 02:52:11 -03:00
/*
C + + implementation of quicktune based on original lua script
*/
// quicktune is not performance sensitive, save flash
# pragma GCC optimize("Os")
# include "AP_Quicktune.h"
# if AP_QUICKTUNE_ENABLED
# define UPDATE_RATE_HZ 40
# define STAGE_DELAY 4000
# define PILOT_INPUT_DELAY 4000
# define YAW_FLTE_MAX 2.0
# define FLTD_MUL 0.5
# define FLTT_MUL 0.5
# define DEFAULT_SMAX 50.0
# define OPTIONS_TWO_POSITION (1<<0)
# include <AP_Common/AP_Common.h>
# include <AP_Vehicle/AP_Vehicle.h>
# include <AP_RCMapper/AP_RCMapper.h>
# include <AP_Logger/AP_Logger.h>
# include <AP_Arming/AP_Arming.h>
# include <GCS_MAVLink/GCS.h>
const AP_Param : : GroupInfo AP_Quicktune : : var_info [ ] = {
// @Param: ENABLE
// @DisplayName: Quicktune enable
// @Description: Enable quicktune system
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO_FLAGS ( " ENABLE " , 1 , AP_Quicktune , enable , 0 , AP_PARAM_FLAG_ENABLE ) ,
// @Param: AXES
// @DisplayName: Quicktune axes
// @Description: Axes to tune
// @Bitmask: 0:Roll,1:Pitch,2:Yaw
// @User: Standard
AP_GROUPINFO ( " AXES " , 2 , AP_Quicktune , axes_enabled , 7 ) ,
// @Param: DOUBLE_TIME
// @DisplayName: Quicktune doubling time
// @Description: Time to double a tuning parameter. Raise this for a slower tune.
// @Range: 5 20
// @Units: s
// @User: Standard
AP_GROUPINFO ( " DOUBLE_TIME " , 3 , AP_Quicktune , double_time , 10 ) ,
// @Param: GAIN_MARGIN
// @DisplayName: Quicktune gain margin
// @Description: Reduction in gain after oscillation detected. Raise this number to get a more conservative tune
// @Range: 20 80
// @Units: %
// @User: Standard
AP_GROUPINFO ( " GAIN_MARGIN " , 4 , AP_Quicktune , gain_margin , 60 ) ,
// @Param: OSC_SMAX
// @DisplayName: Quicktune oscillation rate threshold
// @Description: Threshold for oscillation detection. A lower value will lead to a more conservative tune.
// @Range: 1 10
// @User: Standard
2024-11-24 20:24:04 -04:00
AP_GROUPINFO ( " OSC_SMAX " , 5 , AP_Quicktune , osc_smax , 4 ) ,
2024-07-27 02:52:11 -03:00
// @Param: YAW_P_MAX
// @DisplayName: Quicktune Yaw P max
// @Description: Maximum value for yaw P gain
// @Range: 0.1 3
// @User: Standard
AP_GROUPINFO ( " YAW_P_MAX " , 6 , AP_Quicktune , yaw_p_max , 0.5 ) ,
// @Param: YAW_D_MAX
// @DisplayName: Quicktune Yaw D max
// @Description: Maximum value for yaw D gain
// @Range: 0.001 1
// @User: Standard
AP_GROUPINFO ( " YAW_D_MAX " , 7 , AP_Quicktune , yaw_d_max , 0.01 ) ,
// @Param: RP_PI_RATIO
// @DisplayName: Quicktune roll/pitch PI ratio
// @Description: Ratio between P and I gains for roll and pitch. Raise this to get a lower I gain
// @Range: 1.0 2.0
// @User: Standard
AP_GROUPINFO ( " RP_PI_RATIO " , 8 , AP_Quicktune , rp_pi_ratio , 1.0 ) ,
// @Param: Y_PI_RATIO
// @DisplayName: Quicktune Yaw PI ratio
// @Description: Ratio between P and I gains for yaw. Raise this to get a lower I gain
// @Range: 1.0 20
// @User: Standard
AP_GROUPINFO ( " Y_PI_RATIO " , 9 , AP_Quicktune , y_pi_ratio , 10 ) ,
// @Param: AUTO_FILTER
// @DisplayName: Quicktune auto filter enable
// @Description: When enabled the PID filter settings are automatically set based on INS_GYRO_FILTER
// @Values: 0:Disabled,1:Enabled
// @User: Standard
AP_GROUPINFO ( " AUTO_FILTER " , 10 , AP_Quicktune , auto_filter , 1 ) ,
// @Param: AUTO_SAVE
// @DisplayName: Quicktune auto save
// @Description: Number of seconds after completion of tune to auto-save. This is useful when using a 2 position switch for quicktune. Zero (the default value) disables automatic saving, and you will need to have a 3 position switch to save or use GCS auxilliary functions.
// @Units: s
// @User: Standard
AP_GROUPINFO ( " AUTO_SAVE " , 11 , AP_Quicktune , auto_save , 0 ) ,
// @Param: REDUCE_MAX
// @DisplayName: Quicktune maximum gain reduction
// @Description: This controls how much quicktune is allowed to lower gains from the original gains. If the vehicle already has a reasonable tune and is not oscillating then you can set this to zero to prevent gain reductions. The default of 20% is reasonable for most vehicles. Using a maximum gain reduction lowers the chance of an angle P oscillation happening if quicktune gets a false positive oscillation at a low gain, which can result in very low rate gains and a dangerous angle P oscillation.
// @Units: %
// @Range: 0 100
// @User: Standard
AP_GROUPINFO ( " REDUCE_MAX " , 12 , AP_Quicktune , reduce_max , 20 ) ,
// @Param: OPTIONS
// @DisplayName: Quicktune options
// @Description: Additional options. When the Two Position Switch option is enabled then a high switch position will start the tune, low will disable the tune. you should also set a QUIK_AUTO_SAVE time so that you will be able to save the tune.
// @Bitmask: 0:UseTwoPositionSwitch
// @User: Standard
AP_GROUPINFO ( " OPTIONS " , 13 , AP_Quicktune , options , 0 ) ,
// @Param: ANGLE_MAX
// @DisplayName: maximum angle error for tune abort
2024-11-24 20:24:04 -04:00
// @Description: If while tuning the angle error goes over this limit then the tune will aborts to prevent a bad oscillation in the case of the tuning algorithm failing. If you get an error "Quicktune: attitude error ABORTING" and you think it is a false positive then you can either raise this parameter or you can try increasing the QWIK_DOUBLE_TIME to do the tune more slowly.
2024-07-27 02:52:11 -03:00
// @Units: deg
// @User: Standard
2024-11-24 20:24:04 -04:00
AP_GROUPINFO ( " ANGLE_MAX " , 14 , AP_Quicktune , angle_max , 10 ) ,
2024-07-27 02:52:11 -03:00
AP_GROUPEND
} ;
// Call at loop rate
void AP_Quicktune : : update ( bool mode_supports_quicktune )
{
if ( enable < 1 ) {
if ( need_restore ) {
GCS_SEND_TEXT ( MAV_SEVERITY_WARNING , " QuickTune disabled " ) ;
abort_tune ( ) ;
}
return ;
}
const uint32_t now = AP_HAL : : millis ( ) ;
if ( ! mode_supports_quicktune ) {
/*
user has switched to a non - quicktune mode . If we have
pending parameter changes then revert
*/
if ( need_restore ) {
GCS_SEND_TEXT ( MAV_SEVERITY_CRITICAL , " QuickTune aborted " ) ;
}
abort_tune ( ) ;
return ;
}
if ( need_restore ) {
const float att_error = AC_AttitudeControl : : get_singleton ( ) - > get_att_error_angle_deg ( ) ;
if ( angle_max > 0 & & att_error > angle_max ) {
GCS_SEND_TEXT ( MAV_SEVERITY_CRITICAL , " Quicktune: attitude error %.1fdeg - ABORTING " , att_error ) ;
abort_tune ( ) ;
return ;
}
}
if ( have_pilot_input ( ) ) {
last_pilot_input_ms = now ;
}
SwitchPos sw_pos_tune = SwitchPos : : MID ;
SwitchPos sw_pos_save = SwitchPos : : HIGH ;
if ( ( options & OPTIONS_TWO_POSITION ) ! = 0 ) {
sw_pos_tune = SwitchPos : : HIGH ;
sw_pos_save = SwitchPos : : NONE ;
}
const auto & vehicle = * AP : : vehicle ( ) ;
if ( sw_pos = = sw_pos_tune & &
( ! hal . util - > get_soft_armed ( ) | | ! vehicle . get_likely_flying ( ) ) ) {
if ( now - last_warning_ms > 5000 ) {
GCS_SEND_TEXT ( MAV_SEVERITY_WARNING , " Quicktune: Must be flying to tune " ) ;
last_warning_ms = now ;
}
return ;
}
if ( sw_pos = = SwitchPos : : LOW | | ! hal . util - > get_soft_armed ( ) | | ! vehicle . get_likely_flying ( ) ) {
// Abort, revert parameters
if ( need_restore ) {
need_restore = false ;
restore_all_params ( ) ;
GCS_SEND_TEXT ( MAV_SEVERITY_WARNING , " Quicktune: Reverted " ) ;
tune_done_time_ms = 0 ;
}
reset_axes_done ( ) ;
return ;
}
if ( sw_pos = = sw_pos_save ) {
// Save all params
if ( need_restore ) {
need_restore = false ;
save_all_params ( ) ;
}
}
if ( sw_pos ! = sw_pos_tune ) {
return ;
}
if ( now - last_stage_change_ms < STAGE_DELAY ) {
// Update slew gain
if ( slew_parm ! = Param : : END ) {
const float P = get_param_value ( slew_parm ) ;
const AxisName axis = get_axis ( slew_parm ) ;
adjust_gain ( slew_parm , P + slew_delta ) ;
slew_steps = slew_steps - 1 ;
Write_QWIK ( get_slew_rate ( axis ) , P , slew_parm ) ;
if ( slew_steps = = 0 ) {
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " %s %.4f " , get_param_name ( slew_parm ) , P ) ;
slew_parm = Param : : END ;
if ( get_current_axis ( ) = = AxisName : : DONE ) {
GCS_SEND_TEXT ( MAV_SEVERITY_NOTICE , " Quicktune: DONE " ) ;
tune_done_time_ms = now ;
}
}
}
return ;
}
const AxisName axis = get_current_axis ( ) ;
if ( axis = = AxisName : : DONE ) {
// Nothing left to do, check autosave time
if ( tune_done_time_ms ! = 0 & & auto_save > 0 ) {
if ( now - tune_done_time_ms > ( auto_save * 1000 ) ) {
need_restore = false ;
save_all_params ( ) ;
tune_done_time_ms = 0 ;
}
}
return ;
}
if ( ! need_restore ) {
need_restore = true ;
// We are just starting tuning, get current values
GCS_SEND_TEXT ( MAV_SEVERITY_NOTICE , " Quicktune: Starting tune " ) ;
// Get all params
for ( uint8_t p = 0 ; p < uint8_t ( Param : : END ) ; p + + ) {
param_saved [ p ] = get_param_value ( Param ( p ) ) ;
}
// Set up SMAX
const Param is [ 3 ] { Param : : RLL_SMAX , Param : : PIT_SMAX , Param : : YAW_SMAX } ;
for ( const auto p : is ) {
const float smax = get_param_value ( p ) ;
if ( smax < = 0 ) {
adjust_gain ( p , DEFAULT_SMAX ) ;
}
}
}
if ( now - last_pilot_input_ms < PILOT_INPUT_DELAY ) {
return ;
}
if ( ! BIT_IS_SET ( filters_done , uint8_t ( axis ) ) ) {
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " Starting %s tune " , get_axis_name ( axis ) ) ;
setup_filters ( axis ) ;
}
const Param pname = get_pname ( axis , current_stage ) ;
const float pval = get_param_value ( pname ) ;
const float limit = gain_limit ( pname ) ;
const bool limited = ( limit > 0.0 & & pval > = limit ) ;
const float srate = get_slew_rate ( axis ) ;
const bool oscillating = srate > osc_smax ;
// Check if reached limit
if ( limited | | oscillating ) {
float reduction = ( 100.0 - gain_margin ) * 0.01 ;
if ( ! oscillating ) {
reduction = 1.0 ;
}
float new_gain = pval * reduction ;
if ( limit > 0.0 & & new_gain > limit ) {
new_gain = limit ;
}
float old_gain = param_saved [ uint8_t ( pname ) ] ;
if ( new_gain < old_gain & & ( pname = = Param : : PIT_D | | pname = = Param : : RLL_D ) ) {
// We are lowering a D gain from the original gain. Also
// lower the P gain by the same amount so that we don't
// trigger P oscillation. We don't drop P by more than a
// factor of 2
const float ratio = fmaxf ( new_gain / old_gain , 0.5 ) ;
const uint8_t P_TO_D_OFS = uint8_t ( Param : : RLL_D ) - uint8_t ( Param : : RLL_P ) ;
const Param P_name = Param ( uint8_t ( pname ) - P_TO_D_OFS ) ; //from D to P
const float old_pval = get_param_value ( P_name ) ; ;
const float new_pval = old_pval * ratio ;
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " Adjusting %s %.3f -> %.3f " , get_param_name ( P_name ) , old_pval , new_pval ) ;
adjust_gain_limited ( P_name , new_pval ) ;
}
// Set up slew gain
slew_parm = pname ;
const float slew_target = limit_gain ( pname , new_gain ) ;
slew_steps = UPDATE_RATE_HZ / 2 ;
slew_delta = ( slew_target - get_param_value ( pname ) ) / slew_steps ;
Write_QWIK ( srate , pval , pname ) ;
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " Quicktune: %s done " , get_param_name ( pname ) ) ;
advance_stage ( axis ) ;
last_stage_change_ms = now ;
} else {
float new_gain = pval * get_gain_mul ( ) ;
// cope with the gain starting at zero (some users with have a zero D gain)
new_gain = MAX ( new_gain , 0.0001 ) ;
adjust_gain_limited ( pname , new_gain ) ;
Write_QWIK ( srate , pval , pname ) ;
if ( now - last_gain_report_ms > 3000U ) {
last_gain_report_ms = now ;
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " %s %.4f sr:%.2f " , get_param_name ( pname ) , new_gain , srate ) ;
}
}
}
/*
abort the tune if it has started
*/
void AP_Quicktune : : abort_tune ( )
{
if ( need_restore ) {
need_restore = false ;
restore_all_params ( ) ;
}
tune_done_time_ms = 0 ;
reset_axes_done ( ) ;
sw_pos = SwitchPos : : LOW ;
}
void AP_Quicktune : : update_switch_pos ( const RC_Channel : : AuxSwitchPos ch_flag )
{
sw_pos = SwitchPos ( ch_flag ) ;
}
void AP_Quicktune : : reset_axes_done ( )
{
axes_done = 0 ;
filters_done = 0 ;
current_stage = Stage : : D ;
}
void AP_Quicktune : : setup_filters ( AP_Quicktune : : AxisName axis )
{
if ( auto_filter < = 0 ) {
BIT_SET ( filters_done , uint8_t ( axis ) ) ;
return ;
}
AP_InertialSensor * imu = AP_InertialSensor : : get_singleton ( ) ;
if ( imu = = nullptr ) {
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return ;
}
const float gyro_filter = imu - > get_gyro_filter_hz ( ) ;
adjust_gain ( get_pname ( axis , Stage : : FLTT ) , gyro_filter * FLTT_MUL ) ;
adjust_gain ( get_pname ( axis , Stage : : FLTD ) , gyro_filter * FLTD_MUL ) ;
if ( axis = = AxisName : : YAW ) {
const float FLTE = get_param_value ( Param : : YAW_FLTE ) ;
if ( FLTE < 0.0 | | FLTE > YAW_FLTE_MAX ) {
adjust_gain ( Param : : YAW_FLTE , YAW_FLTE_MAX ) ;
}
}
BIT_SET ( filters_done , uint8_t ( axis ) ) ;
}
// Check for pilot input to pause tune
bool AP_Quicktune : : have_pilot_input ( ) const
{
auto & RC = rc ( ) ;
const float roll = RC . get_roll_channel ( ) . norm_input_dz ( ) ;
const float pitch = RC . get_pitch_channel ( ) . norm_input_dz ( ) ;
const float yaw = RC . get_yaw_channel ( ) . norm_input_dz ( ) ;
if ( fabsf ( roll ) > 0 | | fabsf ( pitch ) > 0 | | fabsf ( yaw ) > 0 ) {
return true ;
}
return false ;
}
// Get the axis name we are working on, or DONE for all done
AP_Quicktune : : AxisName AP_Quicktune : : get_current_axis ( ) const
{
for ( int8_t i = 0 ; i < int8_t ( AxisName : : DONE ) ; i + + ) {
if ( BIT_IS_SET ( axes_enabled , i ) & & ! BIT_IS_SET ( axes_done , i ) ) {
return AxisName ( i ) ;
}
}
return AxisName : : DONE ;
}
// get the AC_PID object for an axis
AC_PID * AP_Quicktune : : get_axis_pid ( AP_Quicktune : : AxisName axis ) const
{
auto & attitude_control = * AC_AttitudeControl : : get_singleton ( ) ;
switch ( axis ) {
case AxisName : : RLL :
return & attitude_control . get_rate_roll_pid ( ) ;
case AxisName : : PIT :
return & attitude_control . get_rate_pitch_pid ( ) ;
case AxisName : : YAW :
return & attitude_control . get_rate_yaw_pid ( ) ;
default :
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
break ;
}
return nullptr ;
}
// get slew rate parameter for an axis
float AP_Quicktune : : get_slew_rate ( AP_Quicktune : : AxisName axis ) const
{
auto * pid = get_axis_pid ( axis ) ;
if ( pid = = nullptr ) {
return 0 ;
}
return pid - > get_pid_info ( ) . slew_rate ;
}
// Move to next stage of tune
void AP_Quicktune : : advance_stage ( AP_Quicktune : : AxisName axis )
{
if ( current_stage = = Stage : : D ) {
current_stage = Stage : : P ;
} else {
BIT_SET ( axes_done , uint8_t ( axis ) ) ;
GCS_SEND_TEXT ( MAV_SEVERITY_NOTICE , " Quicktune: %s done " , get_axis_name ( axis ) ) ;
current_stage = Stage : : D ;
}
}
void AP_Quicktune : : adjust_gain ( AP_Quicktune : : Param param , float value )
{
need_restore = true ;
BIT_SET ( param_changed , uint8_t ( param ) ) ;
set_param_value ( param , value ) ;
if ( get_stage ( param ) = = Stage : : P ) {
// Also change I gain
const uint8_t P_TO_I_OFS = uint8_t ( Param : : RLL_I ) - uint8_t ( Param : : RLL_P ) ;
const uint8_t P_TO_FF_OFS = uint8_t ( Param : : RLL_FF ) - uint8_t ( Param : : RLL_P ) ;
const Param iname = Param ( uint8_t ( param ) + P_TO_I_OFS ) ;
const Param ffname = Param ( uint8_t ( param ) + P_TO_FF_OFS ) ;
float FF = get_param_value ( ffname ) ;
if ( FF > 0 ) {
// If we have any FF on an axis then we don't couple I to P,
// usually we want I = FF for a one second time constant for trim
return ;
}
BIT_SET ( param_changed , uint8_t ( iname ) ) ;
// Work out ratio of P to I that we want
float pi_ratio = rp_pi_ratio ;
if ( get_axis ( param ) = = AxisName : : YAW ) {
pi_ratio = y_pi_ratio ;
}
if ( pi_ratio > = 1 ) {
set_param_value ( iname , value / pi_ratio ) ;
}
}
}
void AP_Quicktune : : adjust_gain_limited ( AP_Quicktune : : Param param , float value )
{
adjust_gain ( param , limit_gain ( param , value ) ) ;
}
float AP_Quicktune : : limit_gain ( AP_Quicktune : : Param param , float value )
{
const float saved_value = param_saved [ uint8_t ( param ) ] ;
if ( reduce_max > = 0 & & reduce_max < 100 & & saved_value > 0 ) {
// Check if we exceeded gain reduction
const float reduction_pct = 100.0 * ( saved_value - value ) / saved_value ;
if ( reduction_pct > reduce_max ) {
const float new_value = saved_value * ( 100 - reduce_max ) * 0.01 ;
GCS_SEND_TEXT ( MAV_SEVERITY_INFO , " Limiting %s %.3f -> %.3f " , get_param_name ( param ) , value , new_value ) ;
value = new_value ;
}
}
return value ;
}
const char * AP_Quicktune : : get_param_name ( AP_Quicktune : : Param param ) const
{
switch ( param )
{
case Param : : RLL_P :
return " Roll P " ;
case Param : : RLL_I :
return " Roll I " ;
case Param : : RLL_D :
return " Roll D " ;
case Param : : PIT_P :
return " Pitch P " ;
case Param : : PIT_I :
return " Pitch I " ;
case Param : : PIT_D :
return " Pitch D " ;
case Param : : YAW_P :
return " Yaw P " ;
case Param : : YAW_I :
return " Yaw I " ;
case Param : : YAW_D :
return " Yaw D " ;
default :
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return " UNK " ;
}
}
float AP_Quicktune : : get_gain_mul ( ) const
{
return expf ( logf ( 2.0 ) / ( UPDATE_RATE_HZ * MAX ( 1 , double_time ) ) ) ;
}
void AP_Quicktune : : restore_all_params ( )
{
for ( uint8_t p = 0 ; p < uint8_t ( Param : : END ) ; p + + ) {
const auto param = Param ( p ) ;
if ( BIT_IS_SET ( param_changed , p ) ) {
set_param_value ( param , param_saved [ p ] ) ;
BIT_CLEAR ( param_changed , p ) ;
}
}
}
void AP_Quicktune : : save_all_params ( )
{
for ( uint8_t p = 0 ; p < uint8_t ( Param : : END ) ; p + + ) {
const auto param = Param ( p ) ;
set_and_save_param_value ( param , get_param_value ( param ) ) ;
param_saved [ p ] = get_param_value ( param ) ;
BIT_CLEAR ( param_changed , p ) ;
}
GCS_SEND_TEXT ( MAV_SEVERITY_NOTICE , " Quicktune: Saved " ) ;
}
AP_Quicktune : : Param AP_Quicktune : : get_pname ( AP_Quicktune : : AxisName axis , AP_Quicktune : : Stage stage ) const
{
const uint8_t axis_offset = uint8_t ( axis ) * param_per_axis ;
switch ( stage )
{
case Stage : : P :
return Param ( uint8_t ( Param : : RLL_P ) + axis_offset ) ;
case Stage : : D :
return Param ( uint8_t ( Param : : RLL_D ) + axis_offset ) ;
case Stage : : FLTT :
return Param ( uint8_t ( Param : : RLL_FLTT ) + axis_offset ) ;
case Stage : : FLTD :
return Param ( uint8_t ( Param : : RLL_FLTD ) + axis_offset ) ;
default :
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return Param : : END ;
}
}
AP_Quicktune : : Stage AP_Quicktune : : get_stage ( AP_Quicktune : : Param param ) const
{
if ( param = = Param : : RLL_P | | param = = Param : : PIT_P | | param = = Param : : YAW_P ) {
return Stage : : P ;
} else {
return Stage : : END ; //Means "anything but P gain"
}
}
AP_Float * AP_Quicktune : : get_param_pointer ( AP_Quicktune : : Param param ) const
{
const AxisName axis = get_axis ( param ) ;
auto * pid = get_axis_pid ( axis ) ;
if ( pid = = nullptr ) {
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return nullptr ;
}
const Param roll_param = Param ( uint8_t ( param ) % param_per_axis ) ;
switch ( roll_param )
{
case Param : : RLL_P :
return & pid - > kP ( ) ;
case Param : : RLL_I :
return & pid - > kI ( ) ;
case Param : : RLL_D :
return & pid - > kD ( ) ;
case Param : : RLL_SMAX :
return & pid - > slew_limit ( ) ;
case Param : : RLL_FLTT :
return & pid - > filt_T_hz ( ) ;
case Param : : RLL_FLTD :
return & pid - > filt_D_hz ( ) ;
case Param : : RLL_FLTE :
return & pid - > filt_E_hz ( ) ;
case Param : : RLL_FF :
return & pid - > ff ( ) ;
default :
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return nullptr ;
}
}
float AP_Quicktune : : get_param_value ( AP_Quicktune : : Param param ) const
{
AP_Float * ptr = get_param_pointer ( param ) ;
if ( ptr ! = nullptr ) {
return ptr - > get ( ) ;
}
return 0.0 ;
}
void AP_Quicktune : : set_param_value ( AP_Quicktune : : Param param , float value )
{
AP_Float * ptr = get_param_pointer ( param ) ;
if ( ptr ! = nullptr ) {
ptr - > set ( value ) ;
}
}
void AP_Quicktune : : set_and_save_param_value ( AP_Quicktune : : Param param , float value )
{
AP_Float * ptr = get_param_pointer ( param ) ;
if ( ptr ! = nullptr ) {
ptr - > set_and_save ( value ) ;
}
}
AP_Quicktune : : AxisName AP_Quicktune : : get_axis ( AP_Quicktune : : Param param ) const
{
if ( param > = Param : : END ) {
return AxisName : : END ;
}
return AxisName ( uint8_t ( param ) / param_per_axis ) ;
}
const char * AP_Quicktune : : get_axis_name ( AP_Quicktune : : AxisName axis ) const
{
switch ( axis )
{
case AxisName : : RLL :
return " Roll " ;
case AxisName : : PIT :
return " Pitch " ;
case AxisName : : YAW :
return " Yaw " ;
default :
INTERNAL_ERROR ( AP_InternalError : : error_t : : flow_of_control ) ;
return " UNK " ;
}
}
float AP_Quicktune : : gain_limit ( AP_Quicktune : : Param param ) const
{
if ( get_axis ( param ) = = AxisName : : YAW ) {
if ( param = = Param : : YAW_P ) {
return yaw_p_max ;
}
if ( param = = Param : : YAW_D ) {
return yaw_d_max ;
}
}
return 0.0 ;
}
// @LoggerMessage: QWIK
// @Description: Quicktune
// @Field: TimeUS: Time since system startup
// @Field: ParamNo: number of parameter being tuned
// @Field: SRate: slew rate
// @Field: Gain: test gain for current axis and PID element
// @Field: Param: name of parameter being being tuned
void AP_Quicktune : : Write_QWIK ( float srate , float gain , AP_Quicktune : : Param param )
{
# if HAL_LOGGING_ENABLED
AP : : logger ( ) . WriteStreaming ( " QWIK " , " TimeUS,ParamNo,SRate,Gain,Param " , " s#--- " , " ----- " , " QBffN " ,
AP_HAL : : micros64 ( ) ,
unsigned ( param ) ,
srate ,
gain ,
get_param_name ( param ) ) ;
# endif
}
# endif //AP_QUICKTUNE_ENABLED