引言
作为这篇博客使用抓包盒进行EtherCAT报文时间抖动的分析方法-CSDN博客的延申,在报文有时间戳的情况下,通过提取出来LRW字段中的Target Position 与 Actual Positon 数据,画成曲线,可以直观得分析出指令跟随情况。
解决的问题
先说下为什么想到这么做:在自研的主站控制自研的从站运行时,出现了从站抖动的情况。
从主站端打印出发送的位置指令 与 接受到的 位置反馈 数值,无异常。
从站端打印出接受到的位置指令,与实际的位置反馈 数值,指示出为主站发送的问题。
于是,为了找出究竟谁说了谎,直接抓取网络报文,从报文中提取出来相应字段,继续分析。
具体方法
1、首先抓取到通讯过程的报文,并筛选出主站发送的部分,且保存为pcap格式。
2、提取出LRW字段,与时间戳字段,另存为CSV文件,用于后续的python数据处理。可通过这条指令解决:
tshark -r "name.pcap" -n -Y "ecat.cmd == 12" -T fields -e esl.timestamp -e ecat.data -E separator=, > "lrwtimestamp_data.csv"输出的CSV文件内容示例:第一列为64位的硬件时间戳,单位为ns。第二列为LRW的28个Byte。
0x00012f1db1c69c48,00000f00a89effff0800eaff000052ff8c2dffff37120f9fffff0800 0x00012f1db1e521b8,00000f00a89effff0800ebff00005dffea2affff3712099fffff0800 0x00012f1db203a8e0,00000f00a89effff0800e5ff00000cffea2affff3712039fffff0800 0x00012f1db2222bf8,00000f00a89effff0800e3ff000021ffe42dffff3712fc9effff0800 0x00012f1db240b078,00000f008a9effff0800e6ff000031ff6830ffff3712f69effff0800 0x00012f1db25f3638,00000f008a9effff0800d9ff00003fff3531ffff3712ef9effff0800 0x00012f1db27db770,00000f008a9effff0800f2ff000028ff2733ffff3712e99effff0800 0x00012f1db29c3bf0,00000f008a9effff0800e4ff000027ffee36ffff3712e39effff0800 0x00012f1db2bac5e8,00000f008a9effff0800f4ff0000a1ff913dffff3712dd9effff0800 0x00012f1db2d945b8,00000f006c9effff0800d9ff0000d1fe7d42ffff3712d79effff0800本例中LRW内的报文按此组织:
PACKED_BEGIN typedef struct PACKED { int16_t targetTorque; uint16 controlword; int32 targetPostion; int8_t modeOperation; int8_t node; }PDO_Outputs; PACKED_END PACKED_BEGIN typedef struct PACKED { int16_t actTorque; int16_t errCode; int16_t actCurrent; int32_t actVelocity; uint16 statusWord; int32 actualPostion; int8_t actRunMode; int8_t node; }PDO_Input; PACKED_END从代码中可知,targetPostion为bit4-bit7。actualPostion为bit22-25。
3、通过python代码将上述csv文件中的数据提取出 时间戳 位置指令 位置反馈 ,并画出图,示例代码如下:
import csv import struct import matplotlib.pyplot as plt csv_file = "lrwtimestamp_data.csv" LRW_LENGTH = 28 time_s = [] target_pos = [] actual_pos = [] # ---------- 读 CSV 并解析 ---------- with open(csv_file, newline="") as f: reader = csv.reader(f) for row in reader: if len(row) < 2: continue # 时间戳:hex ns → s t_ns = int(row[0], 16) t_s = t_ns * 1e-9 data = bytes.fromhex(row[1]) if len(data) != LRW_LENGTH: continue target = struct.unpack_from("<i", data, 4)[0] actual = struct.unpack_from("<i", data, 22)[0] time_s.append(t_s) target_pos.append(target) actual_pos.append(actual) # 时间轴归零(推荐) t0 = time_s[0] time_s = [t - t0 for t in time_s] # Following Error following_error = [a - t for a, t in zip(actual_pos, target_pos)] # ---------- 单位换算 ---------- target_pos_deg = [p / 1024.0 for p in target_pos] actual_pos_deg = [p / 1024.0 for p in actual_pos] following_error_deg = [a - t for a, t in zip(actual_pos_deg, target_pos_deg)] # ---------- 创建 Figure 和子图 ---------- fig, (ax1, ax2) = plt.subplots( 2, 1, sharex=True, figsize=(10, 6) ) # ---------- 子图 1:Target vs Actual ---------- ax1.plot(time_s, target_pos_deg, label="TargetPosition") ax1.plot(time_s, actual_pos_deg, label="ActualPosition") ax1.set_ylabel("Position (°)") ax1.set_title("Target vs Actual Position (LRW)") ax1.legend() ax1.grid(True) # ---------- 子图 2:Following Error ---------- ax2.plot(time_s, following_error_deg, label="Following Error") ax2.set_xlabel("Time (s)") ax2.set_ylabel("Error (°)") ax2.set_title("Following Error") ax2.grid(True) plt.tight_layout() plt.savefig( "lrw_position_and_following_error_deg.png", dpi=300, bbox_inches="tight" ) plt.show()4、输出的图像示例如下:
从图中看,位置指令是按预期发送的,位置反馈出现了波动,定位出了是从站的问题。