QGC 固件升级与硬件适配
7.0 总体架构
QGC 4.0 将「固件烧录」与「运行时硬件/协议适配」分为两条相对独立的链路:
┌─────────────────────────────────────────────────────────────────┐ │ 离线烧录链路(USB 串口) │ │ FirmwareUpgrade.qml → FirmwareUpgradeController │ │ → PX4FirmwareUpgradeThread → Bootloader → QSerialPort │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ 在线运行链路(MAVLink 连接后) │ │ MultiVehicleManager → Vehicle │ │ → FirmwarePluginManager → FirmwarePlugin(PX4/APM/Generic)│ │ → AutoPilotPlugin → VehicleComponent[](传感器/机架/电台…) │ │ → ParameterManager + *ParameterMetaData │ └─────────────────────────────────────────────────────────────────┘设计原则:
FirmwarePlugin:飞行栈(PX4 / ArduPilot)相关的全部差异逻辑应集中在此AutoPilotPlugin+VehicleComponent:Setup 向导、传感器校准、机架选择等 UI/参数逻辑Vehicle与MissionManager等保持MAVLink 通用,差异通过 Plugin 钩子注入
涉及的主要设计模式:
| 模式 | 体现 |
|---|---|
| Plugin 模式 | FirmwarePlugin/AutoPilotPlugin抽象飞行栈差异 |
| Factory + 注册表 | FirmwarePluginFactory构造时自注册到FirmwarePluginFactoryRegister |
| Singleton(懒加载) | 各 Factory 内_pluginInstance单例复用 |
| MVC | FirmwareUpgradeController(C++)+FirmwareUpgrade.qml(View) |
| Worker Thread | PX4FirmwareUpgradeThreadController在独立线程执行串口 I/O |
| Strategy | 按 URI/板型/协议选择不同固件 URL、Bootloader 命令集 |
| Template Method | VehicleComponent定义 setup 流程骨架,子类实现具体 QML/参数 |
| Adapter | adjustIncomingMavlinkMessage修正 APM 与标准 MAVLink 差异 |
| Hash Map 配置 | _rgFMUV5Firmware等 boardId → URL 映射表 |
涉及语法与技术:
- C++:
QObject、Q_PROPERTY、Q_INVOKABLE、Q_ENUM、signals/slots - Qt Serial:
QSerialPort、QSerialPortInfo - JSON/XML:
QJsonDocument(.px4/.apj/manifest)、QXmlStreamReader(参数元数据) - Intel Hex:
.ihx解析(SiK Radio) - MAVLink:
mavlink_message_t、MAV_AUTOPILOT、MAV_TYPE - QML:
SetupPage、FirmwareUpgradeController注册为QGroundControl.Controllers
7.1 飞控固件烧录流程开发
7.1.1 模块与文件索引
| 文件 | 职责 |
|---|---|
VehicleSetup/FirmwareUpgrade.qml | 固件升级 UI(Setup → Firmware) |
VehicleSetup/FirmwareUpgradeController.h/.cc | MVC 控制器:选固件、下载、调度烧录 |
VehicleSetup/PX4FirmwareUpgradeThread.h/.cc | 独立线程:找板、同步 Bootloader、擦除/编程/校验 |
VehicleSetup/Bootloader.h/.cc | PX4 Bootloader 二进制协议实现 |
VehicleSetup/FirmwareImage.h/.cc | 固件镜像解析(.bin/.px4/.apj/.ihx) |
comm/QGCSerialPortInfo.h/.cc | USB VID/PID 识别板型 |
comm/USBBoardInfo.json | 板型 VID/PID 配置表 |
Settings/FirmwareUpgradeSettings.* | APM ChibiOS、机型偏好等 |
7.1.2 用户操作流程(状态机)
Plug USB → startBoardSearch() → 扫描串口 (canFlash) → 发现板 (foundBoard) → UI 显示板名 → 用户选 Stack(PX4/APM) + 版本(Stable/Beta/Dev) + 机型 → flash() → 等待 Bootloader (foundBootloader) → 解析 board_id / flash_size → 查 Hash 得固件 URL → QGCFileDownload 下载 → FirmwareImage::load() 校验 board_id、解压元数据 → ThreadController::flash() → erase → program → verify → reboot → flashComplete → 恢复 LinkManager 连接入口startBoardSearch()关键行为:
void FirmwareUpgradeController::startBoardSearch(void) { LinkManager* linkMgr = qgcApp()->toolbox()->linkManager(); linkMgr->setConnectionsSuspended(tr("Connect not allowed during Firmware Upgrade.")); ... _threadController->startFindBoardLoop(); }烧录期间禁止新建 MAVLink 连接,避免与 Bootloader 串口冲突。
7.1.3 USB 板型识别
QGCSerialPortInfo::getBoardInfo()读取:/json/USBBoardInfo.json:
"boardInfo": [ { "vendorID": 9900, "productID": 16, "boardClass": "Pixhawk", "name": "PX4 FMU V1" }, { "vendorID": 9900, "productID": 17, "boardClass": "Pixhawk", "name": "PX4 FMU V2" }, ... { "vendorID": 9900, "productID": 50, "boardClass": "Pixhawk", "name": "PX4 FMU V5" },匹配逻辑:先VID+PID,失败则description/manufacturer 正则 fallback。
canFlash()仅对三类板返回 true:
bool QGCSerialPortInfo::canFlash(void) const { ... switch(boardType){ case QGCSerialPortInfo::BoardTypePixhawk: case QGCSerialPortInfo::BoardTypePX4Flow: case QGCSerialPortInfo::BoardTypeSiKRadio: return true;新增可烧录硬件的第一步:在USBBoardInfo.json增加 VID/PID 条目,并在Bootloader.h增加boardID*常量(若为新 PX4 板型)。
7.1.4 Bootloader 通信协议
Bootloader类实现 PX4 官方 Bootloader 协议(也用于 3DR Radio 变体):
协议字节(节选):
| 符号 | 值 | 含义 |
|---|---|---|
PROTO_INSYNC | 0x12 | 同步前缀 |
PROTO_EOC | 0x20 | 命令结束 |
PROTO_OK/PROTO_FAILED | 0x10 / 0x11 | 响应 |
PROTO_GET_SYNC | 0x21 | 建立同步 |
PROTO_CHIP_ERASE | 0x23 | 全片擦除 |
PROTO_PROG_MULTI | 0x27 | 多块写入(最大 64 字节,4 字节对齐) |
PROTO_GET_CRC | 0x29 | CRC 校验(Bootloader ≥3) |
PROTO_BOOT | 0x30 | 重启进应用 |
烧录核心循环(.bin格式):
while (bytesSent < imageSize) { ... if (_write(port, PROTO_PROG_MULTI)) { if (_write(port, (uint8_t)bytesToSend)) { if (_write(port, imageBuf, bytesToSend)) { if (_write(port, PROTO_EOC)) { if (_getCommandResponse(port)) { failed = false; } } } } } ... _imageCRC = QGC::crc32((uint8_t *)imageBuf, bytesToSend, _imageCRC); emit updateProgress(bytesSent, imageSize); }校验策略:
- Bootloader ≤2 或
.ihx:逐字节PROTO_READ_MULTI回读比对 - Bootloader ≥3 且
.bin:PROTO_GET_CRC与预计算 CRC 比较 - 完成后
reboot()发送PROTO_BOOT
Board ID 常量(与固件包内board_id对应):
static const int boardIDPX4FMUV2 = 9; static const int boardIDPX4FMUV4 = 11; static const int boardIDPX4FMUV5 = 50; static const int boardIDPX4FMUV3 = 255; // V2 大 Flash 模拟 ID static const int boardIDDurandalV1 = 139; ...7.1.5 独立线程 Worker
PX4FirmwareUpgradeThreadController将耗时串口操作移出 UI 线程:
Controller (主线程) Worker (子线程) startFindBoardLoop ──signal──► _findBoardOnce() flash(image) ──signal──► _flash(): erase→program→verify cancel ──signal──► 关闭端口 ◄── foundBootloader / updateProgress / flashComplete找 Bootloader 流程:
- 枚举
QGCSerialPortInfo::availablePorts(),过滤canFlash() - 首次发现 emit
foundBoard(UI 等待用户确认/选固件) - 第二次循环(非 firstAttempt)打开串口 →
Bootloader::sync()→getPX4BoardInfo()读INFO_BL_REV / INFO_BOARD_ID / INFO_FLASH_SIZE - SiK Radio 特殊路径:先发
+++/AT&UPDATE强制进 Bootloader
完整烧录_flash():
if (_erase()) { if (_bootloader->program(_bootloaderPort, _controller->image())) { ... } if (_bootloader->verify(_bootloaderPort, _controller->image())) { ... } } emit _reboot(); emit flashComplete();7.1.6 固件镜像格式(FirmwareImage)
| 扩展名 | 格式 | 用途 |
|---|---|---|
.bin | 原始二进制 | 直接编程 |
.px4 | JSON 包装(PX4 传统) | 含 base64 镜像 + 压缩 parameter/airframe XML |
.apj | JSON 包装(ArduPilot ChibiOS) | 同.px4结构,MAV_AUTOPILOT=APM |
.ihx | Intel Hex | 3DR SiK Radio |
.px4/.apj加载流程:
QJsonDocument doc = QJsonDocument::fromJson(bytes); ... uint32_t firmwareBoardId = (uint32_t)px4Json.value(_jsonBoardIdKey).toInt(); if (!isCompatible(_boardId, firmwareBoardId)) { emit statusMessage(...); return false; }兼容规则示例:FMUv3(board_id=255)可烧 FMUv2(id=9)固件;AUAV X2.1 同理。
解压后的parameter XML写入缓存并注册到ParameterManager::cacheMetaDataFile(),使烧录后 Setup 界面立即可用最新参数元数据,无需等飞控在线。
7.1.7 固件 URL 来源
(1)PX4 静态 Hash 表
_initFirmwareHash()为每块板维护QHash<FirmwareIdentifier, QString>:
- Key:
AutoPilotStackType+FirmwareBuildType+FirmwareVehicleType - Value:S3 URL,如
http://px4-travis.s3.amazonaws.com/Firmware/stable/px4fmu-v5_default.px4
FMUv2/V3/V4/V5、Durandal、KakuteF7 等各有独立 Hash。
(2)PX4 GitHub Releases 动态版本
_determinePX4StableVersion()拉取https://api.github.com/repos/PX4/Firmware/releases解析 stable/beta 标签。
(3)ArduPilot manifest.json
void FirmwareUpgradeController::_downloadArduPilotManifest(void) { ... downloader->download(QStringLiteral("http://firmware.ardupilot.org/manifest.json")); }解析字段:board_id、mav-type、url、mav-firmware-version-type、USBID、bootloader_str、brand_name等,动态构建_rgManifestFirmwareInfo,供 ChibiOS 板按名称列表选择固件。
(4)SingleFirmwareMode
Custom 构建可通过QGCOptions::firmwareUpgradeSingleURL()指定单一 URL,跳过用户选择。
7.1.8 Controller 与 QML 绑定
FirmwareUpgradeController暴露给 QML 的属性示例:
boardPort/boardDescription/pixhawkBoardselectedFirmwareBuildType(Stable/Beta/Dev/Custom)apmFirmwareNames/apmFirmwareUrls(APM manifest 动态列表)progressBar/statusLog(QQuickItem 指针,C++ 直接setProperty("value", ...))
QML 调用:
FirmwareUpgradeController { onFlashComplete: ... } // Q_INVOKABLE: controller.startBoardSearch() controller.flash(AutoPilotStackPX4, StableFirmware, DefaultVehicleFirmware)7.1.9 扩展烧录流程的开发指南
若需支持新 Bootloader 协议或新文件格式:
- 扩展
FirmwareImage::load()增加解析分支 - 在
Bootloader中实现新命令集,或新建XxxBootloader类 - 修改
PX4FirmwareUpgradeThreadWorker::_findBootloader()的打开/同步逻辑 - 在
FirmwareUpgradeController::_initFirmwareHash()或 manifest 解析处增加 URL - 更新
USBBoardInfo.json与Bootloader::boardID*常量
若仅需支持新 PX4 兼容板(沿用 PX4 Bootloader):通常只需 JSON + Hash URL,无需改协议代码。
7.2 新增机型、外设传感器适配
7.2.1 运行时对象模型
Vehicle 创建 └─ _firmwarePlugin = FirmwarePluginManager::firmwarePluginForAutopilot(type, mavType) └─ _firmwarePlugin->initializeVehicle(this) └─ ParameterManager 就绪后 └─ AutoPilotPlugin::vehicleComponents() └─ AirframeComponent / SensorsComponent / RadioComponent / ... └─ 各 Component 绑定 setup QML + Fact 参数名Vehicle 中获取 Plugin:
void Vehicle::_commonInit() { _firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType);7.2.2 FirmwarePluginFactory 注册机制
全局静态 Factory 对象在构造时自注册:
FirmwarePluginFactory::FirmwarePluginFactory(void) { FirmwarePluginFactoryRegister::instance()->registerPluginFactory(this); }PX4 Factory:
QList<MAV_AUTOPILOT> PX4FirmwarePluginFactory::supportedFirmwareTypes(void) const { list.append(MAV_AUTOPILOT_PX4);APM Factory(按 MAV_TYPE 分派):
switch (vehicleType) { case MAV_TYPE_QUADROTOR: case MAV_TYPE_HELICOPTER: return _arduCopterPluginInstance; case MAV_TYPE_FIXED_WING: case MAV_TYPE_VTOL_QUADROTOR: return _arduPlanePluginInstance; case MAV_TYPE_GROUND_ROVER: return _arduRoverPluginInstance; case MAV_TYPE_SUBMARINE: return _arduSubPluginInstance;新增「机型」在 QGC 语义下通常指:
- 新的MAV_TYPE组合 → 新建或扩展
ArduXxxFirmwarePlugin - 新的机架/airframe→ PX4
AirframeComponent+PX4AirframeLoaderXML - 新的Setup 步骤/外设→ 新建
VehicleComponent子类
7.2.3 AutoPilotPlugin 与 VehicleComponent
VehicleComponent 抽象接口:
virtual QString name(void) const = 0; virtual bool requiresSetup(void) const = 0; virtual bool setupComplete(void) const = 0; virtual QUrl setupSource(void) const = 0; // 完整 Setup 面板 QML virtual QUrl summaryQmlSource(void) const = 0; // 摘要卡片 QML virtual QStringList setupCompleteChangedTriggerList(void) const = 0;PX4 Setup 组件列表示例:
| Component | 职责 | 关键参数 Fact |
|---|---|---|
AirframeComponent | 机架/机型选择 | SYS_AUTOSTART,SYS_AUTOCONFIG |
SensorsComponent | IMU/罗盘/气压计/空速计校准 | CAL_*,SENS_* |
PX4RadioComponent | 遥控校准 | RC_* |
FlightModesComponent | 飞行模式映射 | RC_MAP_* |
PowerComponent | 电池/电源 | BAT_* |
MotorComponent | 电机测试 | PWM_* |
SafetyComponent | 返航/地理围栏 | RTL_*,GF_* |
PX4TuningComponent | PID 调参 | 各控制器增益 |
APM 对应:APMSensorsComponent、APMAirframeComponent、APMMotorComponent、APMSubFrameComponent(ROV 框架)、APMLightsComponent等。
7.2.4 新增外设/传感器适配步骤(PX4 为例)
步骤 1:确认参数名与校准命令
PX4 传感器校准通过 MAVLinkMAV_CMD_PREFLIGHT_CALIBRATION或参数读写完成,QGCSensorsComponent的 QML 触发 C++ 发送命令。新传感器需确认固件暴露的参数名(如SENS_EN_XXX)和校准流程。
步骤 2:扩展 SensorsComponent
- 修改
setupCompleteChangedTriggerList()增加新参数 - 在
setupComplete()中检查校准状态参数(如CAL_ACC0_ID非零表示已校准) - 在
SensorsSetup.qml(或对应 QML)增加 UI 入口
步骤 3:参数元数据(Parameter MetaData)
PX4 使用 XML 描述参数短名、单位、枚举、增量:
void loadParameterFactMetaDataFile (const QString& metaDataFile); FactMetaData* getMetaDataForFact (const QString& name, MAV_TYPE vehicleType); void addMetaDataToFact (Fact* fact, MAV_TYPE vehicleType);元数据来源:
- 飞控在线:
ParameterManager向飞控请求 - 离线/烧录后:
.px4包内parameter_xml解压缓存 - 内置:编译资源
:/FirmwarePlugin/PX4/PX4ParameterFactMetaData.xml
新增参数 UI 显示:在固件 Parameter XML 中加入定义即可被 Fact 系统自动识别;若需特殊控件,扩展FactMetaData的enumStrings或自定义 QML FactControl。
步骤 4:机架/Airframe 元数据
PX4AutoPilotPlugin构造时:
_airframeFacts = new PX4AirframeLoader(this, _vehicle->uas(), this); PX4AirframeLoader::loadAirframeMetaData();Airframe XML 定义SYS_AUTOSTARTID 与机型名称映射。新增 PX4 机架需在 PX4 固件侧airframes/添加,QGC 通过烧录包或在线同步 XML 自动更新列表。
步骤 5:FactGroup 扩展(遥测显示)
新传感器若通过 MAVLink 消息上报(非参数),在Vehicle或专用XxxFactGroup中解析消息并暴露Fact,供 Fly 视图仪表板使用。例如_distanceSensorFactGroup、_battery1FactGroup。
7.2.5 APM 传感器与机型差异
APM 的APMAutoPilotPlugin::vehicleComponents()按vehicleType + 参数存在性动态组装:
- 直升机:
APMHeliComponent - 潜水器:
APMSubFrameComponent、APMLightsComponent - 相机:
APMCameraComponent(检测CAM1_TYPE等) - ESP8266 WiFi:
ESP8266Component
if ( _vehicle->supportsRadio() ) { _radioComponent = new APMRadioComponent(_vehicle, this);supportsRadio()来自FirmwarePlugin::supportsRadio()虚函数,可按机型关闭 RC Setup。
7.2.6 USB 外设自动连接
LinkManager扫描串口时调用QGCSerialPortInfo::getBoardInfo(),对 RTK GPS、SiK Radio 等可自动创建连接。新增 USB 外设类型:
- 在
USBBoardInfo.json增加boardClass(如RTK GPS) - 在
LinkManager自动连接逻辑中增加对应处理
7.2.7 Custom 定制示例
custom-example/展示最小定制路径:
QList<MAV_AUTOPILOT> CustomFirmwarePluginFactory::supportedFirmwareTypes() const { list.append(MAV_AUTOPILOT_PX4);继承PX4FirmwarePlugin/PX4AutoPilotPlugin,Override 飞行模式、任务命令、Setup 组件列表,无需 fork 整个 QGC。
7.2.8 新增机型适配检查清单
| 层次 | 修改位置 | 说明 |
|---|---|---|
| USB 识别 | USBBoardInfo.json | VID/PID → 板名 |
| 烧录 | Bootloader.hboard ID + Firmware Hash | 固件 URL |
| 协议 | XxxFirmwarePlugin | 飞行模式、GUIDED、任务 |
| Setup | VehicleComponent+ QML | 校准/配置 UI |
| 参数 | PX4/APM Parameter XML | 名称/单位/枚举 |
| 机架 | Airframe XML | SYS_AUTOSTART |
| 任务 | MavCmdInfo*.json | 航线命令 UI |
| 连接 | LinkManager | 自动连接规则 |
7.3 不同飞控协议兼容改造
QGC 4.0 核心 MAVLink 处理保持栈无关;协议差异通过 FirmwarePlugin 钩子消化。
7.3.1 插件选择与 Fallback
FirmwarePlugin* FirmwarePluginManager::firmwarePluginForAutopilot(MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType) { FirmwarePluginFactory* factory = _findPluginFactory(firmwareType); if (factory) { plugin = factory->firmwarePluginForAutopilot(firmwareType, vehicleType); } if (!plugin) { if (!_genericFirmwarePlugin) { _genericFirmwarePlugin = new FirmwarePlugin; } plugin = _genericFirmwarePlugin; } return plugin; }未知 Autopilot 回退Generic FirmwarePlugin,提供基础 MAVLink 能力,无 PX4/APM 特有 Guided 等功能。
7.3.2 MAVLink 消息适配钩子
Vehicle 收消息前:
if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) {返回false则丢弃该消息(用于过滤重复 STATUSTEXT 等)。
Vehicle 发消息前:
_firmwarePlugin->adjustOutgoingMavlinkMessage(this, link, &message);APM 入站适配(典型):
bool APMFirmwarePlugin::adjustIncomingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message) { if (message->msgid == MAVLINK_MSG_ID_HEARTBEAT) { _handleIncomingHeartbeat(vehicle, message); return true; } if (_ardupilotComponentMap[vehicle->id()][message->compid]) { switch (message->msgid) { case MAVLINK_MSG_ID_PARAM_VALUE: _handleIncomingParamValue(vehicle, message); break; case MAVLINK_MSG_ID_STATUSTEXT: return _handleIncomingStatusText(vehicle, message, false); ... } } return true; }APM 兼容要点:
- 组件识别:通过 HEARTBEAT 的
autopilot字段维护_ardupilotComponentMap,仅对 ArduPilot 组件做方言转换 - STATUSTEXT 严重级别:旧版 APM 使用非标准 severity 编码,
_adjustSeverity()映射到 MAV_SEVERITY 标准值 - PARAM_VALUE:参数名可能带
@后缀或索引差异,_handleIncomingParamValue规范化 - RC_CHANNELS vs RC_CHANNELS_RAW:合并处理不同版本消息
- 出站 PARAM_SET:
_handleOutgoingParamSet处理 APM 参数名/类型差异
PX4 入站适配:
bool PX4FirmwarePlugin::adjustIncomingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message) { if (message->compid == MAV_COMP_ID_UDP_BRIDGE) { return true; } switch (message->msgid) { case MAVLINK_MSG_ID_AUTOPILOT_VERSION: _handleAutopilotVersion(vehicle, message); break; } return true; }主要处理版本过低警告、AUTOPILOT_VERSION解析;PX4 较贴近标准 MAVLink,适配量小于 APM。
7.3.3 飞行模式映射
各栈实现flightMode(base_mode, custom_mode)与setFlightMode(name, &base, &custom)。
APM Copter使用APMCopterMode枚举 +APMCustomMode映射表:
setEnumToStringMapping({ { STABILIZE, "Stabilize"}, { ACRO, "Acro"}, { GUIDED, "Guided"}, { LOITER, "Loiter"}, { RTL, "RTL"}, ... });PX4使用union px4_custom_mode位域解析custom_mode,支持MAIN_MODE/SUB_MODE。
Fly 视图下拉列表来自FirmwarePlugin::flightModes(vehicle),各子类按固件能力返回不同列表。
7.3.4 能力位(Capabilities)
typedef enum { SetFlightModeCapability = 1 << 0, PauseVehicleCapability = 1 << 1, GuidedModeCapability = 1 << 2, OrbitModeCapability = 1 << 3, TakeoffVehicleCapability = 1 << 4, ROIModeCapability = 1 << 5, } FirmwareCapabilities;UI 与 Joystick 通过isCapable(vehicle, GuidedModeCapability)决定是否显示 Guided Takeoff、Orbit 等按钮,避免对不支持栈发送无效命令。
7.3.5 参数名版本 remap(APM 重点)
APM 跨版本常重命名参数。FirmwarePlugin定义三层 Map:
typedef QMap<QString, QString> remapParamNameMap_t; typedef QMap<int, remapParamNameMap_t> remapParamNameMinorVersionRemapMap_t; typedef QMap<int, remapParamNameMinorVersionRemapMap_t> remapParamNameMajorVersionMap_t;ArduCopterFirmwarePlugin::paramNameRemapMajorVersionMap()在静态初始化中填充,如 3.5 版本"CHUKE_" → "CHUTE_"类映射。ParameterManager请求参数前查表转换,保证 QGC 内部统一使用新名称。
7.3.6 任务命令树(MissionCommandTree)
任务编辑器命令列表按MAV_AUTOPILOT × MAV_TYPE二维索引:
for (MAV_AUTOPILOT firmwareType: _toolbox->firmwarePluginManager()->supportedFirmwareTypes()) { FirmwarePlugin* plugin = ...->firmwarePluginForAutopilot(firmwareType, MAV_TYPE_QUADROTOR); for(MAV_TYPE vehicleType: vehicleTypes) { QString overrideFile = plugin->missionCommandOverrides(vehicleType); if (!overrideFile.isEmpty()) { _staticCommandTree[firmwareType][vehicleType] = new MissionCommandList(overrideFile, ...); } } }各 Plugin 返回 JSON 路径如:/json/MavCmdInfoMultiRotor.json,定义命令显示名、参数 Fact 元数据、是否支持。
新增协议命令 UI:在对应MavCmdInfo*.json增加条目,或在 Custom Plugin 中 overridemissionCommandOverrides()。
7.3.7 地理围栏 / Rally / Follow Me
GeoFenceManager/RallyPointManager:基类 MAVLink 通用,Plugin 提供supported()与格式差异FollowMe:PX4 支持Follow Me模式字符串;APM 部分版本通过 Plugin 扩展
7.3.8 编译期协议裁剪
#if !defined(NO_ARDUPILOT_DIALECT) _downloadArduPilotManifest(); #endifNO_ARDUPILOT_DIALECT宏可构建纯 PX4 版本,移除 APM manifest、APM 固件 URL 等,减小体积。
7.3.9 协议兼容改造实践指南
| 场景 | 推荐改造点 |
|---|---|
| 新 MAVLink 消息字段与标准不符 | adjustIncomingMavlinkMessage解码后重写 |
| 发送命令被拒 | adjustOutgoingMavlinkMessage或 Plugin 专用 send 方法 |
| 新飞行模式 | 子类flightModes+setFlightMode+ custom_mode 位定义 |
| 参数 rename | paramNameRemapMajorVersionMap |
| 新任务命令 | MavCmdInfo*.json+ MissionController 验证逻辑 |
| 完全新飞控栈 | 新建XxxFirmwarePluginFactory+XxxAutoPilotPlugin+ 全局静态 Factory 实例 |
| 仅改品牌/隐藏 APM | CustomQGCCorePlugin+CustomFirmwarePlugin继承 PX4 |
7.4 FirmwareUpgradeSettings 配置
| Fact | 作用 |
|---|---|
apmChibiOS | 优先 ChibiOS vs NuttX 固件路径 |
apmVehicleType | 默认 APM 机型过滤(Copter/Plane/Rover/Sub) |
变更时触发_buildAPMFirmwareNames()刷新 manifest 匹配列表。
7.5 关键类方法速查
| 类 | 方法 | 作用 |
|---|---|---|
FirmwareUpgradeController | startBoardSearch()/flash() | UI 入口 |
FirmwareUpgradeController | _initFirmwareHash() | PX4 URL 表 |
FirmwareUpgradeController | _downloadArduPilotManifest() | APM 动态固件 |
PX4FirmwareUpgradeThreadWorker | _findBootloader() | 同步 Bootloader |
PX4FirmwareUpgradeThreadWorker | _flash() | 擦写校验 |
Bootloader | sync/erase/program/verify | 协议实现 |
FirmwareImage | load()/isCompatible() | 镜像解析 |
QGCSerialPortInfo | canFlash()/getBoardInfo() | USB 识别 |
FirmwarePluginManager | firmwarePluginForAutopilot() | 运行时选栈 |
FirmwarePlugin | adjustIncomingMavlinkMessage() | 协议适配 |
AutoPilotPlugin | vehicleComponents() | Setup 组件 |
VehicleComponent | setupComplete() | 校准完成判定 |
MissionCommandTree | getMissionCommands() | 任务命令 UI |
7.6 本章小结
QGroundControl 4.0 的固件升级子系统采用Controller + Worker Thread + Bootloader 协议三层架构,通过 USB VID/PID(USBBoardInfo.json)识别 Pixhawk/PX4Flow/SiK 设备,经 PX4 Bootloader 二进制协议完成擦除、分块编程与 CRC/回读校验。固件来源包括 PX4 S3 静态表、GitHub Releases、ArduPilotmanifest.json动态清单;.px4/.apj包同时携带参数与机架元数据,烧录后即可更新 Setup 界面。
机型与外设适配依托FirmwarePluginFactory → FirmwarePlugin → AutoPilotPlugin → VehicleComponent插件链,参数/display 由 Fact 系统 + Parameter XML 驱动,传感器校准/机架选择通过 QML Setup 面板与 MAVLink 命令完成。新增硬件通常需同步修改 JSON 板型表、Parameter/Airframe 元数据及对应 Component。
协议兼容遵循「Vehicle 通用、Plugin 消化差异」原则,APM 侧通过 heartbeat 组件映射、STATUSTEXT 严重级别修正、参数 remap 等机制对齐 MAVLink 标准;PX4 侧适配较轻。任务命令、飞行模式、Guided 能力均通过 Plugin 虚函数与 JSON 配置扩展,Custom 示例提供了不修改主干的定制路径。