4、Python日志解析库:使用 pymavlink 库读取 .bin 日志,安装与基础API使用

做无人机飞控这么多年,我处理过最多的数据格式就是 .bin 日志。说实话,刚开始接触 ArduPilot 的二进制日志时,我也挺头疼的——一堆二进制数据,用记事本打开全是乱码。后来发现 pymavlink 这个库,简直就是救星。

这一节,我们就来聊聊怎么用 pymavlink 读取 .bin 日志。我会把安装步骤、基础 API 调用,以及我踩过的坑都讲清楚。

4.1 为什么选择 pymavlink?

pymavlink 是 ArduPilot 官方推荐的 Python 库。它不仅能解析 MAVLink 协议,还能直接读取 .bin 日志文件。说白了,它就是飞控数据的一把万能钥匙。

我个人习惯用 pymavlink 做日志分析,原因有三:

  • 原生支持:ArduPilot 的 .bin 日志格式,pymavlink 直接就能读
  • 数据完整:不会丢失任何字段,包括一些冷门传感器数据
  • 社区活跃:遇到问题,GitHub 上基本都能找到答案
小提示:如果你用的是 PX4 的 .ulog 格式,pymavlink 也能读,但需要额外转换。我个人建议 PX4 用户直接用 pyulog 库,更省事。

4.2 安装 pymavlink

安装其实很简单,但有几个细节要注意。我刚开始装的时候,就因为在 Windows 上少了 C++ 编译环境,折腾了半天。

4.2.1 基础安装

# 最基础的安装方式
pip install pymavlink

# 如果你需要完整功能(包括图形界面工具)
pip install pymavlink[all]

4.2.2 常见安装问题

嗯,这里要注意。pymavlink 底层依赖一些 C 扩展,编译时容易出问题。我曾经在 Windows 上遇到过这样的报错:

error: Microsoft Visual C++ 14.0 is required...

解决办法其实很简单:

  • Windows 用户:先安装 Visual Studio Build Tools,或者直接用 Anaconda 环境
  • Linux 用户:先装好 gcc 和 python3-dev
  • macOS 用户:确保 Xcode Command Line Tools 已安装
避坑指南:我曾经在树莓派上装 pymavlink,因为内存不够编译失败。后来改用预编译的 wheel 包才搞定。如果你也在嵌入式设备上装,建议先试试 pip install --only-binary :all: pymavlink

4.3 核心 API 使用

安装好之后,我们来看看怎么用。我会从最基础的读取日志开始,一步步带你上手。

4.3.1 打开日志文件

读取 .bin 日志,核心就一个函数:mavutil.mavlink_connection()。你想想看,这个函数名字起得挺直白——建立 MAVLink 连接。只不过这里的"连接"对象不是飞控,而是日志文件。

from pymavlink import mavutil

# 打开 .bin 日志文件
log_file = "flight_log.bin"
mlog = mavutil.mavlink_connection(log_file)

print(f"日志已打开: {log_file}")
print(f"日志格式版本: {mlog.logformat}")

4.3.2 遍历消息

打开日志后,怎么读取里面的数据?pymavlink 把每条数据都封装成消息对象。我们可以用 recv_msg() 一条一条地读:

# 遍历所有消息
msg_count = 0
while True:
    msg = mlog.recv_msg()
    if msg is None:
        break
    msg_count += 1
    # 只打印前5条消息的类型
    if msg_count <= 5:
        print(f"消息类型: {msg.get_type()}, 时间戳: {msg._timestamp}")

print(f"总共读取了 {msg_count} 条消息")

这里有个小技巧:msg.get_type() 返回的是消息类型名称,比如 GPSIMUATT 这些。我刚开始分析日志时,就是靠这个函数先摸清日志里有哪些数据。

4.3.3 按类型筛选消息

实际分析中,我们通常只关心特定类型的数据。比如炸机分析,最常看的就是 GPS 和 IMU 数据。pymavlink 提供了 recv_match() 方法,可以按类型筛选:

# 只读取 GPS 消息
gps_count = 0
while True:
    msg = mlog.recv_match(type='GPS', blocking=False)
    if msg is None:
        break
    gps_count += 1
    if gps_count <= 3:
        print(f"GPS 状态: {msg.Status}, 卫星数: {msg.Satellites}")

