☰
欧姆龙PLC数据采集:虚拟机+Fins协议实战指南
2026/9/29 18:37:36 网站建设 项目流程

欧姆龙PLC在产线设备层占有率极高,尤其是CP/CJ/CS系列,很多老产线跑了几十年还在稳定服役。但要把这些PLC里的数据实时抓出来,接到上位机或者MES系统里,很多人第一反应是"装个组态软件不就行了"。组态软件确实省事,但授权费用高、点位受限、灵活性差,遇到定制化需求就抓瞎。所以越来越多的工程师开始走"自己写采集程序"这条路——用一台虚拟机跑采集服务,通过Fins协议直接跟PLC通信,数据想怎么处理就怎么处理。

这篇内容就是把我自己在项目里反复验证过的一套做法完整拆开讲。核心思路是:在VMware虚拟机里搭一个干净的Windows环境,装好欧姆龙官方通信组件,用Fins协议走以太网跟PLC建立连接,然后写代码读写DM区、CIO区数据。适合有一定网络基础和编程基础、想自己掌控数据采集链路的工程师,也适合刚接触欧姆龙PLC通信、被各种驱动和配置搞得头大的朋友。下面从环境搭建到协议配置到代码实操,一步步来。

1. 为什么选虚拟机跑采集服务而不是直接上工控机

1.1 虚拟机方案在产线环境里的真实优势

先说清楚为什么要在VM里做这件事。直接在工控机上装采集软件当然可以,但实际项目里会遇到几个很现实的问题。

第一是环境隔离。采集程序往往需要装各种运行库、驱动、通信组件,这些东西跟工控机上原有的组态软件、OPC服务很容易打架。我遇到过一次,装完某个通信DLL之后,原来的组态软件直接起不来了,排查了一整天才发现是版本冲突。用虚拟机就完全没这个问题,采集环境是独立的,搞崩了直接快照回滚,不影响主机上任何东西。

第二是迁移和备份。虚拟机就是一个文件包,换台机器直接拷过去就能跑,不用重新配环境。产线上工控机坏了要换,传统方式得重新装一遍所有软件,虚拟机方案十分钟搞定。

第三是多版本共存。有些项目要同时对接不同年代的欧姆龙PLC,老设备可能只支持Fins/TCP,新设备支持Fins/UDP,甚至有些还要走串口。虚拟机可以开多个,每个跑一套独立的通信环境,互不干扰。

当然虚拟机也有代价,主要是网络延迟会比物理机略高一点点,但对于PLC数据采集这种秒级、甚至百毫秒级的场景,这点延迟完全可以忽略。实测下来,VMware桥接模式下ping PLC的延迟跟物理机基本没差别。

1.2 虚拟机网络模式的选择逻辑

这是最容易踩坑的地方。VMware有三种主要网络模式:桥接、NAT、仅主机。做PLC采集必须用桥接模式,原因很简单——PLC和采集服务必须在同一个网段里直接通信。

NAT模式下虚拟机的IP是VMware虚拟网卡分配的,PLC根本看不到虚拟机,通信必然失败。仅主机模式更不行,虚拟机只能跟主机通信,出不去。只有桥接模式,虚拟机会像一台独立设备一样接入物理网络,拿到跟主机同网段的IP,PLC才能正常响应。

具体操作:虚拟机设置里网络适配器选"桥接",然后编辑虚拟网络编辑器,桥接目标选主机实际连接PLC的那块物理网卡。如果主机有多块网卡(比如一块连办公网、一块连设备网),一定要选对,选错了虚拟机就跑到办公网段去了,跟PLC不在一个网里。

提示:桥接模式下如果虚拟机拿不到IP,先检查物理网卡的网线是否插好、交换机端口是否正常。另外有些企业网络有MAC地址绑定或者端口安全策略,虚拟机的虚拟MAC可能被拦截,这种情况需要找网络管理员放行。

1.3 虚拟机资源配置的合理区间

采集服务本身不重,但Windows系统加上欧姆龙通信组件,资源给太少会卡。我的经验配置是:CPU给2核,内存给4GB,硬盘给60GB。这个配置跑Windows 10或者Windows 7都够用,采集几百个点位毫无压力。

