ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PLC做Socket从站:汇川EASY系列TCP通讯实战指南

PLC做Socket从站:汇川EASY系列TCP通讯实战指南 1. 项目背景为什么要让PLC做socket从站事情得从一条产线改造说起。现场有一台汇川EASY系列PLC原本只走Modbus RTU和触摸屏通讯但后来要接一套MES系统上位机需要直接读PLC里的产量、故障码、设备状态。传统做法是加一个网关模块或者让上位机通过Modbus TCP轮询。但问题是MES这边是Java开发他们只肯用JSON格式的数据而且要求PLC主动推送不想要轮询的通讯方式。这就逼着PLC这边开一个socket服务端端口做一个真正的从站——上位机连上来PLC把数据打包成JSON发过去或者接收上位机下发的配方参数。汇川EASY系列里的EASY521、EASY522这类带以太网口的CPU自带socket库函数支持TCP/UDP完全能干这个活。很多人一听PLC做socket从站就觉得高大上其实落地说穿了就三件事PLC监听端口、等待连接、收发数据。难的从来不是socket本身而是怎么把PLC里几百个变量的读写逻辑安排好怎么处理断线重连怎么保证数据格式稳定。这篇博文就把我用EASY系列做socket从站的完整思路和踩坑记录写出来从通讯原理到程序框架再到排查问题。不管你是要把PLC数据推给MES还是让两个品牌的PLC做以太网直连这套思路都通用。2. 底层原理看懂socket通讯的数据流2.1 用打电话理解socket机制socket通讯初学者最容易卡在概念上。我给你打个比方整个以太网通讯就像打电话。服务器的IP地址就是电话号码端口号就是分机号。你给总机拨号连接IP转接到分机端口通上话之后两边就可以双向说话了。TCP协议就像打电话接通后保持通话谁都不挂断数据有来有回顺序不会乱UDP协议就像发短信编辑一条内容扔过去对方收不收得到、什么时候收到你没办法保证。在EASY系列PLC里我们的角色是接电话的那个人也就是从站或者服务端。PLC先开机然后在某个端口上守着相当于把电话放在桌上等着响铃。上位机按IP和端口拨过来PLC检测到有连接请求同意接听accept这个通话就建立起来了。关键点在于socket通讯是全双工的就跟打电话一样能同时说和听。所以PLC可以在同一时刻既发送数据给上位机也接收上位机下发的内容。这一点和Modbus这种半双工总线协议完全不同因为Modbus的请求应答模式决定了同一时刻只有一个方向在传输。2.2 TCP与UDP在实际工控场景中的选择做PLC通讯选型TCP还是UDP这个决定直接影响后面程序的复杂度和稳定性。TCP是面向连接的协议有三次握手、确认应答、超时重传这些机制。数据发出去了如果对方没收到系统会自动重发接收方收到错乱的数据包系统会丢弃。对于PLC上报产量、设备状态、报警信息这些数据一个都不能丢的场景TCP是首选。UDP就简单粗暴得多它只负责把数据报发出去不管对方收没收到。好处是快没有握手和确认这些额外开销但坏处也很明显丢包、乱序、重复。纯UDP适合什么场景呢广播类的应用比如PLC把自己的状态每隔几秒发一次上位机收到算幸运收不到就等下一条。但如果你是做MES对接人家那边要一条不多一条不少的数据UDP就不合适了。实际项目中我还有第三种方案TCP长连接加上自定义心跳。这个在4.2节里详细说不属于UDP也不完全是TCP的默认行为而是协议层的设计思路。2.3 EASY系列PLC的网络硬件特性聊完协议再来看硬件。汇川EASY系列分好几个子型号EASY521、EASY522、EASY523这些是带以太网口的CPU本体一般有1路以太网接口支持10/100M自适应。EASY系列有的型号还支持EtherCAT总线但要注意区分EtherCAT是运动总线协议socket通讯是普通TCP/IP协议栈的服务两者不冲突但功能定位完全不同。EASY系列的以太网口支持两种工作方式一种是编程口直连就是你在INOTECH软件里在线监控程序用的另一种是用户通讯口就是我们做socket服务用的。这两个功能可以同时启用IP地址也是同一个也就是说上位机既可以通过网口下载程序也可以同时作为socket客户端连接PLC上的服务端口。规格上有一点需要提前确认EASY521的socket资源数量是有限的我记得是支持多个同时连接但具体要看固件版本。如果你的项目需要多个上位机同时连接同一台PLC建议提前查一下对应型号的《用户手册》里socket通道数的说明避免程序写完了才发现资源不够。3. 方案设计socket从站的整体架构与关键指标3.1 从站模式的三层数据流设计一个完整的PLC socket从站项目绝不是简单地在PLC里面开个口子收发数据而是要设计清晰的数据流。我通常分成三层来规划。数据接入层PLC采集现场的设备状态、传感器数据、工艺参数这些数据分布在保持寄存器、内部继电器、定时器里。需要提前规划好哪些数据要往上传映射到专门的通信变量区。协议处理层把通信变量区封装成特定的报文格式。如果你自己定了JSON格式的协议这一层就要做字符串拼接和解析如果你是走Modbus TCP这一层就是标准的MBAP帧处理。socket传输层负责TCP连接管理、数据收发、断线重连、收发缓冲区的读写。这一层在EASY系列里是通过socket库函数完成的。这么分层设计的好处是每一层改动不会影响其他层。后期如果MES系统决定把JSON协议改成XML你只需要把协议处理层换掉socket层和变量映射层都不用动。3.2 通信变量区规划先定协议再写代码我做过几个以太网通讯的项目最深刻的体会就是写socket程序之前先把协议文档定义清楚然后规划通信变量区。以汇川EASY系列为例我建议在PLC里专门开辟一段连续的保持寄存器作为通信映射区。比如你定义M区里的M0~M99作为协议解析后的内部标志D区里的D1000~D1100作为通信数据映射区。上位机发送过来的配方数据PLC解析后写入D1000开始的一段地址程序内部再从这些地址读取使用PLC要上传给上位机的数据程序先把它们汇聚到D2000开始的地址区socket发送函数直接从这个区域取值。这种做法的优势非常明显。调试的时候你在INOTECH软件的监控表里观察D1000和D2000这两个区域一眼就能判断是PLC程序的问题还是socket通讯的问题。如果D1000里的数据到了但上位机没收到说明socket发送环节有bug如果D1000里的数据本身就不对问题就在PLC程序和上位机下发的协议上。3.3 关键指标响应时间、吞吐量与连接数通讯方案需要量化指标。我建议在方案设计阶段就定下三个关键数值后面做测试才有标准。响应时间从上位机发送请求到PLC返回应答的时间。这个受PLC扫描周期、socket处理频率和网络延迟共同影响。EASY系列CPU的扫描周期通常在毫秒级加上socket库的处理一般20ms内的响应时间基本都能达到。吞吐量单位时间内传输的数据量。PLC场景下你不可能像PC那样跑大文件传输。一般的MES读取、配方下发一帧数据几十到几百字节一秒钟几十次交互就足够了。如果需求是每秒几兆字节的传输那PLC做socket就不太合适了得上专门的数据采集网关。连接数同一时刻支持多少个客户端连接。对于单台上位机的场景1个连接就够。但如果你有多个MES节点同时连接就需要注意EASY系列支持的socket通道数限制。一般支持2~4个是没有问题的但建议加连接数监控超过限制时主动拒绝新连接。4. 实操实现从零搭建EASY系列的socket从站程序4.1 初始化配置IP地址与端口设置先做准备工作。用网线连接EASY系列PLC和电脑在INOTECH软件的通讯设置里给PLC分配一个固定IP地址。注意这个IP必须是设备所在的局域网地址不要用DHCP自动获取因为PLC做socket服务端时IP如果变了上位机就永远连不上了。举例说明假设PLC的IP设置为192.168.1.10子网掩码255.255.255.0默认网关192.168.1.1。上位机电脑的IP要设成192.168.1.x网段内的地址比如192.168.1.20保证它们两个在同一个局域网里。然后确定端口号。端口号的选型有个原则避开知名端口和易冲突端口一般选1024以上的高位端口。实际项目中我用过5020、8000、9000都挺稳定的。避免用5000这类常见的开发端口防止和现场其他软件的端口冲突。在EASY系列的库函数里socket初始化一般用Socket_Server_Init之类的指令里面配置好本地端口号、TCP或UDP模式、最大连接数这些参数。4.2 核心程序框架完整状态机思维PLC的程序和PC程序最大的不同在于PLC没有main循环从main开始执行到结束这个概念它的程序是按扫描周期不断重复执行的。所以socket服务程序必须用状态机的方式来组织。我用一个程序块来管理整个socket服务端逻辑用状态字来标识当前处于哪个阶段。状态机大致是这个流程状态0关闭状态。程序初始化时进入这个状态把socket关闭标志位复位。状态10监听状态。PLC创建socket服务端并开始监听端口相当于把电话放在桌上等铃响。如果监听成功跳转到状态20如果失败记录错误码并返回状态0等待重试。状态20等待连接状态。PLC一直在检查是否有新的客户端连接请求。这个检查是每扫描周期执行一次的EASY系列的库函数会返回是否有连接建立。有连接来了跳转到状态30。状态30通讯运行状态。这是核心工作状态。程序在这个状态里做三件事接收上位机发来的数据、处理数据并执行相应逻辑、把回发数据打包发送出去。状态40断开处理状态。当TCP连接断开对方关机、网线拔了、通讯超时程序要能及时发现这个事件然后清理缓冲区、释放连接资源回到状态20继续等待新的连接。这个状态机思路看着简单但特别重要。如果你不用状态机而是试图在程序里写一个while循环去等连接PLC会卡死在那里后面的程序全部不扫描了这绝对是新手最爱犯的错误。4.3 监听、等待连接与超时重连机制具体到EASY系列的库函数监听端口之后需要自己写一个查询是否有新连接的逻辑。这个过程通常是每扫描周期调用一次Socket_Accept之类的函数这个函数会返回一个布尔值或者错误码告诉你当前有没有新的客户端连上来。这里要特别注意超时处理。上位机可能连着连着突然崩了或者网线松了但TCP连接不会立刻断要等TCP超时机制检测到。TCP默认的超时时间可能要几十秒甚至更久这在工业现场没法接受因为你需要快速判断连接状态然后做出相应处理。解决方法是自己加心跳机制。PLC作为从站不需要上位机发什么只需每5秒向上位机发送一个特定的心跳报文比如字符串PING上位机收到后回应一个PONG。如果PLC连续3次发送心跳都没收到上位机的回应就认为这条连接已经死了主动关闭socket回到等待连接状态重新等待新的客户端接入。我在自己的项目里用过心跳方案实测非常可靠。即使上位机程序崩溃PLC最多15秒左右就能发现连接异常并恢复比干等TCP默认超时靠谱得多。4.4 数据接收的边界问题与缓冲区设计socket通讯中数据接收有一个天然的问题你没办法保证一次接收就拿到完整的一帧数据。TCP是流式协议它没有消息边界的概念上位机发来的数据可能被分成好几个TCP包到达也可能好几个数据帧合并成一个包到达你的接收缓冲区。举例说明上位机打算发送10字节的数据但PLC的接收缓冲区可能第一轮只读到4字节剩下的6字节要到下一轮扫描周期才读到。如果你在程序里假设一次接收一定是一帧完整数据就会解析出错。应对方法就一句话接收缓冲区帧完整性判定。具体做法是PLC每次调用socket接收函数把读到的字节追加到一个自定义的缓冲区数组里然后检查缓冲区中的数据长度是否达到一帧要求的长度或者检查缓冲区中是否出现了帧尾字符比如\n。如果满足就取出完整的一帧进行处理剩余的数据留在缓冲区等待和下一轮收到的新数据拼成新帧。我在项目中用的方法是定义帧尾。上位机每次发送的数据以固定字符结尾比如用换行符\n或者回车符\r\n。PLC收到数据后往存储区里追加然后搜索存储区里有没有这个帧尾字符。找到就从缓冲区开头到这个帧尾字符提取出来作为一帧完整请求剩下的部分留在缓冲区等待后续的数据来接上。同时要设置缓冲区上限防止异常数据堆积导致内存溢出比如缓冲区最多存256字节如果超出还没找到帧尾就强制清空让上位机重新发。4.5 数据发送的防阻塞与长度控制数据发送看起来简单就是一条发送指令但同样有细节。EASY系列的socket发送函数通常需要指定发送数据的起始地址和数据长度。我在程序里定义了一个发送缓冲区和发送长度变量。需要发送的数据先组合好放入发送缓冲区更新长度变量然后触发发送标志程序扫描到发送标志后调用一次发送函数。需要注意的是发送函数不会因为你指定了100字节就保证一次调用发出去100字节。TCP发送可能只发走部分数据剩余的你要在下一次扫描周期继续发送。所以程序中要记录还有多少字节没发完每次扫描都检查发送缓冲区中剩余的数据直到全部发送出去才清除发送标志。这就是所谓的防阻塞发送。还有一种常见情况是发送频率过高。比如上位机要求每秒更新一次产量数据但PLC的扫描周期是10ms如果你没做发送频率限制就可能在10ms内发出去好几次数据把上位机打懵。我的做法是用定时器控制发送周期数据更新标志位和发送动作解耦第N次扫描到了发送时间点才把当前最新的数据发出去。这样既保证了对上位机数据的时效性又不至于把网络通道塞满。5. 实战中的那些坑问题排查与解决方案5.1 启动失败的排查bind: only one usage of each socket address这是socket编程的经典错误无论在PC端还是PLC端都会遇到。它的意思是你想绑定的IP地址和端口号已经被其他程序或者同机的另一个socket占用了系统不允许你重复绑定。在EASY系列PLC上遇到这个问题最常见的原因是PLC程序重启的时候上一次程序运行建立的socket连接没有正常释放TCP的TIME_WAIT状态还没结束你又尝试在同一个端口上监听。或者程序里做了双实例——如果你不小心把socket初始化放在了一个每个扫描周期都执行的分支里第一次执行打开了端口第二次再执行的时候就提示端口已经被占用了。排查思路分两步第一步检查程序逻辑确认socket初始化只执行一次通常配合一个初始化完成标志位。第二步如果程序逻辑没问题那就是TIME_WAIT问题需要在断开连接后延时一段时间再重新监听或者在初始化时设置端口重用属性让socket允许在相同地址和端口上重新绑定。5.2 网络状态异常的排查连接被重置与超时无响应连接被重置就是上位机电脑那边关闭了socketPLC这边还在发数据系统会返回一个RST包收到这个包的socket就会报错。处理办法很简单程序里检测到这个错误码就把当前连接关闭清空缓冲区回到等待连接状态。超时无响应的问题稍微隐蔽一点。上位机明明连上了PLC发数据它也没反馈看起来连接还活着但数据就是没回声。这种情况通常是防火墙的问题——上位机电脑的防火墙拦掉了PLC发来的数据包PLC端以为连接正常其实数据根本没到对方应用层。如果你在现场调试遇到连接建立但收不到数据的情况先别急着改PLC程序去查上位机电脑的防火墙设置把对应端口的入站规则打开或者直接关闭防火墙测试一下往往一下就通了。5.3 跨设备通讯字节序问题Modbus和自定义协议都要注意工业以太网通讯绕不开字节序问题。不同架构的CPU在内存中存多字节数据的顺序可能不一样有的用大端高字节在前有的用小端低字节在前两者不统一数据解读出来就是天差地别。汇川EASY系列PLC的寄存器是16位的存储一个32位的浮点数或32位整数通常占用两个连续的寄存器。这里就有寄存器顺序的问题——到底低地址放高16位还是低16位不同品牌PLC的约定可能不一样。如果你和上位机自定义协议必须明确约定字节序否则就会出现数字变成天文数字这种经典bug。处理方式在协议文档里明确规定多字节数据的高低位存放顺序通信双方严格按这个规则解析。EASY系列做多字节数据拼装往往要写一个数据处理块来做高低位字节交换注意不要用错指令。5.4 通讯建立后偶尔数据错位的原因分析与解决正常通讯中偶尔出现一条数据解析错误这类问题在socket通讯里十有八九是缓冲区处理不当或者帧边界判定不够严格。我遇到过这种情况上位机每次发来25字节的请求PLC每次都按25字节去解析但偶尔解析出来的内容是乱的。后面排查发现上位机发送间隔不固定两个请求相隔太近时PLC第一次接收的缓冲区里已经存了30字节如果程序只取前25字节解析剩下的5字节残留在缓冲区时间长了缓冲区里面的残留数据新数据就杂乱了。解决方式就是我4.4节说的帧尾判定法而不是固定长度判断。如果你坚持用固定长度那就要在解析完后强制把缓冲区里该帧剩余部分清掉确保下一帧从头开始。5.5 上位机调试工具选择建议全程抓包验证调试环节我强烈推荐大家用好抓包工具。就算你用Modbus Poll、NetAssist这类现成的socket调试助手也建议同时开一个Wireshark抓包看看。因为调试助手显示的往往是应用层数据而抓到的包能看到TCP层的真实交互包括握手、确认、重传、断电重连这些底层行为。Wireshark里抓包最重要是设置过滤条件。如果PLC是192.168.1.10端口是5020抓包过滤就写成tcp.port 5020 (ip.addr 192.168.1.10 || ip.addr 192.168.1.20)这样过滤出来的就是PLC和上位机之间的全部TCP流量。每个包展开看就能确认交互是否正常是在哪个环节出的问题。顺手还推荐一个工具如果是电脑端调试上位机连PLC用NetAssist这类网络调试助手就够了界面直观支持TCP/UDP客户端和服务端能直接收发字符串和十六进制数据。遇到连接问题先在电脑上用调试助手连PLC如果助手能连上基本排除PLC侧问题剩下的就是上位机软件的问题。6. 工程化落地从测试到上线的注意事项6.1 通信稳定性测试方法论技术实现完了总得上线跑上线前稳定性测试是关键。我见过不少项目CP联调时一切正常一上线就各种小问题冒出来。这就是测试环节没做到位。我用过比较稳的测试方法是连续连续运行至少72小时的可靠性测试。期间每隔一定时间比如5分钟上位机读取一次PLC的特定数据区记录数据值和时间戳同时PLC也记录每次通讯的交互时间。测试结束后对比两边的日志检查有没有数据丢失、通讯断线、响应超时。过程中要主动制造异常来做故障注入测试。拔网线模拟链路断开然后重新插上观察PLC能不能自动恢复连接并继续正常工作重启上位机测试强制断开时PLC的状态恢复能力修改上位机的请求频率测试超负荷下PLC的响应是否还会在可接受范围内。这些故障注入测试能帮你提前发现重连机制和缓冲区处理上的薄弱点。6.2 程序防错设计的几条铁律写EASY系列的socket程序有几条铁律我每次都会在开工前强调给团队的同事。第一条socket初始化绝对不能让它在每个扫描周期都执行。一定要用初始化标志位确保只执行一次。否则第一次扫描打开的端口还没关第二次扫描又来绑定直接报占用错误。第二条所有socket库函数的调用都要检查返回值。EASY系列的函数一般会返回错误码别忽略它每个调用都根据错误码做对应的处理逻辑。有了错误码排查问题会快很多而且很多异常状态可以在错误码层面被提前拦截。第三条程序的所有固定参数比如端口号、IP地址、缓冲区大小、心跳时间尽量集中放到一个配置文件或者程序头部的定义区统一管理。改一个端口号就要去程序里面翻几十处这种设计太痛苦了集中管理能节省大量维护时间。第四条保持程序模块化把socket相关功能封装成独立的功能块通讯逻辑和业务逻辑分离。调试时只看通讯块业务改动只改业务块两边互相不影响。6.3 现场交付必须具备的技术文档上线交付时我不光给客户一套跑通的程序还会额外准备三份文档这对后期维护极其关键。第一份是通讯协议文档。明确每个数据帧的命令字、数据域定义、字节序、心跳机制、故障码含义。这份文档如果写清楚了不管是客户的MES工程师还是你团队里接手的其他人都能快速上手排查问题。第二份是IP地址和端口规划表。记录现场所有设备的IP、端口、用途包括PLC、上位机、触摸屏、连接的其他IO设备。没有这张表现场设备多了之后就是一场灾难。第三份是操作手册。说明如何检查PLC通讯状态如何重启程序重新初始化socket服务如何查看通讯错误码对应的含义。别让客户遇到问题就打电话找你给一份能自助排障的手册大家都轻松。7. 技术细节补充从EASY扩展到其他PLC和场景7.1 汇川其他系列PLC做socket从站的差异点如果你之后在AM系列、AC系列这些更高端的汇川PLC上做socket从站思路类似但库函数名称和参数细节会有差异。高端系列的可视化调试能力更强可以看到更详细的socket状态信息而且支持的socket连接数和缓冲区大小都有提升。另外如果你要把EASY系列放到Modbus TCP的从站模式其实不需要自己写socket——EASY系列本身支持Modbus TCP从站功能在系统参数里启用即可底层协议栈和socket对接是处理好的。但如果你要自定义协议就需要自己用socket函数实现这就是本文讲的内容。7.2 触摸屏与PLC的以太网通讯参考一些热搜词里提到了mt8072ie与fx5uj的以太网通讯虽然那是威纶通触摸屏和三菱PLC的组合但在做汇川EASY项目时也会遇到类似需求需要触摸屏和PLC走以太网而不是传统的串口线。触摸屏连接EASY系列可以通过Modbus TCPEASY系列开启Modbus TCP从站威纶通触摸屏在设备列表里选择对应的驱动填好PLC的IP地址连接就建立了不需要你在触摸屏端写任何socket脚本。如果触摸屏需要发的数据格式比较特殊比如自定义协议那就要在触摸屏的宏指令里写socket脚本本质上和本文讲的socket编程是一样的思路。7.3 多PLC数据汇聚与边缘网关最后扩展一点我想特别提的当现场有多台汇川EASY系列PLC时你可以用socket通讯把数据汇聚到一个边缘计算网关或者一台工控机上由网关统一处理和转发给MES。这种方式比每台PLC都直接对接MES更加灵活也更符合现代工厂边缘层集中采集、云端统一分析的架构思路。每台PLC作为socket从站监听同一个端口上位机网关或工控机作为socket客户端主动去连接每一台PLC。采集程序里用多线程分别管理各条连接把不同PLC采集到的数据打上标签后统一上传。这个架构的好处是新增一台PLC只需要在网关的配置文件中加一条IP记录就行对现有系统的影响几乎为零。8. 扩展思考socket从站方案的边界与选型写到这里最后分享一点个人在项目选型时的心得。每次拿到通讯需求我会先做一次方案边界评估问自己三个问题数据量多大实时性要求多高通讯拓扑是点对点还是多对多如果数据量小、交互次数少、对响应时间没有硬性要求几十毫秒到百毫秒都可以接受用EASY系列的socket从站是完全可行的而且成本最低。如果响应时间要求苛刻比如从站数据要在5ms以内送达到上位机那建议升级到EtherCAT或者专门的数据采集网关因为PLC的扫描周期和socket处理机制决定了它难以保证极低延迟。如果有多台设备要协同通讯比如两台PLC之间要做实时数据交换EASY系列的socket通讯也够用前提是你自己把通讯调度逻辑处理好。但如果实时性要求到了运动控制那种级别那就要换EtherCAT总线方案了——这里顺便多说一句EtherCAT和socket是两条完全不同的技术路线千万别拿来做错误的替换。工具选型对了后面写程序省一半力气。我们这次选型时就是先做了需求评估确认了是低压量、低频率、点对点的数据采集需求才决定用EASY系列自身的socket能力实现。实际上线之后稳定跑了几个月一次通信故障都没发生说明这条路是走得通的。
返回列表