4、QGC地面站二次开发环境:QGC源码下载、Qt环境配置、QGC插件机制、自定义UI面板
地面站是无人机系统的「眼睛」和「手」。没有它,你连飞机在飞什么都看不到。
QGC(QGroundControl)是目前PX4生态里最主流的开源地面站。我最早接触它的时候,第一反应是「这玩意儿代码量也太大了」。但后来摸透了它的插件机制,才发现——其实核心逻辑并不复杂。
这一章,我们就从零开始,把QGC的二次开发环境搭起来。顺便聊聊它的插件系统,最后手撸一个自定义UI面板。
4.1 QGC源码下载与版本选择
先搞定源码。QGC托管在GitHub上,地址是:https://github.com/mavlink/qgroundcontrol。
我个人习惯用 git clone 而不是直接下载ZIP。为什么?因为后续你要切分支、拉更新,用git方便得多。
版本选择建议
QGC的master分支更新很快,但有时候会引入不稳定的API改动。我做项目时一般选 Stable 标签版本,比如 v4.2.0 或 v4.3.0。这些版本经过充分测试,插件接口也相对稳定。
# 克隆最新源码
git clone https://github.com/mavlink/qgroundcontrol.git
# 切换到稳定版本(以v4.3.0为例)
cd qgroundcontrol
git checkout tags/v4.3.0 -b stable_v4.3.0
克隆完成后,你会看到这样的目录结构:
| 目录/文件 | 说明 |
|---|---|
src/ |
核心源码,包括UI、通信、飞行逻辑 |
plugins/ |
插件目录,我们二次开发的主战场 |
qgroundcontrol.pro |
Qt项目文件,编译入口 |
deploy/ |
打包部署脚本 |
4.2 Qt环境配置——别踩这些坑
QGC基于Qt 5.15.x开发。我试过Qt 6,兼容性问题一堆,不建议在生产项目里用。
我的推荐配置:
- Qt版本:5.15.2 LTS
- 编译器:MSVC 2019(Windows)/ GCC 9+(Linux)/ Clang(macOS)
- 额外组件:Qt Charts、Qt Location、Qt Serial Port、Qt WebEngine
注意:Qt 5.15.2 的离线安装包需要商业许可。个人开发可以用在线安装器,或者从 qt.io 下载开源版本。我遇到过有人用5.12编译,结果Qt Charts模块缺失,折腾了一整天。
安装完成后,用Qt Creator打开 qgroundcontrol.pro。第一次加载会有点慢,因为要解析所有依赖。别急,去泡杯咖啡。
编译前,检查一下 .qmake.conf 里的配置:
# 确保这些宏定义正确
CONFIG += qtquickcompiler
DEFINES += QT_NO_DEBUG_OUTPUT
DEFINES += QGC_DISABLE_UVC
然后按 Ctrl+R(或点击运行按钮)。如果一切顺利,你会看到QGC的启动界面。我第一次编译成功时,屏幕上弹出地图的那一刻,说实话,挺有成就感的。
4.3 QGC插件机制——为什么说它是「乐高」
QGC的插件系统,说白了就是一套「热插拔」的模块化架构。你不需要修改核心代码,只需要写一个插件,就能添加新功能。
它的核心接口是 QGCPlugin 类。每个插件都是一个独立的动态库(.dll / .so / .dylib)。
插件生命周期:
- QGC启动时扫描
plugins/目录 - 加载所有有效的
.so/.dll文件 - 调用每个插件的
init()方法 - 插件注册自己的UI面板、菜单项、通信接口
我画了一张图,帮你理解这个流程:
你看,整个流程很清晰。你只需要关注 init() 里注册了什么,其他事情QGC帮你搞定。
4.4 自定义UI面板——手写一个「测绘参数面板」
理论说完了,来点实战。我们写一个测绘专用的参数面板,显示当前测绘任务的覆盖面积、航点数量、预计飞行时间。
第一步:创建插件目录
在 plugins/ 下新建 SurveyPanel/ 文件夹。里面放两个文件:
SurveyPanel.pro—— 插件项目文件SurveyPanel.h/SurveyPanel.cpp—— 插件实现
第二步:编写插件类
// SurveyPanel.h
#pragma once
#include "QGCPlugin.h"
class SurveyPanel : public QGCPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.qgroundcontrol.QGCPlugin" FILE "SurveyPanel.json")
Q_INTERFACES(QGCPlugin)
public:
SurveyPanel(QObject *parent = nullptr);
void init() override;
};
// SurveyPanel.cpp
#include "SurveyPanel.h"
#include "SurveyPanelWidget.h"
SurveyPanel::SurveyPanel(QObject *parent) : QGCPlugin(parent) {}
void SurveyPanel::init()
{
// 注册一个自定义UI面板
registerPanel("测绘参数", [](QWidget *parent) -> QWidget* {
return new SurveyPanelWidget(parent);
});
}
第三步:实现UI界面
新建 SurveyPanelWidget,继承自 QWidget。我用QML写了一个简单的布局:
// SurveyPanelWidget.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
Rectangle {
width: 300
height: 200
color: "#f5f5f5"
Column {
anchors.centerIn: parent
spacing: 10
Text { text: "测绘参数面板"; font.bold: true; font.pixelSize: 16 }
Text { text: "覆盖面积: 12.5 km²" }
Text { text: "航点数量: 48" }
Text { text: "预计飞行时间: 32 min" }
}
}
第四步:注册到QGC菜单
在 init() 里,还可以添加菜单项:
void SurveyPanel::init()
{
registerPanel("测绘参数", ...);
registerMenuAction("工具", "打开测绘面板", this, SLOT(openSurveyPanel()));
}
小技巧:调试插件时,不用每次都重新编译整个QGC。在Qt Creator里,右键点击你的插件项目,选择「构建」即可。QGC支持动态加载插件,你甚至可以在运行中替换 .dll 文件——不过记得先停掉插件线程。
4.5 避坑指南——我踩过的几个坑
做插件开发,有几个地方特别容易翻车。我列出来,你注意一下:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 插件加载失败 | Qt版本不匹配,插件编译用的Qt版本与QGC不同 | 确保插件和QGC使用同一套Qt库编译 |
| UI面板不显示 | 未正确调用 registerPanel() |
检查 init() 是否被调用,打印日志确认 |
崩溃在 Q_PLUGIN_METADATA |
缺少 .json 文件或格式错误 |
确保 SurveyPanel.json 存在且内容正确 |
| 菜单项点击无反应 | 信号槽连接错误或SLOT函数未声明为 public slots |
检查 Q_OBJECT 宏和函数声明 |
我曾经有一次,插件编译通过、加载成功,但面板就是不出来。折腾了两小时,最后发现是 registerPanel 的第二个参数——那个lambda表达式——捕获了错误的 this 指针。嗯,从那以后我写lambda都格外小心。
4.6 小结
这一章我们做了三件事:下载QGC源码、配好Qt环境、写了一个测绘参数面板插件。插件机制是QGC二次开发的灵魂,你想想看,以后不管加什么功能——测绘参数、电池监控、自定义航线——都可以用同样的套路。