對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 的關節脈沖指令值以及反饋值。
在開始階段需要將當前的脈沖指令值和反饋值進行同步一下。