如果只是跑采集,不需要图形界面,其实用Windows Server Core或者精简版系统更省资源,但欧姆龙的某些配置工具需要图形界面,所以还是建议装完整版Windows。系统装好后第一件事是装VMware Tools,这个直接影响虚拟机的网络性能和显示效果,不装的话网卡驱动可能都不正常。

硬盘建议用固定大小而不是动态扩展,虽然占空间但性能稳定,不会因为动态扩展导致采集过程中出现IO抖动。快照功能要善用,装完系统打一个快照,装完通信组件再打一个,后面出问题随时回滚。

2. Fins协议到底是怎么跟欧姆龙PLC对话的

2.1 Fins协议的本质:一套命令-响应机制

Fins全称Factory Interface Network Service,是欧姆龙自己的一套工业通信协议。理解它其实不难,本质就是上位机发一条命令帧,PLC回一条响应帧,跟HTTP请求响应是一个道理,只不过格式是二进制的,更紧凑。

命令帧里包含几个关键信息:目标网络号、目标节点号、目标单元号,这三个合起来叫目标地址,用来定位具体是哪台PLC的哪个单元。然后是命令码,比如读DM区是0101,写DM区是0102,读CIO区是0101但区域代码不同。最后是具体的地址和长度,比如"从D100开始读10个字"。

响应帧就是PLC把结果返回,包含结束码(判断成功失败)和读到的数据。结束码00表示正常,其他值对应各种错误,比如0x40表示地址越界,0x20表示命令不支持。

2.2 Fins/TCP和Fins/UDP的区别与选型

Fins协议可以跑在TCP上,也可以跑在UDP上,这是两个不同的封装方式。

Fins/TCP是面向连接的,通信前要先建立TCP连接,默认端口9600。优点是可靠,数据不会丢,适合对数据完整性要求高的场景。缺点是连接维护有开销,PLC那边能同时接受的TCP连接数有限,一般就几个。

Fins/UDP是无连接的,直接发数据包,默认端口也是9600。优点是轻量、快,适合高频采集。缺点是不保证送达,网络不好的时候可能丢包。

实际项目里怎么选?我的经验是:采集频率低于100ms的用TCP,高于100ms的用UDP。大部分产线数据采集是秒级或者几百毫秒级,用TCP完全够,而且省心。如果要做高速数据记录,比如振动监测那种毫秒级的,才考虑UDP,但要在应用层自己做重传和校验。

欧姆龙PLC默认两个都开着,但需要在PLC的以太网单元设置里确认。有些老型号默认只开了一个,这个后面配置章节会细说。

2.3 欧姆龙PLC的地址体系:DM区、CIO区、WR区怎么对应

这是新手最容易晕的地方。欧姆龙PLC的地址分好几个区,Fins协议里每个区有对应的区域代码:

区域名称区域代码地址范围典型用途
CIO区0xB0CIO0~CIO6143输入输出继电器、内部继电器
WR区0xB1W0~W511工作继电器
HR区0xB2H0~H511保持继电器
DM区0x82D0~D32767数据存储,最常用
EM区0x98~0x9DE0_0~E0_32767扩展数据存储

采集最常用的是DM区,因为它是纯数据存储,不受程序逻辑影响,适合放工艺参数、产量计数、配方数据这些。CIO区更多是跟实际IO和内部逻辑相关,采集状态位的时候会用到。

地址换算要注意:Fins协议里地址是字节偏移,而欧姆龙习惯说"字"。比如D100,在Fins命令里要写成100*2=200的字节偏移,或者直接用字地址加区域代码。不同库的封装方式不一样,用的时候要看清文档。

3. 虚拟机里把欧姆龙通信环境搭起来

3.1 系统准备与必要的运行库

虚拟机装好Windows之后,别急着装欧姆龙的东西,先把基础运行库补齐。欧姆龙的通信组件很多是早年开发的,依赖VC++运行库和.NET Framework。

