项目标题里写了“工业物联网实战”这个项目我听了很多次“老旧货梯”就头疼。但真正上手做下来发现这里面的门道其实比新建一个智能产线还多。某制造企业有一台用了快二十年的货梯五层楼继电器接触器控制每天的物料转运全靠人工按按钮。后来车间上了几台自主移动机器人结果卡在乘梯这个环节一卡就是半年。今天聊聊我和团队如何用声明式梯控改造的思路把这台“老家伙”变成能听懂机器人说话的智能电梯重点拆解架构实现和协议重构这两个环节希望能给正在跟老旧设备较劲的同仁一些参考。这个项目适合谁看如果你是负责自动化产线改造的工程师正在为AGV乘梯发愁或者你需要把老设备接入工业物联网平台那么这篇内容应该能帮上忙。我会把从信号采集到接口设计从代码实现到现场调试的全部过程还原出来包括一些踩坑记录。1. 项目背景与需求拆解老旧货梯与机器人乘梯的隐形障碍1.1 老旧货梯的现状继电器时代的产物这台货梯是某制造企业2005年左右安装的。所谓继电器接触器控制就是所有逻辑都靠物理继电器和接触器的通断组合来实现。比如你按了一下“上行”按钮线圈得电触点吸合电机开始转到了一层机械限位开关被撞开继电器断开电机停。这套系统没有PLC程序更没有通信接口只有一堆布满灰尘的端子和线排。听起来很原始但它在当年是很成熟的技术稳定、抗干扰、维护起来也就万用表加螺丝刀的事。问题在于机器人不会用肢体去按按钮也无法感知电梯门有没有开。想让机器人自主乘梯就必须要让电梯具备对外交互能力。我们盘点了这台梯的“家底”几个典型特征控制回路电压是AC110V触点信号多公共端复杂。楼层检测靠各楼层的干簧管轿厢顶部有随行电缆。没有任何现成的总线接口连调试用的串口都没有。维保人员只懂电气原理图不懂网络通信。所以第一步不是写代码而是搞清楚这台电梯现有的信号有哪些、哪些能采集、哪些必须要避开。1.2 需求拆解从“能按按钮”到“声明式调度”项目目标很明确让机器人在不需要人类帮助的情况下自主呼叫电梯、进入轿厢、选择目标楼层、到达后出梯。最初设想过一个方案用机械臂去按按钮。但机械臂需要定位按钮位置而且不同梯型的按钮布局不一样可靠性低维护成本高很快就放弃了。深入思考后发现机器人真正需要的不是模拟人手而是“把请求告诉电梯系统等待结果”。这就引出了“声明式调度”的概念机器人只需要声明“我从3层到7层很重要”梯控系统负责分解成一系列电梯控制动作。与之相对的是“命令式”方式机器人要一条条执行“按下上行按钮”、“等待开门”、“进入后按楼层7”、“确认电梯到达7层”。我在实际设计前做了一张对比表用来跟团队和客户对齐对比维度命令式声明式控制粒度精确到每个物理动作精确到任务目标容错能力任何一步失败都需要人工恢复状态机自动超时与复位适配成本不同电梯需要重写操作逻辑只需适配底层信号上层不变故障追踪往往需要逐条日志分析状态转换清晰定位较快最终选择了声明式。这也成了整个项目的核心设计理念让复杂逻辑下沉把简洁留给上层。后续选型、协议设计都是围绕这个理念展开的。2. 技术选型与整体架构为什么声明式架构更可靠2.1 协议重构前必须想清楚的事很多人一听“协议重构”就觉得要把电梯整个控制系统推倒重来其实恰恰相反。老旧货梯的安全回路、机械结构、电机驱动系统都属于特种设备范畴不能随意改动。我们说的协议重构是把电梯对外暴露的物理触点信号按钮、指示灯、传感器重新封装成标准化消息让上层系统能读懂、能操作而电梯本身的核心控制逻辑保持不变。这背后的原因很现实改造成本、审批周期、风险控制。如果替换整台电梯控制器相当于做一次特种设备改造不仅费用高而且需要重新验收可能影响生产。旁路改造则是在电梯原有的信号回路基础上用高阻抗的干接点隔离采集不做任何短接或切断最大限度降低安全风险。改造前需要明确采集哪些信号我们列了一份信号清单当前楼层从轿厢平层开关或楼层编码器读取。运行方向从上行/下行接触器辅助触点读取。门状态开门到位开关和关门到位开关。门锁状态串联在安全回路中的门锁触点。内呼按钮轿厢内各楼层选层按钮。外呼按钮各层厅门的上行/下行召唤按钮。这些信号通过隔离模块接入IO网关。网关向上提供Modbus TCP接口用于控制同时将状态通过MQTT发布到边缘服务器。2.2 分层架构设计与核心组件整个系统分四层每一层只负责单一职责避免上层逻辑与硬件深度耦合应用层机器人调度系统它只关心“任务请求”不关心电梯型号。机器人会发送“从A层到B层”的请求并订阅电梯状态事件。声明式接口层这是核心通常运行在边缘网关或工控机上。它维护任务队列、解析请求、控制适配层完成动作并向应用层提供REST API和MQTT主题。适配层负责把操作指令转化为物理动作。比如“呼叫上行”对应某一路继电器的闭合“选择3层”对应内呼板上对应的继电器动作。有些方案还会用PLC来做这一层我们手头是边缘网关加IO模块所以直接用了IO模块的Modbus寄存器。物理层继电器阵列、光耦隔离模块、传感器触点、接触器辅助触点。这一层是整个系统里“最容易脏”的部分也是最需要谨慎对待的部分。这里给个简单图示[机器人调度系统] -HTTP/MQTT- [梯控服务(Edge)] -Modbus TCP/GPIO- [IO模块] -干接点- [电梯原控制系统]每层的修改点有明确边界。比如机器人接入时只需要调用梯控服务的接口电梯换维保单位时只影响适配层不影响应用层。2.3 声明式接口的设计思路接口设计是决定这个项目好不好用的关键。我们定义了两个核心接口任务请求和状态订阅。任务请求采用JSON格式示例如下{ request_id: b7a1f8e2, call_type: dispatch, from_floor: 3, to_floor: 7, priority: high, timeout_sec: 60 }其中“call_type”统一为“dispatch”表示这是一个完整的派梯请求梯控服务会自行处理上行呼叫、等待开门、内呼登记、到达确认等。机器人的任务就是发送这个请求然后等待状态事件。状态事件同样用JSON{ car_id: LIFT-01, floor: 3, direction: up, door_state: open, fault_code: 0 }为什么选择MQTT而不是直接让机器人读Modbus寄存器因为Modbus是点对点协议如果三台机器人同时读一个寄存器需要自己做并发控制而且数据含义不直观。MQTT是发布订阅模式一台电梯就是一个主题机器人按需订阅逻辑清晰容错性也更好。REST API用于低频管理操作比如更新电梯配置、查询故障记录。有一个设计细节值得说接口里没有暴露任何与电梯操作强相关的字段比如“按下上行按钮”、“打开内呼板”这些命令在应用层是不可见的。这就保证了上层系统永远不需要知道电梯的物理细节真正做到声明式。提示接口版本化也很重要。我们在URL路径中加入/v1后续改造不同梯型时通过新版本扩展不会影响已经上线的机器人。3. 实操过程从继电器到总线到声明式接口的实现细节3.1 改造前准备收集电梯资料与制定安全策略这个环节我们花了两周比写代码的时间还多。安全永远是第一位的。第一次进场时我们先找来电梯的电气原理图跟厂家维保工程师逐页翻标出所有跟按钮、指示灯、传感器相关的回路。特别注意安全回路比如门锁回路、急停回路这些是绝对不能动的地方。为了不干扰原控制逻辑所有外部采集信号都用干接点隔离模块。干接点是一种无源触点通过光耦隔离与电梯原回路完全电隔离。控制端则使用带有中间继电器的驱动板驱动板线圈电压选DC24V触点容量要求较高至少AC120V/2A保证能驱动原控制回路。必备工具列了一个清单万用表、示波器、绝缘电阻表、DC24V开关电源、信号隔离模块、继电器驱动板、IO集线器、一台装了Docker的轻量边缘网关。现场还拉了一根独立的网络线单独组成梯控内部局域网避免与办公网络冲突。注意任何对安全回路的改动哪怕只是加一根线都必须先与电梯维保单位确认并且做好封线记录。特种设备监管不是开玩笑的。安全策略上我们做了三件事。第一增加独立的急停开关放在电梯控制柜旁边紧急情况下能直接让梯控系统释放全部控制权。第二所有软件中都加入“看门狗”逻辑网关死机时自动断开继电器驱动防止误动作。第三改造期间全程有电梯维保工程师在旁监护每次通电测试前都要口头确认一遍。3.2 核心实现梯控服务端的功能代码解析我们的梯控服务跑在一台边缘网关上操作系统是轻量Linux环境业务代码用Python编写。Python的优点在于生态好、搞Modbus和MQTT都方便缺点是不适合做硬实时控制但梯控这个场景响应时间在几百毫秒完全够用。下面是适配层的核心代码片段演示如何读取楼层和发送外呼指令import json import time import modbus_tk import modbus_tk.defines as cst from modbus_tk import modbus_tcp import paho.mqtt.client as mqtt class ElevatorAdapter: def __init__(self, host, port, unit_id): self.master modbus_tcp.TcpMaster(host, port) self.master.set_timeout(1.0) self.unit_id unit_id self.mqtt mqtt.Client() self.mqtt.connect(127.0.0.1, 1883, keepalive60) def read_floor(self): # 读取输入寄存器地址0表示当前楼层 res self.master.execute(self.unit_id, cst.READ_INPUT_REGISTERS, 0, 1) return res[0] def request_up(self, floor): # 触发指定楼层的上行召唤按钮 # 这里以IO模块的线圈地址对应各楼层举例 coil_addr 10 floor * 2 self.master.execute(self.unit_id, cst.WRITE_SINGLE_COIL, coil_addr, 1) time.sleep(3) # 模拟按钮保持时间 self.master.execute(self.unit_id, cst.WRITE_SINGLE_COIL, coil_addr, 0) def publish_state(self): floor self.read_floor() state {car_id: LIFT-01, floor: floor} self.mqtt.publish(iot/elevator/state, json.dumps(state))当然这只是示意代码实际工程中还有大量防御性处理比如异常重连、超时重试、状态缓存。为了把IO映射和业务逻辑解耦我们把所有硬件地址写在一个YAML配置里。现场调整某层的传感器接线时只改配置不用改Python代码# io_mapping.yaml io_module: host: 192.168.1.20 port: 502 unit_id: 1 coils: up_call_2: 0 up_call_3: 2 down_call_2: 1 down_call_3: 3 internal_call_2: 4 internal_call_3: 5 inputs: floor_1: 0 floor_2: 1 gate_open: 2 gate_closed: 3声明式接口层则是一个Flask服务接收机器人发来的JSON请求解析后调用适配层并返回请求ID。同时启动一个状态机跟踪当前电梯在哪个阶段空闲、响应召唤、等待进梯、运行中、到达输出。状态机是声明式架构的核心它把任务拆分为明确定义的有限状态每个状态都有超时时间。比如“响应召唤”状态超过20秒没有检测到门打开就自动复位取消本次请求并上报失败。这个机制很重要能避免机器人卡在电梯门口。3.3 协议重构把“点对点信号”封装成语义动作协议重构听起来高大上落到实地就是做一张映射表物理信号和语义动作之间的一一对应。比如原来维保师傅要靠万用表测量某两个端子判断电梯是否到1层现在我们把平层传感器的信号采集上来在代码里封装成“floor_reached(1)”这样一个函数。以“呼叫上行”为例原来按一下按钮是硬接线动作现在变成三步梯控服务收到“dispatch”请求后先从状态机判断电梯是否可用然后驱动对应楼层的外呼继电器保持一定时间再释放同时监听电梯状态直到电梯到达目标层并且门打开。这里有两个细节值得分享。第一个是去抖继电器和触点都有机械抖动直接读取信号可能由“0”变成“1”再变“0”造成误判。我们用软件滤波连续采样50次每5毫秒一次如果50次中超过40次为高才认为信号到位。第二个是互锁有些老旧电梯的上下行继电器不能同时得电否则可能烧电机所以我们在驱动逻辑中加了“三秒内不允许切换方向”的限制。我把这部分封装成协议转换模块输入是标准语义指令输出是实际的IO操作。这样当电梯维保单位更换某种继电器时只需要修改这个模块不用动上层接口。4. 调试与排查现场最常踩的坑4.1 继电器粘连与信号干扰改造进入实测阶段时出现了一个非常隐蔽的问题电梯每隔几个小时就会自己上一趟没人按按钮机器人也是待命状态。开始怀疑软件逻辑查了很久没找到原因最后带着万用表去控制柜排查发现是驱动外呼按钮的继电器触点粘住了。原来继电器在断开瞬间会产生电弧触点表面形成碳化层用久了就粘连在一起导致外呼按钮回路一直被接通。解决方法是双管齐下。软件上增加互锁逻辑比如驱动完上行外呼后设置3秒冷却时间并且在每次驱动前检测线圈电流如果异常就报警。硬件上替换成带灭弧功能的继电器同时在继电器触点并联RC吸收电路减少电弧。这个经历让我明白梯控改造里最“原始的”硬件反而是最容易出问题的地方不要以为上了物联网就万事大吉。4.2 状态感知不准导致的丢单与卡死另一个高频故障是机器人进入电梯后一直卡在轿厢里系统没确认到达目标楼层。排查发现一层楼装了平层感应器但它发出的信号有时会丢脉冲原因可能是感应器安装位置偏了或者磁铁退磁。我们从两个维度做了修正双通道确认不只靠平层信号还结合楼层编码器计算脉冲数。当两者结果一致时才认为到达目标楼层。超时强制复位如果连续10秒没有状态变化就主动收梯门并尝试重置请求状态。原则是宁可不动作不能卡死。加了这个机制后丢单率明显下降机器人乘梯成功率从最开始不到80%拉到了99%以上。4.3 常见问题速查表调试期整理了下面这张表基本涵盖了能遇到的典型场景问题现象排查点解决方案电梯无响应继电器驱动是否动作、IO模块通信是否正常检查Modbus连接和线圈状态楼层读数跳变传感器损坏或电压不稳用示波器抓波形更换平层开关门开了机器人没进机器人路径规划偏差或状态上报顺序不对增加“door_open”事件机器人收到后再移动多台机器人同时唤梯任务冲突状态机串扰引入请求队列同一时间只处理一个任务网关重启后电梯不受控恢复逻辑不完整配置持久化重启后自动查询电梯当前状态这张表后来直接变成了运维手册减少了大量重复沟通。5. 效果评估与经验总结梯控改造的价值与边界5.1 改造后的性能指标与实际收益改造交付后客户做了两周的数据对比。机器人乘梯成功率稳定在99.2%人工干预次数下降90%平均等待时间从原来的人工呼叫3分钟降到45秒。这些数据是怎么采的机器人任务日志里记录了每次发请求到实际到达的时间梯控服务也记录了每次请求的响应时间、等待时间、是否成功。投入产出比也很直观。这次项目主要成本是边缘网关、IO模块、继电器、传感器和人工调试费用远低于更换一部新电梯。而且梯控系统上线后物料搬运环节不再依赖人夜班也可以靠机器人持续工作节省的人力成本是长期的。5.2 安全与运维的进一步思考梯控系统接入工业物联网后安全成了不可回避的话题。我强烈建议任何做类似改造的人都要考虑“影子模式”和“点名机制”。影子模式是说梯控系统在默认情况下只监听不发指令只有当收到合法请求且满足安全条件时才短暂接管控制权。点名机制则是让梯控系统每隔30秒向机器人调度系统发送心跳如果心跳中断机器人就不能再发指令避免产生“瞎子操作”场景。运维上由于老旧电梯的继电器和触点都属于易损件我们设置了每月巡检提醒建议操作人员用万用表检查关键继电器触点电阻如果比初始值高20%就要更换。梯控服务侧也要定期看日志关注有没有异常重连、状态机卡死等现象。5.3 后续扩展方向多梯联动与预测性维护这个项目虽然针对的是单台货梯但架构其实是可扩展的。下一步很自然的演进是多梯联动。当厂里有三台甚至五台电梯时梯控服务可以收集所有电梯的状态结合每台机器人的任务优先级做群控分配。声明式接口的好处在这里就体现出来了上层调度系统完全不需要知道哪台梯符合机器人所需空间梯控系统会告诉你哪个电梯响应最快、门最合适。另一个方向是预测性维护。我们的梯控服务记录了每天电梯的运行次数、每次召唤到到达的时间、继电器动作次数。这些数据积累下来可以用简单的统计模型来判断继电器是否快要磨损。比如某层外呼按钮被频繁触发触发次数超过阈值后系统会提前建议维保人员检查该层信号触点。按我的经验老旧设备改造的魅力就在于你越尊重原来的物理世界越理解信号的本质上层数字化就越扎实。梯控只是一小步但它背后打通的数据链能让整座工厂的生产调度上一个台阶。如果你也在做类似的改造记住一个基本原则先摸清楚每一根线是干什么的再谈云端联动。