我最近做了一个关于温度控制的项目。 我会记在这里。 方便以后找。 另外,也请作为参考。 欢迎您的指正。 所有的数据都是实验数据,绝对真实。
1 .位置式PID控制原型: u(t )=kp*e(t ) t ) ki*[e(1)1(e )2(e ) t ) ]KD*[e(t )-e(t-1 ) ]
2 .控制对象:控制加热/制冷机(2分钟内不能再加热后切换至冷却)、密闭腔体(空间体积大小15cm*20cm*65cm )的温度。
3 .控制原理: MCU输出比较模块(OCM )产生PWM波驱动h桥电路(目标温度与环境温度对比确定加热或制冷)。
4.PID参数整定
温度控制是滞后控制系统,因此可以采用工业控制中常用的滞后控制参数整定模型(Ziegler-Nichols参数整定方法)
控制器
Ti
Td
京坂府
Ki
Kd
p
0.5Kc
PD
0.15Pc
0.65Kc
Kp*Td/T
PI
0.85Pc
0.45Kc
Kp*T/Ti
PID
0.5Pc
0.15Pc
0.65Kc
Kp*T/Ti
Kp*Td/T
参数说明:
(Kc )在仅采用比例控制的条件下,使控制系统的稳态误差最小时的Kp值。
Pc :在仅采用比例控制的条件下,控制系统的振荡周期。
Ti :控制系统的积分时间。
Td :控制系统的微分时间。
T: PID控制采样计算周期。
Kp、Ki、Kd :整定的参数。
1 )获取适当的Kc值,将Ki、Kd设定为0。 当前温度进入目标温度3.5后开始PID控制,以前采用90%恒功率加热。
图1(KC=5) )。
图2(KC=9) )。
图3(KC=20 ) )。
从上述4组数据可以看出,Kc=5时,控制系统的稳态误差最小。 在目标范围的正负3之间选择Kc=5。
2 )计算Pc值。 使用excel转换上面的图1(.CSV格式的数据文件,并将鼠标悬停在曲线上,将自动显示此点的坐标。 如图所示,取4个振动周期的合计720点,1个振动周期为Pc=720*5/4=900s。
3 )根据个人需要采用哪个PID组合,计算Ti、Td、Kp、Ki、Kd。 温度控制是滞后控制,但在PID控制中微分项具有超前调节的作用,必须引入; 积分项对误差的作用依赖于时间的积分,随着时间的推移积分项变大。 这样,即使误差小,积分项也随时间而变大,使控制器的输出向稳态误差变小的方向变化,直到稳态误差为零。 我用PID的组合控制。 Ti=900*0.5=450s。 Td=900*0.15=135s。
Kp=5*0.65=3.25; Ki=Kp*T/Ti=3.25*5/450=0.036; Kd=Kp*Td/
T=3.25*135s /5=88。4):采用PID控制温度,无论高温低温,稳态误差均在正负0.5°范围之内。如下所示:
一般根据模型计算的参数不一定是适合所有的控制系统(这里实验得到的最佳Kd值为120,而我们算出来的是88),根据特定的环境调节参数范围,找到最优参数,因本系统是滞后系统,微分项起主导作用,我暂时还只做了调整kd值的实验,Ki一般反应在系统达到稳态的时候是否存在稳定误差,从实验结果得出,稳态误差几乎可以忽略。
零下一度的目标温度,连续8小时的温度控制数据:
附录://PWM频率为1Khz,定时器的计数周期为5000(mPID.MaxDuty = 5000*90%),PID返回值和上次的的定时器技术值决定本次的占空比。
INT32 PID_calculate(double CurTemp)
{
INT32 RetValue;
doubleresult_value;
// Keep previouserror
mPID.PrevError =mPID.Error;
// calculatecurrent error
mPID.Error =mPID.Target - CurTemp;
// calculateintegral
mPID.SumError +=mPID.Error;
if(mPID.Kd >0.0001)
{
result_value =mPID.Kp * mPID.Error + mPID.SumError * mPID.Ki +
mPID.Kd* (mPID.Error - mPID.PrevError);
}
else
{
result_value =mPID.Kp * mPID.Error + mPID.SumError * mPID.Ki;
}
RetValue =(INT32)result_value;
return RetValue;
}
//Timer interrupt enable control flag, execute temperaturecontrol.
//
void TemperatureControl()
{
INT32 ret = 0;
if(mPID.type ==HEAT)
{
INT32 DutyValue= OC4RS;
if(fabs(mPID.Current- mPID.Target) <= PIDControlStartPoint)
{
PIDControlStartPoint = 12;
ret =PID_calculate(mPID.Current);
}
elseif(fabs(mPID.Current - mPID.Target) <= TempControlStartPoint)
{
OC4RS = INITPWMPERIOD16 * 50 / 100.0;
ret = 0;
return ;
}
else
{
ret = 0;
}
if( (DutyValue+ ret) > mPID.MaxDuty)
OC4RS =mPID.MaxDuty;
else if(DutyValue+ ret < mPID.MinDuty)
OC4RS =mPID.MinDuty;
else
OC4RS +=ret;
}
else if(mPID.type== COOL)
{
INT32 DutyValue= OC3RS;
if(fabs(mPID.Current - mPID.Target) <= PIDControlStartPoint)
{
PIDControlStartPoint = 12;
ret =PID_calculate(mPID.Current);
ret = -ret;// must be negative
}
elseif(fabs(mPID.Current - mPID.Target) <= TempControlStartPoint)
{
if(mPID.Target > 5.1)
OC3RS =INITPWMPERIOD16 * 70 / 100.0;
else
OC3RS =INITPWMPERIOD16 * 78 / 100.0;
ret = 0;
return ;
}
else
{
ret = 0;
}
if( (DutyValue+ ret) > mPID.MaxDuty)
OC3RS =mPID.MaxDuty;
elseif(DutyValue + ret < mPID.MinDuty)
OC3RS =mPID.MinDuty;
else
OC3RS +=ret;
}
else
{}
}