3. MAVLink报文捕获:从抓包到解析的完整链路
报文捕获,说白了就是给无人机和地面站之间的对话装个「窃听器」。你想想看,SITL仿真里跑着那么多MAVLink消息,如果不抓出来看看,你怎么知道飞控到底在发什么?
我个人习惯,在开始任何SITL调试之前,先把抓包环境搭好。这就像修车之前先准备好万用表,省得后面手忙脚乱。
3.1 三把抓包利器: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。
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 本章知识体系
下面这张图把三种抓包方式的关系和流程串起来了:
这张图把三种抓包方式的流程串起来了。从SITL仿真出发,三条路径分别通向MAVProxy、Wireshark和pymavlink,每种方式都有自己的子方法和输出格式。你可以在实际项目中根据需求灵活选择。
核心要点:抓包不是目的,分析才是。无论用哪种方式,最终都要能从报文里提取出有价值的信息。我建议你从MAVProxy开始练手,熟悉了报文的基本结构之后,再切换到Wireshark做深度分析,最后用pymavlink写自动化脚本。循序渐进,别一口吃成胖子。