对WireShark 中的EtherCAT抓包数据进行解析
对WireShark 中的EtherCAT抓包数据进行解析
EtherCAT数据包结构
EtherCAT数据帧结构如下:
采用 Python 实现对 EtherCAT 数据包进行解析
import numpy as np
import matplotlib.pyplot as plt
from IPython import embed
from collections import Counter
import pyshark
import pcapng
from datetime import datetime
import dpkt
import socket
from dpkt.utils import mac_to_str, inet_to_str# https://zhuanlan.zhihu.com/p/582336672#打开抓包文件# 位置寻址
# - APRD(1): Auto Increment Read
# - APWR(2): Auto Increment Write
# - APRW(3): Auto Increment Read Write
# # 节点寻址
# - FPRD(1): Configuration address Read
# - FPWR(2): Configuration address Write
# - FPRW(3): Configuration address Read Write
# # 广播寻址
# - BRD(1): Broadcast Read
# - BWR(2): Broadcast Write
# - BRW(3): Broadcast Read Write
# # 逻辑寻址
# - LRD(1): Logic Memory Read
# - LWR(2): Logic Memory Write
# - LRW(3): Logic Memory Read Write
# # 位置寻址
# - APMW(13): Auto Increment Read Multiple Writecnt = 2
old_timestamp = 0
file_path = "./TestJoint.pcapng"time_list_pc_to_control = []
time_list_control_to_pc = []
data_list = []joint_cmd = []
joint_fd = []
with open(file_path,"rb") as fp:pcapng_data = dpkt.pcapng.Reader(fp)for timestamp, buf in pcapng_data:eth = dpkt.ethernet.Ethernet(buf)cnt += 1## Ethernet_II 帧格式# ## 1、目标 Mac 地址# eth.dst# ## 2、源 Mac 地址# eth.src## 3、得到Ethernet II 数据帧的类型。类型字段(Type )用于标识数据字段中包含的高层协议。类型字段取值为0x0800的帧代表IP协议帧;类型字段取值为0x0806的帧代表ARP协议帧。## 0x0800: IP IP协议## IPv4: 0x0800## ARP: 0x0806## IPV6: 0x86DD## EtherCAT: 0x88A4# print(hex(eth.type))# 如果是EtherCAT 的数据帧if(eth.type == 0x88a4):ethercat_data = eth.data## 解析EtherCAT 头,数据帧的前两个字节ethercat_data_head = int.from_bytes(ethercat_data[:2], byteorder='little')### 得到数据的长度 11 bit, 后面有一个bit的保留位ethercat_data_length = (ethercat_data_head & 0x0fff)### 得到EtherCAT 的类型 4bitethercat_data_cmd = (ethercat_data_head & 0xf000) >> 12## 解析一个子报文## 解析子报文的头ethercat_subdata_head = int.from_bytes(ethercat_data[2:12], byteorder='little')## 命令 8 bit## LRW = 12ethercat_subdata_head_cmd = ethercat_data[2]if ethercat_subdata_head_cmd == 12:## 索引 8 bitethercat_subdata_head_index = ethercat_data[3]## 地址区 32 bitethercat_subdata_head_address = int.from_bytes(ethercat_data[4:8], byteorder='little')## 长度 11 bit 216 个字节ethercat_subdata_head_length = int.from_bytes(ethercat_data[8:10], byteorder='little') & 0x0eff## R 3 bitethercat_subdata_head_R = (int.from_bytes(ethercat_data[8:10], byteorder='little') & 0x3000) >> 13## C 1 bitethercat_subdata_head_C = (int.from_bytes(ethercat_data[8:10], byteorder='little') & 0x4000) >> 14## M 1 bit## 0: 表示只有 1 包数据## 1:表示后面还有数据包ethercat_subdata_head_M = (int.from_bytes(ethercat_data[8:10], byteorder='little') & 0x8000) >> 15## 状态位 16 bitethercat_subdata_head_status = int.from_bytes(ethercat_data[10:12], byteorder='little')## 1:表示后面还有数据包if(ethercat_subdata_head_M == 1):ethercat_subdata_data = ethercat_data[12:12 + ethercat_subdata_head_length ]j1_cmd = int.from_bytes(ethercat_subdata_data[4:8], byteorder='little', signed = True)j2_cmd = int.from_bytes(ethercat_subdata_data[16:20], byteorder='little', signed = True)j3_cmd = int.from_bytes(ethercat_subdata_data[28:32], byteorder='little', signed = True)j4_cmd = int.from_bytes(ethercat_subdata_data[40:44], byteorder='little', signed = True) j5_cmd = int.from_bytes(ethercat_subdata_data[52:56], byteorder='little', signed = True)j6_cmd = int.from_bytes(ethercat_subdata_data[64:68], byteorder='little', signed = True) j1_fd = int.from_bytes(ethercat_subdata_data[76:80], byteorder='little', signed = True) j2_fd = int.from_bytes(ethercat_subdata_data[100:104], byteorder='little', signed = True) j3_fd = int.from_bytes(ethercat_subdata_data[124:128], byteorder='little', signed = True) j4_fd = int.from_bytes(ethercat_subdata_data[148:152], byteorder='little', signed = True)j5_fd = int.from_bytes(ethercat_subdata_data[172:176], byteorder='little', signed = True)j6_fd = int.from_bytes(ethercat_subdata_data[196:200], byteorder='little', signed = True) joint_cmd.append([j1_cmd, j2_cmd, j3_cmd, j4_cmd, j5_cmd, j6_cmd])joint_fd.append([j1_fd, j2_fd, j3_fd, j4_fd, j5_fd, j6_fd])joint_cmd_1 = np.mat(joint_cmd)
joint_fd_1 = np.mat(joint_fd)for i in range(6):plt.plot(joint_cmd_1[:,i],label = 'cmd')plt.plot(joint_fd_1[:,i],label = 'fd')plt.xlabel("time[ms]")plt.ylabel("pos[cnt]")plt.legend()plt.show()
下面是从数据包解析得到的关节1 和 关节 5 的关节脉冲指令值以及反馈值。
在开始阶段需要将当前的脉冲指令值和反馈值进行同步一下。