1. 项目概述与核心挑战大家好我是老张一个在工业自动化领域摸爬滚打了十几年的工程师。今天想和大家深入聊聊一个让我印象深刻的实战项目——2021年“西门子杯”中国智能制造挑战赛离散行业自动化赛项我们团队凭借一套3部10层电梯的联控程序最终拿下了东北赛区的一等奖。这个项目听起来可能只是一个比赛作品但它背后涉及的逻辑复杂性、对PLC编程功底的考验以及如何将理论转化为稳定可靠的工业级控制逻辑其深度绝不亚于一个真实的楼宇电梯群控系统改造项目。很多刚接触PLC的朋友可能觉得电梯程序就是几个按钮、几层楼、电机正反转但当你面对3部电梯、10层楼、几十个内外呼信号并且要追求最优的调度效率、最低的能耗和最高的可靠性时你会发现这完全是一个全新的世界。这个项目的核心远不止是让电梯“能动起来”。它要求我们构建一个智能调度系统在瞬息万变的内外呼请求中实时为三部电梯分配任务目标是最小化乘客的平均等待时间和乘梯时间。同时还要处理一大堆工业现场才会遇到的细节比如如何防止电梯“空跑”和“盲跑”如何应对急停、故障复位等安全工况如何通过WinCC上位机清晰、实时地监控整个系统的状态这些才是真正考验工程师从“编程”到“系统设计”能力跃迁的关键。接下来我就把这套程序的“五脏六腑”拆开结合我们当时踩过的坑和总结的经验给大家讲个明白。2. 整体系统架构与设计思路拆解2.1 硬件平台与软件生态选型我们当时采用的硬件核心是西门子S7-1200系列PLC具体型号为1215C DC/DC/DC选择它主要基于几个考量首先其处理性能足够应对多部电梯的复杂逻辑运算和实时调度其次本体的I/O点数加上信号板扩展能够满足3部电梯所有楼层按钮、开关门限位、平层信号、安全回路等数字量信号的接入最后它集成的PROFINET接口为后续与WinCC上位机的通讯以及未来可能的网络化扩展提供了便利。上位机监控部分我们使用了西门子WinCC Runtime Advanced当时集成在TIA Portal V16内因为它与S7-1200是无缝集成的组态和变量连接非常方便能快速构建出直观的电梯运行状态监控界面。注意这里有一个初学者常踩的坑。TIA Portal博途是一个集成软件平台里面包含了PLC编程Step 7和HMI/SCADA组态WinCC两部分。务必确保你安装的TIA Portal版本包含了所需的“WinCC Advanced”或“WinCC Professional”授权并且与PLC固件版本兼容。我们初期就曾因版本不匹配导致WinCC变量无法正确连接白白浪费了一天时间排查。2.2 控制逻辑的顶层设计状态机与任务队列面对复杂的联控逻辑最忌讳的就是写成一锅粥的梯形图。我们采用了基于状态机Finite State Machine, FSM的设计思想来构建每部电梯的核心控制逻辑。简单来说就是把一部电梯抽象成几个明确的状态比如“空闲待命”、“向上运行”、“向下运行”、“停靠开门”、“停靠关门”、“故障”等。电梯在任何时刻都只处于其中一个状态并且根据特定的条件触发事件在这些状态之间切换。这种设计让程序结构异常清晰调试和维护也变得容易。对于3部电梯的调度我们引入了中央任务调度器的概念。这个调度器维护着一个“呼叫登记表”和“任务队列”。当有新的楼层呼叫无论是轿厢内选层还是厅外召唤产生时调度器并不立即指派给某部电梯而是先进行一轮“选举”。选举的算法就是我们程序的核心竞争力。我们综合评估了以下几个因素来为每个新呼叫分配合适的电梯顺向性优先指派与呼叫方向相同的电梯。距离计算每部电梯当前位置与呼叫楼层的绝对距离。当前任务负载考虑电梯已登记但未执行的内选和外呼数量。预测路径结合电梯当前运行方向和已登记任务预测其未来路径是否会经过呼叫楼层。通过一个加权评分算法调度器为每个新呼叫选择综合得分最高的电梯并将该呼叫登记到该电梯的专属任务列表中。每部电梯则根据自身的状态和任务列表独立决定是加速运行、减速平层还是开关门。3. 核心功能模块的深度解析3.1 单梯运行控制从启停到精准平层单部电梯的控制是基础其稳定性和精确度直接决定了整个系统的性能。这部分程序主要处理以下几个核心环节电机驱动与速度曲线我们使用了PLC的PWM脉宽调制输出功能来控制变频器进而驱动电梯主机。关键在于生成一条S型速度曲线加速-匀速-减速而不是简单的启停。这能极大提升乘坐舒适感减少机械冲击。在PLC里我们通过计算运行距离和预设的加速度、减速度值实时计算出目标速度并通过PID算法微调PWM占空比来跟踪这条曲线。精准平层控制这是电梯的“基本功”却也是容易出问题的地方。我们采用了“双稳态”检测法。在每层楼的平层区域安装了两个光电传感器或磁簧开关一个用于“提前减速点”一个用于“精确平层点”。当电梯进入减速点程序开始以较低速度爬行当触发平层点时立即切断电机动力并施加抱闸。同时程序会持续监测编码器反馈的脉冲数进行位置闭环校正防止因钢丝绳打滑等原因产生的累积误差。实操心得平层精度调试是最耗时的环节之一。建议先将电梯置于检修模式手动点动到每层楼的平层位置记录下编码器在该层的准确脉冲值并存入一个数组中作为基准。在自动运行时将实时脉冲值与基准值比较进行微调。另外抱闸的打开和闭合时序一定要与电机励磁配合好通常要求“先上电后松闸”和“先抱闸后断电”否则会出现溜车或冲击。开关门控制与安全保护开关门逻辑需要处理多种信号开门按钮、关门按钮、门机力矩保护、光幕/安全触板信号、关门时限等。我们设计了一个带超时和障碍物检测的关门流程。如果光幕或安全触板在关门过程中被触发门会立即反向打开并在延时后再次尝试关门。连续尝试数次如3次失败后电梯会保持开门状态并向上位机报警。同时必须确保门锁回路的安全联锁只有在所有厅门和轿门都确认关好且锁紧后电梯才能启动运行。3.2 多梯协同调度算法详解这是整个项目的“大脑”也是比赛拿高分的关键。我们摒弃了简单的“先到先得”或“固定分区”算法实现了一个动态的、基于综合代价函数的调度算法。1. 呼叫登记与分类 所有呼叫被分为两类内选指令轿厢内按钮具有明确的目的楼层和外呼指令厅外上行/下行按钮只有方向和所在楼层。系统为每个呼叫生成一个唯一的数据结构包含呼叫ID、类型、方向、所在楼层、时间戳、状态等待、已分配、已完成以及被分配的电梯ID。2. 调度决策周期 调度器并非每时每刻都在重新分配所有任务那样计算量太大且可能导致决策震荡。我们设置了一个固定的决策周期如200ms。在每个周期内收集新请求扫描所有新产生的、状态为“等待”的呼叫。为每个新请求计算代价对于每一个新呼叫遍历三部电梯计算如果将该呼叫分配给此电梯所需的“代价”。基础代价 物理距离电梯当前位置到呼叫楼层的楼层差。方向惩罚如果电梯当前运行方向与呼叫方向相反则增加一个很大的惩罚值例如100层这意味着除非万不得已否则不指派反向任务。负载惩罚根据该电梯当前任务列表的长度按比例增加少量代价。路径重合度奖励如果电梯的预测路径根据当前方向和任务列表计算会自然经过呼叫楼层则减少一部分代价。指派与更新将每个新呼叫指派给为其计算出的综合代价最小的电梯。更新该电梯的任务列表并将该呼叫状态改为“已分配”。3. 电梯本地的任务管理 每部电梯PLC内有一个任务队列存放调度器分配过来的任务。电梯的控制逻辑状态机会从这个队列中取出最“紧迫”的任务来执行。如何定义“紧迫”我们采用了LOOK算法的变种。当电梯处于上行状态时它只响应方向和位置在当前位置上方的任务包括上呼、下呼以及内选并按照楼层顺序依次执行。到达最高任务楼层后再改变方向为下行同理处理下方的任务。这避免了传统SCAN电梯扫描算法空跑过头的现象提高了效率。3.3 上位机监控WinCC设计与通讯一个优秀的自动化项目必须有一个“看得见”的大脑。我们利用WinCC Runtime Advanced开发了上位机监控界面主要实现以下功能1. 实时动态画面绘制了3部电梯井道的示意图电梯轿厢图标能根据PLC传来的实时楼层数据浮点数上下平滑移动。每层楼的厅外上行、下行按钮指示灯以及每部电梯轿厢内的内选按钮指示灯都能实时显示状态熄灭/常亮/闪烁。例如有外呼时指示灯常亮已被某部电梯响应后变为闪烁到达该层后熄灭。显示每部电梯的当前状态运行/停止/开门/故障、运行方向、当前楼层、载重等信息。2. 数据记录与报警建立了一个报警视图记录所有重要事件如电梯启停、开关门异常、超载、故障等并带有时间戳。这对于后期调试和运维至关重要。通过WinCC的变量记录功能可以趋势图的形式查看电梯速度、电流等关键模拟量的变化。3. 关键实现细节通讯与脚本通讯S7-1200与WinCC之间通过S7通信协议基于以太网连接。在TIA Portal中只需在设备和网络视图里配置好连接然后在WinCC中创建连接并添加变量即可非常方便。所有需要监控的PLC变量如楼层数据、按钮状态、故障代码等都必须在PLC中定义为DB块数据块中的变量WinCC通过访问这些DB块来读写数据。动画与简单逻辑轿厢的上下移动动画是通过将PLC传来的楼层整数1-10转换为画面中垂直方向的像素位置来实现的。在WinCC的图形编辑器中将轿厢图标的“垂直位置”属性动态链接到这个计算后的变量即可。按钮的闪烁效果可以通过在WinCC的“事件”中编写简单的VBS脚本来实现例如当“已分配”状态为真时触发一个定时器交替改变按钮的显示颜色。避坑指南WinCC变量连接中最常见的问题是地址错误和数据类型不匹配。务必确保WinCC中变量的地址如DB1.DBX0.0与PLC中DB块的绝对地址或符号地址完全一致。另外PLC中的Int对应WinCC的16-bit signedReal对应32-bit floating point。如果画面数据显示异常首先检查这两个地方。4. 程序结构与关键代码段剖析4.1 PLC程序组织架构TIA Portal在TIA Portal中我们严格按照功能模块化组织程序结构这极大地提高了代码的可读性和可维护性。组织块OBOB1主循环组织块调用所有功能块FB和函数FC。OB100启动组织块用于系统上电后的初始化如复位所有呼叫记录、电梯回归初始位置1层、清零故障标志等。OB82-OB86等用于处理硬件中断和诊断错误例如编码器断线、通信故障等触发相应的报警。功能块FB与背景数据块DBFB_Elevator_Ctrl单部电梯控制功能块。我们创建了三个该FB的实例FB_Elevator_Ctrl_DB1,DB2,DB3分别对应三部电梯。每个实例拥有自己独立的数据背景DB存储该电梯的所有状态变量、任务队列、速度曲线参数等。这是面向对象思想在PLC编程中的体现。FB_Scheduler中央调度器功能块。它维护着全局的呼叫登记表并执行前面所述的调度算法。FB_Door_Ctrl门控功能块被FB_Elevator_Ctrl调用。FB_Motor_Ctrl电机驱动与速度曲线生成功能块。数据块DBDB_Global_Calls全局呼叫登记表以数组形式存储所有活跃的呼叫请求。DB_System_Para系统参数块存储楼层总数、电梯数量、加速度、减速度、开关门时间等常量或可调参数。DB_HMI_Comms专门用于与WinCC交换数据的接口DB。所有需要在上位机显示或操作的变量都集中放在这里便于管理。4.2 调度算法核心代码示意SCL语言虽然比赛主要使用梯形图LAD但对于复杂的算法我们更倾向于使用SCL结构化控制语言它类似于高级语言如Pascal/C更适合进行数学运算和逻辑判断。以下是调度器为新呼叫分配电梯的核心代价计算函数的简化伪代码FUNCTION Calc_Cost : Int VAR_INPUT newCall : Struct_Call; // 新呼叫请求 elevator : REFERENCE TO Struct_Elevator; // 被评估的电梯 END_VAR VAR cost : Int : 0; predictedPath : Array[1..10] of Bool; // 预测路径数组 END_VAR // 1. 计算基础距离代价 cost : ABS(elevator.currentFloor - newCall.floor); // 2. 方向性惩罚 IF elevator.status RUNNING_UP THEN IF newCall.direction DOWN AND newCall.floor elevator.currentFloor THEN cost : cost 100; // 严重惩罚反向且“背道而驰”的呼叫 END_IF; ELSIF elevator.status RUNNING_DOWN THEN IF newCall.direction UP AND newCall.floor elevator.currentFloor THEN cost : cost 100; END_IF; END_IF; // 3. 负载惩罚轻微 cost : cost (elevator.taskCount * 2); // 4. 路径重合度奖励如果电梯预测会经过该层则减成本 predictedPath : Predict_Elevator_Path(elevator); // 预测路径函数 IF predictedPath[newCall.floor] TRUE THEN cost : cost - 5; END_IF; Calc_Cost : cost; END_FUNCTION4.3 单梯状态机实现关键点在FB_Elevator_Ctrl中我们使用一个枚举变量E_State来表示电梯状态并在每个扫描周期执行一个大的CASE语句。CASE state OF STATE_IDLE: // 空闲状态 IF taskQueueNotEmpty THEN // 分析任务队列决定下一个目标楼层和方向 Determine_Next_Target(); state : STATE_ACCELERATING; // 切换到加速状态 END_IF; STATE_ACCELERATING: // 加速状态 // 控制变频器按S曲线增加速度 IF currentSpeed cruiseSpeed THEN state : STATE_CRUISING; // 切换到匀速状态 END_IF; STATE_CRUISING: // 匀速状态 // 判断是否接近目标楼层准备减速 IF Distance_To_Target() decelerationDistance THEN state : STATE_DECELERATING; END_IF; STATE_DECELERATING: // 减速状态 // 按S曲线降低速度 IF currentSpeed crawlingSpeed THEN state : STATE_LEVELING; END_IF; STATE_LEVELING: // 平层状态 // 低速爬行寻找平层信号 IF levelingSensorTriggered THEN Stop_Motor(); Apply_Brake(); state : STATE_DOOR_OPENING; END_IF; STATE_DOOR_OPENING: // 开门状态 // 触发开门继电器 doorTimerStart(); state : STATE_DOOR_OPEN; STATE_DOOR_OPEN: // 门已开状态 // 保持开门等待定时或关门按钮 IF doorTimerExpired OR closeButtonPressed THEN state : STATE_DOOR_CLOSING; END_IF; // ... 其他状态 END_CASE;5. 调试过程、常见问题与实战心得5.1 系统联调与故障模拟程序写完后真正的挑战才刚刚开始。我们搭建了一个简易的测试平台用按钮和指示灯模拟10层楼的所有外呼内选用拨码开关模拟平层和门锁信号用一个小电机模型模拟电梯运行。调试分几步走单机调试先让一部电梯脱离调度器手动触发呼叫确保其从启动、运行、平层到开关门的整个流程完全正确特别是位置闭环控制要精准。调度逻辑调试将三部电梯接入调度器但暂时屏蔽真实的电机输出。通过上位机监控和调试表观察在模拟各种呼叫场景下调度器的分配决策是否合理。我们编写了多个典型场景的测试用例例如“高峰上行期”、“分散呼叫”、“同层反向呼叫”等。全系统联调接入所有硬件进行真实带载运行。这里暴露的问题最多也最真实。5.2 遇到的典型问题与解决方案问题现象可能原因排查步骤与解决方案电梯平层不准每次停靠位置有偏差1. 编码器脉冲计数有误差或丢脉冲。2. 平层传感器安装位置不精确或抖动。3. 抱闸动作与电机断电时序不当导致轻微溜车。1. 检查编码器接线是否可靠屏蔽是否做好。在OB中增加编码器断线诊断。2. 重新校准每层的平层传感器位置并在程序中增加软件去抖滤波如连续检测到3个扫描周期有效才确认。3. 精确调整抱闸控制时序确保电机在仍有保持力矩时抱闸闭合。可尝试在程序中增加一个短暂的“预抱闸”延时。多梯调度出现“抢单”或“漏单”1. 调度器决策周期内电梯状态发生变化导致计算基础数据不一致。2. 呼叫登记表在读写时出现资源竞争虽然PLC是顺序扫描但逻辑复杂时可能产生类似问题。3. 代价函数权重设置不合理。1. 在调度周期开始时对所有电梯的当前状态楼层、方向、任务列表进行一次“快照”用这个快照数据参与本轮所有新呼叫的代价计算确保决策依据的一致性。2. 对全局呼叫登记表的读写操作进行“保护”例如使用一个“操作锁”标志确保同一时间只有一个流程在修改它。3. 通过大量模拟测试调整距离、方向、负载等因子的权重系数找到最平衡的一组参数。WinCC画面数据更新延迟或闪烁1. 通讯负载过大扫描周期设置不当。2. WinCC画面中动画或脚本过于复杂消耗资源。3. 变量类型或地址连接错误。1. 优化PLC与WinCC的通讯设置增加通讯扫描周期或只将必要的变化量上传使用“变化率传输”。2. 简化画面减少不必要的动态效果。将复杂的闪烁逻辑尽量放在PLC侧完成WinCC只接收一个“闪烁状态”位。3. 使用TIA Portal的“在线与诊断”功能监控通讯连接状态和错误信息。逐一核对变量表。电梯在无呼叫时偶尔会自行移动1. 变频器干扰或受外部电磁干扰。2. PLC输出点受干扰误触发。3. 程序逻辑缺陷在某种罕见条件下产生了运行指令。1. 检查动力线与信号线的布线是否分开做好接地和屏蔽。2. 在PLC输出点后增加中间继电器隔离输出程序段中增加严格的互锁条件。3. 审查状态机所有转移条件增加“安全状态”检查。例如在任何从“空闲”到“运行”的转移前必须确认“目标楼层有效”且“门锁闭合”。5.3 从比赛到工程的思考这个比赛项目虽然规模可控但它完整地覆盖了一个小型自动化系统的全生命周期需求分析、方案设计、硬件选型、软件编程、调试排故、人机界面开发。做完这个项目我深刻体会到几点第一结构化编程是生命线。面对成百上千个变量和复杂的逻辑如果没有清晰的模块划分如调度、单梯控制、门控、通讯程序很快就会变成一团乱麻调试无从下手。FB背景DB的模式是西门子PLC应对复杂项目的利器。第二调试工具要用到极致。TIA Portal的在线监控、变量表、跟踪功能以及WinCC的报警和趋势记录都是发现问题的眼睛。不要只靠“看现象猜原因”要学会用数据说话。我们曾通过趋势图记录电机电流发现了一个因机械卡阻导致的周期性过载问题。第三安全与冗余思维。比赛程序可能更注重功能实现但工业现场程序必须把安全放在第一位。每一个输出动作如启动电机、打开抱闸前面都应该有充分的互锁和条件检查。对于关键信号如安全回路、门锁可以考虑冗余检测或增加“心跳”监测。第四文档与注释同样重要。我们为每个重要的FB/FC都编写了详细的接口说明和内部逻辑注释。在后期调试和功能微调时这些文档节省了大量回溯理解代码的时间。良好的变量命名规范如bDoorOpenCmd_HMI也能极大提升代码可读性。最后我想说这个“3部10层电梯”的程序其核心价值不在于它控制了多少部电梯而在于它展示了一种用PLC解决复杂离散逻辑问题的系统化方法。无论是流水线上的AGV调度、仓储中的堆垛机管理还是其他任何需要多设备协同、实时响应的场景其背后的设计思想——状态机、任务调度、模块化、数据驱动——都是相通的。希望这次分享能为你打开一扇窗看到PLC编程更广阔、也更精彩的那一面。如果你在实现类似项目时遇到了具体问题比如如何优化调度算法减少乘客等待时间或者WinCC动画如何做得更流畅欢迎随时交流我们可以继续深入探讨那些在官方手册里找不到的“实战细节”。