1. 基础PID代码片段
int cal_pid(int target, int feedbck)
{
static int last_err;
int err, err_sum;
err = target - feedback;
err_sum += err;
out = kp * err + ki * err_sum + kd * (err - last_err);
last_err = err;
return out;
}
2. 抗积分饱和
积分饱和就是,积分项数值一直朝一个方向累加(一直减小或一直增大)。导致积分项的值非常大或非常小。下次改变目标值后,由于积分项绝对值太大,导致控制器调整输出的速度变慢。所以要增加一些代码逻辑来抗积分饱和。
这里根据百度出来的结果,简单举几种方法:
2.1 积分器分离
误差大于或小于某个值,关闭积分器;
在基础代码片段更改如下语句即可:
if(err > 10)
{
err_sum += err;
}
2.2 静态积分限幅
将基础代码段中的err_sum限制在一定的取值范围内。
err_sum += err;
if(err_sum > 8000)
{
err_sum = 8000; // 该值可根据应用场景灵活变动
}
else if(err_sum <-8000)
{
err_sum = -8000;
}
2.3 动态积分限幅
当pid计算得到的值大于系统输出值时,就将积分项减去多余的值。
out = kp * err + ki * err_sum + kd * (err - last_err); //这里假设out是直接输出到定时器的值
if(out > MAX_DUTY) // MAX_DUTY是定时器PWM的最大输出值,初始化是就能确定了
{
int extra = out - MAX_DUTY;
if(err > 0)
{
err_sum -= extra;
}
else
{
err_sum += extra;
}
out = kp * err + ki * err_sum + kd * (err - last_err);
}
2.4 增量PID
增量PID用的比较少,虽然对积分饱和有改善,但会引入其它问题。
暂时不深究这个方案。
3. PID参数整定
PID参数整定绝对是PID最核心的内容了。笔者用的最多的就是试凑法,其它方法笔者也不懂。
下图是当年刚接触PID时记录的一些参数整定口诀。感谢当年一起参加电赛的小伙伴整理的资料。