4、地面站与飞控的MAVLink通信:QGroundControl与Mission Planner的MAVLink实现、串口与UDP通信配置、mavlink-router的使用

地面站和飞控之间的通信,是无人机系统里最基础也最关键的一环。说白了,飞控在天上飞,地面站在地上看,中间靠的就是MAVLink这条“电话线”。今天咱们就聊聊这条线怎么拉、怎么配、怎么让它跑得稳。

核心要点:地面站与飞控的MAVLink通信,本质上是串口或UDP链路上的MAVLink帧封装与解析。QGC和MP是两种主流实现,mavlink-router则是多链路转发的利器。

4.1 QGroundControl与Mission Planner的MAVLink实现

QGC和MP,这两个地面站我都用了好多年。它们虽然界面不同,但底层对MAVLink的处理逻辑其实大同小异。

4.1.1 QGC的MAVLink通信架构

QGC用的是Qt框架,它的MAVLink层封装在MAVLinkProtocol类里。我印象最深的是它的多链路管理——你可以同时连串口、UDP、TCP,它自己会合并消息流。

  • 链路层:支持串口、UDP、TCP、蓝牙
  • 协议层:MAVLink 1.0 和 2.0 自动协商
  • 应用层:心跳检测、参数同步、航点上传

QGC有个习惯,它会每5秒发一次MAV_CMD_REQUEST_MESSAGE来拉取飞控状态。我在项目里遇到过,如果飞控响应慢了,QGC会反复重试,导致串口被刷爆。后来我加了消息去重,才算消停。

4.1.2 Mission Planner的MAVLink实现

MP是基于C#的,它的MAVLink解析器是MAVLinkInterface。说实话,MP的串口通信比QGC更“暴力”——它默认用115200波特率,而且会一次性拉取所有参数。

特性 QGC MP
开发语言 C++ (Qt) C# (.NET)
默认波特率 57600 115200
多链路支持 原生支持 需插件
MAVLink 2.0 完全支持 部分支持
参数同步方式 按需拉取 全量拉取

我的建议:如果你在开发阶段,用QGC调试更方便,因为它日志更详细。如果是飞手现场调参,MP的界面更直观。我一般两个都装,各取所长。

4.2 串口与UDP通信配置

串口和UDP,是地面站和飞控之间最常见的两种物理链路。串口适合近距离有线连接,UDP适合无线数传。嗯,这里有个坑,我踩过好几次。

4.2.1 串口配置实战

串口通信,说白了就是让地面站和飞控用同一套“方言”说话。关键参数就四个:波特率、数据位、停止位、校验位。

// QGC串口配置示例(伪代码)
SerialLink link = new SerialLink();
link.setPortName("/dev/ttyUSB0");
link.setBaudRate(57600);
link.setDataBits(8);
link.setStopBits(1);
link.setParity(Parity.NONE);
link.connect();

我曾经在项目里遇到过,飞控用的是115200,但QGC默认是57600,结果死活连不上。折腾了半天才发现是波特率没对上。所以我的习惯是:先看飞控的SRx_参数,再配地面站。

注意:串口通信时,飞控的SERIALx_BAUD参数必须和地面站一致。不一致的话,地面站收不到心跳包,会显示“连接失败”。

4.2.2 UDP通信配置

UDP比串口灵活,但不可靠。为什么?因为UDP不保证数据包一定到达。不过对于无人机来说,偶尔丢一帧心跳包问题不大,飞控会自己重发。

UDP配置的核心是IP和端口。地面站和飞控需要约定好:

  • 飞控端:监听某个端口(比如14550),接收地面站指令
  • 地面站端:向飞控IP+端口发送数据,同时监听另一个端口接收遥测
// QGC UDP配置示例
UDPLink link = new UDPLink();
link.setLocalPort(14550);      // 本地监听端口
link.setRemoteHost("192.168.1.100"); // 飞控IP
link.setRemotePort(14550);     // 飞控端口
link.connect();

我记得有一次,客户说地面站收不到数据,我一看,原来是防火墙把UDP端口封了。所以配UDP的时候,记得先检查防火墙规则。

4.3 mavlink-router的使用

mavlink-router,这玩意儿是Intel出的,专门用来做MAVLink消息的路由转发。说白了,它就是个“消息二传手”——把飞控的消息分发给多个地面站,或者把多个地面站的指令合并发给飞控。

4.3.1 为什么需要mavlink-router?

你想想看,一个飞控只有一个串口,但你可能同时想连QGC调试、连MP调参、再连一个ROS节点做数据处理。怎么办?串口不能分叉啊。这时候mavlink-router就派上用场了。

  • 场景一:飞控串口 → mavlink-router → QGC (UDP) + MP (UDP)
  • 场景二:飞控UDP → mavlink-router → 多个地面站
  • 场景三:飞控串口 → mavlink-router → ROS节点 (TCP)

4.3.2 安装与配置

mavlink-router的安装很简单,源码编译或者apt安装都行。我一般用源码编译,因为可以定制一些参数。

# 安装依赖
sudo apt install git meson ninja-build

# 克隆源码
git clone https://github.com/mavlink-router/mavlink-router.git
cd mavlink-router

# 编译安装
meson setup build
ninja -C build
sudo ninja -C build install

配置文件是/etc/mavlink-router/main.conf,核心就是定义输入和输出。

[General]
MavlinkDialect = common
DebugLogLevel = info

[UartEndpoint to_fc]
Device = /dev/ttyS0
Baud = 57600

[UdpEndpoint to_qgc]
Mode = server
Port = 14550

[UdpEndpoint to_mp]
Mode = server
Port = 14551

这个配置的意思是:从串口/dev/ttyS0读飞控数据,然后转发到两个UDP端口——14550给QGC,14551给MP。这样两个地面站就能同时工作了。

避坑指南:我曾经把Mode配成了client,结果mavlink-router一直在尝试连接地面站,而不是等地面站来连。改成server模式就正常了。记住:地面站是客户端,mavlink-router是服务端。

4.3.3 运行与调试

启动mavlink-router很简单:

sudo systemctl start mavlink-router
sudo systemctl enable mavlink-router  # 开机自启

想看日志?用journalctl -u mavlink-router -f实时跟踪。我一般会先开一个终端跑日志,再开地面站,这样出问题能第一时间看到。

常见的调试命令:

  • mavlink-routerd -c /etc/mavlink-router/main.conf — 前台运行,方便看输出
  • mavlink-routerd -v — 开启详细日志
  • mavlink-routerd -l /var/log/mavlink-router.log — 指定日志文件

4.4 本章知识体系

下面这张图,是我自己总结的MAVLink通信链路结构。你看一眼,基本就明白整个数据流了。

地面站与飞控MAVLink通信链路结构 地面站与飞控MAVLink通信链路结构 飞控 (PX4/ArduPilot) 串口 (UART) UDP / TCP mavlink-router 消息路由转发 多链路分发 协议转换 QGroundControl Mission Planner ROS / 其他节点 说明: 1. 飞控通过串口或UDP发出MAVLink消息 2. mavlink-router接收后,根据配置分发到多个地面站 3. 每个地面站独立处理消息,互不干扰

这张图里,飞控在最左边,地面站在最右边,mavlink-router在中间当“调度员”。串口和UDP是两条“管道”,mavlink-router负责把数据从管道里接过来,再分发给不同的地面站。

总结一下:QGC和MP是两种主流地面站实现,串口和UDP是两种物理链路,mavlink-router是解决多链路分发的利器。配好这三样,地面站和飞控的通信基本就稳了。