1. 项目概述与核心思路
1.1 为什么用S7-1200做恒温热水器控制
之前接了一个小型恒温热水器的控制项目,客户要求把水温稳定在设定值正负1度以内,而且要在进水流量波动的情况下尽量不产生大幅温度起伏。我第一反应就是用温控表,但客户现场已经有了一套S7-1200 PLC在跑其他逻辑,不希望为了一个温度回路单独再上一块表,于是直接在S7-1200里做PID控制就成了最顺理成章的方案。
选择S7-1200而不是S7-200 SMART或者S7-300,主要考虑三点。第一,S7-1200的CPU自带模拟量输入输出通道,通过扩展SM1231/ SM1232或者直接用1214C DC/DC/DC再加模拟量模块,就能采集温度传感器信号并输出控制量给加热执行器,不需要额外的PID控制器硬件。第二,TIA Portal里集成了PID_Compact指令,这是西门子专门为S7-1200/1500做的PID功能块,内部已经封装好了抗积分饱和、手动/自动无扰切换、自整定等逻辑,比自己写位置式或增量式算法省太多事。第三,S7-1200的扫描周期足够快,PID运算一般放在OB30循环中断里执行,中断时间设个100到200毫秒,对温度这种大惯性对象来说完全够用。
这个项目的控制对象是一个储水式加热罐,加热管功率大概6kW,温度传感器用PT100,通过SB1231热电阻模块接入PLC。执行机构是可控硅调功器,输出4到20mA信号控制加热功率。整个回路从传感器采样到加热功率变化,中间隔着水的热容量和罐体热传导,惯性很大,纯靠手动开关加热的方式会让温度上下乱窜,所以必须用PID做闭环调节。
1.2 PID控制方案选型:串联级联还是单回路
有朋友问过我,恒温热水器需不需要上串级PID。串级PID一般用在对象滞后很大、或者说内外两个被控量之间有明显耦合关系的场合,比如加热炉的外壁温度和炉膛温度,或者蒸汽换热器的出口温度和蒸汽流量。热水器这种单容对象,水的混合和传热过程虽然有一定惯性,但用单回路PID加合理的参数整定就能达到不错的控制效果,上串级反而会把系统搞复杂,调起来也麻烦。
那有没有必要用模糊PID或者自适应PID呢?实话说,S7-1200的PID_Compact里已经包含了自适应能力——它可以根据过程值的变化趋势动态调整部分参数,但对于恒温热水器这种工况相对固定的对象,固定参数的PID完全够用。我最后采用的是单回路PID_Compact,控制模式选为“温度调节”,输出直接控制可控硅调功器的电流信号。
这里也顺便说说位置式PID和增量式PID的区别。如果自己写算法,位置式PID输出的直接是执行机构应该达到的开度绝对值,比如加热功率百分之六十;增量式PID输出的是在当前开度基础上的变化量,比如在当前开度上再加百分之二。位置式的缺点是容易出现积分饱和,也就是长时间偏差大时积分项不断累积,导致输出打到上限,误差消掉后还要很久才能退回来。增量式因为输出的是增量,天然不会积分饱和,但需要外部累加逻辑来记录当前实际输出值。PID_Compact内部用的是什么形式?看西门子的资料和反推它的行为,它实现的是带抗积分饱和的位置式PID变体,内部对积分项做了限幅和动态调整,所以不需要我额外处理积分饱和的问题。
2. 硬件配置与接线实操
2.1 硬件清单和信号类型选择
我的CPU选的是1214C DC/DC/DC,订货号6ES7 214-1AG40-0XB0。这个CPU自带14路数字量输入、10路数字量输出和2路模拟量输入,温度信号我额外加了一块SM1231 AI 4xRTD模块,用来接PT100热电阻。可控硅调功器的控制信号是4到20mA电流,所以还需要一路模拟量输出,于是又加了一块SM1232 AQ 2xAO模块。
这里要特别提醒,温度信号采样的硬件选型决定了后面PID控制的天花板。PT100用三线制接法接SM1231,西门子这个模块支持两线制和四线制,三线制需要把三根线分别接到对应通道的I+、I-和COM上。实际接线时我花了点时间整理屏蔽线和接地,因为现场有一台变频器在附近运行,如果屏蔽层接地处理不好,温度信号上会叠加高频干扰,PID运算出来的结果就会抖得厉害,输出电流也跟着来回摆。
模拟量输出到可控硅调功器,信号线用屏蔽双绞线,屏蔽层单端接地。可控硅调功器的输入阻抗一般是250欧姆,4到20mA信号对应0到100%功率。我在程序里把PID_Compact的输出上限设为100.0,下限设为0.0,输出值直接作为模拟量输出的工程量百分比。
2.2 硬件接线中的几个坑
第一个坑是PT100传感器的接线。SM1231模块的通道端子是分A、B、C三个接线位的,三线制PT100的红色线(电源线)接I+,另一根红色(同一根,PT100三线制实际上就是热电阻两端各引出两根线,其中一端有两根线会并联成一个公共端)接COM,白色线对应另一端的信号线接I-。这里如果不仔细看模块端子图,很容易把三根线顺序接错,导致温度读数偏差或者干脆报错。
第二个坑是模拟量输出模块的供电。SM1232需要外部供电才能输出4到20mA信号吗?其实它由背板总线供电,但输出回路的负载电阻大小会影响精度。我用的调功器输入阻抗约250欧姆,属于模块的推荐负载范围。如果遇到输入阻抗更大的执行器,比如500欧姆以上,就需要确认模块是否还能满足精度要求,不然输出电流会偏低。
第三个坑是接地和布线。这种模拟量信号最怕和动力线走同一个线槽。我第一次调试时温度值一直在正负0.5度左右波动,后来把所有模拟量信号线单独走了一个弱电线槽,离动力线至少保持30厘米以上,波动明显小了很多。
3. TIA Portal中PID_Compact的组态与参数设置
3.1 添加PID_Compact指令
打开TIA Portal V16,在OB1里可以从“指令”选项卡的“PID控制”下找到PID_Compact V2.2版本的指令。拖拽到程序段中时,系统会提示为PID_Compact分配一个背景数据块,我给它命名为“DB_PID_WaterHeater”。
PID_Compact指令的背景数据块里包含了一堆参数,包括Setpoint(设定值)、Input(过程值)、Output(输出值)、ManualEnable(手动模式使能)、ManualValue(手动输出值)、Retain参数等。实际编写程序时,我是在OB30循环中断里调用PID_Compact的,这样时间基准稳定,PID运算周期可控。
如果放在OB1里调用,由于OB1的扫描周期会随着程序量变化,PID的采样时间就不固定,控制效果会变差。把PID_Compact放在OB30里调用,中断时间设为200毫秒,这样每一轮PID运算间隔都是恒定的200毫秒。
3.2 设定值、过程值、输出值的量纲处理
PID_Compact的输入输出都是实数,且范围默认是0到100,代表百分比。对于温度控制,我做了这样的映射:PT100通过SM1231读到的原始温度值(比如45.6),我直接在程序里用SCALE_X指令或者直接做标准化,把0到100摄氏度映射到0到100的PID量程。
这里有个关键点:如果将Input直接连接到温度值(比如45.6度)而PID_Compact内部认为最大值就是100,那45.6在内部计算时会被当成45.6%来处理,控制逻辑会错乱。所以必须明确量程。我在输入侧这样处理:
"DB_PID_WaterHeater".Input := INT_TO_REAL("测温模块通道".温度原始值) / 100.0 * 100.0;其实更规范的做法是给PID_Compact组态一个InputScaler。在PID_Compact的属性中有一个“输入缩放”选项,可以定义InputPerOn(输入上限工程值)、InputPerOff(输入下限工程值)。我把InputPerOn设为100,InputPerOff设为0,Input直接连实际温度值45.6,PID_Compact内部就知道45.6对应于45.6%的量程。
输出侧也类似。Output默认是0到100,可以直接接到模拟量输出的格式化指令上。SM1232模块在TIA中组态成4到20mA信号,程序里将0到100的实数输出线性映射为0到27648的整数,然后送到模拟量输出地址。这一步要用NORM_X和SCALE_X指令完成。
3.3 PID参数组态界面详解
PID_Compact组态界面分几个Tab:基本设置、参数、输出限制、高级设置。我习惯先在“基本设置”里选择控制类型为“温度”,因为温度对象一般是一阶惯性加纯滞后,PID_Compact会根据控制类型给出默认的算法结构。
“参数”选项卡里能看到自动模式和手动模式两套PID参数。自动模式下可以填PID增益、积分时间、微分时间,也可以勾选“微分激活”。温度控制我一般不建议开太大的微分作用,因为温度信号本身噪声不大,但微分对高频噪声敏感。S7-1200 PID_Compact里微分项是作用于过程值的,也就是只对测量值变化率做响应,不作用于设定值变化,这样可以避免设定值改变瞬间输出发生冲击。
“输出限制”选项卡里可以设定输出上限、下限以及输出变化率限制。对于可控硅调功器,变化率限制比较重要。如果允许输出从0%直接跳到100%,可能让加热管和供电线路承受较大的冲击电流,甚至会因为水温惯性造成超调。我这里设了最大变化率为每秒钟10%,相当于输出从0到100需要10秒,加热功率是斜坡上升的,实际运行效果不错。
3.4 PID_Compact的自整定功能
S7-1200 PID_Compact自带自整定,里面有两个模式:“启动阶段整定”和“运行阶段整定”。自整定按钮在在线模式下,监控PID_Compact的背景数据块时可以看到“Start Self-tuning”的触发位。
自整定的原理是:PID_Compact会先强制输出一个阶跃信号(从当前值突然增加或者减少一定幅度的输出),观察过程值(温度)的响应曲线,然后基于响应曲线上的一阶惯性加纯滞后模型来推算PID参数。这个方法本质上是基于反应曲线法和Ziegler-Nichols经验公式的工程实现。
在实际项目的自整定过程里,我先把设定值设到了45度,此时水温从常温开始加热,PID_Compact先以开环方式让温度爬升到接近设定值,然后自动开始阶跃扰动测试。整定过程大概持续了5分钟,期间输出有一个明显的小幅阶跃变化。整定完成后,背景数据块里的PID参数被自动更新。
自整定得到的结果能否直接用?我的经验是,自整定参数可以作为很好的初始值,但要根据实际运行效果再微调。比如自整定给的积分时间可能偏短,系统会有点振荡。我这次自整定后得到的增益约8.5,积分时间约120秒,微分时间被自动设为0。实际运行时水温在设定值附近有大约正负0.8度的波动,我手动把增益降到6.0,积分时间提高到150秒,波动收窄到正负0.3度以内。
4. 手动整定PID参数的完整流程
4.1 工程上的整定顺序
有人会问,能不能不自整定,直接手动调?完全可以,而且了解了手动整定的思路,才能更好地理解自整定给你的参数意味着什么。我整理了一套适合温度对象的整定流程。
第一步,先把积分和微分全部关掉,只保留比例项。也就是说,积分时间设成很大(相当于不积分),微分时间设成0。然后给一个设定值,观察温度变化。举个例子,如果设定值是50度,刚开始加热时温度慢慢爬升,接近设定值时,由于纯比例控制存在稳态误差,最后温度可能停在47度就上不去了。这时把增益逐步加大,比如从2.0加到4.0再到6.0,观察哪个增益下温度在设定值附近开始出现周期性小振荡。临界振荡的增益记为临界增益Ku。
第二步,在纯比例临界振荡的基础上测量振荡周期Tu。然后在工程上通常用Ziegler-Nichols参数表来整定,比如:
| 控制规律 | 比例增益Kp | 积分时间Ti | 微分时间Td |
|---|---|---|---|
| P | 0.5Ku | — | — |
| PI | 0.45Ku | 0.85Tu | — |
| PID | 0.6Ku | 0.5Tu | 0.125Tu |
我这次用的是PID_Compact本身对温度对象的处理方式,未开微分,所以可以按PI规律来参考。实测得到Ku约为12.0,Tu约为50秒,那么参考值就是Kp约5.4,Ti约42.5秒。但这是临界比例法给出的保守参数,实际加上分别调整后,我用Kp=6.0、Ti=150秒效果反而更好,原因在于温度对象滞后较大,过短的积分时间会加剧振荡。
第三步就是微调。增益偏大会产生超调,增益偏小会有稳态误差;积分时间偏大是调节太慢,偏小是产生低频振荡。我调完参数后做的第一个测试是设定值从45度阶跃到50度,观察实际温度曲线的超调量。最终调出来超调量在1度以内,调节时间约3分钟,达到了客户的期望。
4.2 PID参数整定中的关键观察指标
调试时不能只盯着温度最终稳不稳,要同时看两个信号:温度过程值和PID输出值。在TIA Portal的监控表里,我同时加了“DB_PID_WaterHeater”.Input和“DB_PID_WaterHeater”.Output,用趋势视图观察。
如果温度在设定值附近持续小幅振荡,幅度大约正负0.5度,且输出也在周期性波动,说明增益偏大或者积分时间偏短。如果温度偏离设定值后长时间回不来,比如进水流量突然增大导致温度跌了2度,过了5分钟还没回到设定值附近,说明积分作用太弱或者增益太小。
还有一个非常有用的观察点——输出变化率的合理性。温度控制的电动调节是慢工出细活,如果输出值像锯齿一样频繁大幅变动,说明参数过于激进,对执行机构和供电线路都是不利的。
另外,我建议在PID_Compact的输出侧加一个低通滤波或者SM1232模块本身的平滑处理来稳定输出吗?对于可控硅调功器,其实可以用这种方式减小输出的频繁跳变。但要注意,PID_Compact的输出已经经过其内部的输出值平滑处理,采样周期固定为200毫秒,只要参数不是太激进,输出不会太跳。
5. 程序逻辑与辅助功能实现
5.1 手动模式和自动模式的无扰切换
PID_Compact自带手动/自动切换功能,通过ManualEnable输入指定。ManualEnable为FALSE时是自动模式,为TRUE时是手动模式。手动模式下,输出值直接由ManualValue决定,PID算法仍然在后台计算,保证切换回自动模式时输出不会突变,这就是无扰切换。
我在工程上做了两个辅助逻辑:一是当系统刚上电、温度还没建立起来的时候,强制切到手动模式,输出一个较小值比如20%进行预热,避免PID在温度很低时因为偏差过大导致输出直接冲到100%。二是当温度超过安全上限比如80度时,无论当前模式是什么,都直接切断加热输出,这个逻辑放在PID_Compact输出的后面作为硬性保护。
这个安全上限的逻辑很重要,尤其是PID处于自动模式时,如果温度传感器出现故障(比如断线),过程值会突然变成负值或者不正常的数值,PID会误以为温度偏低而全功率加热,非常危险。所以程序里我加了传感器断线检测功能,一旦SM1231反馈的通道状态位为故障,立即将输出切为零,并在人机界面上报警。
5.2 设定值斜坡功能
另一个实用的功能是设定值斜坡。PID_Compact支持设定值斜坡发生器(Setpoint Ramp),可以在组态里启用。这个功能的作用是让设定值不是阶跃变化,而是按指定的速率缓慢变化到目标值。比如设定值从45度改到55度,如果不加斜坡,PID会立刻感受到10度的偏差,增益又大,输出瞬间打满,温度超调会很大。加上斜坡后,设定值以每分钟1度的速率爬升,整个升温过程平稳很多。
我在组态里把斜坡上升速率设为每分钟2度,下降速率同样每分钟2度。这样做在换班或调整目标温度时非常好用,避免了每次都把水温冲过头再降下来,浪费能量。
5.3 模拟量输入输出处理的标准程序片段
下面是我在OB30里调用PID_Compact时的核心程序片段,供参考:
// OB30中,200ms循环中断 // 模拟量输入 - 温度值标准化(SM1231的CH0,整型,4-20mA对应PT100量程) "温度原始值" := "SM1231_CH0".AI_RAW; // 0~27648 "温度工程值" := INT_TO_REAL("温度原始值") * 100.0 / 27648.0; // 0~100度映射 // 手动/自动切换 "DB_PID_WaterHeater".ManualEnable := "HMI手动模式"; "DB_PID_WaterHeater".ManualValue := "HMI手动输出百分比"; // 调用PID_Compact "DB_PID_WaterHeater"( Setpoint := "目标温度", Input := "温度工程值", Output => "PID输出百分比" ); // 输出限幅处理(在PID内部已完成,这里做安全保护) IF "温度工程值" >= 80.0 OR "传感器故障信号" THEN "加热输出指令百分比" := 0.0; ELSE "加热输出指令百分比" := "PID输出百分比"; END_IF; // 输出标准化至模拟量模块(SM1232,0~27648对应4~20mA) "输出原始值" := REAL_TO_INT("加热输出指令百分比" * 27648.0 / 100.0); "SM1232_CH0".AQ_RAW := "输出原始值";注意一个细节:PID_Compact的Input我连接的是温度工程值,量程是0到100度。如果现场最高温度超过100度,比如热水器可能到120度,那InputPerOn要相应改成120,否则PID内部计算会错误地认为过程值超量程。
6. 调试过程中遇到的典型问题与排查方法
6.1 温度振荡不停,PID输出也在大幅波动
这个问题在实际调试中最常见。我遇到过一次,温度在设定值附近正负1.5度持续振荡,输出电流也从4mA到20mA来回猛拉。排查步骤是这样的:
第一步检查传感器信号是否正常。用万用表在SM1231的端子上测PT100的电阻值,换算成温度后和程序里的读数对比。如果没有偏差,说明传感器和模块没问题。
第二步检查PID的采样周期是否设置正确。如果OB30的中断周期设成了200ms,而PID_Compact内部又从组态里读到了一个不同的采样时间,会导致控制节拍错乱。这个可以通过在趋势视图里看Output是每200ms更新一次还是不定期跳变来判断。
第三步是回头去看参数。振荡多半是因为增益太大或者积分时间太短。我的做法是把PID参数先切到手动模式,输出一个固定值比如50%,等温度稳定后再切回自动模式,观察切换瞬间的输出变化。如果自动模式一开始输出就有大幅阶跃,说明增益设置过于敏感。
6.2 设定值附近始终有残余偏差
这种情况和前面的振荡相反,温度可能稳定在设定值以下0.8度就再也不动了。纯比例控制有静差是正常的,但PID_Compact默认是有积分项的,所以不会出现比例控制那种静差。如果还有偏差,先检查积分时间是否设太大,比如设到3000秒以上,积分作用几乎不存在。如果积分时间合理,还要检查PID_Compact是否处于手动模式,或者积分项是否被保持功能冻结了。
另外,PID_Compact的背景数据块里有一个参数叫“ResetIntegral”,当它被触发时会清零积分。如果程序里不小心把这个位置为TRUE,积分永远累积不起来,同样会有静差。我犯过这个错,排查了很久才注意到是有人误触发了这个保持位。
6.3 输出不够大,温度怎么都提不上去
这通常是量程映射的问题。我遇到过一次,PID输出已经打到100%,但加热棒就是不工作。查了一圈发现是SM1232的输出接线接反了,4到20mA的负极没有接对。还有一种情况是PID_Compact的输出上限被设成了50%,导致无论怎么调增益,输出都最多只有50%。
从现象上区分这两种原因的办法是:在监控表里强制给SM1232通道发一个20mA对应的值27648,如果加热棒能全功率工作,说明执行机构和输出通道没问题,问题在PID组态;如果强制输出也不动作,那就要回头查硬件接线和模块配置。
6.4 常见问题速查表
| 现象 | 可能原因 | 快速排查方法 |
|---|---|---|
| 温度高频小幅波动 | 信号受到干扰或微分作用过强 | 检查屏蔽接地,关闭微分 |
| 温度长时间缓慢波动 | 积分时间过短 | 增大积分时间 |
| 温度稳定但有静差 | 积分项异常或ManualEnable误置真 | 检查ResetIntegral和ManualEnable |
| 输出经常打到上限 | 输出限制设置不合理或增益过小 | 检查输出上限和PID参数 |
| PID参数自整定失败 | 工艺过程中存在强干扰或系统不稳定 | 先手动稳定工况再自整定 |
| 传感器断线导致全功率加热 | 缺少断线检测保护 | 添加通道状态判断和输出安全逻辑 |
6.5 自整定的使用建议
自整定不是万灵丹,它对工况稳定性的要求比较高。如果整定过程中进水流量波动频繁,或者恒温罐的负载时大时小,自整定给出的参数可能不靠谱。我建议在夜间或者产线停机的时候做自整定,尽量让对象处于一个相对稳定的条件下。
而且自整定完成后要观察一段时间,至少一个完整的升温-保温周期。有些参数在设定值附近看还行,但在升温过程中可能出现超调。我自己习惯用“自整定参数打底加经验微调”的组合策略,这样既走捷径又保留了对工况的掌控感。
7. 实际运行效果
项目交付后已经运行了将近两个月,水温控制稳定在设定值正负0.3度左右。客户的进水流量大约每小时200升,温度设定在45到55度之间可调,从25度进水加热到设定温度大约需要10到15分钟。能耗方面,PID控制明显比之前他们用的通断式温控器节省电能,因为加热功率是连续调节的,不像通断式那样频繁地满负荷启停。
有人问过我为啥不直接买一台市售温控器非要费劲在PLC里做PID,其实除了前面说的硬件复用考虑,还有一个重要原因是客户想把温度曲线记录下来,做生产追溯。PLC方案天然能和HMI、上位机通信,实时记录温度趋势和加热功率曲线,这是传统温控器做不到的。
这个项目做完之后,我的体会是S7-1200的PID_Compact指令其实已经把很多底层细节封装好了,但真正决定控制效果的不是指令本身,而是对过程对象的理解和对参数整定逻辑的把握。你如果能说清楚你的对象是快是慢、是纯滞后还是一阶惯性,再去看PID参数该往哪个方向调,心里就有底了。最后分享一个小技巧——调试结束后别忘了把PID参数备份一份到存储卡里,免得以后程序被误删或者CPU更换时重新调参。