位置式PID定速控制 链接到标题
测试闭环的缺点0 链接到标题
使用电机驱动的测试程序,
- 显示电机给的驱动力
- 显示由编码器测量得到的实际速度
显然,当我们给转盘阻力的时候转盘会变慢,这也就是闭环的缺点了。
编码器设置 链接到标题
测速的代码是这样的
Count++;
if(Count>=40)
{
Count=0;
Speed=Encoder_Get();
}
这意味着每计数40转就测一次速,根据平均速度测量的一些经验我们知道
- 测量周期越长,测到的速度就越精确(在被测速度接近于匀速的情况下)
- 但是刷新周期也会越长 因此合理选择测速周期也是一个博弈。在之后引入PID后一般会将其设置为与PID的调控周期保持一致。
引入PID 链接到标题
- 需要将主程序中所有的PWM设值部分改成target,表示期望值,至于后面怎么样调PWM是PID要干的事情,
- 按照公式写代码,核心代码如下
Error1=Error0;
Error0=Target-Actual;
ErrorInt+=Error0;
/*PID计算*/
Out=Kp*Error0+Ki*ErrorInt+Kd*(Error0-Error1);
/*输出限幅*/
if(Out>100)
{
Out=100;
}
if(Out<-100)
{
Out=-100;
}
Motor_SetPWM(Out);
PI 链接到标题
- 一开始先不考虑微分项$K_d$,令其为零,开始测试。
- 测试正常进行,
- 不过笔者发现一个bug:在高速的时候看不清不了解,看到定速效果良好,但是在0速度的定速的时候这个程序不仅能定速,还能定位。也就是说在定速为零的时候如果强行扭动转台,转台不仅会施加阻力抵挡,还会在最后回归原始位置。
- 再看代码时发现,强行扭动一定距离产生的error会积累out,最后即使速度为零了,这些out也没有消散,还是要往回抵消,因此也就产生了定位的效果。
- 如果我们去掉积分项目,也容易验证到之前理论部分所展示的动态平衡,也就是实际值始终低于预期值,且差为常数
PID的数量级确定 链接到标题
$$ K\approx \frac{\text{输出}}{\text{输入}} $$ 此处可以实测$out\approx 100$,而输入$Act\approx 180$,所以得到K的数量级就是0.1~1左右。
微调(使用电位器上面的旋钮) 链接到标题
- 使用电位器调节K
- 也将速度的调节也用旋钮来调节
- 需要对累加项进行判断,防止在$K_i$由0变为非零时由于积累误差的出现出现猛然的调控。
这里出现的一些小bug,一开始没有严格按照他的代码进行OLED显示,进而导致OLED显示不出参数,后面推测应该是OLED_Print部分的显示有问题,严格按照他的代码就没有问题了。
实验 链接到标题
定性感性的实验 链接到标题
在实验中可以观察到
- 只有P的情况转动是连续的,但是对于外界的响应感觉有迟钝之感,在P很大时候也能看到抖动的现象,且抖动只发生在平衡状态被破坏至回复平衡状态的过程,在平衡之后不会动,这与其无记忆性吻合。
- 有I且I很大的时候观察到了很明显的自激振荡,但是在手动按住转子顺着那股力(阻尼),让out渐渐变成0可以让其停下来(误差累加值为零即稳定)
- D很大,自激振荡是很恐怖的,并且手动按住无法消除(抗阻尼),目前对其其他性质的探索还在深入。
串口采集数据后电子图像显示 链接到标题
- 串口以及串口接收工具的使用看前面的章节
- 没什么,就是通过图像能更加清晰的看到pid的过程而已
- 实际上,在实际使用的过程中D项不一定是必须项,这需要看图像是否有在靠近平衡位置时出现“猛扎子”,
- 如果有就要
- 没有的话,加了就是画蛇添足
增量式PID定速控制 链接到标题
公式上的区别体现在代码上就是改变的不再是out值而是$\Delta$out值,即调控代码变成了
Actual=Encoder_Get();
Error2=Error1;
Error1=Error0;
Error0=Target-Actual;
Out+=Kp*(Error0-Error1)+Ki*Error0+Kd*(Error0-2*Error1+Error2);
注意,这里使用的是out+,也就是自带了一个 积分器功能,这是使用积分器要注意的。
实际的使用与位置式基本一样,但有一点区别
- 当$K_p$、$K_i$、$K_d$都为0时,增量式PID的输出out直接为0,而位置式PID的输出的只是$\Delta$out为0,但out维持原值不变,在这个过程中我们可以自由设定target值和out值(根据经验设置),此时相当于pid调控暂停,电机控制进入开环状态因此,我们可以用增量式PID来实现**手动控制(开环控制)和自动控制(PID)**的切换。
- 同时,out+=功能的代码顺手也实现了积分限幅的功能(之后会讲到)
定位控制 链接到标题
改代码 链接到标题
- 使用积分累加的形式由测量的速度得到位置
Actual+=Encoder_Get();//通过积分来计算位置
- 改一下一些OLED的显示设置
- 在测量位置实验后发现转一圈大概为408,所以改一下映射关系
Target=RP_GetValue(4)/4095.0*816-408;
实验 链接到标题
- 可以看出在只有P已经很好了,太大的话会出现过冲以及震荡()
- D可以用于削弱P太大导致的过冲,不会产生自激振荡,但是太大的话会降低响应速度造成卡顿。
- I就很关键了,如有需要可以有,但是太大的话就会出现严重的自激振荡,请看下面的图
,这个就是由于I项过大导致的自激振荡。并且如果我不停止,他应该会在驱动力足够的情况下无限增大下去。
增量式 链接到标题
一样的改法,就不在赘述。可以实现手动和自动的切换,但是这里会出现一些问题,
- 就是如果初始的out是错的,纯比例项调节在误差很小情况下呗阻力干扰,无法调节
- 另一方面,这也会影响P的无记忆性。