print(f"共找到 {gps_count} 条 GPS 消息")
重点blocking=False 这个参数很关键。如果不加,recv_match() 会一直阻塞等待,直到读到匹配的消息。加了之后,没找到就返回 None,不会卡死。

4.3.4 按时间范围筛选

炸机分析时,我们往往只关心坠机前后几秒的数据。pymavlink 支持按时间戳筛选:

# 设置时间范围(单位:秒)
start_time = 120.0  # 从第120秒开始
end_time = 130.0    # 到第130秒结束

# 先定位到起始时间
mlog = mavutil.mavlink_connection(log_file)
while True:
    msg = mlog.recv_msg()
    if msg is None:
        break
    if msg._timestamp >= start_time:
        break

# 读取时间范围内的数据
print(f"时间范围: {start_time}s - {end_time}s")
count = 0
while True:
    msg = mlog.recv_msg()
    if msg is None or msg._timestamp > end_time:
        break
    count += 1

print(f"该时间段内共有 {count} 条消息")

我记得有一次分析炸机原因,就是靠这个时间筛选功能,精确锁定了坠机前 0.5 秒的 IMU 数据。发现加速度计突然跳变,最终定位到是减震垫脱落导致的。

4.4 实战:快速提取关键数据

光讲 API 太枯燥,我们直接上一个实战例子。假设你拿到一份炸机日志,想快速提取 GPS 坐标和高度变化:

from pymavlink import mavutil
import csv

def extract_gps_data(log_file, output_csv):
    """从 .bin 日志中提取 GPS 数据并保存为 CSV"""
    
    mlog = mavutil.mavlink_connection(log_file)
    
    # 准备 CSV 文件
    with open(output_csv, 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['时间戳', '纬度', '经度', '高度', '卫星数', '定位状态'])
        
        while True:
            msg = mlog.recv_match(type='GPS', blocking=False)
            if msg is None:
                break
                
            writer.writerow([
                msg._timestamp,
                msg.Lat,
                msg.Lng,
                msg.Alt,
                msg.Satellites,
                msg.Status
            ])
    
    print(f"GPS 数据已保存到: {output_csv}")

# 使用示例
extract_gps_data("crash_log.bin", "gps_data.csv")
个人经验:提取数据后,我习惯先用 Excel 打开 CSV 文件,快速看一下数据趋势。如果发现某个时间点卫星数突然掉到 0,或者高度数据出现异常跳变,那基本就是炸机原因所在了。

4.5 本章知识体系

为了让你更直观地理解 pymavlink 的使用流程,我画了一张图:

pymavlink 日志解析流程 步骤1:安装 pip install pymavlink 步骤2:打开日志 mavlink_connection() 步骤3:读取消息 recv_msg() / recv_match() 步骤4:数据分析 按类型/时间筛选 步骤5:导出结果 保存为 CSV / 绘图 常用消息类型 GPS IMU ATT BAT RCIN pymavlink 日志解析核心流程

4.6 常见问题与避坑

最后,分享几个我实际工作中遇到的问题:

问题 现象 解决办法
日志版本不兼容 读取时抛出 Unknown MAVLink version 升级 pymavlink 到最新版:pip install --upgrade pymavlink
内存占用过高 读取大日志时内存飙升 使用迭代器逐条读取,不要一次性加载所有数据
时间戳异常 某些消息的时间戳为 0 检查日志是否完整,或者用 msg._timestamp 替代 msg.TimeUS
中文路径报错 Windows 下日志路径含中文时读取失败 将日志文件复制到纯英文路径下再读取
避坑指南:我曾经遇到过一个诡异的问题——某份日志用 pymavlink 读取时,GPS 数据全部为 0。折腾了半天才发现,是日志文件在拷贝过程中损坏了。所以拿到日志后,第一件事就是检查文件大小是否正常,别急着分析。

好了,pymavlink 的基础用法就讲到这里。记住一个核心原则:先摸清日志里有什么数据,再针对性地提取分析。下一节我们会用这些 API 做实际的炸机数据提取,到时候你就知道这些基础操作有多重要了。


公众号:蓝海资料掘金营,微信deep3321