简介:QGC地面站源代码面向无人机开发者、QT学习者及飞控研究人员,提供QGroundControl完整开源工程,可用于远程控制、数据传输与任务规划的二次开发。资源包共2551个文件,约31.67MB,以1018个h头文件、245个cc与161个cpp源文件、216个qml界面文件为主,辅以png、svg图标资源及xml、json配置,完整呈现基于QT框架的跨平台工程结构。代码采用模块化设计,涵盖QML用户界面、Mavlink通信、飞行计划管理、数据分析与插件扩展等核心模块,并包含地理围栏、故障检测等安全机制。已有3762人学习下载,适合通过CMake构建、借助Qt Creator或VS Code阅读调试,深入理解无人机地面站架构与QT跨平台开发实践。
1. 拿到 QGC 地面站源代码,先别急着点编译
如果你手头正好有一份 QGC 地面站源代码,第一反应大概率是找 .pro 文件或者 CMakeLists.txt,然后直接开 Qt Creator 点构建。我见过太多人卡在这一步——编译报错几十条,连主窗口都出不来。QGC 全称 QGroundControl,是一套基于 QT 框架开发的无人机地面站软件,支持多旋翼、固定翼、VTOL 等多种机型的航线规划、参数配置、固件烧录和实时遥测。它本身是开源项目,代码量不小,模块划分也细,直接扔进 IDE 硬编很容易被环境依赖劝退。这份源代码适合两类人:一是想二次开发自己地面站的嵌入式工程师,二是想研究 QT 大型项目架构的桌面端开发者。不管你是哪一类,先把编译链路跑通,再谈改代码。
2. 编译环境搭建:QT 版本、CMake 与依赖库的版本对齐
2.1 为什么 QT 版本选错会直接翻车
QGC 对 QT 版本有硬性要求。早期版本用 QT 5.11 或 5.12,新一些的代码库已经迁到 QT 5.15 甚至 QT 6。你拿到的源码包如果没附带版本说明,先看两个地方:一是 .pro 文件里的QT +=模块列表,二是 CMakeLists.txt 里的find_package(Qt5或Qt6声明。常见做法是打开源码根目录,搜QT_VERSION或Qt5_DIR这类变量,能反推出目标版本。
我一般会先确认三件事:QT 安装版本、编译器类型(MSVC 还是 MinGW)、CMake 最低版本要求。这三者不匹配,后面全是玄学报错。比如 QT 5.15 配 MSVC 2019 是稳的,但配 MSVC 2022 就可能遇到QWebEngineView链接失败。MinGW 用户注意,QGC 的某些模块依赖 Windows SDK 里的串口库,MinGW 下需要额外补libserialport。
2.2 依赖库清单与安装命令
QGC 的依赖分两类:QT 自带模块和第三方库。QT 侧需要确保安装时勾选了Qt Charts、Qt Location、Qt Positioning、Qt SerialPort、Qt WebEngine(如果代码里有地图或网页视图)。第三方库常见的有:
| 依赖库 | 用途 | 安装方式 |
|---|---|---|
| libserialport | 串口通信 | apt install libserialport-dev / vcpkg install libserialport |
| mavlink | 通信协议头文件 | 源码内通常自带 submodule,需 git submodule update |
| SDL2 | 游戏手柄支持 | apt install libsdl2-dev / brew install sdl2 |
| OpenSSL | 加密通信 | apt install libssl-dev |
在 Ubuntu 下,我习惯用一条命令把基础依赖拉齐:
sudo apt update sudo apt install -y build-essential cmake git \ libserialport-dev libsdl2-dev libssl-dev \ qtbase5-dev qtdeclarative5-dev qtlocation5-dev \ qtpositioning5-dev libqt5serialport5-dev \ libqt5webengine5-dev qtquickcontrols2-5-dev这段命令里,build-essential提供 gcc/g++ 和 make,cmake是构建工具,git用来拉子模块。QT 相关的 dev 包必须和你要编译的 QT 版本一致,比如qtbase5-dev对应 QT 5.x。如果你用的是 QT 6,包名会变成qt6-base-dev这类。装完后用qmake --version确认版本。
2.3 子模块初始化与 CMake 配置
QGC 源码里通常有.gitmodules文件,mavlink 等库是以子模块形式存在的。如果你下载的是 zip 包而不是 git clone,子模块目录可能是空的。先执行:
git submodule update --init --recursive然后创建构建目录,跑 CMake:
mkdir build && cd build cmake .. -DCMAKE_PREFIX_PATH=/path/to/Qt/5.15.2/gcc_64 \ -DCMAKE_BUILD_TYPE=ReleaseCMAKE_PREFIX_PATH指向你的 QT 安装路径,Linux 下通常在~/Qt/5.15.2/gcc_64,Windows 下类似C:/Qt/5.15.2/msvc2019_64。CMAKE_BUILD_TYPE选 Release 能减少调试符号,编译更快。如果 CMake 报找不到Qt5Location,说明 QT 安装时没勾选对应模块,重新跑 QT 安装器补上。
3. 源码结构拆解:从 main.cc 到飞行控制逻辑的调用链
3.1 入口函数与主窗口初始化
QGC 的入口在src/main.cc。这个文件不长,但做了几件关键事:初始化QGCApplication、注册 QML 类型、加载主窗口。我一般会先看QGCApplication::init()里的顺序,因为它决定了哪些模块先起来。典型流程是:解析命令行参数 → 初始化设置管理器 → 创建主窗口 → 进入事件循环。
// src/main.cc 简化逻辑 int main(int argc, char *argv[]) { QGCApplication app(argc, argv); if (!app.init()) { return -1; } return app.exec(); }app.init()内部会调用QGCApplication::_initCommon(),这里面加载了SettingsManager、LinkManager、MultiVehicleManager等单例。如果你要加自定义模块,通常在这里注册。注意QGCApplication继承自QApplication,所以 QT 的事件循环机制直接适用。
3.2 车辆管理与 MAVLink 通信层
MultiVehicleManager是管理所有连接车辆的核心类。它监听LinkManager的新连接信号,每发现一个 MAVLink 心跳包就创建一个Vehicle对象。Vehicle类又派生出VehicleFactGroup等,把姿态、GPS、电池等数据暴露给 QML 界面。
通信层的关键类是MAVLinkProtocol。它负责 MAVLink 消息的编解码和路由。你如果要做自定义消息,需要改mavlink子模块里的 XML 定义,然后重新生成头文件。常见做法是跑mavlink自带的mavgenerate.py,把新消息加进去。
python3 mavlink/pymavlink/tools/mavgenerate.py \ --xml mavlink/message_definitions/v1.0/common.xml \ --out src/comm/mavlink这条命令会根据 XML 生成 C 头文件,输出到src/comm/mavlink目录。参数--xml指定消息定义文件,--out指定输出目录。生成后需要把新头文件加入 CMake 的 include 路径,否则编译时找不到符号。
3.3 QML 界面与 C++ 后端的交互方式
QGC 的界面几乎全是 QML 写的,C++ 侧通过Q_PROPERTY和Q_INVOKABLE暴露接口。比如Vehicle类里有:
Q_PROPERTY(double latitude READ latitude NOTIFY latitudeChanged) Q_INVOKABLE void setArmed(bool armed);QML 里就能直接写vehicle.latitude或vehicle.setArmed(true)。这种绑定方式很高效,但要注意线程问题:MAVLink 消息在独立线程解析,更新属性时必须用Qt::QueuedConnection或信号槽跨线程,否则界面会随机崩溃。我踩过这个坑,现象是飞行中界面卡死,日志里没有任何异常,最后定位到是直接在工作线程改了 Q_PROPERTY 的值。
4. 避坑与排查:编译失败、运行崩溃、连接超时的常见原因
4.1 编译报错 “undefined reference to QSerialPort”
现象:链接阶段报一堆undefined reference,指向QSerialPort或QSerialPortInfo。 原因:QT 安装时没勾选Qt SerialPort模块,或者 CMake 里没加SerialPort到target_link_libraries。 解决:重新跑 QT 安装器补上 SerialPort 模块;然后在 CMakeLists.txt 里确认有Qt5::SerialPort链接项。如果是 qmake 项目,检查 .pro 里有没有QT += serialport。
4.2 运行时报 “QML module not found”
现象:程序能编译,但启动后白屏,控制台输出QML module not found: QGroundControl。 原因:QML 文件没有正确注册到资源系统,或者QML2_IMPORT_PATH没设置。 解决:检查qrc资源文件是否包含了所有 QML;在main.cc里确认qmlRegisterType调用在engine.load()之前。Linux 下还可以临时设export QML2_IMPORT_PATH=$PWD/qml试试。
4.3 连接飞控后一直显示 “Waiting for vehicle”
现象:串口或 UDP 连接成功,但地面站不显示车辆,心跳包超时。 原因:MAVLink 版本不匹配,或者波特率设错。QGC 默认用 MAVLink 2.0,老飞控可能只发 1.0。 解决:在LinkManager的设置里把MAVLink Version改成 1.0 试试;串口波特率确认是 57600 还是 115200。另外检查防火墙有没有拦 UDP 14550 端口。
4.4 编译到 99% 卡住然后 OOM
现象:编译大型 QML 资源时内存暴涨,最后被系统 kill。 原因:qmlcachegen或rcc处理大文件时吃内存,尤其是 Release 模式下开 LTO。 解决:关掉 LTO(-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF),或者给机器加 swap。我一般会在 CMake 里把CMAKE_BUILD_TYPE改成RelWithDebInfo,比 Release 省内存,调试信息也够用。
4.5 修改代码后界面没变化
现象:改了 QML 文件,重新编译运行,界面还是旧的。 原因:QML 被编译进了 qrc 资源,直接跑 build 目录下的可执行文件不会重新加载外部 QML。 解决:要么每次改完跑一遍make让 rcc 重新打包,要么在调试时用qmlscene单独加载 QML 文件。我习惯在开发阶段把 QML 路径设成外部目录,省去反复编译的时间。
5. 二次开发切入点:自定义仪表盘与航线规划扩展
5.1 新增一个自定义 QML 仪表控件
假设你要加一个显示电池温度的仪表盘。先在src/ui/toolbar或src/ui/controls下新建BatteryTempIndicator.qml:
import QtQuick 2.11 import QtQuick.Controls 2.4 Item { property real temperature: 0 width: 100; height: 50 Rectangle { anchors.fill: parent color: temperature > 60 ? "red" : "green" Text { anchors.centerIn: parent text: temperature.toFixed(1) + " °C" color: "white" } } }然后在主界面 QML 里实例化它,并把Vehicle的温度属性绑上去。注意属性名要和 C++ 侧Q_PROPERTY一致,否则绑定无效。如果温度数据来自自定义 MAVLink 消息,还需要在Vehicle类里加对应的解析逻辑。
5.2 扩展航线规划:增加一个航点类型
QGC 的航线规划在src/MissionManager下。要加自定义航点类型,先改MissionItem的枚举,再在PlanView.qml里加对应的编辑界面。常见做法是继承MissionItem写一个CustomMissionItem,重写save和load方法。注意航点协议要跟飞控固件对齐,否则上传后飞控不认。
class CustomMissionItem : public MissionItem { Q_OBJECT public: CustomMissionItem(Vehicle* vehicle, QObject* parent = nullptr); void save(QJsonObject& json) const override; void load(const QJsonObject& json) override; };save和load负责序列化和反序列化,字段名要和飞控的 MAVLink 消息定义一致。改完记得跑一遍单元测试,QGC 自带MissionManagerTest,能验证航点读写是否正确。
5.3 调试技巧:用 qDebug 和 MAVLink Inspector
QGC 内置了 MAVLink Inspector,在菜单里能打开,实时看消息流。调试通信问题时,我一般先开 Inspector 确认消息有没有收到,再看Vehicle里的解析日志。C++ 侧用qDebug() << "msg:" << msg.id;输出到控制台,Release 下记得关掉,不然日志量很大。
提示:MAVLink Inspector 默认只显示已解析的消息,自定义消息需要先在
MAVLinkProtocol里注册,否则看不到。
6. 从源码到可执行文件:一次完整的构建与验证流程
把前面几步串起来,完整的构建流程是这样的:先确认 QT 版本和依赖库,跑git submodule update --init --recursive,然后 CMake 配置,最后make -j$(nproc)。编译成功后,用./QGroundControl启动,连上飞控或模拟器(比如 jMAVSim 或 Gazebo),检查心跳、姿态、GPS 是否正常刷新。
验证时我习惯做三件事:一是看版本号对不对,二是连模拟器飞一条简单航线,三是改一个 QML 颜色确认界面能重新加载。如果这三步都过,说明源码和环境都没问题,可以开始改代码了。
# 完整构建脚本示例 git clone <QGC源码地址> qgc-src cd qgc-src git submodule update --init --recursive mkdir build && cd build cmake .. -DCMAKE_PREFIX_PATH=$HOME/Qt/5.15.2/gcc_64 \ -DCMAKE_BUILD_TYPE=RelWithDebInfo make -j$(nproc) ./QGroundControl这段脚本里,git clone换成你实际的源码路径,CMAKE_PREFIX_PATH换成你的 QT 安装路径。make -j$(nproc)用满所有 CPU 核心加速编译,但内存小于 8G 的机器建议改成-j2,否则容易 OOM。
从那以后我每次拿到新的 QGC 源码包,都强制先跑一遍qmake --version和cmake --version,确认版本对齐再动手。这个习惯帮我省了至少两天的无效编译时间。希望帮到你。
本文还有配套的精品资源,点击获取