3. 产线通信协议

通信协议这东西,说白了就是设备之间交流的“共同语言”。在缺陷检测产线里,相机、PLC、上位机、机器人,各说各的肯定不行。我见过不少现场,硬件都接好了,灯也亮了,就是数据传不过来——十有八九是协议没对好。

这一章,咱们就把产线通信最核心的几个东西捋清楚。TCP/IP怎么建立连接?Modbus TCP到底传什么?PLC和上位机怎么确认彼此还活着?嗯,这些搞明白了,产线调试至少能少掉一半的坑。

3.1 TCP/IP通信基础——产线通信的“地基”

TCP/IP不是单个协议,而是一整套协议族。在产线场景里,我们最常用的是TCP这个传输层协议。为什么选TCP?因为它可靠——发出去的数据,对方没收到就会重发,顺序也不会乱。

我个人习惯把TCP通信比作“打电话”:先拨号(建立连接),然后通话(传输数据),最后挂断(释放连接)。这个过程在TCP里叫三次握手和四次挥手。

TCP三次握手(建立连接)

  1. 客户端发SYN包,说“我想跟你说话”
  2. 服务器回SYN+ACK包,说“收到,我也准备好了”
  3. 客户端再发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和上位机之间通常有一套固定的握手流程,确保双方状态同步。

我常用的握手流程是这样的:

  1. 上位机发起连接:TCP连接建立后,上位机发送握手请求报文
  2. PLC回复确认:PLC收到后,回复握手确认报文,并带上自身状态
  3. 上位机验证:上位机检查PLC回复的版本号、设备ID等信息
  4. 双方进入就绪状态:握手成功,开始正常数据交换

握手报文里一般包含这些信息:

  • 设备ID:确认连的是不是目标设备
  • 软件版本:防止版本不匹配导致功能异常
  • 时间戳:用于同步时间
  • 状态字:PLC当前运行模式(手动/自动/故障)

下面这张图展示了完整的握手流程:

PLC与上位机握手流程图 PLC与上位机握手流程 上位机 PLC 1. 发起TCP连接 2. TCP连接确认 3. 发送握手请求 4. 回复握手信息 5. 验证设备信息 6. 进入就绪状态 握手成功后,双方开始正常数据交换 若握手失败,上位机应重试或报警

握手失败怎么办?我遇到过几次,原因大多是:

  • 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负载
数据偶尔错乱 字节序不对、寄存器映射错误 用已知值测试,对比高低字节