记一次处理上位机接收下位机数据的bug

记录上位机本应通过串口持续接收 1990 字节长度的数据,但出现不足 1990 字节。正确排查过程。

下位机使用正点原子接收如下

correct recv

其中收到 20634310 个字节,每个包 1990 个字节。20634310 / 1990 是 10369,能整除,说明没有丢包

但是上位机发现丢包

wrong recv

具体排查步骤

排查上位机接收算法,使用的是先找包头,后找包尾。进一步判断原始数据下包头之间的距离和包尾之间的距离

其中包头是DE3A096631,包尾是CEFF

查找包尾并写入对应的 CSV 文件

find_ceff.py
import argparse
import csv

def find_ceff_offsets(filename):
    with open(filename, 'rb') as f:
        data = f.read()

    target = b'\xCE\xFF'
    offset = 0
    count = 0
    offsets = []

    while True:
        idx = data.find(target, offset)
        if idx == -1:
            break

        offsets.append(idx)
        offset = idx + 1  # 继续查找下一个
        count += 1

    if count == 0:
        print("未找到任何 CE FF 序列。")
        return

    print(f"总共找到 {count} 个 CE FF。正在写入 distance.csv...")

    with open("distance.csv", "w", newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(["index", "start_offset", "end_offset", "distance", "is_1990"])
        for i in range(1, len(offsets)):
            start = offsets[i - 1]
            end = offsets[i]
            distance = end - start
            writer.writerow([
                i,
                f"0x{start:08X}",
                f"0x{end:08X}",
                distance,
                "YES" if distance == 1990 else "NO"
            ])

    print("写入完成:distance.csv")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="查找二进制文件中所有 CE FF 的偏移量,并输出间距到 CSV")
    parser.add_argument("file", help="要分析的二进制文件路径")
    args = parser.parse_args()

    find_ceff_offsets(args.file)

运行

python find_ceff.py valid_test/helper/data.raw

绘制对应包尾的距离

find_ceff.py
import pandas as pd
import matplotlib.pyplot as plt

# 读取 CSV 文件
df = pd.read_csv("distance.csv")

# 提取 index 和 distance 列
index = df["index"]
distance = df["distance"]

# 计算常见帧距
expected = distance.mode()[0]

# 绘图
plt.figure(figsize=(12, 6))
plt.plot(index, distance, label='frame distance', marker='o', linewidth=1)

# 标出异常帧距
abnormal = df[distance != expected]
if not abnormal.empty:
    plt.plot(abnormal["index"], abnormal["distance"], 'rx', label='abnormal', markersize=8)

# 添加图形信息
plt.xlabel("frame idx")
plt.ylabel("frame distance")
plt.title("CE FF distance")
plt.grid(True)
plt.legend()
plt.tight_layout()

# 显示或保存图像
plt.savefig("distance_plot.png", dpi=300)  # 可选保存
plt.show()

distance CEFF

发现很多异常距离点

进一步查看包头距离,只要将找包尾代码中的CEFF换成包头的DE3A096631,然后进行查找

distance DE3A096631

发现一切正常

说明单纯根据包尾进行查找存在问题,额外增加条件:数据长度。即我找到了包尾,再判断是否满足 1990 长度,不满足继续查找下一个包尾。

我用 ESP32 写一个平移正弦波曲线,持续发送给上位机,上位机持续接收连续曲线,验证正常了。


comment: