4. 连接飞控:通过串口连接Pixhawk、读取心跳包、验证连接状态

好,咱们进入实战环节的第一个硬骨头——把地面站和飞控真正连起来。

很多初学者觉得这步很简单,插上线就行。嗯,我当年也这么想。结果第一次调参时,地面站死活连不上,折腾了整整一个下午。后来发现,就是波特率没对上。

所以这一章,咱们把串口连接的每个细节都掰开揉碎。你跟着走一遍,以后遇到类似问题,心里就有底了。

4.1 串口通信基础

Pixhawk 和地面站之间,说白了就是通过串口在聊天。一个发,一个收,约定好说话的速度和格式。

参数 Pixhawk 默认值 说明
波特率 115200 每秒传输的比特数,越高越快
数据位 8 每个字节用8位表示
停止位 1 字节结束的标志位
校验位 无 不启用奇偶校验

你可能会问:为什么是 115200?其实早期飞控用 57600 甚至 38400 都有。115200 是后来统一的标准,兼顾了速度和稳定性。我在一个项目中试过 921600,结果线稍微长一点就丢包,得不偿失。

4.2 硬件连接与端口识别

先把 Pixhawk 用 USB 线连到电脑。这时候别急着写代码,先确认系统认没认到设备。

Windows 用户:打开设备管理器,看「端口 (COM 和 LPT)」下面有没有出现类似 USB Serial Device (COM3) 的条目。如果没有,检查驱动或换根线。

Linux / macOS 用户:终端里敲 ls /dev/tty*,找类似 /dev/ttyACM0 或 /dev/ttyUSB0 的设备。Pixhawk 通常是 ACM 开头。

我的小习惯: 每次插拔飞控后,都重新执行一次端口扫描。因为系统有时会重新分配端口号,你写死的 COM3 可能下次就变成 COM5 了。

4.3 Python 串口编程实战

Python 里操作串口,最常用的库是 pyserial。先装好它:

pip install pyserial

然后,咱们写一个最基础的连接脚本:

import serial
import time

# 配置串口参数
ser = serial.Serial(
    port='/dev/ttyACM0',   # Windows 下改成 'COM3'
    baudrate=115200,
    bytesize=8,
    parity='N',
    stopbits=1,
    timeout=2              # 读取超时2秒
)

print(f"已连接到 {ser.portstr}")

# 持续读取数据
try:
    while True:
        if ser.in_waiting > 0:
            data = ser.read(ser.in_waiting)
            print(data.hex())
        time.sleep(0.01)
except KeyboardInterrupt:
    ser.close()
    print("连接已关闭")

跑一下这个脚本,你会看到一串串十六进制数据刷出来。别慌,这就是飞控在不停往外吐的数据流。

注意: 如果你在 Linux 下遇到 Permission denied,说明当前用户没有串口权限。执行 sudo usermod -a -G dialout $USER 然后注销重登,或者临时用 sudo python 跑脚本。

4.4 解读心跳包

飞控发出来的数据里,有一种特殊的报文叫「心跳包」。它的作用是告诉地面站:我还活着,系统状态正常。

MAVLink 协议里,心跳包的 ID 是 0(也就是 HEARTBEAT)。它的结构长这样:

字段 字节偏移 说明
STX(起始标志) 0 0xFD(MAVLink 2)或 0xFE(MAVLink 1)
LEN(长度) 1 有效载荷长度
SEQ(序列号) 2 报文序号,用于检测丢包
SYS ID(系统ID) 3 飞控的编号,通常为1
COMP ID(组件ID) 4 组件编号,飞控通常为1
MSG ID(消息ID) 5-7 0 表示心跳包
有效载荷 8+ 包含系统状态、模式等信息

咱们不需要手动解析每个字节。用 pymavlink 库,几行代码就能搞定:

pip install pymavlink
from pymavlink import mavutil

# 创建连接
master = mavutil.mavlink_connection('/dev/ttyACM0', baud=115200)

# 等待第一个心跳包
print("等待飞控心跳...")
master.wait_heartbeat()
print(f"收到心跳!系统ID: {master.target_system}, 组件ID: {master.target_component}")

# 持续接收并打印心跳
while True:
    msg = master.recv_match(type='HEARTBEAT', blocking=True)
    if msg:
        print(f"模式: {mavutil.mode_string_v10(msg)}, 状态: {msg.system_status}")

跑起来之后,你会看到类似这样的输出:

等待飞控心跳...
收到心跳!系统ID: 1, 组件ID: 1
模式: STABILIZE, 状态: 3
模式: STABILIZE, 状态: 3
模式: ALT_HOLD, 状态: 3

看到没?飞控每隔几秒就会发一次心跳。如果超过 3 秒没收到,那就要检查连接了。

验证连接状态的标准:
  • 连续收到 3 个以上心跳包,且序列号递增
  • 系统状态值在 0-6 之间(0=未初始化,3=活跃,6=紧急)
  • 模式字符串能正确解析
满足这三条,基本可以确认连接是稳定的。

4.5 常见问题与避坑

我在项目里遇到过不少连接问题,挑几个典型的说说:

  • 端口被占用:有时候 Mission Planner 或 QGroundControl 没关干净,串口就被占用了。关掉所有地面站软件再试。
  • 波特率不匹配:有些飞控固件默认是 57600。如果 115200 连不上,试试 57600 或 38400。
  • USB 线质量差:这个坑我踩过好几次。劣质 USB 线只能充电,不能传数据。换根好线立马解决。
  • 驱动问题:Windows 下 Pixhawk 需要装驱动。去官网下载「Zadig」工具,把设备驱动换成 WinUSB 或 libusb。
曾经有一次,我在野外调试,飞控怎么都连不上。折腾了半小时,最后发现是 USB 口进了灰尘。拿气吹吹了一下,立马好了。所以,硬件问题先做最基础的检查。

4.6 知识体系总览

下面这张图,把本章的核心逻辑串起来了:

串口连接飞控核心流程 硬件连接 USB线连接Pixhawk 端口识别 查找 /dev/ttyACM0 串口配置 波特率115200 读取数据流 原始十六进制数据 解析心跳包 MSG ID = 0 验证连接状态 模式/状态/序列号 💡 关键点: 心跳包是飞控的「生命信号」——连续收到3个以上,且序列号递增,才算真正连上了。

从硬件连接开始,到端口识别、串口配置,再到数据读取和心跳解析,最后验证状态——每一步都环环相扣。任何一个环节出问题,地面站都连不上飞控。

4.7 本章小结

到这,你应该能独立完成飞控的串口连接了。总结几个关键点:

  • 串口参数必须和飞控固件一致,尤其是波特率
  • 心跳包是验证连接的黄金标准,学会用 pymavlink 解析它
  • 遇到问题先从硬件排查:线、端口、驱动