Epson机器人发送Fins TCP 命令读写欧姆龙PLC数据

2023-10-11 22:59

本文主要是介绍Epson机器人发送Fins TCP 命令读写欧姆龙PLC数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、硬件与需求

        Epson机器人型号:T3-B401S,欧姆龙PLC型号:CJ2M-CPU35。现场调试时发现Epson这款机器人只支持Modbus做从机被访问,其他通讯方式需要另行购买硬件。

        欧姆龙CJ2M系列PLC内置EtherNet/IP端口,但这里无法直接使用上。

        评估后决定使用标准I/O的方式完成PLC对Epson机器人的控制和一些重要交互,例如机器人程序启停、机器人系统状态、取放料允许信号和取放料完成信号,而其他时效性低的数据例如产品换型等,则通过机器人侧发送FinsTCP报文读写PLC地址,从而实现数据交换。

二、设计程序

         查阅Epson机器人手册,了解TCP/IP通信相关命令。

       查阅欧姆龙通讯命令参考手册,了解Fins/TCP命令格式。也可直接参考他人博客的解说,更容易理解,例如我参考了这篇:《欧姆龙PLC的FinsTCP协议》(http://t.csdn.cn/qk6fY)。

       建议将电脑与PLC用网线连接,然后参照手册中的数据格式,在网络调试助手中手动编辑发送一些报文,接着核对返回数据。对数据格式越熟悉,后面调试机器人中写的通讯程序时,越容易分析出错误原因。

#### 下面是我参照手册用调试助手发送和接收的数据,然后按照自己的理解尝试分析
#### 电脑IP:192.168.250.100
#### PLC_IP: 192.168.250.90
第一步发送握手命令:
TX: 46 49 4E 53 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 64
RX: 46 49 4E 53 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 64 00 00 00 5A 
以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 0C +命令码00 00 00 00 +错误码00 00 00 00) +Fins数据(主机地址00 00 00 64)
以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 10 +命令码00 00 00 01 +错误码00 00 00 00)+Fins数据(主机地址00 00 00 64 +从机地址00 00 00 5A)
第二步读取PLC地址DM300内的数据:
TX: 46 49 4E 53 00 00 00 1A 00 00 00 02 00 00 00 00 80 00 02 00 5A 00 00 64 00 00 01 01 82 01 2C 00 00 01
RX: 46 49 4E 53 00 00 00 18 00 00 00 02 00 00 00 00 C0 00 02 00 64 00 00 5A 00 00 01 01 00 00 00 7B
以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 1A +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定80 00 02 +目标地址00 5A 00 +源地址00 64 00 +固定00) +读功能码01 01 +访问存储区82 + 访问起始地址01 2C +固定00 +访问数量 00 01)
以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 18 +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定C0 00 02 +目标地址00 64 00 +源地址00 5A 00 +固定00) +返回功能码01 01 +固定00 00 + 数据00 78)
第三步向PLC地址DM300写入数据321:
TX: 46 49 4E 53 00 00 00 1C 00 00 00 02 00 00 00 00 80 00 02 00 5A 00 00 64 00 00 01 02 82 01 2C 00 00 01 01 41
RX: 46 49 4E 53 00 00 00 16 00 00 00 02 00 00 00 00 C0 00 02 00 64 00 00 5A 00 00 01 02 00 00
以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 1C +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定80 00 02 +目标地址00 5A 00 +源地址00 64 00 +固定00) +写功能码01 02 +访问存储区82 + 访问起始地址01 2C +固定00 +访问数量 00 01 +数据01 41)
以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 16 +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定C0 00 02 +目标地址00 64 00 +源地址00 5A 00 +固定00) +返回功能码01 02 +正常结束00 00)

       到这里,准备工作已经完成的差不多了,开始设计程序。框架如下:

 三、编写代码

        以下附上我写的尝试实现Omron_FinsTCP的Epson机器人程序。