需要装的:

  • Visual C++ Redistributable 2005/2008/2010/2013/2015-2022,全套装上,别嫌多
  • .NET Framework 3.5和4.8,Windows功能里勾选
  • 如果要用官方配置工具,可能还需要装旧版的.NET 2.0

这些库不装全,后面装通信组件的时候会报各种"找不到DLL"的错误,而且报错信息往往很模糊,很难定位。我吃过这个亏,后来养成习惯,新系统先跑一遍运行库合集包。

3.2 欧姆龙官方通信组件的安装与注册

欧姆龙提供几个跟Fins通信相关的东西:

Sysmac Studio或者CX-One里带的通信驱动,这是最正规的。CX-One是个大包,装完会有FinsGateway或者类似的通信服务。但CX-One体积巨大,几个G,如果只是做采集,没必要装全套。

更轻量的方式是直接用FinsGateway或者Fins通信库。FinsGateway是欧姆龙早期的通信中间件,装完之后会注册一个系统服务,提供Fins/TCP和Fins/UDP的通信能力。装完后在服务里能看到"FinsGateway"相关的服务,确保它是启动状态。

还有一个方式是不装官方组件,直接用第三方库。比如Python的fins库、C#的OmronFins库,这些库自己实现了Fins协议,不需要欧姆龙官方的东西。这种方式最干净,虚拟机里只要有个运行环境就行。我现在的项目基本都走这条路,省事。

注意:如果用官方FinsGateway,安装时可能会提示要装驱动签名,Windows 10以上系统对驱动签名要求严格,可能需要临时关闭驱动签名强制。这个操作有安全风险,建议只在测试环境做,生产环境用第三方库更稳妥。

3.3 网络连通性验证:先ping通再谈协议

装完环境,第一件事是验证网络。虚拟机里打开cmd,ping一下PLC的IP。ping不通的话,后面所有配置都是白搭。

ping通了之后,还要验证端口。Fins/TCP默认9600端口,用telnet或者Test-NetConnection测一下:

Test-NetConnection -ComputerName 192.168.1.10 -Port 9600

如果显示TcpTestSucceeded为True,说明端口是通的。如果False,可能是PLC那边没开Fins/TCP服务,或者防火墙拦了。

这一步看着简单,但实际项目里至少三成的通信问题都出在这里。网络不通,后面代码写得再对也没用。所以养成习惯:先ping,再测端口,最后才写代码。

4. Fins协议配置的完整实操链路

4.1 PLC侧的以太网单元设置

PLC那边要先配置好。以CJ系列配以太网单元为例,用CX-Programmer或者Sysmac Studio连上PLC,找到以太网单元的设置。

关键参数:

  • IP地址:给PLC设一个固定IP,跟虚拟机同网段。比如虚拟机是192.168.1.100,PLC设192.168.1.10
  • 子网掩码:255.255.255.0
  • Fins/TCP端口:默认9600,一般不改
  • Fins/UDP端口:默认9600
  • Fins节点号:这个很重要,每台PLC在Fins网络里要有唯一节点号,默认是根据IP最后一段自动算的,也可以手动指定

设置完要断电重启以太网单元,有些参数改了不重启不生效。重启后用CX-Programmer的在线功能确认一下设置是否生效。

4.2 上位机侧的Fins节点配置

上位机(虚拟机)这边也要有个Fins节点号。如果用官方FinsGateway,它会在安装时让你配一个本地节点号,这个号不能跟PLC的节点号冲突。

如果用第三方库,节点号通常在代码里指定。比如Python的fins库,建立连接的时候要传目标PLC的IP和节点号,本地节点号有些库会自动处理,有些需要手动指定。

节点号冲突是隐蔽的坑。有一次我调试半天连不上,最后发现虚拟机的节点号跟PLC设成一样的了,Fins协议里节点号是网络内唯一的,冲突了就通信异常。后来养成习惯,虚拟机节点号统一用比PLC大很多的号,比如PLC用10,虚拟机用200,避免冲突。

4.3 用测试工具先跑通再写代码

