3. MAVLink报文捕获:从抓包到解析的完整链路

报文捕获,说白了就是给无人机和地面站之间的对话装个「窃听器」。你想想看,SITL仿真里跑着那么多MAVLink消息,如果不抓出来看看,你怎么知道飞控到底在发什么?

我个人习惯,在开始任何SITL调试之前,先把抓包环境搭好。这就像修车之前先准备好万用表,省得后面手忙脚乱。

3.1 三把抓包利器:MAVProxy、Wireshark、pymavlink

这三样东西各有各的脾气,我列个表给你看:

工具 适用场景 我的评价
MAVProxy 实时监控、命令行过滤 轻量级,适合快速看一眼
Wireshark 深度分析、协议解码 可视化强,适合事后复盘
pymavlink 自动化抓取、二次开发 灵活度高,适合写脚本批量处理
我的建议:别只依赖一种工具。我一般先用MAVProxy快速确认报文在跑,再用Wireshark做详细分析,最后用pymavlink写脚本批量提取关键数据。三管齐下,基本不会漏东西。

3.2 MAVProxy抓包:命令行里的实时监控

MAVProxy自带抓包功能,不需要额外装插件。启动SITL之后,在MAVProxy终端里敲几个命令就能看到报文在飞。

最基本的用法:

# 启动SITL和MAVProxy
sim_vehicle.py -v ArduCopter --console --map

# 在MAVProxy终端中,查看所有报文
status

# 只查看特定ID的报文(比如HEARTBEAT,ID=0)
set heartbeat 1

# 将报文保存到文件
log save mylog.tlog

嗯,这里要注意一个坑。我曾经在调试时发现,status命令显示的报文数量跟实际不符。后来才搞明白,MAVProxy默认只显示最近几秒的统计,不是全量。如果你要完整记录,一定要用log save。

避坑指南:我曾经在抓包时忘了关日志,结果跑了半小时,生成了几个G的tlog文件。建议抓包前先估算一下时间,或者用log set maxsize限制文件大小。

3.3 Wireshark过滤规则:从海量数据里捞出你想要的

Wireshark抓MAVLink报文,需要先装一个插件。不过现在新版本的Wireshark已经内置了MAVLink解析器,省了不少事。

启动Wireshark后,选择回环接口(loopback),因为SITL的UDP通信都在本机。然后设置过滤规则:

# 只显示MAVLink报文
mavlink

# 只显示特定系统ID的报文(比如系统ID=1)
mavlink.sysid == 1

# 只显示特定消息ID(比如HEARTBEAT,ID=0)
mavlink.msgid == 0

# 组合过滤:系统ID=1且消息ID=30(ATTITUDE)
mavlink.sysid == 1 && mavlink.msgid == 30

我个人习惯,先不加过滤抓个30秒,看看整体流量。然后再逐步加过滤条件,缩小范围。你想想看,如果一上来就过滤得太死,很可能把关键报文漏掉。

实战技巧:Wireshark的「Follow UDP Stream」功能特别好用。右键点击任意一个UDP包,选择「Follow」→「UDP Stream」,就能看到完整的MAVLink报文流。我经常用这个功能来检查报文顺序和完整性。

3.4 Python pymavlink库:自动化抓包的利器

pymavlink是MAVLink协议的Python实现,功能非常强大。我写自动化测试脚本时,基本都靠它。

先装库:

pip install pymavlink

然后写个简单的抓包脚本:

#!/usr/bin/env python3
"""
从SITL的UDP端口抓取MAVLink报文并打印
"""
from pymavlink import mavutil
import time

# 连接到SITL的UDP端口(默认14550)
master = mavutil.mavlink_connection('udp:127.0.0.1:14550')

print("等待心跳...")
master.wait_heartbeat()
print("已连接,开始抓包")

# 抓取10秒内的报文
start_time = time.time()
while time.time() - start_time < 10:
    msg = master.recv_match(blocking=True)
    if msg:
        print(f"收到报文: {msg.get_type()}")
        print(f"  系统ID: {msg.get_srcSystem()}")
        print(f"  组件ID: {msg.get_srcComponent()}")
        print(f"  原始数据: {msg.to_dict()}")
        print("-" * 40)

这个脚本虽然简单,但已经能抓到所有报文了。不过在实际项目中,我一般会加一些过滤条件:

# 只抓取特定类型的报文
msg = master.recv_match(type='HEARTBEAT', blocking=True)

# 只抓取特定系统ID的报文
msg = master.recv_match(src_system=1, blocking=True)

# 组合过滤
msg = master.recv_match(type='ATTITUDE', src_system=1, blocking=True)
我的经验:recv_match的blocking参数很关键。设为True时,脚本会一直等直到收到匹配的报文;设为False时,如果没有匹配报文就返回None。我写实时监控脚本时用blocking=True,写批量处理脚本时用blocking=False。

3.5 三种抓包方式的对比与选择

我把这三种方式的核心差异整理了一下:

维度 MAVProxy Wireshark pymavlink
上手难度 低 中 高(需要编程基础)
实时性 高 中 高
可视化 低(纯文本) 高(图形界面) 低(需要自己写输出)
自动化能力 低 中(支持命令行) 高(完全可编程)
文件格式 .tlog .pcapng 任意(自己控制)

你想想看,如果只是临时看一眼,MAVProxy就够了。但要做深度分析或者自动化测试,还是得靠Wireshark和pymavlink。

3.6 本章知识体系

下面这张图把三种抓包方式的关系和流程串起来了:

MAVLink报文捕获知识体系 MAVLink报文捕获知识体系 SITL仿真 MAVProxy抓包 Wireshark抓包 pymavlink抓包 status命令 log save mavlink过滤 Follow UDP msgid过滤 recv_match to_dict() wait_heartbeat 报文捕获输出 .tlog文件 .pcapng文件 Python数据结构

这张图把三种抓包方式的流程串起来了。从SITL仿真出发,三条路径分别通向MAVProxy、Wireshark和pymavlink,每种方式都有自己的子方法和输出格式。你可以在实际项目中根据需求灵活选择。

核心要点:抓包不是目的,分析才是。无论用哪种方式,最终都要能从报文里提取出有价值的信息。我建议你从MAVProxy开始练手,熟悉了报文的基本结构之后,再切换到Wireshark做深度分析,最后用pymavlink写自动化脚本。循序渐进,别一口吃成胖子。