目录
摘要
本节主要记录自己学习ardupilot PID控制算法过程,欢迎批评指正。
1.PID简介
在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。PID控制器问世至今已有近70年历史,它 以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的 其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象,或 不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。PID控制器就是根据系统的误差,利用比例、 积分、微分计算出控制量进行控制的。最好的PID教程参考:PID教学视频
1.比例(P)控制
比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差(Steady-state error)。比例控制只有误差才起作用,没有误差不进行任何处理,带来的坏处就是当误差等于0时,会导致系统不受控。
2.积分(I)控制
在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的 或简称有差系统(System with Steady-state Error)。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积 分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到接近于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后几乎无稳 态误差。 积分项对过去小的误差可以实现大的累计控制作用,缺陷是根据过去累计经验来评估当前信息,过去是好的,认为现在就是好的,当积分累计误差等于0时,对系统不进行控制。
3.微分(D)控制
在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后(delay)组件,具有抑制误差的作用, 其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入 “比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能 够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在 调节过程中的动态特性。
2.PID分类
数字PID控制算法通常分为位置式PID和增量式PID:
1.位置式PID
2.增量式PID
3.ardupilot PID控制算法源码
#include <AP_Math/AP_Math.h>
#include "AC_PID.h"
const AP_Param::GroupInfo AC_PID::var_info[] = {
AP_GROUPINFO("P", 0, AC_PID, _kp, 0),
AP_GROUPINFO("I", 1, AC_PID, _ki, 0),
AP_GROUPINFO("D", 2, AC_PID, _kd, 0),
AP_GROUPINFO("FF", 4, AC_PID, _kff, 0),
AP_GROUPINFO("IMAX", 5, AC_PID, _kimax, 0),
AP_GROUPINFO("FLTT", 9, AC_PID, _filt_T_hz, AC_PID_TFILT_HZ_DEFAULT),
AP_GROUPINFO("FLTE", 10, AC_PID, _filt_E_hz, AC_PID_EFILT_HZ_DEFAULT),
AP_GROUPINFO("FLTD", 11, AC_PID, _filt_D_hz, AC_PID_DFILT_HZ_DEFAULT),
AP_GROUPEND
};
AC_PID::AC_PID(float initial_p, float initial_i, float initial_d, float initial_ff, float initial_imax, float initial_filt_T_hz, float initial_filt_E_hz, float initial_filt_D_hz, float dt) :
_dt(dt),
_integrator(0.0f),
_error(0.0f),
_derivative(0.0f)
{
AP_Param::setup_object_defaults(this, var_info);
_kp = initial_p;
_ki = initial_i;
_kd = initial_d;
_kff = initial_ff;
_kimax = fabsf(initial_imax);
filt_T_hz(initial_filt_T_hz);
filt_E_hz(initial_filt_E_hz);
filt_D_hz(initial_filt_D_hz);
_flags._reset_filter = true;
memset(&_pid_info, 0, sizeof(_pid_info));
}
void AC_PID::set_dt(float dt)
{
_dt = dt;
}
void AC_PID::filt_T_hz(float hz)
{
_filt_T_hz.set(fabsf(hz));
}
void AC_PID::filt_E_hz(float hz)
{
_filt_E_hz.set(fabsf(hz));
}
void AC_PID::filt_D_hz(float hz)
{
_filt_D_hz.set(fabsf(hz));
}
float AC_PID::update_all(float target, float measurement, bool limit)
{
if (!isfinite(target) || !isfinite(measurement))
{
return 0.0f;
}
if (_flags._reset_filter)
{
_flags._reset_filter = false;
_target = target;
_error = _target - measurement;
_derivative = 0.0f;
} else
{
float error_last = _error;
_target += get_filt_T_alpha() * (target - _target);
_error += get_filt_E_alpha() * ((_target - measurement) - _error);
if (_dt > 0.0f)
{
float derivative = (_error - error_last) / _dt;
_derivative += get_filt_D_alpha() * (derivative - _derivative);
}
}
update_i(limit);
float P_out = (_error * _kp);
float D_out = (_derivative * _kd);
_pid_info.target = _target;
_pid_info.actual = measurement;
_pid_info.error = _error;
_pid_info.P = P_out;
_pid_info.D = D_out;
return P_out + _integrator + D_out;
}
float AC_PID::update_error(float error, bool limit)
{
if (!isfinite(error))
{
return 0.0f;
}
_target = 0.0f;
if (_flags._reset_filter)
{
_flags._reset_filter = false;
_error = error;
_derivative = 0.0f;
} else
{
float error_last = _error;
_error += get_filt_E_alpha() * (error - _error);
if (_dt > 0.0f)
{
float derivative = (_error - error_last) / _dt;
_derivative += get_filt_D_alpha() * (derivative - _derivative);
}
}
update_i(limit);
float P_out = (_error * _kp);
float D_out = (_derivative * _kd);
_pid_info.target = 0.0f;
_pid_info.actual = 0.0f;
_pid_info.error = _error;
_pid_info.P = P_out;
_pid_info.D = D_out;
return P_out + _integrator + D_out;
}
void AC_PID::update_i(bool limit)
{
if (!is_zero(_ki) && is_positive(_dt))
{
if (!limit || ((is_positive(_integrator) && is_negative(_error))
|| (is_negative(_integrator) && is_positive(_error))))
{
_integrator += ((float)_error * _ki) * _dt;
_integrator = constrain_float(_integrator, -_kimax, _kimax);
}
} else
{
_integrator = 0.0f;
}
_pid_info.I = _integrator;
}
float AC_PID::get_p() const
{
return _error * _kp;
}
float AC_PID::get_i() const
{
return _integrator;
}
float AC_PID::get_d() const
{
return _kd * _derivative;
}
float AC_PID::get_ff()
{
_pid_info.FF = _target * _kff;
return _target * _kff;
}
float AC_PID::get_ff(float target)
{
float FF_out = (target * _kff);
_pid_info.FF = FF_out;
return FF_out;
}
void AC_PID::reset_I()
{
_integrator = 0;
}
void AC_PID::reset_I_smoothly()
{
float reset_time = AC_PID_RESET_TC * 3.0f;
uint64_t now = AP_HAL::micros64();
if ((now - _reset_last_update) > 5e5 ) {
_reset_counter = 0;
}
if ((float)_reset_counter < (reset_time/_dt))
{
_integrator = _integrator - (_dt / (_dt + AC_PID_RESET_TC)) * _integrator;
_reset_counter++;
} else
{
_integrator = 0;
}
_reset_last_update = now;
}
void AC_PID::load_gains()
{
_kp.load();
_ki.load();
_kd.load();
_kff.load();
_kimax.load();
_kimax = fabsf(_kimax);
_filt_T_hz.load();
_filt_E_hz.load();
_filt_D_hz.load();
}
void AC_PID::save_gains()
{
_kp.save();
_ki.save();
_kd.save();
_kff.save();
_kimax.save();
_filt_T_hz.save();
_filt_E_hz.save();
_filt_D_hz.save();
}
void AC_PID::operator()(float p_val, float i_val,
float d_val, float ff_val, float imax_val, float input_filt_T_hz, float input_filt_E_hz, float input_filt_D_hz, float dt)
{
_kp = p_val;
_ki = i_val;
_kd = d_val;
_kff = ff_val;
_kimax = fabsf(imax_val);
_filt_T_hz = input_filt_T_hz;
_filt_E_hz = input_filt_E_hz;
_filt_D_hz = input_filt_D_hz;
_dt = dt;
}
float AC_PID::get_filt_T_alpha() const
{
return get_filt_alpha(_filt_T_hz);
}
float AC_PID::get_filt_E_alpha() const
{
return get_filt_alpha(_filt_E_hz);
}
float AC_PID::get_filt_D_alpha() const
{
return get_filt_alpha(_filt_D_hz);
}
float AC_PID::get_filt_alpha(float filt_hz) const
{
if (is_zero(filt_hz))
{
return 1.0f;
}
float rc = 1 / (M_2PI * filt_hz);
return _dt / (_dt + rc);
}
void AC_PID::set_integrator(float target, float measurement, float i)
{
set_integrator(target - measurement, i);
}
void AC_PID::set_integrator(float error, float i)
{
_integrator = constrain_float(i - error * _kp, -_kimax, _kimax);
_pid_info.I = _integrator;
}
void AC_PID::set_integrator(float i)
{
_integrator = constrain_float(i, -_kimax, _kimax);
_pid_info.I = _integrator;
}
4.ardupilot PID参数
1.姿态角速度控制器
void Copter::fast_loop()
{
....................
attitude_control->rate_controller_run();
...............
}
执行函数
void AC_AttitudeControl_Multi::rate_controller_run()
{
update_throttle_rpy_mix();
_rate_target_ang_vel += _rate_sysid_ang_vel;
Vector3f gyro_latest = _ahrs.get_gyro_latest();
_motors.set_roll(get_rate_roll_pid().update_all(_rate_target_ang_vel.x, gyro_latest.x, _motors.limit.roll) + _actuator_sysid.x);
_motors.set_roll_ff(get_rate_roll_pid().get_ff());
_motors.set_pitch(get_rate_pitch_pid().update_all(_rate_target_ang_vel.y, gyro_latest.y, _motors.limit.pitch) + _actuator_sysid.y);
_motors.set_pitch_ff(get_rate_pitch_pid().get_ff());
_motors.set_yaw(get_rate_yaw_pid().update_all(_rate_target_ang_vel.z, gyro_latest.z, _motors.limit.yaw) + _actuator_sysid.z);
_motors.set_yaw_ff(get_rate_yaw_pid().get_ff()*_feedforward_scalar);
_rate_sysid_ang_vel.zero();
_actuator_sysid.zero();
control_monitor_update();
}
从中可以看出主要调用的函数是update_all()函数
float AC_PID::update_all(float target, float measurement, bool limit)
{
if (!isfinite(target) || !isfinite(measurement))
{
return 0.0f;
}
if (_flags._reset_filter)
{
_flags._reset_filter = false;
_target = target;
_error = _target - measurement;
_derivative = 0.0f;
} else
{
float error_last = _error;
_target += get_filt_T_alpha() * (target - _target);
_error += get_filt_E_alpha() * ((_target - measurement) - _error);
if (_dt > 0.0f)
{
float derivative = (_error - error_last) / _dt;
_derivative += get_filt_D_alpha() * (derivative - _derivative);
}
}
update_i(limit);
float P_out = (_error * _kp);
float D_out = (_derivative * _kd);
_pid_info.target = _target;
_pid_info.actual = measurement;
_pid_info.error = _error;
_pid_info.P = P_out;
_pid_info.D = D_out;
return P_out + _integrator + D_out;
}
其中积分限制幅度的理解如下:
void AC_PID::update_i(bool limit)
{
if (!is_zero(_ki) && is_positive(_dt))
{
if (!limit || ((is_positive(_integrator) && is_negative(_error))
|| (is_negative(_integrator) && is_positive(_error))))
{
_integrator += ((float)_error * _ki) * _dt;
_integrator = constrain_float(_integrator, -_kimax, _kimax);
}
} else
{
_integrator = 0.0f;
}
_pid_info.I = _integrator;
}
其中MP地面站对应的参数如下: 串口打印出来的数据
2.姿态控制器
attitude_control->input_euler_angle_roll_pitch_euler_rate_yaw(target_roll, target_pitch, target_yaw_rate);
_rate_target_ang_vel = update_ang_vel_target_from_att_error(attitude_error_vector);
Vector3f AC_AttitudeControl::update_ang_vel_target_from_att_error(const Vector3f &attitude_error_rot_vec_rad)
{
Vector3f rate_target_ang_vel;
if (_use_sqrt_controller)
{
rate_target_ang_vel.x = sqrt_controller(attitude_error_rot_vec_rad.x, _p_angle_roll.kP(), constrain_float(get_accel_roll_max_radss() / 2.0f, AC_ATTITUDE_ACCEL_RP_CONTROLLER_MIN_RADSS, AC_ATTITUDE_ACCEL_RP_CONTROLLER_MAX_RADSS), _dt);
} else {
rate_target_ang_vel.x = _p_angle_roll.kP() * attitude_error_rot_vec_rad.x;
}
if (_use_sqrt_controller)
{
rate_target_ang_vel.y = sqrt_controller(attitude_error_rot_vec_rad.y, _p_angle_pitch.kP(), constrain_float(get_accel_pitch_max_radss() / 2.0f, AC_ATTITUDE_ACCEL_RP_CONTROLLER_MIN_RADSS, AC_ATTITUDE_ACCEL_RP_CONTROLLER_MAX_RADSS), _dt);
} else
{
rate_target_ang_vel.y = _p_angle_pitch.kP() * attitude_error_rot_vec_rad.y;
}
if (_use_sqrt_controller)
{
rate_target_ang_vel.z = sqrt_controller(attitude_error_rot_vec_rad.z, _p_angle_yaw.kP(),
constrain_float(get_accel_yaw_max_radss() / 2.0f, AC_ATTITUDE_ACCEL_Y_CONTROLLER_MIN_RADSS, AC_ATTITUDE_ACCEL_Y_CONTROLLER_MAX_RADSS), _dt);
} else
{
rate_target_ang_vel.z = _p_angle_yaw.kP() * attitude_error_rot_vec_rad.z;
}
return rate_target_ang_vel;
}
MP地面站对应的参数如下:
3.位置PID控制器
1.高度控制器PID
pos_control->update_z_controller();
run_z_controller();
1.计算垂直高度误差
_vel_target.z = AC_AttitudeControl::sqrt_controller(_pos_error.z, _p_pos_z.kP(), _accel_z_cms, _dt);
2.计算垂直速度PID
_accel_target.z = _p_vel_z.get_p(_vel_error.z);
3.计算垂直加速度PID
thr_out = _pid_accel_z.update_all(_accel_target.z, z_accel_meas, (_motors.limit.throttle_lower || _motors.limit.throttle_upper)) * 0.001f;
|