3. 产线通信协议
通信协议这东西,说白了就是设备之间交流的“共同语言”。在缺陷检测产线里,相机、PLC、上位机、机器人,各说各的肯定不行。我见过不少现场,硬件都接好了,灯也亮了,就是数据传不过来——十有八九是协议没对好。
这一章,咱们就把产线通信最核心的几个东西捋清楚。TCP/IP怎么建立连接?Modbus TCP到底传什么?PLC和上位机怎么确认彼此还活着?嗯,这些搞明白了,产线调试至少能少掉一半的坑。
3.1 TCP/IP通信基础——产线通信的“地基”
TCP/IP不是单个协议,而是一整套协议族。在产线场景里,我们最常用的是TCP这个传输层协议。为什么选TCP?因为它可靠——发出去的数据,对方没收到就会重发,顺序也不会乱。
我个人习惯把TCP通信比作“打电话”:先拨号(建立连接),然后通话(传输数据),最后挂断(释放连接)。这个过程在TCP里叫三次握手和四次挥手。
TCP三次握手(建立连接)
- 客户端发SYN包,说“我想跟你说话”
- 服务器回SYN+ACK包,说“收到,我也准备好了”
- 客户端再发ACK包,说“好,开始吧”
连接建立后,双方才能开始传数据。
我在项目里遇到过一种情况:上位机连PLC,怎么都连不上。查了半天,发现是PLC的TCP端口被防火墙挡住了。你想想看,三次握手的第一步就被拦了,后面当然没戏。
产线通信里,TCP的IP地址和端口号是两个关键参数。IP地址找设备,端口号找设备里的具体服务。比如PLC的Modbus TCP服务,通常监听端口502。
| 参数 | 作用 | 常见值 |
|---|---|---|
| IP地址 | 标识网络中的设备 | 192.168.1.100 |
| 端口号 | 标识设备中的服务 | 502 (Modbus TCP) |
| 子网掩码 | 划分网络范围 | 255.255.255.0 |
| 网关 | 跨网段通信的出口 | 192.168.1.1 |
小技巧:调试时先用ping命令测通不通,再用telnet测端口通不通。两步走完,网络问题基本能定位。
3.2 Modbus TCP协议——PLC与上位机的“通用语言”
Modbus TCP是Modbus协议在TCP/IP网络上的实现。它把Modbus的RTU/ASCII帧直接封装到TCP报文里,省去了串口转换的麻烦。
Modbus TCP的报文结构很简单,我拆开给你看:
| 事务标识符(2B) | 协议标识符(2B) | 长度(2B) | 单元标识符(1B) | 功能码(1B) | 数据(NB) |
| MBAP报文头 (7B) | PDU (至少2B) |
- 事务标识符:用于匹配请求和响应,一般每次通信加1
- 协议标识符:固定为0x0000,表示Modbus协议
- 长度:后续字节数(从单元标识符开始算)
- 单元标识符:从站地址,通常填0x01或0xFF
- 功能码:告诉PLC要做什么操作
- 数据:具体的读写地址和数值
常用的功能码就那么几个,我列个表:
| 功能码 | 名称 | 作用 | 产线场景 |
|---|---|---|---|
| 0x01 | 读线圈 | 读取DO状态 | 读取气缸到位信号 |
| 0x02 | 读离散输入 | 读取DI状态 | 读取传感器信号 |
| 0x03 | 读保持寄存器 | 读取16位数据 | 读取检测结果、计数 |
| 0x06 | 写单个寄存器 | 写入16位数据 | 写入启动/停止指令 |
| 0x10 | 写多个寄存器 | 批量写入数据 | 写入检测参数 |
我曾经在一个项目里踩过坑:上位机用功能码0x03读PLC的D寄存器,结果读回来的值全是0。查了半天,发现PLC的D寄存器起始地址是0,但Modbus地址是从1开始算的。也就是说,我想读D0,Modbus地址要填1。这种偏移问题,你调试时一定要留意。
注意:不同品牌的PLC,Modbus地址映射可能不一样。西门子、三菱、欧姆龙,各有各的映射规则。拿到PLC手册后,第一件事就是确认地址映射表。
3.3 PLC与上位机握手流程——建立通信的“仪式”
握手,就是双方确认“我准备好了,你呢?”的过程。在产线里,PLC和上位机之间通常有一套固定的握手流程,确保双方状态同步。
我常用的握手流程是这样的:
- 上位机发起连接:TCP连接建立后,上位机发送握手请求报文
- PLC回复确认:PLC收到后,回复握手确认报文,并带上自身状态
- 上位机验证:上位机检查PLC回复的版本号、设备ID等信息
- 双方进入就绪状态:握手成功,开始正常数据交换
握手报文里一般包含这些信息:
- 设备ID:确认连的是不是目标设备
- 软件版本:防止版本不匹配导致功能异常
- 时间戳:用于同步时间
- 状态字:PLC当前运行模式(手动/自动/故障)
下面这张图展示了完整的握手流程:
握手失败怎么办?我遇到过几次,原因大多是:
- PLC程序里握手逻辑没写对,回复的报文格式不对
- 上位机等待超时时间设得太短,PLC还没回复就放弃了
- 版本号不匹配,上位机拒绝继续通信
建议:握手超时时间设3-5秒比较合理。太短容易误判,太长影响产线启动速度。
3.4 心跳包机制——确认对方“还活着”
握手只是开始。产线运行过程中,通信随时可能中断——网线松了、PLC死机了、上位机卡住了。怎么及时发现?靠心跳包。
心跳包,就是双方定时互发的一个短报文,告诉对方“我还活着”。如果连续几次没收到心跳,就判定通信中断,触发报警或安全停机。
心跳包的设计要点:
- 发送间隔:一般1-5秒发一次,太频繁浪费带宽,太慢响应不及时
- 超时次数:连续3-5次没收到,判定断连
- 报文内容:尽量短,通常只包含设备ID、序列号、时间戳
- 独立线程:心跳收发最好用独立线程,别跟业务逻辑混在一起
我见过一个项目,上位机用Modbus TCP读PLC数据,读不到就认为PLC挂了。其实只是网络瞬间抖动,读请求丢了。后来加了心跳包机制,连续3次收不到心跳才报警,误报率直接降到零。
心跳包典型实现(伪代码)
// 上位机心跳发送线程
while (true) {
sendHeartbeat(deviceId, seqNum, timestamp);
seqNum++;
sleep(2000); // 2秒发一次
}
// 上位机心跳接收检测
if (lastHeartbeatTime + 5000 < currentTime) {
// 超过5秒没收到心跳
triggerAlarm("PLC通信中断");
enterSafeState();
}
心跳包还有一个妙用:可以用来估算通信延迟。记录发送时间和接收时间,差值就是往返延迟。如果延迟突然变大,说明网络可能有问题,提前预警。
注意:心跳包不能替代业务数据的读写。有些工程师图省事,用心跳包带业务数据,结果心跳丢了业务数据也丢了。心跳就是心跳,别让它干别的活。
3.5 产线通信的常见问题与排查思路
最后,我总结几个产线通信的常见问题,都是我在现场真刀真枪碰到的:
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| TCP连接不上 | IP/端口错、防火墙拦截、网线松动 | ping + telnet,逐层排查 |
| Modbus读写超时 | 地址错误、功能码不支持、PLC忙 | 用Modbus调试工具抓包分析 |
| 握手失败 | 报文格式不对、版本不匹配 | 对比报文结构,检查版本号 |
| 心跳中断 | 网络抖动、PLC死机、线程卡死 | 查看心跳日志,检查CPU负载 |
| 数据偶尔错乱 | 字节序不对、寄存器映射错误 | 用已知值测试,对比高低字节 |