通过modbus通讯,我们可以使用真实的机器人或者robotstudio与plc进行一个通讯,可以通过自己的电脑进行纯虚拟仿真,不管是有没有设备都可以进行调试。
本项目测试设备:
一个实体的plc 1214FC DC/DC/DC
一台实体的机器人 ABB120
一台虚拟的机器人 120
1.数据类型
1.1plc数据类型讲解
首先得明白需要通讯的数据是一个什么类型的数据,有多少个位?例如:我要给机器人发一个或接收一个Real(浮点数),一个浮点数在PLC这边是占4个位(记住这是重点)。
如果不知道一个数据占多少个位,我们可以从plc里面查看。
创建一个DB块,在里面建立一些数据,选择浮点型并且在设置中取消优化访问块(点击数据块——右击属性——找到优化的访问块取消打勾)。从上面我们可以看到偏移量从0~3刚好是四个位。
在这里可以一个数据块放很多不同的数据类型,但是要注意要调用的数据,偏移量的位置要与机器人相对应,否则会出现数据读取错误或者乱码的问题。
1.2机器人数据类型讲解
对于机器人这边,它对存储的数据类型没有太多的要求。基本使用NUM就可以存储plc绝大多数的常用类型。这里没什么值得注意的,plc那边有多少个数据,机器人这边就建立多少个变量或数组的大小。重要的是下面的报文解读。
2.报文解析
授人以鱼不如授人以渔,机器人本来就是没有modbus通讯的。要实现modbus通讯,我们只能通过报文的解读手搓modbus协议。如果对我下面的报文解读不理解或者需要更详细的可以去看看这位博主的文章,他会有更详细我解读。我这边只是举一个例子,可以根据我的例子自行修改。
下面是关于写数据的:
先看代码
PROC write32float(num slaveID,num start,num length,num arrayValue{*})
VAR byte byte_send{13};
VAR rawbytes raw_data;
ClearRawBytes raw_data; //清空原始自己的内容
byte_send{1}:=0X00;
byte_send{2}:=0X00;
byte_send{3}:=0X00;
byte_send{4}:=0X00; //没有太具体的要求可以不管它
byte_send{5}:=(length*4+7) DIV 256;
byte_send{6}:=(length*4+7) mod 256;
byte_send{7}:=slaveID;
byte_send{8}:=0X10;
byte_send{9}:=start div 256;
byte_send{10}:=start mod 256;
byte_send{11}:=length*2 div 256;
byte_send{12}:=length*2 mod 256;
byte_send{13}:=length*4;
FOR i FROM 1 TO 13 DO
PackRawBytes byte_send{i},raw_data,(RawBytesLen(raw_data)+1)\Hex1;
ENDFOR
FOR i FROM 1 TO length DO
PackRawBytes arrayValue{i},raw_data\Network,(RawBytesLen(raw_data)+1)\Float4;
ENDFOR
SocketSend modbustcp_plc\RawData:=raw_data;
ENDPROC
关于四个输入变量它们分别是:设备号,起始地址,数据长度,存放的数组
接下来我们看rawbytes,这是一个原始字节,它是用来存放需要接收或者发送到plc那边的数据。机器人需要进num的数据转换成可以给plc读取到的数据。
modbus 常用功能代码
注意不同的功能码所对应的报文有所不同
十进制 | 十六进制 | 功能 | 数据类型 |
---|---|---|---|
01 | 0x01 | 读取 多个线圈 | 位 |
02 | 0x02 | 读取 多个离散量输入量 | 位 |
03 | 0x03 | 读取 多个保持寄存器 | 16进制整型 |
04 | 0x04 | 读取 多个输入寄存器 | 16进制整型 |
05 | 0x05 | 写入 单个线圈 | 位 |
06 | 0x06 | 写入 单个寄存器 | 16进制整型 |
15 | 0x0F | 写入 多个线圈 | 位 |
16 | 0x10 | 写入 多个寄存器 | 16进制整型 |
我们再看byte_send数组
第1,2位 00 01 交互标识
第3,4位 00 00 协议标识
第5,6位 00 06 后面报文长度 有6位
第 7 位 设备地址,发送什么,响应什么(一般是多个设备需要标记的到时候用到)
第 8 位 功能码(程序使用的是0x10 写入多个寄存器)
第9,10位00 01 起始地址
第11,12位 00 10查询线圈长度(就是往后读取多少给数据)
第13位 是后面数据的字节
先看第 5 ,6位。为什么是 4+7,其实这是一个固定的计算方法。4 是因为一个浮点数有4位,所以如果发10个浮点数出去,那就是104。那后面的 加7就是从第五位开始数6~12刚好7位。而后面 DIV 和MOD* 256只是做一个转换成十六进制的操作。
那其实报文已经讲过了,那具体发送一些什么样的数据,我没讲!那么请看下面的操作。
下半部分的代码
FOR i FROM 1 TO 13 DO
PackRawBytes byte_send{i},raw_data,(RawBytesLen(raw_data)+1)\Hex1;
ENDFOR
FOR i FROM 1 TO length DO
PackRawBytes arrayValue{i},raw_data\Network,(RawBytesLen(raw_data)+1)\Float4;
ENDFOR
SocketSend modbustcp_plc\RawData:=raw_data;
第一次循环是把上半部分的报文存入 RawBytesLen
第二次是把 arrayValue数组里面的数据打包进去
这里需要注意的是raw_date\Network 是指大端输入还是小端输入
而后面的**\Float4**就是以浮点数的形式存入
最后的socketsend就不用说了,把打包好的数据发送出去。这样plc就可以收到了。
读数据:
读取和写入的其实差不多,来看代码!!!
PROC ReadHoldingRegister(num slaveID,num start,num length,inout num arrayValue{*})
VAR byte byte_send{12};
VAR byte byte_receive{72};
byte_send{1}:=0X00;
byte_send{2}:=0X00;
byte_send{3}:=0X00;
byte_send{4}:=0X00;
byte_send{5}:=0x00;
byte_send{6}:=0x06;
byte_send{7}:=slaveID;
byte_send{8}:=0X03;
byte_send{9}:=start div 256;
byte_send{10}:=start mod 256;
byte_send{11}:=length*2 div 256;
byte_send{12}:=length*2 mod 256;
SocketSend modbustcp_plc\Data:=byte_send;
SocketReceive modbustcp_plc\data:=byte_receive;
Get32Float byte_receive,length*2,arrayValue;
ENDPROC
proc Get32Float(byte recebuffer{*},num length,inout num arrayValue{*})
VAR byte receive{4};
VAR rawbytes raw_data;
VAR num value;
VAR num nCount:=1;
FOR i FROM 1 TO length*2 STEP 4 DO
FOR j FROM 1 TO 4 DO
receive{j}:=recebuffer{9+i+(j-1)};
ENDFOR
ClearRawBytes raw_data;
FOR t FROM 4 TO 1 DO
PackRawBytes receive{t},raw_data,(RawBytesLen(raw_data)+1)\Hex1;
ENDFOR
UnpackRawBytes raw_data,1,value\Float4;
arrayValue{nCount}:=value;
Incr nCount;
ENDFOR
ENDPROC
功能码差不多,看Get32Float就可以了。先是把打包好的功能码(不带数据)发送给plc,然后我们就可以收到plc发过来的数据。Get32Float就是解包这些数据的,关键也就UnnpackRawBytes这个命令。具体不知道这个函数怎么使用,可以去看ABB的手册。没有的也可以私信我,给你发。
差点忘记了这个 VAR byte byte_receive{72};,因为ABB的数组不能像C语言或者python那种一样可以给你自动生成数组长度,所以我们要自己去计算。4*15+12=72,4是指一个浮点数有四个位,15是指数据的长度,12是报文的长度。
3.实现代码(例子)
3.1博图代码
博图的代码比较简单,plc作为一个服务器,机器人是客户端。
首先添加一个modbus tcp协议的功能块,这是一个服务器的功能块。
然后建立两个DB块,一个用来存储跟机器人链接的IP地址等数据,另一个就是存储跟机器人交互的数据。
图一:
图二:
两个图片其实没什么太大的区别,那我还放出来干嘛!!!
图一是连接真实际机器人的设置
图二是连接虚拟机器人的设置(robotstudio)
两个的ID和IP不一样,ID为什么不一样上面有讲了,不废话。IP不一样是我在调试的时候发现,如果指定PC的IP,有时候会出现连接不上的问题。或者两个块只连接了其中一个,另一个一直报错。
文章来源:https://www.toymoban.com/news/detail-776338.html
3.2RAPID代码
module modbustcp
VAR socketdev modbustcp_plc;
VAR intnum it1;
VAR intnum it2;
VAR intnum it3;
PERS num arrayValue_pose{15};
VAR num value;
PROC interupt()
IDelete it1;
CONNECT it1 WITH jt;
isignaldi robot_stop,1,it1;
IDelete it2;
CONNECT it2 WITH write_plc;
ITimer 0.24,it2;
ENDPROC
TRAP read_plc
ReadHoldingRegister 1,0,15,arrayValue_pose;
ENDTRAP
TRAP write_plc
write32float 1,0,15,arrayValue_pose;
ENDTRAP
PROC modbus_socket(string address,num port)
SocketClose modbustcp_plc;
SocketCreate modbustcp_plc;
SocketConnect modbustcp_plc,address,port;
ENDPROC
PROC write32float(num slaveID,num start,num length,num arrayValue{*})
VAR byte byte_send{13};
VAR rawbytes raw_data;
ClearRawBytes raw_data;
byte_send{1}:=0X00;
byte_send{2}:=0X00;
byte_send{3}:=0X00;
byte_send{4}:=0X00;
byte_send{5}:=(length*4+7) DIV 256;
byte_send{6}:=(length*4+7) mod 256;
byte_send{7}:=slaveID;
byte_send{8}:=0X10;
byte_send{9}:=start div 256;
byte_send{10}:=start mod 256;
byte_send{11}:=length*2 div 256;
byte_send{12}:=length*2 mod 256;
byte_send{13}:=length*4;
FOR i FROM 1 TO 13 DO
PackRawBytes byte_send{i},raw_data,(RawBytesLen(raw_data)+1)\Hex1;
ENDFOR
FOR i FROM 1 TO length DO
PackRawBytes arrayValue{i},raw_data\Network,(RawBytesLen(raw_data)+1)\Float4;
ENDFOR
SocketSend modbustcp_plc\RawData:=raw_data;
ENDPROC
PROC ReadHoldingRegister(num slaveID,num start,num length,inout num arrayValue{*})
VAR byte byte_send{12};
VAR byte byte_receive{72};
byte_send{1}:=0X00;
byte_send{2}:=0X00;
byte_send{3}:=0X00;
byte_send{4}:=0X00;
byte_send{5}:=0x00;
byte_send{6}:=0x06;
byte_send{7}:=slaveID;
byte_send{8}:=0X03;
byte_send{9}:=start div 256;
byte_send{10}:=start mod 256;
byte_send{11}:=length*2 div 256;
byte_send{12}:=length*2 mod 256;
SocketSend modbustcp_plc\Data:=byte_send;
SocketReceive modbustcp_plc\data:=byte_receive;
Get32Float byte_receive,length*2,arrayValue;
ENDPROC
proc Get32Float(byte recebuffer{*},num length,inout num arrayValue{*})
VAR byte receive{4};
VAR rawbytes raw_data;
VAR num value;
VAR num nCount:=1;
FOR i FROM 1 TO length*2 STEP 4 DO
FOR j FROM 1 TO 4 DO
receive{j}:=recebuffer{9+i+(j-1)};
ENDFOR
ClearRawBytes raw_data;
FOR t FROM 4 TO 1 DO
PackRawBytes receive{t},raw_data,(RawBytesLen(raw_data)+1)\Hex1;
ENDFOR
UnpackRawBytes raw_data,1,value\Float4;
arrayValue{nCount}:=value;
Incr nCount;
ENDFOR
ENDPROC
pric main()
modbus_socket "192.168.125.1",520;
interupt;
endproc
ENDmodule
机器人的代码就这样了,上面讲的很清楚了。如果需要项目源码什么的,就私信吧。开摆!!!!文章来源地址https://www.toymoban.com/news/detail-776338.html
到了这里,关于ABB机器人与西门子1200/1500进行modbus tcp通讯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!