2026/10/21 16:22:10

料箱输送线程序精华:WCS与PLC的Socket接口设计及分拣状态机实战

料箱输送线程序精华:WCS与PLC的Socket接口设计及分拣状态机实战 做物流自动化这块的同行应该都有同感输送线程序本身不算难真正让人掉头发的是上位机和下位机之间怎么把数据“接”明白尤其是带着 WCS 的料箱输送线项目。光有合流、分拣、缓存、回流这几段逻辑PLC 写得再花哨只要 WCS 和 PLC 之间的 Socket 接口没设计好联调阶段就是大型翻车现场。这些年我经手过的输送线项目里只要涉及 WCS 调度最核心的难点永远是两个一是 Socket 接口的通信协议设计二是分拣控制程序的状态逻辑。这两个部分做扎实了项目就稳了一半做不好后面就是无穷无尽的“丢任务”“撞车”“错分”等着你。这篇文章把料箱输送线程序里的这两块精华单独拎出来聊从架构设计、报文格式、状态机逻辑到联调排查把我实际踩过的坑和验证过的方案一次说清楚。不管你是刚接触物流自动化的电气工程师还是想深入了解 WCS 和 PLC 通信逻辑的软件工程师这篇都应该能给你一些能直接用的东西。1. 先搞明白料箱输送线项目里到底在控制什么很多新人一上来就抱着 PLC 写代码写了两周才发现自己写的不是输送线程序而是一堆孤立的启停、正反转。要真正理解这个项目必须先跳出程序本身把整个系统的物理构成和数据流看清楚。1.1 输送线系统的物理组成与控制对象一条典型的料箱输送线物理上通常由几段组成进料段来料口、主线贯穿输送通道、合流段多条支线汇入主线、分拣段主线两侧分出若干个格口、缓存段暂时存放或回流异常料箱。PLC 控制的对象大致分三类马达类辊筒电机、皮带电机、提升机电机执行机构类挡停器、换向器转向器、分拣摆轮检测类对射光电、反射光电、读码器、称重设备程序层面要做的就是让这些设备按照既定的节拍和逻辑动作起来。但请注意单机运行和一个真正接入 WCS 的输送线系统程序复杂度是两个量级。单机运行只需要考虑“这一段有没有料箱有就往前传”带 WCS 之后程序要考虑的就变成“这个料箱要去几号格口现在能不能放行任务完成后怎么汇报”。1.2 合流和分拣这两个工序难在哪合流和分拣看起来很简单合流不就是两条皮带并一条嘛分拣不就是读个码然后推一下嘛。但在实际项目里这两个工序是整个输送线最容易出幺蛾子的地方原因有下面几个。合流的难点在于不确定性和竞争。两条支线上料箱的到达时间是随机的谁先到、谁先走不能让两个箱子在同一时刻进入汇合区否则就是物理撞击。这个裁决逻辑必须在 PLC 侧以毫秒级完成因为 WCS 的调度指令是宏观的它不会帮你精确到“哪一秒放行”。分拣的难点在于精确性和确认机制。料箱在移动中读码、在移动中触发换向器、在入格后还要确认“真正进去了”这中间任何一个环节延误都会导致错分或者堵料。而且分拣动作的触发时机和正在高速行走的料箱位置强相关窗口时间往往只有几百毫秒。1.3 为什么要 PLC 加 WCS 两层架构有人会问分拣逻辑 PLC 里自己都能写为什么非要一个 WCS 在中间调度答案很简单柔性和可维护性。PLC 的运行逻辑擅长处理物理世界的实时控制但不擅长处理业务订单。业务层今天可能要求“料箱 A 去 3 号格口”明天可能改成“料箱 A 去 7 号格口”后天可能还要加上“优先级料箱先走”。如果这些规则全部写死在 PLC 里每一单业务变化都要改 PLC 程序都得停机下载现场根本没法接受。所以更合理的分工是WCS 负责任务分配、路径决策、格口管理、订单绑定PLC 负责物理执行、位置追踪、设备逻辑、分拣动作这样分WCS 换策略不动 PLCPLC 改了设备逻辑也不影响上层业务。接口处只需要定义一套稳定的通信协议即可这也是 Socket 接口会成为项目精华的第一个原因。2. 精华之一WCS 与 PLC 的 Socket 接口设计Socket 接口听起来很技术实际上就是让 WCS 和 PLC 之间建立起一个可靠的 TCP 连接然后两个人按约定好的格式“说话”。这个环节看起来只是写点报文收发但它决定了整个系统能不能稳定跑起来。我做过的项目里凡是联调阶段反复出问题、三天两头断线丢任务的八成是接口设计没想清楚。2.1 接口协议设计报文格式怎么定很多人第一次做 Socket 接口时最容易犯的错误是直接用字符串拼接传输比如发一个“ABC123,35,1”没有任何长度标识和校验。这种格式在数据量小、传输频率低的场景还能勉强工作但一旦并发量上去、数据稍微复杂一点粘包、断包、误码问题就全来了。我惯用的方案是自定义一个固定格式的应用层报文结构上分成报文头、命令字、数据体、校验四部分段名称长度字节说明报文头2固定标识比如 0xAA55用于识别一个报文的开始命令字1报文的类型例如 0x01 表示心跳0x02 表示任务下发数据长度2数据体的字节数不含报文头和校验数据体N实际业务数据可以做成 ASCII 字符串也可以做成二进制结构体校验和1从命令字到数据体所有字节的累加和用于简单的误码检测举一个具体的例子假设 WCS 要给 PLC 下发一个分拣任务料箱条码是 BX1024目标格口是 6 号那么数据体可以设计成 ASCII 字符串TASK,BX1024,6,0加上报文头和命令字后完整报文看起来像这样AA 55 02 00 10 54 41 53 4B 2C 42 58 31 30 32 34 2C 36 2C 30 7F AA 55 —— 报文头 02 —— 命令字任务下发 00 10 —— 数据体长度16 字节 54 41 ... 30 —— “TASK,BX1024,6,0” 7F —— 校验和为什么要这样设计三个理由第一固定报文头解决了“数据从哪开始”的问题。接收方只要一看到 0xAA55就能确认这是新包起点配合数据长度字段可以精确截取一个完整报文粘包的问题基本被消解。第二校验和字段能识别传输过程中的干扰。工业现场电磁环境并不好偶尔一个字节被冲掉很正常如果没有校验错误数据被当成任务执行那就是重大事故。第三命令字的存在让协议可扩展。后续要增加报警上报、状态查询、路径切换指令只需要在命令字里新定义几个值接收方的解析状态机做相应分支完全不影响老报文。2.2 心跳、超时和断线重连机制TCP 是面向连接的但“连接还在”不等于“对方还活着”。如果 WCS 进程卡死了PLC 这边可能还觉得连接正常等到任务下发的时候才发现没反应已经晚了。所以双方必须有心跳机制。心跳间隔一般建议 1 到 3 秒具体看项目对实时性的要求。我见过有人用 10 秒心跳结果 WCS 死了一半时间现场才发现。反过来心跳间隔太短也会增加 PLC 的通信扫描负担1 到 3 秒是比较平衡的选择。超时判定要设置成心跳间隔的 3 到 5 倍。也就是说如果 5 到 10 秒内没有收到对方的任何数据包括业务报文也算就可以认定连接已经死了。此时双方都要做两件事标记异常状态、触发报警并开始重连流程。这里有一个关键设计重连应该由谁发起。我在项目里通常把 PLC 做成 TCP 服务端固定端口监听WCS 做成客户端负责主动连接。这样做的考虑是 PLC 程序相对固化不太方便频繁重启去重连对方而 WCS 作为软件系统做重连逻辑非常灵活。WCS 侧的重连逻辑类似这样while (!isConnected) { try { plcClient new TcpClient(); plcClient.Connect(plcIp, plcPort); StartHeartbeatTimer(); break; } catch { Thread.Sleep(GetRetryInterval(retryCount)); retryCount; } }重连间隔不要一直是固定值最好先快后慢第一次失败等 1 秒第二次等 2 秒最多等 10 秒避免 PLC 重启过程中 WCS 反复狂刷连接请求把 PLC 的通信资源打满。2.3 位置上报和任务下发的数据流模型Socket 接口不仅仅是传字符串传什么、什么时候传、谁先传这些规则必须在协议设计阶段就定义好。我自己总结下来料箱输送线的数据流模型可以分成三大类。第一类是上行汇报报文PLC 主动发给 WCS 的。典型的有料箱到位上报料箱进入某个关键位置需要 WCS 下发下一步指令、任务完成上报料箱成功入格任务闭环、异常报警上报卡料、满箱、读码失败。第二类是下行指令报文WCS 发给 PLC 的。典型的有任务下发告知 PLC 某个条码的料箱应该去哪个格口、放行指令允许合流段把料箱放出去、暂停恢复指令。第三类是双向握手报文。这类报文必须带序列号每次请求发一个自增序号响应报文必须回相同的序号这样双方才能匹配“我刚才那条指令的结果”。位置上报的时机特别重要。太频繁WCS 会被垃圾信息淹没太疏WCS 根本不知道料箱到哪儿了调度就会瞎指挥。一个合理的做法是只在“关键位置”上报进料口、合流口、分拣读码位、格口入口、缓存口。中间那些连续几十个辊筒的位置不需要逐段上报PLC 自己跟踪就够了。2.4 通信中间件选型要还是不要有些人喜欢在 WCS 和 PLC 之间加一层 MQTT 或者 OPC UA理由是好扩展、好维护。我的观点是如果项目只是单台 PLC 和 WCS 对接直接用最原始的 TCP Socket不要画蛇添足。中间件的优势在多个系统协同的场景下才能体现出来比如多台 PLC、多台机器人、立体库堆垛机都要数据中间件可以做统一分发。但如果只有一台 PLC引入中间件意味着 PLC 侧又要多一层网关协议转换排查问题的时候多了一个变量响应速度也慢了。Socket 裸接口的实时性是最可控的毫秒级延迟非常稳定。最后提醒一句无论用哪种通信方式必须把“网络中断时设备处于什么状态”这个策略提前定好。我的默认策略是通信断开的瞬间PLC 自动把输送线降速并锁定合流和分拣动作保证料箱不会因为失去任务指令而被错误分拣或发生碰撞。等通信恢复后再继续放行。3. 精华之二分拣控制程序的逻辑实现分拣控制程序是 PLC 侧的核心算法部分。它做得好不好不看指令发得有多远就看料箱走过分拣段的时候动作是不是干净利落、没有任何犹豫。3.1 合流点调度谁先过怎么等合流段的物理布局通常是两条支线或三条汇入一条主线交叉点前后各有光电和挡停器。控制目标非常朴素任何时刻最多只能有一个方向的料箱进入汇合区。但实现起来有些讲究。最简单的做法是轮询也就是两条支线交替放行各放一个。这种策略在两条支线来料均匀时没问题但如果其中一条支线来得多、另一条来得少轮询会让多余料箱堵在支线上主线吃不饱整线效率就下来了。更合理的策略是给每条支线设定不同的优先级按照优先级仲裁来决定放行方向。优先级判断可以基于几个维度支线缓存区的剩余容量快满了优先放料箱的任务紧急程度加急单优先主线上一次放行来自哪一侧避免单侧长时间等待实际执行时合流点两侧的挡停器动作顺序是先释放优先级高的一侧等这个料箱完全越过汇合区下游的光电确认点后再释放另一侧。注意“完全越过”这个条件不能只看料箱头部过了汇合区就放行另一侧要等尾部也通过否则尾部和另一侧料箱的头部会在汇合区追尾。PL C 合流仲裁的核心伪代码大概这样// 两个进料请求输入 IF (requestFromLeft AND requestFromRight) THEN // 左侧缓存区更满或者左侧有加急任务则先放左 IF (leftCacheLevel rightCacheLevel OR leftUrgentFlag TRUE) THEN releaseSide : LEFT; ELSE releaseSide : RIGHT; END_IF; END_IF; // 等待已放行料箱离开汇合区 WHILE (mergeConfirmSensor.remaining TRUE) DO ; // 阻塞等待实际程序里用定时扫描轮询 END_WHILE; ActivateRelease(releaseSide);这个逻辑看起来简单但实际调试过程中极容易因为传感器安装位置不对或者确认点选取不恰当导致明明已经空下来了另一侧还是不放行进而整个合流段憋车。3.2 分拣状态机与格口执行逻辑分拣段的控制对象包括读码器、分拣时机判断、换向器、格口入口挡停器。整个流程可以用一个清晰的五态状态机来描述状态 S0空闲态等待料箱进入分拣读码区状态 S1读码等待态料箱已触发读码光电等待条码读取结果状态 S2决策等待态已读到条码与 WCS 通信中等待目标格口指令状态 S3输送执行态目标格口已下发等待料箱到达该格口入口状态 S4入格确认态料箱触发格口入口挡停器确认入格动作完成这个状态机的核心思想是状态之间的迁移条件必须全部来自“物理传感器的确认”而不是纯粹靠时间延时来推算。很多初学者喜欢用延时指令来估算“料箱大概走到哪了”结果一旦皮带打滑、料箱超重实际位置偏离预期分拣时机就全错了。PL C 分拣状态机示例CASE state OF S0: // 等待到位 IF readSensor THEN state : S1; END_IF; S1: // 等待读码完成 IF barcodeReady THEN SendBarcodeToWCS(barcodeData); state : S2; ELSIF readTimeout THEN HandleReadFailure(); state : S0; END_IF; S2: // 等待 WCS 分拣目标 IF taskReceived THEN targetChute : receivedChute; state : S3; ELSIF waitTimeout THEN HandleTaskTimeout(); state : S0; END_IF; S3: // 料箱向目标格口运动 IF chuteEntrySensor THEN ActivateDiverter(targetChute); state : S4; END_IF; S4: // 入格确认 IF chuteLoadSensor THEN SendTaskComplete(barCode, targetChute); state : S0; ELSIF entryTimeout THEN HandleInfeedError(); state : S0; END_IF; END_CASE;这里有一个重要的细节换向器的触发时机不是“料箱到了格口入口就动作”而是要在料箱的特定位置比如料箱中部或者箱体大部分越过前段时动作同时结合皮带速度与转向器动作时间提前计算出发射时刻。对于 12 米每分钟的输送线换向器动作时间约 0.3 秒料箱长度 0.6 米那么触发点应该是在料箱头部距离格口入口还有约 0.6 米到 1 米的位置。这个值不见得用公式硬套现场测试两台箱通过情况再微调即可。3.3 异常分支满箱、错分和回退处理分拣程序不能只写正常路径异常路径才是真正见功底的地方。下面的异常分支是任何项目都躲不开的。第一个异常是格口满箱。WCS 在任务分配时就应该根据格口实时容量决定是否继续分配但 PLC 侧必须有硬件保护。一旦格口入口的光电被满箱料箱挡住且持续超过一定时间PLC 要主动封锁该格口的分拣动作防止后面的料箱不断送进来叠罗汉。第二个异常是读码失败。读码器偶尔读不到是常态不要一读不到就把料箱送到异常口。建议做法是第一次读码失败后经过一个位置偏移量再补读一次两次都失败再上报 WCS 并走异常缓存道。补读的偏移量要根据输送线速度和读码器触发区长度来整定一般 200 到 400 毫秒后再触发一次。第三个异常是任务超时。PLC 发送条码给 WCS 后WCS 迟迟没有返回目标格口这时候 PLC 必须停止该料箱的输送绝对不能让它直接冲过主线然后上报通信异常等待人工或 WCS 指令处理。第四个异常是入格超时或者未确认。料箱已经被换向器导入格口但格口入口光电始终没有亮可能的原因是料箱卡在格口内部、换向器没有到位、或者料箱在进入过程中被后续料箱撞偏。PLC 要在这个异常发生时立即停掉整个分拣段主线防止连环追尾。4. 联调阶段的实战经验与问题排查程序写完之后真正的重头戏是联调。很多问题写代码的时候根本暴露不出来一上现场就被放大了。下面这些经验都是我一次次在项目现场熬出来的。4.1 Socket 联调的标准流程联调千万不要直接拿着两家系统就开始真枪实弹地测一定要分成四个步骤走。第一步是纯网络联调。用网络调试助手连 PLC 的通信端口确认端口能连通、心跳报文能正常收发。这一步看着简单但能筛掉一半的“连不上”问题比如 IP 写错、端口被占用、防火墙拦截。第二步是模拟 WCS 联调。在 PC 上装一个模拟上位机软件按你们定义的协议周期性发送心跳、随机下发任务同时观察 PLC 的响应。这个过程可以把协议定义里的死角和 bug 全部暴露出来比如命令字节序不一致、长度字段解析错误、CRC 校验算法不匹配。第三步是真实 WCS 手动模式联调。启用手动功能由人工在 WCS 界面上逐个下发任务PLC 单步执行分拣动作。这步主要验证数据映射关系、料箱条码是否正确关联到 PLC 的内部编号、格式是否符合 PLC 侧预期。第四步是自动模式带载联调。这一步要从单箱开始逐步增加到整线连续运行观察节拍和异常处理是否稳定。前两步有问题时最好不要进入这一步否则你根本分不清问题是通信的还是机械的还是程序的。4.2 节拍瓶颈分析与参数整定分拣线能否达到设计产能不是靠事后感觉而是靠节拍计算提前估算出来的。这里分享一个我常用的简化算法。假设主线运行速度是 V 米/分钟料箱沿传送方向的平均长度是 L 米那么主线单位时间能通过的最大箱数为主线最大通过率 V / L 箱/分钟如果设计节拍要求 10 箱/分钟而主线速度是 12 米/分钟、料箱长度 0.6 米那么主线最大通过率是 20 箱/分钟理论上有余量。但加上合流和分拣段的占用因素实际通过率会显著下降。分拣段有一个重要参数叫“分拣循环时间”从读码器触发、WCS 下发指令、到料箱完成入格确认的整个周期。假设读码耗时 0.3 秒WCS 通信耗时 0.2 秒换向器动作 0.3 秒料箱从读码区到格口入口的输送耗时 1.5 秒那么这个循环时间就是 2.3 秒左右。理论上每 2.3 秒可以通过一箱换算成每分钟约 26 箱。但实际情况中WCS 的响应时间会波动、料箱间距也不均匀所以设计时至少打七折使用。如果在联调时发现分拣段成为了瓶颈通常的优化手段有两种一是让 PLC 在读码器读到条码之前就开始向 WCS 请求任务预请求把通信等待时间从循环时间中剔除二是在格口入口增加预减速段减少料箱在挡停器前等待的时间。4.3 常见问题速查表下面的问题是联调阶段出现频率最高的我按问题现象、根因和解决办法整理成了一张速查表现场排查的时候可以直接对照着查。问题现象可能原因解决措施通信频繁断开重连心跳间隔太短或 PLC 通信扫描周期过长调整心跳间隔到 2~3 秒检查 PLC 通信任务优先级WCS 下发的任务 PLC 收不到报文长度字段计算错误、校验和算法不一致用网络抓包和 PLC 监视变量对比原始报文分拣时料箱在换向器前“犹豫”换向器预触发时间太晚料箱已经走过分拣点提前触发点或者在读码区就提前计算触发距离合流处偶尔撞车一侧料箱未被确认完全离开汇合区就放行另一侧检查下游确认光电的位置确保尾端通过后再释放复位后任务丢失分拣状态机没有设置掉电保持PLC 重启后状态复位对关键任务号、当前目标格口用掉电保持变量存储格口满箱后仍在分拣只有 WCS 侧满箱判断PLC 侧缺少满箱保护PLC 增加格口入口光电持续占用时间判断并封锁分拣4.4 日志与调试工具排查问题必备说到最后我特别想强调日志的重要性。很多现场问题为什么排查了几天都没头绪因为系统一跑状态满天飞你根本不知道故障发生前后几十秒内系统的准确状态顺序是什么。建议在 WCS 侧给每一个关键动作都打点日志包括任务下发时间戳、条码内容、目标格口、报文方向、报文内容摘要。PLC 侧也把关键状态变量传到触摸屏或调试软件里至少保留最近 100 条报警记录。这样出现问题时先对日志时间轴再看 PLC 状态跳变基本 5 分钟内能定位问题方向。调试工具方面我常用的组合是被迫对抓包软件加串口打印。网络通信层面用抓包软件看报文是否及时送达应用层面用 PLC 在线监视表看状态机跳变。两者结合起来协议问题、逻辑问题都能快速区分开。这个项目做下来我最大的体会是料箱输送线程序里真正体现工程水平的不是设备逻辑有多复杂而是通信协议是否细致、状态机是否严谨、异常分支是否完整。Socket 接口设计的理不理想直接影响联调能不能顺利推进分拣控制程序写得好不好直接决定现场实际产量能不能达到设计要求。最后分享一个我常用的技巧正式联调之前先在 PC 上用脚本写一个模拟 WCS把协议和分拣任务流程全部仿真一遍。很多通信问题、状态机漏洞你在去现场之前就已经顺手解决了到了现场再调试的时候遇到的问题会少很多。这个习惯帮我避了无数不必要的工厂日夜加班。