'######## 程序说明 ########
'尝试构建FinsTcp协议与Omron PLC通讯,固定读取DM300+5个字和写入DM310+5个字
'######## 程序开始 ########
'#### 声明变量 ####
UByte RDM_Data(10)	'保存读取到的数据,分成高低字节,便于其他程序中使用
UByte WDM_Data(10)	'缓存要发送的数据,分成高低字节,便于其他程序中更改
UByte SendDataByte(50)	'允许最大发送256byte数据,本程序只写5个字地址,所以最多发送44byte数据
UByte RcevDataByte(50)	'允许最大接收256byte数据,本程序只读5个字地址,所以最多接收40byte数据
UShort CountCom	'用于统计通讯次数(0~65535)
UShort CountErr	'用于统计通讯失败次数(不允许超过3次)
UByte i	'用于批量删改数组内的数据
UByte j	'用于批量打印数组内的数据
UByte Epson_ip4	'Epson机器人的网络节点(IP第四位)
UByte Omron_ip4	'Omron PLC的网络节点(IP第四位)
UShort RDM_StartAddL, RDM_StartAddH  '读取DM区的起始地址,拆成两个字节
UShort WDM_StartAddL, WDM_StartAddH  '写入DM区的起始地址,拆成两个字节
UByte RDM_number '读取DM区的地址数量
UByte WDM_number '写入DM区的地址数量
Function main'#### 通讯设置 ####'机器人的IP为192.168.250.97(客户端),PLC的IP为192.168.250.90(服务器)'SetNet #208, "192.168.250.90", 9600, CR, NONE, 0   '设置TCP/IP端口参数,只执行一次Epson_ip4 = 97	'以下97用十六进制0x61表示Omron_ip4 = 90	'以下90用十六进制0x5A表示RDM_StartAddH = &H01	'本程序中需要读DM300+5个字,所以起始地址为300(0x012C)RDM_StartAddL = &H2CWDM_StartAddH = &H01	'本程序中需要写DM310+5个字,所以起始地址为310(0x0136)WDM_StartAddL = &H36RDM_number = 5	'本程序中读5个字WDM_number = 5	'本程序中写5个字'#### 重新连接 ####Tag_ResetNet:Print "开始连接"CloseNet #208	'关闭208端口Wait 1			'延时1sCountCom = 0	'清空通讯相关计数CountErr = 0OpenNet #208 As Client '打开端口WaitNet #208	'等待208网络端口连接成功Print "连接成功"'#### 清空接收区 ####Tag_ClearRecv:i = 0Do While i < 50RcevDataByte(i) = 0	'清空接收区数据SendDataByte(i) = 0	'清空发送区数据i = i + 1Loop'#### 检测端口 ####Tag_CheckNet:If ChkNet(208) = -3 ThenPrint "网络异常"GoTo Tag_ResetNETEndIf'#### 发送FinsTCP代码Tag_SendMessages:If CountCom = 0 Then	'第一次请先握手Print "握手 ="'以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 0C +命令码00 00 00 00 +错误码00 00 00 00) +Fins数据(主机地址00 00 00 61)SendDataByte(0) = &H46; SendDataByte(1) = &H49; SendDataByte(2) = &H4E; SendDataByte(3) = &H53		'FINS标识SendDataByte(4) = &H00; SendDataByte(5) = &H00; SendDataByte(6) = &H00; SendDataByte(7) = &H0C		'报文长度SendDataByte(8) = &H00; SendDataByte(9) = &H00; SendDataByte(10) = &H00; SendDataByte(11) = &H00	'握手命令码SendDataByte(12) = &H00; SendDataByte(13) = &H00; SendDataByte(14) = &H00; SendDataByte(15) = &H00	'错误码SendDataByte(16) = &H00; SendDataByte(17) = &H00; SendDataByte(18) = &H00; SendDataByte(19) = Epson_ip4	'主机网络节点WriteBin #208, SendDataByte(), 20	'指定端口以bin类型发送20字节数据'若正常以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 10 +命令码00 00 00 01 +错误码00 00 00 00)+Fins数据(主机地址00 00 00 61 +从机地址00 00 00 5A)i = 24	'如果通讯正常会返回24字节的数据j = 0	'跳转到握手结果校验ElseIf CountCom Mod 2 = 1 Then	'奇数次通讯为读地址代码,读DM300+5Print "读地址"'以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 1A +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定80 00 02 +目标地址00 5A 00 +源地址00 61 00 +固定00) +读功能码01 01 +访问存储区82 + 访问起始地址01 2C +固定00 +访问数量 00 05)SendDataByte(0) = &H46; SendDataByte(1) = &H49; SendDataByte(2) = &H4E; SendDataByte(3) = &H53		'FINS标识SendDataByte(4) = &H00; SendDataByte(5) = &H00; SendDataByte(6) = &H00; SendDataByte(7) = &H1A		'报文长度SendDataByte(8) = &H00; SendDataByte(9) = &H00; SendDataByte(10) = &H00; SendDataByte(11) = &H02	'数据命令码SendDataByte(12) = &H00; SendDataByte(13) = &H00; SendDataByte(14) = &H00; SendDataByte(15) = &H00	'错误码SendDataByte(16) = &H80; SendDataByte(17) = &H00; SendDataByte(18) = &H02; SendDataByte(19) = &H00	'Fins头SendDataByte(20) = Omron_ip4; SendDataByte(21) = &H00; SendDataByte(22) = &H00; SendDataByte(23) = Epson_ip4	'目标地址和源地址SendDataByte(24) = &H00; SendDataByte(25) = &H00; SendDataByte(26) = &H01; SendDataByte(27) = &H01	'读功能码SendDataByte(28) = &H82; SendDataByte(29) = RDM_StartAddH; SendDataByte(30) = RDM_StartAddL; SendDataByte(31) = &H00	'访问DM区+起始地址SendDataByte(32) = &H00; SendDataByte(33) = RDM_number	'访问地址数量WriteBin #208, SendDataByte(), 34	'指定端口以bin类型发送34字节数据'若正常以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 20 +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定C0 00 02 +目标地址00 61 00 +源地址00 5A 00 +固定00) +返回功能码01 01 +固定00 00 + 数据1 +数据2 +数据3 +数据4 +数据5)i = 30 + (RDM_number * 2) 	'如果通讯正常会返回(固定头部30+RDM_number * 2)个字节的数据j = 1	'跳转到读地址结果校验Else '偶数次通讯为写地址代码,写DM310+5Print "写地址"'以HEX发送:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 24 +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定80 00 02 +目标地址00 5A 00 +源地址00 61 00 +固定00) +写功能码01 02 +访问存储区82 + 访问起始地址01 36 +固定00 +访问数量 00 05 +数据1 +数据2 +数据3 +数据4 +数据5)SendDataByte(0) = &H46; SendDataByte(1) = &H49; SendDataByte(2) = &H4E; SendDataByte(3) = &H53		'FINS标识SendDataByte(4) = &H00; SendDataByte(5) = &H00; SendDataByte(6) = &H00; SendDataByte(7) = 26 + WDM_number * 2 	'报文长度SendDataByte(8) = &H00; SendDataByte(9) = &H00; SendDataByte(10) = &H00; SendDataByte(11) = &H02	'数据命令码SendDataByte(12) = &H00; SendDataByte(13) = &H00; SendDataByte(14) = &H00; SendDataByte(15) = &H00	'错误码SendDataByte(16) = &H80; SendDataByte(17) = &H00; SendDataByte(18) = &H02; SendDataByte(19) = &H00	'Fins头SendDataByte(20) = Omron_ip4; SendDataByte(21) = &H00; SendDataByte(22) = &H00; SendDataByte(23) = Epson_ip4	'目标地址和源地址SendDataByte(24) = &H00; SendDataByte(25) = &H00; SendDataByte(26) = &H01; SendDataByte(27) = &H02	'写功能码SendDataByte(28) = &H82; SendDataByte(29) = WDM_StartAddH; SendDataByte(30) = WDM_StartAddL; SendDataByte(31) = &H00	'访问DM区+起始地址SendDataByte(32) = &H00; SendDataByte(33) = WDM_number	'访问地址数量i = 0j = 34	'固定FinsTcp写代码发送数据的头部字节数Do While i < (WDM_number * 2)	'写入数据的字节数,(WDM_number * 2)SendDataByte(j) = WDM_Data(i)i = i + 1j = j + 1Loop'Print "写地址发送字节数j = ", jWriteBin #208, SendDataByte(), j	'指定端口以bin类型发送44字节数据,j = (34 + WDM_number * 2)'若正常以HEX接收:FinsTCP头(FINS标识46 49 4E 53 +报文长度00 00 00 16 +命令码00 00 00 02 +错误码00 00 00 00) +Fins数据(Fins头(固定C0 00 02 +目标地址00 61 00 +源地址00 5A 00 +固定00) +返回功能码01 02 +正常结束00 00)i = 30	'如果通讯正常会返回30字节的数据j = 2	'跳转到写地址结果校验EndIf'#### 解析返回数据 ####Tag_ParsingRcvDatas:Wait 0.1	'延时0.1s,减轻系统负担'Print "接收字节数i =", iReadBin #208, RcevDataByte(), i	'以bin类型读取指定端口接收到的i字节数据'Print "返回数据 = ", RcevDataByte(7), RcevDataByte(20), RcevDataByte(23), RcevDataByte(27)'Print "CountCom = ", CountComIf j = 0 And RcevDataByte(7) = (24 - 8) And RcevDataByte(19) = Epson_ip4 And RcevDataByte(23) = Omron_ip4 Then '核对返回数据长度和主从机IPPrint "握手成功"CountErr = 0ElseIf j = 1 And RcevDataByte(7) = (i - 8) And RcevDataByte(20) = Epson_ip4 And RcevDataByte(23) = Omron_ip4 And RcevDataByte(27) = &H01 Then '核对返回数据长度、主从机IP和读功能码CountErr = 0i = 0j = 30	'固定FinsTcp读代码返回数据的头部字节数Do While i < (WDM_number * 2) 	'有效数据的字节数RDM_Data(i) = RcevDataByte(j) 	'将接收到的有效数据保存到RDM_Data(),方便其他程序使用i = i + 1j = j + 1LoopPrint "地址读取=", RDM_Data(0), RDM_Data(1), RDM_Data(2), RDM_Data(3), RDM_Data(4), RDM_Data(5), RDM_Data(6), RDM_Data(7), RDM_Data(8), RDM_Data(9)ElseIf j = 2 And RcevDataByte(7) = (30 - 8) And RcevDataByte(20) = Epson_ip4 And RcevDataByte(23) = Omron_ip4 And RcevDataByte(27) = &H02 Then '核对返回数据长度、主从机IP和写功能码CountErr = 0Print "地址写入=", WDM_Data(0), WDM_Data(1), WDM_Data(2), WDM_Data(3), WDM_Data(4), WDM_Data(5), WDM_Data(6), WDM_Data(7), WDM_Data(8), WDM_Data(9)ElseCountErr = CountErr + 1Print "返回数据异常CountErr =", CountErrEndIf'#### 通讯测试,成功后请删除本段 ####'##把读取到的数据又发送出去     '(Epson) RDM_Data <---  DM300 (Omron)WDM_Data(0) = RDM_Data(0)		'		   ||           WDM_Data(1) = RDM_Data(1)		'	    WDM_Data ----> DM310WDM_Data(2) = RDM_Data(2)WDM_Data(3) = RDM_Data(3)WDM_Data(4) = RDM_Data(4)WDM_Data(5) = RDM_Data(5)WDM_Data(6) = RDM_Data(6)WDM_Data(7) = RDM_Data(7)WDM_Data(8) = RDM_Data(8)WDM_Data(9) = RDM_Data(9)'#### 单次通讯结束 ####If CountErr < 3 ThenIf CountCom < 65535 Then	'Epson数据溢出会报错CountCom = CountCom + 1	'通讯次数自增1ElseCountCom = 1EndIfGoTo Tag_CheckNet			'跳转至网络检查ElseGoTo Tag_ResetNET			'跳转至网络重启EndIf
Fend

