尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于SCL与For循环的电梯楼层优先级调度算法实战详解

发布时间:2026/9/24 8:59:33

资讯中心
01
ARTICLE

基于SCL与For循环的电梯楼层优先级调度算法实战详解

基于SCL与For循环的电梯楼层优先级调度算法实战详解
说到电梯楼层调度我第一反应就是早年在项目现场调电梯的那段日子明明是十几层的楼按钮按下去电梯要么不理你要么直接冲过你要去的楼层再折回来业主天天打电话催。后来我把整套逻辑用西门子PLC重写核心调度算法全部改用SCL加For循环实现配合触摸屏做联动演示逻辑一下变得非常清晰。这篇文章就是想把这段实战经验完整拆开从需求分析、数据建模、算法实现到HMI联动一步步讲给你听。不管你是刚接触SCL的新手还是已经用梯形图写过电梯逻辑、正想找个更优雅的写法的老手这篇内容都能给你一套可以直接改着用的方案。在正式开始之前先把这篇文章解决的问题说清楚。电梯楼层优先级调度说白了就是回答这么几个问题电梯现在该往哪走、中间哪几层要停、停完之后要不要换向、同方向多个请求先响应谁。传统写法用梯形图做比较指令、置位复位、跳转堆一屏楼层一多改起来头大。SCL的好处是接近高级语言数组、For循环、分支语句都支持可以把“从当前层往上找最近呼叫”“判断上方是否还有顺向请求”这类逻辑写得像伪代码一样直白。看完这文你能得到一套完整的单梯调度模型包括DB块设计、FC/FB代码、触摸屏变量映射和演示方法。1. 电梯楼层优先级调度先搞清“优先级”从哪来1.1 楼宇里最朴素的规则顺向截梯电梯这玩意儿市面上绝大多数电梯用的都是“顺向截梯”这个核心原则。什么意思就是电梯在往上走的过程中凡是上行方向一致的楼层呼叫只要还没到电梯都应该顺路停反过来下行的时候下行方向的呼叫优先响应。只有在当前方向上已经没有请求了电梯才考虑换向去响应反方向的呼叫。这是从乘客体验和能耗双重角度得出的最优解。举个例子电梯在3楼5楼有人按上行8楼也有人按上行同时2楼有人按下行。如果电梯先下去接2楼的人5楼和8楼的人就得眼睁睁看着电梯往反方向走体验很差而且电梯反复来回跑电机频繁启停能耗和机械损耗都受不了。所以正确做法是先往上走到5楼再接8楼直到上方没有上行请求了才可以换向处理2楼的下行。网上那些“电梯调度算法”帖子动不动就上粒子群、遗传算法说实话民用建筑里的单梯根本用不着。真正实用的优先级模型就三层内呼优先于外呼、顺向优先于反向、同向时由远及近决定换向时机。理解了这三句话代码怎么写都有了方向。1.2 用SCL落地的三层请求模型要把调度规则变成PLC程序先把“请求”这个概念结构化。电梯里的请求分三种轿厢内呼、厅外上呼、厅外下呼。内呼优先级最高因为乘客已经在轿厢里了不可能让他坐过站外呼中和电梯当前运行方向一致的优先方向一致的多个外呼按楼层远近自然排序响应。这里有个很容易被忽略的细节请求信号是“持续电平”还是“脉冲”。实际上乘客按按钮按钮灯亮了这个信号会一直保持着直到电梯到达该楼层开门。所以PLC里不能直接把按钮输入当成瞬时脉冲处理得自己做一个“请求锁存”和“到达复位”的流程。这也是我坚持用数组的原因每一层楼是否有人呼叫就是一个BOOL数组元素置位、复位都清清楚楚。把三个请求类型放进数组就得到下面这样的数据模型CarCall[1..N]内呼乘客在轿厢里按的楼层UpCall[2..N]厅外上行呼最底层没有上行按钮DownCall[1..N-1]厅外下行呼最高层没有下行按钮调度逻辑每周期扫描时先把三组数组“或”成一个停靠请求表StopReq[i]然后基于这个表做方向判断和楼层搜索。这样做的好处是算法只认一张表不用每个方向各写一套复杂判断后面加新功能也容易。1.3 为什么这个场景用For循环最合适很多用梯形图写过电梯的人都有一个感受往上找附近的呼叫梯形图真心不好写。你要做一堆比较指令如果楼层有16层你就得写16个比较楼层再多点程序容量先扛不住。而且每一次增加楼层数量梯形图那段都得重新改。For循环恰恰是为这种“顺序查找”场景设计的。你要找“当前楼层以上最近的一层有请求”一行For循环从CurrentFloor1扫到最高层找到第一个就退出你要找“当前方向是否还有请求”也是For循环扫一遍有一个就置标志位。这跟电梯调度的“按楼层顺序扫描”天然契合。另外SCL写出来的代码自解释性很强。你三个月后回来看代码看见“FOR i : CurrentFloor 1 TO MAX_FLOOR DO IF StopReq[i] THEN”这一行马上就知道在找最近的上行停靠点。梯形图里一条条触点说实话过几天自己都未必记得当初是干嘛的。2. 数据块与变量设计调度逻辑的地基2.1 DB块应该放什么、怎么放数据块是整个调度算法的地基设计得好不好直接决定代码好不好写。我习惯单独建一个电梯控制DB把所有跟电梯状态相关的变量集中放在里面调用FC/FB的时候直接用符号寻址访问调试的时候监控一个DB就能看全所有状态。我常用的DB结构大概是这样变量名数据类型作用CurrentFloorINT当前楼层1~NDirectionINT运行方向1上行0停止-1下行CarCallARRAY[1..16] OF BOOL内呼请求UpCallARRAY[2..16] OF BOOL外呼上行请求DownCallARRAY[1..15] OF BOOL外呼下行请求StopReqARRAY[1..16] OF BOOL合并后的停靠请求表TargetFloorINT当前目标楼层DoorOpenBOOL开门指令输出RunningBOOL运行中标志变量命名我尽量用英文方便在不同品牌PLC之间移植。有些人喜欢用中文变量名博途也支持但触摸屏那边映射变量名的时候经常遇到编码问题所以我个人建议还是英文名。每个数组的上下标边界要特别注意比如UpCall没有第1层DownCall没有第N层很多新手在这里出错数组越界在博途里不一定有明确提示但运行起来逻辑就是不对。2.2 数组寻址与楼层映射的踩坑点SCL里数组下标默认从0开始也可以显式写成ARRAY[1..16]。我强烈建议你写成1开始的数组让下标和楼层号一一对应。这样写代码时脑子里不用做“减一”的转换避免了大量低级错误。还有一个坑是触摸屏映射BOOL数组。威纶通、西门子HMI映射1位BOOL变量没问题但如果你在DB里声明了一个ARRAY[0..15] OF BOOL触摸屏上想按位对应地址不同品牌的映射规则不一样有的按字节偏移有的按位偏移很容易对不上。我的做法是HMI上要显示的楼层状态宁可单独声明几个单独的BOOL变量或者在HMI里用索引变量去访问数组别在图上一口气放16个点位那样调试起来能疯掉。另外如果用的是S7-1200/1500的优化DB变量的绝对地址不可见触摸屏通信反而更简单直接变量名对接。但注意优化DB的BOOL变量不能按位单独访问如果你有旧设备走Modbus TCP之类的协议需要按位寻址就得考虑取消优化访问或者在DB里用BYTE外加位操作。2.3 请求信号的边沿处理电梯按钮信号有一个“按下、保持、电梯到达后消除”的过程。PLC扫描周期很短人按按钮最少也有一两百毫秒扫描周期可能只有5毫秒所以直接用I/O点去置位请求标志大概率没问题。但如果是来自HMI的按钮或者是通信读进来的信号我就一定会做边沿检测。触发一个内呼请求// HMI按钮按下产生一个上升沿 上升沿M.CarCallEdge : HMI_CarCall_1; IF 上升沿M.CarCallEdge AND NOT 上升沿M.CarCallOld THEN DB_Elevator.CarCall[1] : TRUE; END_IF; 上升沿M.CarCallOld : 上升沿M.CarCallEdge;这样写的好处是即使HMI按钮一直按住也不会重复触发请求。到达楼层后用楼层检测信号统一复位对应的请求位这样请求生命周期就完整了。3. 核心算法实现For循环写电梯调度3.1 请求合并一个For循环生成停靠表调度逻辑每个扫描周期都从合并请求开始。合并规则很简单任何一层有内呼、有顺向上呼或者有顺向下呼这一层就进入停靠表。// 请求合并任何请求都认为该层需要停靠 FOR i : 1 TO MAX_FLOOR DO DB_Elevator.StopReq[i] : DB_Elevator.CarCall[i] OR DB_Elevator.UpCall[i] OR DB_Elevator.DownCall[i]; END_FOR;这里MAX_FLOOR是全局常量我一般用16。需要注意的一点这个合并结果只用于调度判断真正到站开门之后要单独把相应方向的请求复位不能把整张表清空否则其他方向同楼层的请求也被误清了。比如电梯上行到达7楼开门7楼同时有一个下行外呼。如果你在开门瞬间把StopReq[7]、UpCall[7]、DownCall[7]全部复位那7楼那个下行请求就丢了。正确做法是开门时只复位CarCall[7]和当前运行方向对应的那个外呼反方向的请求保留等电梯换向下来时再响应。3.2 寻找上行目标从近到远的For扫描当电梯处于上行状态时目标楼层的选择逻辑是从当前楼层的上一层开始往上扫找到第一个有停靠请求的楼层这个就是最近要停的楼层。注意我找的是“最近”不是“最远”。因为电梯是一路往上走的途中每一层有请求都会停真正决定电梯要不要继续往上走的是最远那个请求而决定“下一站停哪”的是最远和最近共同作用的结果。// 上行状态下寻找最近的顺向停靠点 DB_Elevator.TargetFloor : 0; // 0表示未找到 IF DB_Elevator.Direction 1 THEN FOR i : DB_Elevator.CurrentFloor 1 TO MAX_FLOOR DO IF DB_Elevator.StopReq[i] THEN DB_Elevator.TargetFloor : i; EXIT; // 找到第一个就退出 END_IF; END_FOR; END_IF;EXIT是SCL里跳出循环的关键字只跳出当前这一层循环。这个For循环的扫描范围是从CurrentFloor1开始这本身就是在实现“方向限制”——下行楼层不在扫描范围内。等电梯到了TargetFloor开门乘客进出然后重新扫描下一段。这里要说明一下实际电梯控制里不会真的只找一个目标然后一股脑往那跑。轿厢每到一个停靠层都要重新决策一次是继续走、还是停、还是换向。所以这段For循环其实在每一个“已停靠楼层”之后都会重新执行一遍执行频率不需要太高放在OB1里每周期跑完全没问题因为SCL的运算速度对这个体量来说绰绰有余。3.3 换向判断反向请求怎么响应电梯跑到最上层停完以后怎么知道该换向下去了答案是上行状态下扫描当前楼层以上的区域如果没有发现任何请求再扫描当前楼层以下的区域如果下方有请求就换向。// 上行时检查上方是否还有请求 DB_Elevator.HasReqAbove : FALSE; FOR i : DB_Elevator.CurrentFloor 1 TO MAX_FLOOR DO IF DB_Elevator.StopReq[i] THEN DB_Elevator.HasReqAbove : TRUE; EXIT; END_IF; END_FOR; // 如果上方没有请求但下方有请求换向下行 DB_Elevator.HasReqBelow : FALSE; FOR i : 1 TO DB_Elevator.CurrentFloor - 1 DO IF DB_Elevator.StopReq[i] THEN DB_Elevator.HasReqBelow : TRUE; EXIT; END_IF; END_FOR;把这个逻辑用语言翻译过来就是电梯正在上行如果上面还有人要停就继续往上如果上面没人了下面还有人那电梯就换向Direction从1变成-1开始处理下行请求。在实际程序中这个换向判断不需要每个周期都做可以做成“电梯停在某层、门关好、准备启动”时才判断一次防止运行中出现逻辑抖动。要说优先级“上方请求存在”的判断要优先于“下方换向”的判断顺序不能反。万一上方和下方都有请求电梯应该继续往上走完再考虑下来这是把顺向优先原则落到代码里的关键一步。3.4 运行控制输出方向、目标、到站停车逻辑有了目标楼层和方向接下来让电梯动起来。方向输出很简单Direction1就给上行接触器通电Direction-1就给下行接触器通电TargetFloor0或者方向没确定时两个都断开。到站停车则依赖于楼层位置检测一般用编码器或者平层开关。简化模型里我建议用当前楼层值和目标楼层值做比较来确定是否停车CurrentFloor TargetFloor就说明电梯已经到达目标楼层此时断开运行接触器、输出开门指令、复位对应请求。// 到站逻辑 IF DB_Elevator.CurrentFloor DB_Elevator.TargetFloor AND DB_Elevator.TargetFloor 0 THEN DB_Elevator.DoorOpen : TRUE; // 开门 DB_Elevator.Running : FALSE; // 停止运行 // 复位当前楼层的全部请求内呼和同向外呼 DB_Elevator.CarCall[DB_Elevator.CurrentFloor] : FALSE; IF DB_Elevator.Direction 1 THEN DB_Elevator.UpCall[DB_Elevator.CurrentFloor] : FALSE; ELSIF DB_Elevator.Direction -1 THEN DB_Elevator.DownCall[DB_Elevator.CurrentFloor] : FALSE; END_IF; // 停车后清零目标等待下一次决策 DB_Elevator.TargetFloor : 0; END_IF;代码里有一个容易被忽视的细节复位请求时我复位的是CurrentFloor对应的请求而不是TargetFloor对应的请求。这两者在“到站”那一刻是相等的但程序执行到后面再复位时CurrentFloor和TargetFloor可能已经不一样了。用当前楼层做索引即使下一次扫描周期里电梯已经启动了也不会误复位前面的楼层请求。3.5 完整代码串讲把这些零件拼成一台“会思考的电梯”前面几段代码都是零件现在把它们拼成一个完整的FB块。这个FB块名字叫FB_ElevatorDispatch里面需要调用前面的请求合并、方向保持、目标搜索、换向判断、到站复位几个部分。建议的调用顺序是采样当前楼层更新CurrentFloor合并所有请求生成StopReq数组如果电梯处于停止状态Direction0先做启动决策如果电梯运行中按当前方向寻找最近目标到站则停车、开门、复位请求运行方向上无请求则换向启动决策的代码很有意思电梯静止时先看当前楼层是否有请求。如果有人在当前层按电梯直接在当前层开门不用启动。如果当前层没有那就先往上找最近的请求找到了就上行找不到再往下找找到了就下行两个方向都没有就继续停着。// 停止状态下选择方向 IF DB_Elevator.Direction 0 AND NOT DB_Elevator.DoorOpen THEN // 优先处理当前楼层请求 IF DB_Elevator.StopReq[DB_Elevator.CurrentFloor] THEN DB_Elevator.DoorOpen : TRUE; DB_Elevator.TargetFloor : DB_Elevator.CurrentFloor; ELSE // 找上方最近请求 DB_Elevator.TargetFloor : 0; FOR i : DB_Elevator.CurrentFloor 1 TO MAX_FLOOR DO IF DB_Elevator.StopReq[i] THEN DB_Elevator.TargetFloor : i; EXIT; END_IF; END_FOR; IF DB_Elevator.TargetFloor 0 THEN DB_Elevator.Direction : 1; ELSE // 上方没有找下方最近请求 FOR i : DB_Elevator.CurrentFloor - 1 TO 1 BY -1 DO IF DB_Elevator.StopReq[i] THEN DB_Elevator.TargetFloor : i; EXIT; END_IF; END_FOR; IF DB_Elevator.TargetFloor 0 THEN DB_Elevator.Direction : -1; END_IF; END_IF; END_IF; END_IF;注意FOR循环步长不是1的情况从当前楼层往下找要用“FOR i : CurrentFloor - 1 TO 1 BY -1”这个BY -1表示步长为-1是SCL里常见的向下循环写法。排查问题的时候很多新手拿这个循环从上往下扫却怎么也扫不到数据十有八九是忘了写BY -1。4. 触摸屏联动演示从PLC到HMI的完整数据链路4.1 HMI变量映射与画面规划调度算法跑通之后必须让它“看得见”才好给业主演示、给同事讲逻辑。触摸屏在这套系统里是两个角色一是操作面板二是运行监视器。推荐用西门子KTP系列或者威纶通MT系列两者和S7-1200/1500通信都非常顺手。威纶通在中小项目里性价比高软件EBpro上手快而且支持标签导入工程文件迁移成本很低。画面布局我习惯规划成五个区域顶层显示当前楼层和运行方向中间16行显示每层的三色状态灯内呼、上呼、下呼底部放内呼数字键盘和上下行呼梯按钮右侧放运行模式切换和故障复位。状态灯用颜色区分红色代表有请求绿色代表电梯当前停靠层灰色代表无请求。变量映射最核心就是一个原则HMI上的按钮不直接驱动PLC的输出点只驱动DB里的请求位或中间变量。这样做隔离性最好万一操作员误触也只影响调用逻辑不会直接动作接触器。我见过有人把触摸屏按钮直接映射到Q点上的那是典型的危险设计检修时按错一下就可能出事故。4.2 演示场景设计与联合调试演示要好看关键是模拟一个“多方向抢梯”的场景。我在做演示时习惯先复位所有请求然后按以下顺序点按钮在3楼厅外按上行呼梯在6楼厅外按下行呼梯在9楼厅外按上行呼梯观察电梯初始位置如果电梯在1楼它应该先响应3楼上行再响应9楼上行最后才换向下来处理6楼下行在轿厢里设置几个内呼比如乘客从3楼上到8楼然后电梯在上行途中应该优先停8楼而不是中途跑去接反向呼叫这个演示顺序能让观看者在一分钟内直观感受到“顺向优先”和“换向规则”。我在触摸屏画面里还会实时用指示灯显示当前扫描到哪一层配合目标楼层数值的变化逻辑一目了然。联合调试时我第一步先不做闭环只是用HMI的按钮触发请求然后监控PC端博途里的DB变量确认每一位请求都能正确置位。第二步才让电机带动编码器动起来验证到站复位逻辑。第三步再做多请求组合测试。千万不要一上来就全联动出了问题都不知道是按钮层、逻辑层还是驱动层的问题。4.3 没有实体触摸屏怎么跑仿真很多朋友手上没有现成的HMI设备那也可以演示。两个方案第一用博途集成的WinCC Runtime仿真和PLCSIM配合虚拟触摸屏直接跑第二用威纶通EBpro自带的离线模拟器它能模拟触摸屏和PLC通信但前提是你得装上Modbus TCP驱动或者S7驱动并正确填写PLC的IP地址和机架号。WinCC仿真我建议用这套参数PLC按S7-1500建IP设成192.168.0.1HMI连接里填同样IP通讯驱动选S7-1500机架0插槽1。在线模拟时打开PLCSIM并下载程序到虚拟PLC然后WinCC点启动仿真两边的变量就会实时同步。调试完成后如果换实体屏改动也小HMI里变量引用的DB结构不变只需要重新建立连接即可。用仿真还有一个额外好处可以随时暂停、单周期执行方便把电梯停在某个特定楼层来测边界情况。实体电梯可做不到你想停哪就停哪。我测边界条件几乎全是在PLCSIM里跑的比如“电梯在1楼收到16楼下呼”“电梯在16楼收到1楼上呼”这种极端情况实体设备上很难制造仿真里按两个按钮就行。5. 常见问题与排查技巧实录5.1 问题速查表这几年代码写多了周围同事和朋友踩过的坑我也见过不少专门整理一个排查表现象常见原因排查思路电梯不响应任何呼叫请求合并表没更新或者方向一直为0监控StopReq数组看按钮置位是否传到数组电梯总是过站不停楼层检测信号没进入CurrentFloor目标楼层和当前楼层对不上检查编码器/平层开关信号对比CurrentFloor和TargetFloor电梯只走一个方向换向判断的BY -1写错下方请求扫不到单独监控HasReqBelow标志重点查向下For循环到站后请求没有消除复位逻辑里用的是TargetFloor而不是CurrentFloor换成CurrentFloor做索引触摸屏按钮无效果HMI变量映射到优化DB的位变量访问异常把需要HMI访问的变量放到非优化DB或用字节映射外呼按钮按了马上灭HMI按钮被配置成“按一下有效”的瞬时模式而PLC没有做锁存HMI端按钮模式改“置位”或者PLC里做自锁/边沿锁存满载直驶功能失效超载信号没有参与方向判断逻辑在启动决策之前加一个满载直驶分支5.2 优先级判断老是不对先查这三个地方如果你发现电梯响应顺序总是和预期不一样别急着改算法先用监控表查三个点。第一StopReq数组的值对不对有没有应该复位的请求没复位或者不该置位的请求被置位了。第二CurrentFloor的精度有些编码器信号毛刺大楼层会跳变比如从5楼直接跳到7楼中间6楼的请求就永远没机会响应。楼层检测建议做滤波或者用平层开关做硬定位编码器只能做辅助。第三方向信号和实际运行方向是不是一致。调试初期最容易出现的情况是程序判断Direction为1但电机接线导致电梯实际是在往下走这时候所有基于“当前方向上行”的调度判断全部失效。我建议第一步不要做自动调度手动控制电梯上下各走一遍确认程序里的方向和实际机械方向完全一致了再连调度逻辑。我自己的调试习惯是用HMI加一个“手动/自动”切换开关。手动模式下只通过HMI按钮控制上下行先验证电机和楼层检测的基础功能自动模式下才让调度逻辑接管。两套逻辑互锁不能同时输出否则手动模式下电梯也会被调度带跑。5.3 扩展思考从单梯调度到多梯与驱动联动单梯调度做完以后很多人会想往多梯群控或者和变频器联动方向扩展。这两个方向都是很好的加分项但复杂度完全不在一个量级。先说变频器联动热点上有人问到“西门子PLC和ABB变频器做Modbus通讯控制”如果电梯用变频器驱动PLC只需要发送启停、给定速度然后读当前频率和故障状态驱动模型基本保持前面代码不变只是把“方向接触器输出”换成“变频器控制字”把电流、速度反馈接进来。Modbus通讯建议用PLC自带的RS485或者Modbus TCP块V90、ACS580这些主流变频器都有现成库重点是做好通信超时处理通信失败要置故障停车。多梯群控就复杂得多涉及“最靠近原则”的电梯分配不能每台梯各跑各的。常见做法是加一个群控控制器收集所有外呼计算每台电梯到达呼叫楼层的预估时间选最小者响应。这个计算过程在SCL里也可以实现思路是遍历每台电梯的当前位置和方向用For循环算每台到每个请求的“距离代价”然后找最小值。不过多梯联动建议在单个电梯调度完全稳定之后再做否则排查问题的时候会分不清是单梯逻辑错了还是分配逻辑错了。最后我再提一个小经验如果你准备把这套逻辑用在实际项目中一定要在HMI上留一个“调度逻辑复位”按钮一键把所有请求数组、方向、目标都清零。电梯调试和试运行阶段这个按钮能帮你省掉大把重新置位的功夫。我在每个项目中都保留这个按钮等系统运行稳定后才考虑是否从面向用户的操作面板上移除。我自己写电梯调度的最大体会是代码本身并不难难的是把”遇到什么情况怎么处理“的所有特殊场景都想全并且让每一段循环扫描都有明确的出口条件。你用For循环把优先级逻辑一层层剥离出来以后电梯的运行行为会变得极其可预测这一点在实际交付时比任何花哨的功能都更有价值。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。