目录
一,PID的简介
1,什么是PID
PID 控制器以各种形式使用超过了 1 世纪,广泛应用在机械设备、气动设备 和电子设备.在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法
PID,就是“P比例(proportional)、I积分(integral)、D微分(derivative)”,是一种很常见的控制算法。
2,为什么要用PID
1,以温度控制为例子:假设加热控制要加热到500度,没有PID调节的,就是最简单比较通断式,达到温度停止,低于温度加热;
这样的实际温度抖动可能会比较大,加热装置通断电也比较频繁。
如果使用PID,温度到达后不是停止加热,而是温度接近时小功率加热,温度差的很多时,大功率加热,波动幅度小,可靠性好,体验也好。
2,以上一章咱们将的红外循迹来举例子,大家如果是用的八路或九路以上的传感器,可能红外循迹转直角弯是没有问题的(大部分也不行,可能少部分情况下可以),但是如果是5路或者5路以下的循迹,基本上是完全不能循直角弯,大家可以在B站上面找视频,看他们的小车,循迹特别的稳当,而且小车还很快,基本上是要用PID控制的。
3,PID的应用
PID控制算法是一种常用的控制算法,广泛应用于各种自动控制系统中。其主要应用场景包括:
- 温度控制:PID控制算法可以实现对温度的精确控制,如工业热处理、恒温箱等。
- 机械控制:PID控制算法可以实现机械系统的精确控制,如电机速度控制、位置控制、压力控制等。
- 液位控制:PID控制算法可以实现液位的精确控制,如水池液位控制、加油站油罐液位控制等。
- 流量控制:PID控制算法可以实现对流量的精确控制,如汽轮机进汽量的控制、供水系统控制等。
4,PID的功能和分类
功能:这里我总结了一下PID就是通过负反馈调节,使最终结果达到你的期望值。
分类:位置式PID,增量式PID,串级PID,智能PID等等。
下面我会为大家解释说明位置式PID和增量式PID,串级PID,但后面的智能PID就不说了,本人确实也只是知道名字而已,大家感兴趣就另外了解吧。
二,PID的原理
P、I、D分别为比例(Proportion)、积分(Integral)、微分(Differential)的简写;将偏差的比例、积分和微分通过线性组合构成控制量,用该控制量对受控对象进行控制,称为PID算法。总之,PID就是对输入偏差进行比例积分微分运算,运算的叠加结果去控制执行机构。在工程实践中,一般P是必须的,所以衍生出来很多的PID控制器,如PI、PD、PID等。
PID算法的一般形式:
输入为r(t),输出为c(t),偏差为e(t),e(t)=r'(t)-c'(t)
1,连续性状态方程:
以PWM控制电机调速为例子:
1,r'(t)是预期PWM值
2,c'(t)是实际PWM值
3,e(t)也就是偏差值就是预期值-实际值
2,离散化状态方程:
Kp部分不变;Ki部分,也就是积分部分,将其转化为累计和;Kd部分,也就是微分部分,转化为前一项的偏差和当前偏差的差;
位置式PID离散表示形式:
增量式PID离散表示形式:
因为串级PID的各个部分的计算就是位置式或增量式,最终结果上是多个之和或之差,所以就没有特定的离散表达形式。
其中: Kp ―― 控制器的比例系数
Ti ———控制器的积分时间,也称积分系数
Td ―― 控制器的微分时间,也称微分系数
1)比例部分
作用是对系统瞬间产生的偏差进行快速修正,只有 P 时会有静差 。偏差一旦产生控制器立即产生控制作用, 使控制量向减少偏差的方向变化。
所以比例部分数学表示为:Kp*e(t)
注意:Kp是比例系数,Kp越大,控制作用越强,则过渡过程越快,控制过程的静态偏差也就越小;但是越大,也越容易产生振荡,破坏系统的稳定性。故而,比例系数 选择必须恰当,才能过渡时间少,静差小而又稳定的效果。
2)积分部分
作用是消除系统偏差,补偿系统的静差 ,只要存在偏差, 则它的控制作用就不断的增加; 只有在偏差 时, 它的积分才能是一个常数, 控制作用才是一个不会增加的常数。
所以积分部分数学表示为:Ki*(e(t))
积分环节的调节作用虽然会消除静态误差,但也会降低系统的响应速度,增加系统的超调量。积分常数越大,积分的积累作用越弱, 这时系统在过渡时不会产生振荡;但是增大积分常数 会减慢静态误差的消除过程,消除偏差所需的时间也较长, 但可以减少超调量,提高系统的稳定性。当Ti 较小时, 则积分的作用较强, 这时系统过渡时间中有可能产生振荡, 不过消除偏差所需的时间较短。所以必须根据实际控制的具体要求来确定Ti 。
3)微分部分
作用是加快调节过程,阻止偏差的变化, 偏差变化的越快, 微分控制器的输出就越大,并能在偏差值变大之前进行修正。微分作用的引入, 将有助于减小超调量, 克服振荡, 使系统趋于稳定, 特别对髙阶系统非常有利, 它加快了系统的跟踪速度。但微分的作用对输入信号的噪声很敏感,对那些噪声较大的系统一般不用微分, 或在微分起作用之前先对输入信号进行滤波。
所以微分部分数学表示为:Kd*(e(k)-e(k-1))
Td 越大时, 则它抑制偏差 变化的作用越强; Td越小时,则它反抗偏差 变化的作用越弱。微分部分显然对系统稳定有很大的作用。适当地选择微分常数Td ,可以使微分作用达到最优。
4)总结
Kp使调节更快,Ki使调节更准,Kd使调节更稳
3,PID调参口诀:
参数整定找最佳, 从小到大顺序查。
先是比例后积分, 最后再把微分加。
曲线振荡很频繁, 比例度盘要放大。
曲线漂浮绕大弯, 比例度盘往小扳。
曲线偏离回复慢, 积分时间往下降。
曲线波动周期长, 积分时间再加长。
曲线振荡频率快, 先把微分降下来。
动差大来波动慢, 微分时间应加长。
理想曲线两个波, 前高后低四比一。
一看二调多分析, 调节质量不会低。
1,位置式PID
当前的输出与过去的所有状态都有关系(积分累加也就是误差累加),并且控制器的输出就是实际的输出结果,一旦控制输出出错,那么整个系统都可能奔溃,并且在整定参数时,要防止过冲现象,需对积分处理部分进行特别处理。这里提一句,只用位置式
初始化部分:
int OUTPUT1=0;//小车的左轮PWM值
int OUTPUT2=0;//小车的右轮PWM值
int PID_xs=0;//小车差速PID控制器的PWM输出值
extern int e;//e就是误差 //作为差速PID控制器的传参输入值
差速PID控制函数部分:
int Position_PID(int Encoder)//差速PID控制器Encoder=e
{
float Position_KP,Position_KI,Position_KD;//大家自己去设置值
static float BIAS,PWM,LAST_BIAS,INTEGRAL_BIAS;
BIAS=Encoder;
INTEGRAL_BIAS+=BIAS;//i+=j=>i=i+j
if(INTEGRAL_BIAS>500)INTEGRAL_BIAS=500; //限制INTEGRAL_BIAS的值避免太大
if(INTEGRAL_BIAS<200)INTEGRAL_BIAS=200; //限制INTEGRAL_BIAS的值避免太小
PWM=Position_KP*BIAS+Position_KI*INTEGRAL_BIAS+Position_KD*(BIAS-LAST_BIAS);//PID计算公式
LAST_BIAS=BIAS;
return PWM;
}
最终输出部分:
void sc(void)
{PID_xs=Position_PID(e);
OUTPUT1=4000+PID_xs;//直接给PWM
OUTPUT2=4200-PID_xs;TIM_SetCompare2(TIM2,OUTPUT2);
TIM_SetCompare3(TIM2,OUTPUT1);
}
2,增量式PID
初始部分一样
差速PID控制函数部分:
int Position_PID(int Encoder)//差速PID控制器Encoder=e
{
float Position_KP,Position_KI,Position_KD;
static float BIAS,PWM,LAST_BIAS,LAST_TWO_BIAS;
BIAS=Encoder;
INTEGRAL_BIAS+=BIAS;//i+=j=>i=i+j
PWM=Position_KP*(BIAS-LAST_BIAS)+Position_KI*(BIAS)+Position_KD*(BIAS-2LAST_BIAS+LAST_TWO_BIAS);//PID计算公式LAST_TWO_BIAS=LAST_BIAS;
LAST_BIAS=BIAS;
return PWM;
}
最终输出部分也一样
3,串级PID
初始化部分:
float Kp,Ki,Kd;
float err; //此次误差
float last_err; //上次误差
float err_sum=0; //误差累加
float err_difference; //误差的差值
float VKp,VKi;
float filt_velocity; //滤波后的速度
float last_filt_velocity;//上一次的滤波后的速度
float velocity_sum=0; //速度的累加
直立环PID控制函数部分:
int vertical_PID_value(float measure,float calcu)
{err = measure - calcu; //误差
if(err>=-1&&err<=1)
{err=0;}
err_sum+=err; //误差的累加
err_difference = err - last_err; //误差的差值
last_err = err; //此次误差记录为“上次误差”
return Kp*err + Ki*err_sum + Kd*err_difference;
}
速度环PID控制函数部分:
int velocity_PID_value(int velocity)
{
float a; //滤波系数(反映滤波程度)
filt_velocity = a*velocity + (1-a)*last_filt_velocity; //一阶速度滤波
velocity_sum += filt_velocity; //速度的累加
I_xianfu(3000); //累加限幅
last_filt_velocity = filt_velocity; //此次速度记录为“上次速度”return VKp*filt_velocity + VKi*velocity_sum;
}
最终输出部分:
void shuchu(void)
{
measure = pitch; //pitch测量值
calcu = zhongzhi; //roll理论值velocity = ( read_encoder2() + read_encoder3() )/2; //速度测量值
//PID计算:直立环+速度环
PWM = vertical_PID_value(measure, calcu) + velocity_PID_value(velocity);
PWM_Xianfu(7000,&PWM); //PWM限幅}
串级PID本人是以直立平衡小车为例子,上面的pitch就是MPU6050的俯仰角。大家可以去做一个直立平衡小车,这不仅可以大大提高你对PID的理解,更会让你对PID调参的熟练。大家除了用肉眼通过观察小车的状态去调参,还可以用上位机去调参,更方便快速。
三,实战项目
这里我自己写了一个关于PID单环控制的循迹小车,详细代码将放在最后的结尾处。
关键代码部分:
control.c
#include "stm32f10x.h" // Device header
#include "control.h"
#include "PWM.h"
#include "xunji.h"
#include "Motor.h"
//位置式PID
int OUTPUT1,OUTPUT2;// OUTPUT 是控制舵机的PWM输出值; OUTPUT1 和OUTPUT2 是控制小车左右轮速度的PWM输出值
int PID_xs=0;//小车差速PID控制器的PWM输出值
extern int e;//e就是误差
//这里使用定时器的原因就是用定时中断来更新PWM值,使小车按预期目标运行
void TIM3_IRQHandler(void)//TIM3中断服务函数
{
if(TIM3->SR&0X0001)//定时器每10ms定时中断一次
{
TIM3->SR&=~(1<<0);//清除定时器三的计时标志,执行完TIM3中断服务函数里的操作后定时器会重新计时
PID_xs=PositionPID(e);//将差速PID控制器输出的PWM值赋给PID_xs
xianfu_PID();//限幅函数
sc();//PWM输出函数
}
}
int PositionPID(int Encoder)//差速PID控制器
{
float Position_KP=500/*快*/,Position_KI=0.65/*准*/,Position_KD=4500/*稳*/;
static float BIAS,PWM,LAST_BIAS,INTEGRAL_BIAS;
BIAS=Encoder;
INTEGRAL_BIAS+=BIAS;//i+=j=>i=i+j
if(INTEGRAL_BIAS>500)INTEGRAL_BIAS=500; //限制INTEGRAL_BIAS的值避免太大
if(INTEGRAL_BIAS<250)INTEGRAL_BIAS=250; //限制INTEGRAL_BIAS的值避免太小
PWM=Position_KP*BIAS+Position_KI*INTEGRAL_BIAS+Position_KD*(BIAS-LAST_BIAS);//PID计算公式
LAST_BIAS=BIAS;
return PWM;
}
void sc(void)
{
OUTPUT1=4000+PID_xs;//直接给初始的PWM
OUTPUT2=4200-PID_xs;
TIM_SetCompare2(TIM2,OUTPUT1);//左右两轮的PWM
TIM_SetCompare3(TIM2,OUTPUT2);
}
void xianfu_PID(void)//限幅函数
{
if(OUTPUT1>7200)OUTPUT1=7200;
if(OUTPUT1<0)OUTPUT1=0;
if(OUTPUT2>7200)OUTPUT2=7200;
if(OUTPUT2<0)OUTPUT2=0;
}
四,总结
PID是大家学习控制的核心算法,也是大家读我这篇文章了解到的第一个算法,相信大家看到这里,对PID已经有较为熟悉的认知,大家要多去实战,加深自己的理解,大家在本科阶段了解,以及会初步使用PID是非常够了的,如果想要更优秀,不仅要会把PID更广泛的应用,而且也要了解其他的算法,特别是深度学习和神经网络这方面,根据近几年的电赛来看,由开始的PID应用,开始朝向视觉和PID综合发展,所以革命尚未成功,同志仍需努力呀!
下面是我为大家提供得完整的PID单环控制的小车代码。
链接:https://pan.baidu.com/s/1afFMh8jH613rrMmVsnzDRw?pwd=yl66
提取码:yl66
祝大家学业有成!我们,后会有期!