四、编译、运行与调试

       为了测试通讯成功后能否正常读写PLC地址,所以在机器人程序中添加了一段代码,不断把读取到的数值写入到另一组地址(将读取到的D300~D304中的值写入到D310~311地址),这样方便在PLC侧查看与更改数据,测试如下:

测试一:PLC 地址内的数据:

        Epson机器人侧读取和写入的数据:

测试二:PLC 地址内的数据:

        Epson机器人侧读取和写入的数据:

         需要注意的是,由于发送和接收数据的长度单位为byte,所以D300~D304共5个字的数据被拆分成高低字节保存在一个byte类型的数组中,即占用RDM_Data(0)~RDM_Data(9),共10个元素,且存放顺序是先高字节后低字节。

五、其他说明

        1、注意事项:

         2、上面程序还有BUG,目前有已知两个:一是通讯过程中拔掉网线,机器人程序在执行读端口指令(ReadBin #)时,会报错并直接终止程序;二是程序设计成数据异常超过3次便重启端口,但实际测试中程序会在执行关闭端口(CloseNet #)、打开端口(OpenNet #)或等待端口(WaitNet #)这三个命令中的某一个时假死,我觉得更可能是等待端口那个指令,也许异常超过3次时不重启端口,直接重新握手会更好。

        3、由于项目上精简机器人与PLC的交互数量后,机器人的标准IO足够用(最多支持24bit的输入、16bit的输出),所以后期程序全部改走标准IO交互了,没用到上面的通讯程序,故没再继续优化与测试。

这篇关于Epson机器人发送Fins TCP 命令读写欧姆龙PLC数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/191461

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作