写代码之前,强烈建议先用现成的测试工具验证Fins通信是否正常。欧姆龙官方有个Fins通信测试工具,或者用第三方的Fins调试工具,输入PLC的IP、节点号、区域、地址、长度,点读取,看能不能返回数据。

这一步能排除掉大量配置问题。如果测试工具能读到数据,说明PLC配置、网络、Fins服务都正常,后面写代码只是把同样的参数用代码实现一遍。如果测试工具都读不到,那问题一定在配置层面,先解决配置再谈代码。

我见过太多人跳过这一步,直接写代码,然后代码报错,就开始怀疑代码有问题,改来改去,其实根子在PLC配置上。先用工具验证,再写代码,这个顺序能省大量时间。

5. 代码实操:从零写一个DM区数据采集程序

5.1 Python方案:用fins库快速实现

Python是最快能跑通的方式。装库:

pip install fins

然后写采集代码:

import fins from fins import FinsTCP # 建立连接 plc_ip = "192.168.1.10" plc_port = 9600 plc_node = 10 local_node = 200 client = FinsTCP(plc_ip, plc_port, plc_node, local_node) client.connect() # 读DM区,从D100开始读10个字 dm_address = 100 read_count = 10 data = client.read_dm(dm_address, read_count) print("DM100-DM109:", data) # 写DM区,把D200开始的值改成指定值 write_values = [100, 200, 300] client.write_dm(200, write_values) client.close()

这段代码的核心逻辑:建立TCP连接,发Fins命令帧,解析响应帧。read_dm内部就是把区域代码0x82、地址100、长度10打包成Fins命令发出去,然后把返回的字节流解析成整数列表。

实际项目里不会这么简单,要加异常处理、重连机制、数据缓存。但先跑通这个最小示例,确认能读到数据,再往上加功能。

5.2 C#方案:适合做Windows服务

如果采集程序要长期跑在后台,C#更合适,可以做成Windows服务。用OmronFins或者HslCommunication这类库。

using HslCommunication.Profinet.Omron; OmronFinsNet omron = new OmronFinsNet("192.168.1.10", 9600); omron.DA1 = 10; // PLC节点号 omron.SA1 = 200; // 本地节点号 // 读DM区 var result = omron.ReadInt16("D100", 10); if (result.IsSuccess) { short[] values = result.Content; // 处理数据 } // 写DM区 omron.Write("D200", new short[] { 100, 200, 300 });

HslCommunication这个库在国内工控圈用得很多,封装得比较友好,支持欧姆龙、三菱、西门子等主流PLC。它的地址格式直接用"D100"这种欧姆龙习惯的写法,不用自己算字节偏移,省事。

5.3 采集频率与批量读取的优化

采集频率不是越高越好。PLC的通信资源有限,太频繁的请求会占用PLC的CPU时间,影响控制逻辑。一般产线数据采集,500ms到1s一次足够了。

如果要采的点位多,一定要批量读取,不要一个点一个点读。比如要读D100到D199这100个字,一次读100个,比读100次每次读1个,效率高几十倍。Fins协议单次最多能读960个字(具体看PLC型号),充分利用这个批量能力。

批量读取的代码示例:

# 一次性读100个字 data = client.read_dm(100, 100) # 然后按需解析 temperature = data[0] / 10.0 # D100是温度,放大10倍存的 pressure = data[1] / 100.0 # D101是压力,放大100倍 count = data[2] # D102是产量计数

这种批量读+本地解析的方式,是采集程序的标配。我做过一个项目,采2000多个点位,用批量读取,一轮下来不到200ms,完全满足秒级采集需求。

6. 踩过的坑与排查思路

6.1 连接超时但ping得通:端口和节点号排查

现象:虚拟机ping PLC正常,但Fins连接一直超时。

排查顺序:

  1. 确认PLC的Fins/TCP服务是否开启。有些PLC默认只开UDP,TCP要手动开
  2. 确认端口号。默认9600,但有些项目改过,要跟PLC设置一致
  3. 确认节点号。本地节点号和PLC节点号不能冲突
  4. 确认目标网络号和单元号。跨网段或者多单元的情况下,这两个参数不对也会连不上

