保姆级教程:在QGC 4.1.6地图上自定义显示飞控数据(附完整源码)
深度定制QGC地图界面:从零实现飞控数据可视化实战指南
1. 理解QGC架构与自定义数据显示原理
QGroundControl(QGC)作为开源无人机地面站软件,其核心架构采用Qt框架构建,通过MAVLink协议与飞控通信。地图页面数据显示功能本质上是一个数据流管道系统,涉及以下几个关键组件:
- FactGroup:数据容器基类,管理一组相关数据项(Fact)
- MAVLink消息处理:接收并解析飞控上传的二进制数据
- JSON元数据:定义数据显示的格式、单位等属性
- Qt属性系统:实现数据到UI的自动绑定
在4.1.6版本中,地图页面的数据展示区域采用动态加载机制,开发者可以通过扩展FactGroup体系来添加自定义数据。与简单修改UI不同,这种架构设计保证了:
- 数据与显示分离
- 类型安全校验
- 单位自动转换
- 多语言支持基础
提示:在开始编码前,建议先阅读
Fact.h和FactGroup.h源码,理解基类提供的接口和虚函数作用。
2. 创建自定义FactGroup类
2.1 定义数据结构
在src/Vehicle目录下新建CustomDataFactGroup.h头文件:
#pragma once #include "FactGroup.h" #include "QGCMAVLink.h" class CustomDataFactGroup : public FactGroup { Q_OBJECT public: explicit CustomDataFactGroup(QObject* parent = nullptr); // 暴露给QML的属性 Q_PROPERTY(Fact* voltage READ voltage CONSTANT) Q_PROPERTY(Fact* temperature READ temperature CONSTANT) Q_PROPERTY(Fact* status READ status CONSTANT) Fact* voltage() { return &_voltageFact; } Fact* temperature() { return &_temperatureFact; } Fact* status() { return &_statusFact; } // MAVLink消息处理 void handleMessage(Vehicle* vehicle, mavlink_message_t& message) override; private: static const char* _voltageFactName; static const char* _temperatureFactName; static const char* _statusFactName; Fact _voltageFact; Fact _temperatureFact; Fact _statusFact; };2.2 实现核心逻辑
对应的CustomDataFactGroup.cc实现文件应包含:
#include "CustomDataFactGroup.h" #include "Vehicle.h" // 静态成员初始化 const char* CustomDataFactGroup::_voltageFactName = "customVoltage"; const char* CustomDataFactGroup::_temperatureFactName = "customTemp"; const char* CustomDataFactGroup::_statusFactName = "customStatus"; CustomDataFactGroup::CustomDataFactGroup(QObject* parent) : FactGroup(1000, ":/json/Vehicle/CustomDataFact.json", parent) , _voltageFact(0, _voltageFactName, FactMetaData::valueTypeDouble) , _temperatureFact(0, _temperatureFactName, FactMetaData::valueTypeDouble) , _statusFact(0, _statusFactName, FactMetaData::valueTypeUint32) { _addFact(&_voltageFact, _voltageFactName); _addFact(&_temperatureFact, _temperatureFactName); _addFact(&_statusFact, _statusFactName); // 初始化无效值 _voltageFact.setRawValue(qQNaN()); _temperatureFact.setRawValue(qQNaN()); _statusFact.setRawValue(0); } void CustomDataFactGroup::handleMessage(Vehicle* vehicle, mavlink_message_t& message) { if (message.msgid != MAVLINK_MSG_ID_CUSTOM_DATA) { return; } mavlink_custom_data_t customData; mavlink_msg_custom_data_decode(&message, &customData); voltage()->setRawValue(customData.voltage); temperature()->setRawValue(customData.temperature); status()->setRawValue(customData.status); _setTelemetryAvailable(true); }3. 集成到QGC主系统
3.1 修改项目构建配置
在qgroundcontrol.pro中添加新文件引用:
# 在HEADERS部分添加 HEADERS += \ src/Vehicle/CustomDataFactGroup.h \ ... # 在SOURCES部分添加 SOURCES += \ src/Vehicle/CustomDataFactGroup.cc \ ...3.2 扩展Vehicle类
在Vehicle.h中添加:
// 头文件包含 #include "CustomDataFactGroup.h" // 类成员声明 private: CustomDataFactGroup _customDataFactGroup; public: FactGroup* customDataFactGroup() { return &_customDataFactGroup; } Q_PROPERTY(FactGroup* customData READ customDataFactGroup CONSTANT)在Vehicle.cc中进行初始化:
// 静态成员初始化 const char* Vehicle::_customDataFactGroupName = "customData"; // 构造函数初始化列表 Vehicle::Vehicle(...) : ... , _customDataFactGroup(this) ... { ... _addFactGroup(&_customDataFactGroup, _customDataFactGroupName); }4. 配置元数据与UI绑定
4.1 创建JSON元数据文件
在src/vehicle目录下新建CustomDataFact.json:
{ "version": 1, "fileType": "FactMetaData", "QGC.MetaData.Facts": [ { "name": "customVoltage", "shortDesc": "Custom Voltage", "type": "double", "decimalPlaces": 2, "units": "V" }, { "name": "customTemp", "shortDesc": "Custom Temperature", "type": "double", "decimalPlaces": 1, "units": "°C" }, { "name": "customStatus", "shortDesc": "Custom Status", "type": "uint32" } ] }4.2 添加资源文件引用
在qgroundcontrol.qrc中添加:
<file alias="Vehicle/CustomDataFact.json">src/vehicle/CustomDataFact.json</file>4.3 地图页面数据选择
修改FlightDisplayViewMap.qml,确保自定义数据出现在可选列表中:
// 在数据选择器部分添加 FactPanelController { id: controller factGroup: vehicle.customData }5. 编译与调试技巧
5.1 常见编译错误解决
| 错误类型 | 可能原因 | 解决方案 |
|---|---|---|
| 链接错误 | 未在.pro文件中添加新源文件 | 检查qgroundcontrol.pro配置 |
| 未定义引用 | 头文件包含顺序错误 | 调整#include顺序,确保前置声明正确 |
| QML绑定失败 | 属性名称拼写错误 | 检查Q_PROPERTY和QML中的名称一致性 |
| 数据不显示 | JSON文件路径错误 | 验证.qrc中的资源别名与实际路径 |
5.2 调试MAVLink消息
建议使用mavlink_inspector工具验证自定义消息:
# 在QGC构建目录下 ./debug/mavlink_inspector观察控制台输出,确保:
- 消息ID正确
- 字段解析无误
- 数据更新频率合理
6. 高级定制技巧
6.1 自定义数据显示样式
在FactValueLabel.qml基础上创建新组件:
// CustomDataDisplay.qml import QtQuick 2.0 import QGroundControl.Controls 1.0 FactValueLabel { property color warningColor: "orange" color: { if (fact.value > 30) return warningColor return defaultColor } // 添加单位后缀 text: fact.value.toFixed(fact.decimalPlaces) + " " + fact.units }6.2 性能优化建议
- 数据更新频率:合理设置FactGroup的updateInterval
- 内存管理:注意Qt父子对象关系
- 线程安全:确保MAVLink消息处理不阻塞UI线程
7. 实战案例:温度监控系统
假设我们需要监控无人机电池温度:
- 飞控端:通过自定义MAVLink消息发送温度数据
- 地面站:修改handleMessage处理新消息类型
- UI显示:当温度超过阈值时显示警告图标
关键修改点:
// 在handleMessage中添加 if (temperature()->rawValue().toDouble() > 60.0) { qgcApp()->showMessage("Warning: High temperature detected!"); }对应的JSON配置应增加警告阈值:
{ "name": "customTemp", ... "warning": 60.0 }在QGC地图界面,开发者现在可以:
- 点击数值显示区域
- 选择"Custom Temperature"
- 实时观察温度变化
- 接收超温警告
