一、PID算法简介
在智能车竞赛中,要想让智能车根据赛道的不断变化灵活的行进,PID算法的采用很有意义。
首先必须明确PID算法是基于反馈的。一般情况下,这个反馈就是速度传感器返回给单片机当前电机的转速。简单的说,就是用这个反馈跟预设值进行比较,如果转速偏大,就减小电机两端的电压;相反,则增加电机两端的电压。
图1 PID框架图
控制器公式为:
式中:Kp——比例放大系数 KI——积分放大系数 KD——微分放大系数
顾名思义,P指是比例(Proportion),I指是积分(Integral),D指微分(Differential)。在电机调速系统中,输入信号为正,要求电机正转时,反馈信号也为正(PID算法时,误差=输入-反馈),同时电机转速越高,反馈信号越大。要想搞懂PID算法的原理,首先必须先明白P,I,D各自的含义及控制规律: 比例P:比例项部分其实就是对预设值和反馈值差值的发大倍数。举个例子,假如原来电机两端的电压为U0,比例P为0.2,输入值是800,而反馈值是1000,那么输出到电机两端的电压应变为U0+0.2*(800-1000)。从而达到了调节速度的目的。显然比例P越大时,电机转速回归到输入值的速度将更快,及调节灵敏度就越高。从而,加大P值,可以减少从非稳态到稳态的时间。但是同时也可能造成电机转速在预设值附近振荡的情形,所以又引入积分I解决此问题。 积分I:顾名思义,积分项部分其实就是对预设值和反馈值之间的差值在时间上进行累加。当差值不是很大时,为了不引起振荡。可以先让电机按原转速继续运行。当时要将这个差值用积分项累加。当这个和累加到一定值时,再一次性进行处理。从而避免了振荡现象的发生。可见,积分项的调节存在明显的滞后。而且I值越大,滞后效果越明显。 微分D:微分项部分其实就是求电机转速的变化率。也就是前后两次差值的差而已。也就是说,微分项是根据差值变化的速率,提前给出一个相应的调节动作。可见微分项的调节是超前的。并且D值越大,超前作用越明显。可以在一定程度上缓冲振荡。比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。 二、参数调整一般规则 由各个参数的控制规律可知,比例P使反应变快,微分D使反应提前,积分I使反应滞后。在一定范围内,P,D值越大,调节的效果越好。各个参数的调节原则如下: PID调试一般原则
a. 在输出不振荡时,增大比例增益P。 b. 在输出不振荡时,减小积分时间常数Ti。 c. 输出不振荡时,增大微分时间常数Td。
三、参数调整一般步骤 a.确定比例增益P 确定比例增益P时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0,PID为纯比例调节。输入设定为系统允许的最大值的60%~70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%~70%。比例增益P调试完成。 b.确定积分时间常数Ti 比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。 c.确定积分时间常数Td 积分时间常数Td一般不用设定,为0即可。若要设定,与确定 P和Ti的方法相同,取不振荡时的30%。 d.系统空载、带载联调,再对PID参数进行微调,直至满足要求 四、参数调整 PID控制器参数选择的方法很多,例如试凑法、临界比例度法、扩充临界比例度法等。但是,对于PID控制而言,参数的选择始终是一件非常烦杂的工作,需要经过不断的调整才能得到较为满意的控制效果。依据经验,一般PID参数确定的步骤如下: (1)确定比例系数Kp 确定比例系数Kp时,首先去掉PID的积分项和微分项,可以令Ti=0、Td=0,使之成为纯比例调节。输入设定为系统允许输出最大值的60%~70%,比例系数Kp由0开始逐渐增大,直至系统出现振荡;再反过来,从此时的比例系数Kp逐渐减小,直至系统振荡消失。记录此时的比例系数Kp,设定PID的比例系数Kp为当前值的60%~70%。 (2)确定积分时间常数Ti 比例系数Kp确定之后,设定一个较大的积分时间常数Ti,然后逐渐减小Ti,直至系统出现振荡,然后再反过来,逐渐增大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。 (3) 确定微分时间常数Td 微分时间常数Td一般不用设定,为0即可,此时PID调节转换为PI调节。如果需要设定,则与确定Kp的方法相同,取不振荡时其值的30%。 (4) 系统空载、带载联调 对PID参数进行微调,直到满足性能要求。
PID代码如下:
- #include
- #include
- typedef struct PID {
- double SetPoint; // 设定目标Desiredvalue
- double Proportion; // 比例常数ProportionalConst
- double Integral; // 积分常数IntegralConst
- double Derivative; // 微分常数DerivativeConst
- double LastError; // Error[-1]
- double PrevError; // Error[-2]
- double SumError; // Sums ofErrors
- } PID;
- //===================================================================================================
- //PID计算函数
- //==================================================================================================
- double PIDCalc( PID *pp, double NextPoint)
- {
- doubledError, Error;
- Error =pp->SetPoint - NextPoint; //偏差
- pp->SumError += Error; //积分
- dError =pp->LastError - pp->PrevError; //当前微分
- pp->PrevError =pp->LastError;
- pp->LastError =Error;
- return(pp->Proportion * Error //比例项
- +pp->Integral * pp->SumError //积分项
- +pp->Derivative * dError //微分项 );
- }
- //===================================================================================================
- //PID结构体变量初始化函数
- //===================================================================================================voidPIDInit (PID *pp)
- {
- memset ( pp,0,sizeof(PID));
- }
- //===================================================================================================//读取输入变量函数(在此设定为固定值100)
- //===================================================================================================doublesensor (void)
- {
- return 100.0;
- }
- //======================================================================//输出变量控制函数
- //=====================================================================voidactuator(double rDelta)
- {
- }
- //主函数
- void main(void)
- {
- PID sPID; //PID Control Structure
- double rOut;// PID Response (Output)
- double rIn;// PID Feedback (Input)
- PIDInit (&sPID ); // InitializeStructure
- sPID.Proportion = 0.5; // SetPID Coefficients
- sPID.Integral =0.5;
- sPID.Derivative =0.0;
- sPID.SetPoint = 100.0; // SetPID Setpoint
- for(;;)
- { // Mock Upof PID Processing
- rIn = sensor (); // ReadInput
- rOut = PIDCalc ( &sPID,rIn); // Perform PID Interation
- actuator ( rOut ); // EffectNeeded Changes
- }
- }
复制代码
|