两部四层群控电梯这个项目,说小不小,说大也真不大,但里面该有的东西一样不缺:PLC程序架构、群控调度算法、HMI画面组态、仿真联调,全套流程走下来,对新手练手或者老手做方案验证都是很合适的载体。我做这个项目的时候选的是西门子1200配合博图TIA Portal和WinCC仿真环境,没有用真实电梯井道和物理按钮,而是全部在软件里把逻辑跑通,再把HMI画面通过内部变量跟PLC程序联动起来。整个过程走下来,我觉得最值得分享的不是某个具体的功能块怎么写,而是整个项目从0到1的拆解思路,以及哪些地方特别容易让人栽跟头。
这篇文章我就按我自己实际做这个项目的顺序来写:先讲整体设计和选型考虑,再拆PLC程序与调度逻辑,然后说WinCC画面组态和仿真联调,最后把我在调试中遇到的一堆怪问题整理成排查清单。内容尽量写得“能直接用”,你看完至少能复制一套自己的仿真群控电梯出来。
1. 项目整体设计与方案选型
1.1 群控电梯到底在解决什么问题
所谓群控,就是两台或两台以上的电梯共用一个侯梯厅的呼叫按钮,用一个调度系统决定“哪台梯去响应这次呼梯”。电梯多了之后,问题就来了:如果两台电梯各干各的,很可能出现两台梯同时跑到同一层去服务同一个呼梯,另一层有人等了半天却没人去,效率很差。群控要做的事情,就是通过统一的调度逻辑,让两台梯的响应范围尽量错开,减少重复响应,缩短平均等待时间。
这个项目里是两部电梯、四个楼层,结构不算复杂,但麻雀虽小五脏俱全。四层楼意味着有四个外呼按钮(上行/下行),每部电梯有四个内呼按钮,还有轿厢位置、运行方向、开关门状态这些信号。把这些信号理清楚,调度逻辑才有依据。我做这个项目的时候,给自己定了一个原则:先把单梯逻辑搞干净,再做群控调度,最后才碰画面。单梯逻辑不干净,群控就是空中楼阁。
1.2 为什么选西门子1200而不是200 SMART或1500
很多人上来就问:这不就是个简单控制吗,用200 SMART不是更便宜?说实话,200 SMART做单梯很轻松,但做群控就会暴露短板:通信能力弱、指令集精简、数据块管理不方便。算法稍复杂一点,程序写起来就非常别扭,尤其是做派梯运算时,数组处理、结构体封装、间接寻址这些能力,200 SMART用起来远不如1200顺手。
S7-1200的优势在于它是西门子博图平台的入门主力,支持STRUCT、ARRAY、UDT(用户自定义数据类型),数学运算指令丰富,而且自带以太网口,支持S7通信和开放式TCP/UDP通信。更重要的是,1200可以直接在博图里启用“仿真”功能,不需要实物PLC就能调试程序,这对没有设备环境的人来说是很大的便利。
至于1500,性能确实更强,但做四层两梯的群控属于“杀鸡用牛刀”,而且1500的价格标签摆在那,学习和演示成本都偏高。所以综合下来,1200是这个项目最合适的选择。我在博图里用的是CPU 1214C DC/DC/DC这个型号,理由是它自带14个数字量输入和10个数字量输出,对本项目来说I/O容量刚好够用,扩展模块都不用加。
1.3 仿真环境搭建与项目配置的几个关键点
选择博图版本的时候要先想清楚,我用的TIA Portal V16,配WinCC Professional(也就是博图内置的WinCC)。这个组合支持对PLC程序进行仿真,并且HMI画面仿真也能同时跑起来,两者之间通过虚拟连接完成数据交换。如果你用的是V13、V15或V17,操作逻辑基本一样,但个别菜单名称和图标位置略有出入。
建项目时有几个关键点我踩过坑,先提前说明:
- PLC选型要和博图版本兼容:TIA V16完美支持S7-1200全系列,但要注意固件版本。比如CPU 1214C出厂固件是V4.0,博图V16默认支持V4.1以上,可以在组态里把固件版本改成与仿真一致。
- HMI组态时要选“WinCC Professional”,而不是“WinCC Comfort”,因为只有Professional版本才支持通过仿真实现全功能联动。严格来说Comfort也能仿真,但功能受限,尤其在画面脚本和系统函数上会卡脖子。
- 仿真时PLC和HMI要在同一个项目中,不要分开建两个项目再调用。分开建也行,但连接配置会麻烦很多,新手没必要自找苦吃。
项目建好后,第一件事就是把PLC的IP和HMI的以太网地址规划好。我给自己定的是PLC地址192.168.0.1,HMI地址192.168.0.2,同一个网段,方便仿真时内部通信直接通过虚拟网卡完成。
2. 电梯单机控制程序架构与I/O规划
2.1 四层两梯的输入输出信号清单
写程序之前,我强烈建议先把I/O表列出来。这一步看着简单,但决定了后续所有编程工作的稳定性。我做这个项目时,信号规划大致如下:
每部电梯的输入信号:
- 限位信号:1楼至4楼平层限位(4个数字量输入)
- 轿厢内呼按钮:1楼至4楼(4个数字量输入,也可以是触摸屏上的内部变量)
- 轿厢门状态:开门到位、关门到位(2个数字量输入)
- 运行反馈:上行接触器反馈、下行接触器反馈(2个数字量输入)
每部电梯的输出信号:
- 运行方向:上行输出、下行输出(2个数字量输出)
- 开关门:开门输出、关门输出(2个数字量输出)
- 楼层指示(也可以用通讯方式传给HMI,不必接物理输出)
两部电梯满打满算大概需要输入24点、输出12点,CPU 1214C自带14DI/10DO,明显不够,所以我额外组态了一个SM 1223数字量扩展模块(8DI/8DO)。如果你已经提前规划好,完全可以在一开始就选1215C或1217C,自带I/O数量更多,省得加扩展。这属于项目定型的细节,但直接影响后面所有工作。
2.2 PLC程序模块划分:OB、FC、FB的使用策略
写1200程序,我习惯按“主循环+功能封装+数据接口”的思路来组织。OB1是主组织块,FC和FB承担具体功能,DB用来存数据。
本项目我是这么划分的:
- OB1:主程序循环,按顺序调用各功能块
- FB1_Elevator_Single:单梯运行控制功能块,每个电梯一个实例DB,内部封装了平层判断、开关门时序和方向输出逻辑
- FC1_Call_Collect:呼梯信号采集与登记,处理外呼/内呼信号的锁存与消除
- FC2_Dispatch_Algorithm:群控调度算法,核心是派梯决策
- FB2_Door_Timer:开关门定时控制,管理开门保持时间、关门延时
- DB1_Common_Data:全局共享数据区,包括各电梯状态、呼梯登记表、调度结果
- DB2_Alarm_Data:故障信息记录
这里有个关键经验:单梯的运行逻辑一定要做成FB,并且用一个实例DB。两台电梯的结构完全一样,只是数据和I/O地址不同。做成FB以后,复制粘贴就能生成第二台梯的逻辑,只需要更换背景数据块和I/O映射。这是复用思维的体现,也大大减少改程序时漏改出错的可能。
2.3 单梯运行逻辑的几个关键状态与时序
电梯单机运行,核心就是“方向+平层+开门+关门”这个循环。我处理的时候把电梯状态分成几个典型状态:
- IDLE(待机):无任务,停在某层,门关闭
- RUN_UP(上行):目标楼层在当前楼层上方,启动上行输出,直到目标平层
- RUN_DOWN(下行):目标楼层在下方,启动下行输出
- DOOR_OPEN(开门):平层停车后开门,开门到位后启动开门保持定时
- DOOR_CLOSE(关门):保持时间结束或收到关门命令后关门,关门到位后重新进入IDLE或响应下一个任务
关键时序上有几个容易犯错的地方:
第一是平层判断不要用方向继电器的反馈。程序里要维护一个“当前楼层”变量,在平层限位信号从0变1的那一刻更新当前楼层值。这个用边沿检测来做,在梯形图里就是R_TRIG或者P触点。比如电梯在2楼平层限位检测到上升沿,就把当前楼层写入2。用普通常开触点来更新的话,如果限位信号抖动,当前楼层值会来回跳,调度算法拿到错误楼层数据,派梯就全乱套了。
第二是方向输出必须加互锁。上行输出和下行输出在物理上绝对不能同时为1,否则接触器会短路,仿真环境里虽然不烧硬件,但逻辑上极其不严谨,而且一旦以后移植到真实设备就是大事故。梯形图里最简单的方式是上行输出回路串联下行输出常闭触点,下行输出回路串联上行输出常闭触点。软件层面的另一道保险是,启动上升方向时先复位下降方向的内部标志。
第三是开关门时序要用定时器做状态机。我用的方法是开门动作触发后,开信号置位,开门到位信号到位后再计时开门保持时间(我设置的是5秒),保持结束后自动触发关门。如果关门过程中遇到门区检测(仿真里可以用变量模拟),就重新开门。在纯仿真条件下没有物理传感器,这些信号都是内部变量,但时序逻辑还是要按真实场景来写,不能偷懒。
2.4 I/O映射与内部变量解耦的做法
还有一个编程习惯非常值得养成:程序内部不要直接使用物理I/O地址,而是通过I/O映射变量中转。
比如外呼信号的采集,我是在OB1的循环扫描里,先把物理输入I0.0~I0.7读入到DB块里的“外呼采集区”,程序里所有逻辑判断都用DB变量,输出也一样——先计算“想输出”的逻辑结果,放到DB输出区,最后统一把DB输出区写到Q点。这么做的好处有两个:
- 一旦物理接线或PLC的I/O通道有变动,只需要改映射部分,功能逻辑完全不用动
- 仿真时可以直接强制DB变量来模拟输入信号,比强制物理输入点方便得多,而且不会误触其他诊断功能
比如我在调群控算法的时候,就是直接给DB1里的“1楼外呼上行请求”变量置TRUE,完全不用通过HMI按钮,效率非常高。
3. 群控调度算法:两部四层电梯的派梯逻辑
3.1 调度信息的数据结构设计
群控调度光有单梯逻辑不够,必须有一个中央数据区来汇总所有电梯的状态和所有呼梯请求。我定义了一个UDT(用户自定义数据类型)来描述单部电梯的状态快照,字段包含:
- 当前楼层(INT)
- 当前方向(0停止、1上行、2下行)
- 当前状态(0待机、1运行、2开门、3故障)
- 已登记的内呼目标楼层表(ARRAY[1..4] OF BOOL)
- 已响应的外呼楼层表(ARRAY[1..4] OF BOOL)
然后定义一个全局DB,里面放两个这样的UDT变量(电梯1和电梯2),再加四个外呼信号变量:1楼外呼、2楼上行外呼、2楼下行外呼、3楼上行外呼、3楼下行外呼、4楼外呼。注意,四层楼的外呼按钮数量不是4个而是6个,因为中间层(2楼和3楼)要有上行和下行两个方向的按钮,这属于很典型的新手容易漏的细节。
布局放在DB里的好处是,两台电梯的FB可以方便地读这些数据,调度算法的输入输出都集中在一个地方,后续扩展成三梯四梯只需要在DB里加变量,算法稍微修改即可。
3.2 派梯算法的核心思路:最近距离优先
这个项目的群控算法我没有搞太复杂,用的是经典的最近距离优先算法(Shortest Distance First, SDF)。核心思想很简单:某个外呼信号登记后,计算每台电梯到这个呼梯楼层的代价,谁代价小谁去响应。
代价计算要考虑的不只是“距离近”,还有“方向顺不顺着”。举个例子:电梯1在3楼正在上行,电梯2停在一楼待机,这时候2楼上行外呼响起。只看距离的话,电梯1离2楼只有1层,电梯2离2楼也是1层,好像都是1层。但问题是,电梯1正在上行,让它顺路停一下2楼响应上行呼梯是合理的(同向顺路);可如果2楼是下行外呼,电梯1正在上行,它就必须先上行到4楼再掉头回来下行,代价就很大了。所以代价公式必须把方向因素放进去。
我用的代价计算公式大致长这样:
代价 = ABS(电梯当前楼层 - 呼梯楼层) + 方向惩罚系数 + 顺路奖励系数
具体实现时,我分了几种情况:
- 电梯处于待机状态:代价 = 距离楼层差。因为闲着也是闲着,直接派过去就行。
- 电梯正在上行,呼梯方向也是上行:如果目标楼层在电梯当前楼层上方或等于当前楼层,算顺路,代价 = 楼层差(小),否则代价 = 楼层差 + 惩罚值(比如10层)。
- 电梯正在下行,呼梯方向是下行:同理,目标楼层在下方算顺路。
- 电梯运行方向与呼梯方向相反:代价 = 楼层差 + 惩罚值,让调度算法优先选择方向一致的电梯。
这个算法在博图里用梯形图写会比较啰嗦,但也不是写不了。我是用SCL语言实现这个派梯函数的,坦白说,群控调度这类带较多分支判断和计算的逻辑,用SCL比梯形图舒服太多了。博图1200支持SCL,建议早点上手,不必非得抱着梯形图不放。
3.3 SCL实现派梯算法的一个可参考示例
我贴一段当时写的核心代码逻辑,不是完整程序,但思路完全够用。项目里用的是类似下面这样的SCL结构:
// 派梯函数,输入是楼号和外呼方向,输出是电梯编号 FUNCTION FC_Dispatch : INT VAR_INPUT Floor : INT; // 呼梯楼层 Dir : INT; // 呼梯方向,1上行,2下行 END_VAR VAR_TEMP cost1 : INT; cost2 : INT; dist1 : INT; dist2 : INT; END_VAR // 先计算电梯1的代价 dist1 := ABS(DB1.Elevator1.CurrentFloor - Floor); IF DB1.Elevator1.CurrentDir = 0 THEN cost1 := dist1; // 待机,直接距离代价 ELSIF DB1.Elevator1.CurrentDir = Dir THEN cost1 := dist1; // 方向一致,距离代价 ELSE cost1 := dist1 + 10; // 方向不一致,加惩罚 END_IF; // 同理计算电梯2的代价 dist2 := ABS(DB1.Elevator2.CurrentFloor - Floor); IF DB1.Elevator2.CurrentDir = 0 THEN cost2 := dist2; ELSIF DB1.Elevator2.CurrentDir = Dir THEN cost2 := dist2; ELSE cost2 := dist2 + 10; END_IF; // 返回代价小的电梯编号 IF cost1 <= cost2 THEN FC_Dispatch := 1; ELSE FC_Dispatch := 2; END_IF;真实项目里我还会加一个“任务锁定”的机制:一旦派梯结束,就把这条外呼请求与某部电梯绑定,在电梯响应完成前,其他电梯不再对这个呼梯信号做响应。否则每次扫描周期都重新算派梯,可能把已经派出去的电梯又拉回来,造成“反复分配”的震荡。
这个绑定的实现方式是在DB里维护一个“外呼责任表”:每个外呼楼层/方向对应一个“分配电梯编号”的变量,初始为0。当外呼信号为1且分配编号为0时,才允许调用派梯函数,把返回的电梯编号写入分配表。直到这层呼梯被取消(电梯到达该层并开门),才把分配编号清零。
3.4 顺路响应与捎带逻辑怎么处理
群控电梯还有一个细节很重要:电梯在去响应某条外呼的路上,经过有内呼或顺路外呼的楼层,应该停下来。如果每部电梯一次只响应一个任务,效率会大打折扣,这和真实电梯的运行体验差距太大。
我的做法是给每部电梯维护自己的“目标楼层集合”,而不是单一目标楼层。这个集合包括:
- 内呼登记的楼层
- 分配给自己响应的外呼楼层
- 当前要去的“主目标”楼层(调度指令)
电梯运行过程中,每到达一个楼层,如果该楼层在当前运行方向上的目标集合里,就停下开门。如果只是顺路目标,开门后清掉对应的登记信号;如果本次已经完成了主目标,清掉主目标后,从剩余目标集合里取一个新的作为主目标。
这个逻辑我用了一个数组循环遍历来实现。比如电梯上行时,从当前楼层的下一层开始向上遍历每层,检查目标集合,遇到需要停的楼层就输出该楼层的平层停车信号。梯形图写这个遍历循环非常痛苦,SCL就轻松很多。这里也是我强烈建议用SCL的一个重要原因。
3.5 关于防“打架”与死锁的几点思考
两部电梯四层楼,面对简单情况不用太担心死锁,但有两个场景值得提前预防:
第一个场景:A梯上行响应4楼呼梯,途中经过3楼时开门上下客,此时门开着,另一部电梯B也恰好要经过3楼。现实中这没什么问题,各走各的。但在仿真里,如果两梯共用同一个开门信号或同一个门状态变量,就会出现A梯开门时B梯也被打开门的bug。所以我从一开始就坚持:两台电梯的门状态、开门定时器、门锁信号必须是互相独立的实例变量,绝不能共用。
第二个场景:两台电梯同时停在1楼和4楼,中间层的呼梯不断出现,A梯上行到4楼后收到下行呼梯,B梯下行到1楼后收到上行呼梯,两台梯开始对向来回跑。这在四层楼这种小系统里其实不会造成“死锁”,但会造成效率低下。我处理的办法是对每部电梯加一个“最大响应楼层数”限制,超过三层楼没有可响应目标时,强制进入待机,然后重新由调度函数分配。这个策略在真实群控里叫“闲梯复位”,在仿真里主要是让现象看着更合理。
4. WinCC画面组态与HMI仿真联调
4.1 画面布局:电梯井道与楼层指示怎么做
HMI画面的整体布局,我是按现场监控效果来设计的。左右各放一部电梯的竖直井道剖面,井道旁边放楼层数字指示、上下行箭头、门状态图标,中间底部放外呼按钮面板。
模拟井道的方式有很多种,最简单的做法是画一个竖着的长方形做轿厢,用移动动画让它上下移动。移动的驱动变量就是电梯当前楼层对应的高度坐标。有人会直接用当前楼层变量乘楼层高度当Y坐标,这样动画是“跳变”的,不够自然。稍微进阶一点的做法是用一个“平滑显示值”变量,通过PLC里的斜坡函数或者HMI脚本让轿厢的Y坐标连续变化。我在WinCC里是在PLC侧做了个“模拟位置输出”:用运行方向和时间累计位置值,这样画面上的轿厢就是连续移动的,效果好看很多。
楼层指示器用四个圆形的指示灯,当前楼层点亮,其他楼层熄灭。指示灯的颜色我用了传统的绿色,电梯门开时再加一个黄色蜂鸣提示。上行/下行箭头直接绑定电梯的方向输出变量,运行时箭头会实时变化。
4.2 变量的连接方式:内部变量与PLC变量的选择
WinCC Professional里,HMI变量可以连接PLC的变量区,也可以使用HMI内部变量。这个项目里有两类变量要分开处理:
- 外呼按钮、内呼按钮、消防复位等操作类信号,我全部使用PLC变量,让按钮按下直接置位PLC里的呼梯登记位。这样调度的处理逻辑在PLC侧一丝不变,HMI只是“显示和触发”。
- 画面美化类的变量,比如轿厢显示位置、运行时间、页面切换标志,这些用HMI内部变量就够了。比如轿厢平滑移动的位置值,我就是在HMI里用内部变量+脚本周期累加,避免增加PLC的程序负担。
关于连接,有一点必须强调:WinCC仿真连接PLC仿真时,必须在HMI的连接配置里选择“模拟运行”的访问方式,并且IP地址要跟PLC仿真组态的IP对得上。我自己就被这个问题卡过很久,配置上写了一堆地址,结果仿真时画面上所有变量都是######,后来发现是IP地址没对上,HMI的虚拟IP和PLC的虚拟IP不在同一网段。
4.3 HMI脚本的应用:按钮事件与动画控制
WinCC里按钮的事件动作(Event)可以支持VBS脚本或C脚本。我主要用VBS,因为语法简单,在处理按钮按下/释放和页面切换时比较方便。
比如外呼按钮的“按下”事件,我写了类似这样的VBS:
Dim plc Set plc = HMIRuntime.Tags("PLC1_Floor1_UpCall") plc.Write True同时按钮的“释放”事件里什么也不做。这样PLC侧检测到外呼变量从0变成1,就记录呼梯登记。这里有个好处:不要用“切换”方式写按钮,因为那会导致按下一次为True,再按一次变False。呼梯是锁存型信号,只能由PLC完成响应后复位,不能用按钮来回切换。
轿厢平滑移动的动画脚本,我在HMI的周期任务里写了一个值累加器:
Dim pos Dim target pos = HMIRuntime.Tags("Car1_Position").Read target = HMIRuntime.Tags("PLC1_Floor").Read * 100 If pos < target Then pos = pos + 2 ElseIf pos > target Then pos = pos - 2 End If HMIRuntime.Tags("Car1_Position").Write pos这样画面上的轿厢移动速度大约是每秒2个像素单位的补间速度,看起来就很顺滑。实际速度你可以根据画面尺寸调整,核心思路就是“用PLC变量作为目标,用HMI内部变量作为动画实时值,二者通过脚本做中间过渡”。这种方法在博图WinCC里很好用,而且不需要PLC写太多额外的模拟输出。
4.4 仿真联调的全过程与操作步骤
联调我是按下面这个顺序走的,这个顺序建议新手直接抄:
- 先把PLC程序下载到仿真的PLC里,下载成功后启动仿真。注意不是点“下载到设备”就完事,需要在项目树里勾选“启动仿真”选项,博图会自动打开一个S7-PLCSIM窗口。
- 在S7-PLCSIM里设置IP地址,我设置的是192.168.0.1,然后启动CPU运行。
- 再启动HMI仿真:右键WinCC画面组态节点,选择“仿真启动”。这时候博图会弹出一个新的WinCC仿真窗口,里面有HMI的画面。
- 关键一步:确认S7-PLCSIM和WinCC仿真直接建立了连接。在WinCC画面里如果所有变量都显示#####,说明连接没通。这时候要检查HMI的连接配置里类型的访问地址对不对,以及仿真窗口的IP有没有保持组态里的192.168.0.2。
- 连接正常后,操作画面里的呼梯按钮,PLC的仿真状态里对应的变量应该能看到变化。我在调的时候喜欢同时在S7-PLCSIM的监控表里添加关键DB变量,一边点按钮一边看地址值变化,排查逻辑问题特别有效率。
仿真联调的一个优势是可以随时强制变量和修改逻辑再下载,不会损坏硬件。比如我发现调度算法里方向惩罚值设大了,导致某台电梯长期不被派梯,就地改了SCL代码,重新编译下载到仿真PLC,马上就能复现。这在真实电梯上几乎是不可能的,也是很多人做验证阶段首选仿真的原因。
5. 常见问题与排查经验整理
5.1 博图仿真启动失败或PLC启动不了
这个算是我见过最多的问题,新手概率极高。具体表现是:点击“开始仿真”后,S7-PLCSIM窗口打不开,或者打开后CPU状态一直是STOP,点RUN也没有反应。
我遇到这种情况,基本都是这三个原因之一:
- 博图版本和仿真组件不匹配。博图不是装了就能全功能仿真,它需要对应版本的S7-PLCSIM组件。我最早装V16时没勾选PLCSIM,导致仿真一直起不来,重装了一次才解决。检查方法是看项目树里的“仿真”工具菜单是否可用,灰色就说明组件没装好。
- PLC固件和博图的兼容性冲突。1200选择固件版本时如果选得太老,博图可能不支持仿真。我在组态里统一改用V4.0以上版本后基本没再出过这个问题。
- 后台进程残留。西门子软件卸载不干净的问题非常普遍,我有一台电脑装了V13又装V16,仿真时经常报找不到STEP 7的错,后来把旧版本彻底卸载干净才算稳定。如果实在卸载不干净,建议直接清理注册表里Siemens对应的条目,或者重装系统(实践过的朋友应该知道我在说什么)。
5.2 HMI仿真按钮点了没反应
这也是高频问题。现象是:WinCC画面启动了,按钮也有“按下”的动画反馈,但PLC里的变量值一点变化都没有。
排这个问题的顺序我一般这么来:
- 先看变量连接:打开HMI变量表,检查按钮绑定的变量和PLC变量表的地址是否一一对应。最常见的问题是在变量拖拽的时候选错了地址,比如绑到了某个不存在的DB块偏移量上,画面能启动但数据传来传去都是空。
- 再看连接是否激活:在HMI仿真窗口的顶部或工具栏区域,有一个“在线/离线”切换按钮,如果是在离线模式,所有通信都是断的,当然没反应。
- 检查PLC仿真的运行状态:如果S7-PLCSIM里的CPU是STOP,程序都不跑,按钮值写进去也没有逻辑动作,看起来就是“没反应”。把CPU切到RUN就好了。
- 最后看画面脚本:如果按钮事件里写了VBS脚本,确认脚本语法正确。VBS脚本写错时,点按钮会直接报错弹窗,看到弹窗就很好定位了。
如果是WinCC V7.x或其它版本还有“握手错误”的说法,但在博图WinCC Professional里一般不至于遇到,更多是变量地址或连接配置层面的事。
5.3 群控算法“不按套路派梯”的调试思路
明明这段算法逻辑对着纸面推演毫无问题,但跑起来就是会出现“左边电梯闲着,右边电梯被呼来呼去”的诡异现象。我第一次碰到这种问题时也很懵,后来按下面的方法排查,基本都能找到根源:
**第一步,在数据库里加一个“当前决策日志”区。**我把最近一次派梯的输入快照(各电梯楼层、方向、状态、外呼楼层)和输出结果(派给了哪台梯)都写到DB里。这样出问题时直接看数据,不需要瞎猜。这个思路我非常推荐,尤其是仿真调试阶段,数据就是真相。
**第二步,检查复位逻辑。**外呼请求必须在电梯到达楼层开门后复位。常见问题就是复位条件写得不对——比如电梯只是经过这个楼层但没开门,结果外呼就被清掉了,然后同一层下一分钟又呼梯,算法前脚刚做完决定后脚就被推翻,于是不断改变主意,这在画面上看起来就是“电梯疯了一样来回窜”。
**第三步,检查电梯状态是否卡死在“运行中”。**如果电梯完成后门开着但状态没回到待机,调度算法就会认为它还在忙,所有派梯都压到另一台梯上。这种问题通常要回到单梯FB的状态机里看转换条件,很有可能是关门到位的信号没触发,状态机滞留在了开门状态。
5.4 防踩坑总结:几条我建议你写在本子上的经验
整理一下这个项目从头到尾我认为最值得记得的经验,都是比较实操向的:
- 仿真不是拿真实PLC替代品,它模拟的是指令和逻辑行为,不是真实的电气时序。同一条指令在仿真里能跑,不代表拿到真实1200上就一定稳,尤其是涉及定时器精度、高速计数、硬件中断的部分。但这个项目里逐步扫描的逻辑非常适合仿真,可以放心用。
- SCL和梯形图混用不丢人。群控计算、数组遍历用SCL,单梯安全逻辑(互锁方向输出)直接用梯形图看得直观。混用代码在博图项目里是完全和谐的。
- 变量表、数据块命名规范一定要在项目早期定好。我给自己定的命名规则是:全局数据块用前缀DB_,FB实例DB用背景命名,HMI变量加HMI_前缀。这个项目做到后期,变量数量超过一两百个时,规范命名能省下一半的排查时间。
- 定时器尽量都用IEC定时器(TON、TOF、TP),不要用S5定时器。S5定时器在1200里不是不能用,而是实例化和管理上不如IEC定时器清晰,尤其是多台电梯各有自己的一组定时器时,IEC的方式更符合结构化思维。
- 留下注释和版本说明。博图的注释功能很好用,建议每个FB的接口变量和核心SCL段都写上注释,哪怕就一句话。这个习惯让我在一个月后再回看代码时依然能快速进入状态,不用从头顺着逻辑再摸一遍。
6. 这个项目做完后的个人扩展想法
把两部四层群控电梯在博图WinCC仿真下跑通之后,我个人最大的体会是:这类项目真正的难点其实不在“写电梯逻辑”,而在于“调度策略的建模”和“调试手段的建立”。电梯单机程序无非是状态机加定时器,任何一个受过基础训练的人都能写,但一旦要求两台梯协同、有序、不打架、效率高,问题就从“会不会编程”变成了“懂不懂运筹和调度”。这个转变很有意思,也是工业自动化里比较有含金量的分水岭。
我的建议是,如果你正在学西门子1200和博图,这个项目完全可以作为自己练手的毕业设计或职业技能项目。做完之后,你可以再给自己加一点扩展任务:比如把两部梯改成三部梯,看调度算法需要动多少地方;比如加入故障信号模拟,看看一台梯故障后群控系统如何把负载自动切给另一台;再比如用博图的追踪功能去分析某次特定派梯决策的完整时间线,这些扩展比单纯再抄一遍教程题有用得多。
最后再分享一个小技巧:仿真联调时,把WinCC仿真窗口和S7-PLCSIM监控窗口分别放在两个显示器上(或左右分屏),左边看画面,右边看数据变化,整个调试效率会明显提升。条件允许的话,再把博图的程序监视窗口打开,三个窗口同时联动,你会发现很多理论上想不明白的逻辑问题,一跑起来就自动浮出水面了。