我遇到最隐蔽的一次是PLC的以太网单元设置了"仅允许特定IP访问",虚拟机的IP不在白名单里,ping能通但Fins连接被拒。后来在PLC设置里把虚拟机IP加进去就好了。

6.2 读到的数据全是0或者乱码:地址和数据类型问题

现象:连接正常,但读回来的数据不对。

常见原因:

  • 地址偏移算错。Fins协议用字节偏移,欧姆龙习惯用字地址,差2倍。D100在协议里是200字节偏移,写成100就读到D50去了
  • 数据类型不匹配。PLC里存的是16位整数,代码里按32位读,就会把两个寄存器的值拼在一起
  • 字节序问题。欧姆龙是大端序,有些库默认小端,读出来高低字节反了

排查方法:先在PLC编程软件里确认D100的实际值,然后用测试工具读同样的地址,对比结果。如果测试工具读的对,代码读的不对,就是代码里的地址或类型处理有问题。

6.3 长时间运行后连接断开:心跳与重连机制

采集程序跑几天后连接断了,这是很常见的。原因可能是网络抖动、PLC重启、交换机端口老化等。

解决办法是加心跳和重连。每隔一段时间(比如30秒)发一个轻量的读命令,确认连接还活着。如果连续几次失败,就关闭连接重新建立。

import time def keep_alive(client): try: client.read_dm(0, 1) # 读一个点,确认连接 return True except Exception: return False while True: if not keep_alive(client): client.close() time.sleep(5) client = FinsTCP(plc_ip, plc_port, plc_node, local_node) client.connect() time.sleep(30)

这个逻辑看着简单,但能解决大部分"跑一段时间就断"的问题。生产环境的采集程序,重连机制是必须的,不能假设网络永远稳定。

6.4 虚拟机快照回滚后网络异常的处理

虚拟机用快照回滚之后,有时候网络会出问题,表现为拿不到IP或者网络适配器显示感叹号。这是因为快照回滚后,虚拟网卡的状态跟主机侧对不上。

解决办法:

  1. 虚拟机设置里把网络适配器先移除,再重新添加
  2. 编辑虚拟网络编辑器,还原默认设置
  3. 虚拟机里禁用再启用网卡
  4. 实在不行,删掉虚拟机目录下的.lck文件和网卡配置文件,重启虚拟机

这个问题在VMware Workstation和ESXi里都遇到过,快照用多了就容易出。我的习惯是快照只保留最近两三个,太老的删掉,减少这类问题的概率。

7. 采集程序上线前的检查清单

程序写完了,别急着扔到产线上跑。上线前过一遍这个清单,能避免大部分现场问题。

检查项检查内容常见问题
网络虚拟机与PLC同网段,ping通,端口通桥接选错网卡
PLC配置Fins/TCP开启,节点号唯一,IP白名单默认只开UDP
节点号本地与PLC不冲突都设成10
地址区域代码、字节偏移正确字/字节混淆
数据类型16位/32位、字节序匹配大端小端反了
异常处理超时、重连、日志断线不恢复
资源占用CPU、内存、网络带宽采集频率过高
持久化数据存储、断点续传重启丢数据

这份清单是我从多个项目里总结出来的,每次上线前对着过一遍,基本能覆盖90%的现场问题。剩下的10%往往是现场环境特有的,比如电磁干扰导致网络丢包、PLC固件版本差异导致某些命令不支持,这些只能到现场再调。

采集程序上线后,前三天要重点观察。看日志有没有异常、数据有没有断档、PLC的通信负载是否正常。稳定跑一周之后,基本就可以放心了。

最后说一个实际体会:Fins协议本身不复杂,复杂的是现场环境。同样的代码,在实验室跑得好好的,到现场可能因为一根网线、一个交换机配置、一个PLC参数就卡住。所以做数据采集,三分靠代码,七分靠调试。把网络和PLC配置的基础打牢,代码反而是最简单的一环。虚拟机方案的好处就在于,它把环境问题隔离了,让你能专注于通信本身,出了问题也能快速回滚重来,这在现场调试时特别有价值。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询