QGC 固件升级与硬件适配

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/参数逻辑
  • VehicleMissionManager 等保持 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++:QObjectQ_PROPERTYQ_INVOKABLEQ_ENUMsignals/slots
  • Qt Serial:QSerialPortQSerialPortInfo
  • JSON/XML:QJsonDocument.px4/.apj/manifest)、QXmlStreamReader(参数元数据)
  • Intel Hex:.ihx 解析(SiK Radio)
  • MAVLink:mavlink_message_tMAV_AUTOPILOTMAV_TYPE
  • QML:SetupPageFirmwareUpgradeController 注册为 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() 关键行为:

114:128:src/VehicleSetup/FirmwareUpgradeController.cc 复制代码
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

8:17:src/comm/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:

350:366:src/comm/QGCSerialPortInfo.cc 复制代码
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 格式):

193:232:src/VehicleSetup/Bootloader.cc 复制代码
    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 且 .binPROTO_GET_CRC 与预计算 CRC 比较
  • 完成后 reboot() 发送 PROTO_BOOT

Board ID 常量(与固件包内 board_id 对应):

64:85:src/VehicleSetup/Bootloader.h 复制代码
    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 流程:

  1. 枚举 QGCSerialPortInfo::availablePorts(),过滤 canFlash()
  2. 首次发现 emit foundBoard(UI 等待用户确认/选固件)
  3. 第二次循环(非 firstAttempt)打开串口 → Bootloader::sync()getPX4BoardInfo()INFO_BL_REV / INFO_BOARD_ID / INFO_FLASH_SIZE
  4. SiK Radio 特殊路径:先发 +++ / AT&UPDATE 强制进 Bootloader

完整烧录 _flash()

277:309:src/VehicleSetup/PX4FirmwareUpgradeThread.cc 复制代码
    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 加载流程:

218:264:src/VehicleSetup/FirmwareImage.cc 复制代码
    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

856:868:src/VehicleSetup/FirmwareUpgradeController.cc 复制代码
void FirmwareUpgradeController::_downloadArduPilotManifest(void)
{
    ...
    downloader->download(QStringLiteral("http://firmware.ardupilot.org/manifest.json"));
}

解析字段:board_idmav-typeurlmav-firmware-version-typeUSBIDbootloader_strbrand_name 等,动态构建 _rgManifestFirmwareInfo,供 ChibiOS 板按名称列表选择固件。

(4)SingleFirmwareMode

Custom 构建可通过 QGCOptions::firmwareUpgradeSingleURL() 指定单一 URL,跳过用户选择。

7.1.8 Controller 与 QML 绑定

FirmwareUpgradeController 暴露给 QML 的属性示例:

  • boardPort / boardDescription / pixhawkBoard
  • selectedFirmwareBuildType(Stable/Beta/Dev/Custom)
  • apmFirmwareNames / apmFirmwareUrls(APM manifest 动态列表)
  • progressBar / statusLog(QQuickItem 指针,C++ 直接 setProperty("value", ...)

QML 调用:

qml 复制代码
FirmwareUpgradeController {
    onFlashComplete: ...
}
// Q_INVOKABLE:
controller.startBoardSearch()
controller.flash(AutoPilotStackPX4, StableFirmware, DefaultVehicleFirmware)

7.1.9 扩展烧录流程的开发指南

若需支持新 Bootloader 协议新文件格式

  1. 扩展 FirmwareImage::load() 增加解析分支
  2. Bootloader 中实现新命令集,或新建 XxxBootloader
  3. 修改 PX4FirmwareUpgradeThreadWorker::_findBootloader() 的打开/同步逻辑
  4. FirmwareUpgradeController::_initFirmwareHash() 或 manifest 解析处增加 URL
  5. 更新 USBBoardInfo.jsonBootloader::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:

431:433:src/Vehicle/Vehicle.cc 复制代码
void Vehicle::_commonInit()
{
    _firmwarePlugin = _firmwarePluginManager->firmwarePluginForAutopilot(_firmwareType, _vehicleType);

7.2.2 FirmwarePluginFactory 注册机制

全局静态 Factory 对象在构造时自注册:

32:35:src/FirmwarePlugin/FirmwarePlugin.cc 复制代码
FirmwarePluginFactory::FirmwarePluginFactory(void)
{
    FirmwarePluginFactoryRegister::instance()->registerPluginFactory(this);
}

PX4 Factory:

25:28:src/FirmwarePlugin/PX4/PX4FirmwarePluginFactory.cc 复制代码
QList<MAV_AUTOPILOT> PX4FirmwarePluginFactory::supportedFirmwareTypes(void) const
{
    list.append(MAV_AUTOPILOT_PX4);

APM Factory(按 MAV_TYPE 分派):

37:71:src/FirmwarePlugin/APM/APMFirmwarePluginFactory.cc 复制代码
    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 + PX4AirframeLoader XML
  • 新的 Setup 步骤/外设 → 新建 VehicleComponent 子类

7.2.3 AutoPilotPlugin 与 VehicleComponent

VehicleComponent 抽象接口:

46:64:src/VehicleSetup/VehicleComponent.h 复制代码
    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 对应: APMSensorsComponentAPMAirframeComponentAPMMotorComponentAPMSubFrameComponent(ROV 框架)、APMLightsComponent 等。

7.2.4 新增外设/传感器适配步骤(PX4 为例)

步骤 1:确认参数名与校准命令

PX4 传感器校准通过 MAVLink MAV_CMD_PREFLIGHT_CALIBRATION 或参数读写完成,QGC SensorsComponent 的 QML 触发 C++ 发送命令。新传感器需确认固件暴露的参数名(如 SENS_EN_XXX)和校准流程。

步骤 2:扩展 SensorsComponent

  • 修改 setupCompleteChangedTriggerList() 增加新参数
  • setupComplete() 中检查校准状态参数(如 CAL_ACC0_ID 非零表示已校准)
  • SensorsSetup.qml(或对应 QML)增加 UI 入口

步骤 3:参数元数据(Parameter MetaData)

PX4 使用 XML 描述参数短名、单位、枚举、增量:

29:38:src/FirmwarePlugin/PX4/PX4ParameterMetaData.h 复制代码
    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 系统自动识别;若需特殊控件,扩展 FactMetaDataenumStrings 或自定义 QML FactControl。

步骤 4:机架/Airframe 元数据

PX4AutoPilotPlugin 构造时:

49:52:src/AutoPilotPlugins/PX4/PX4AutoPilotPlugin.cc 复制代码
    _airframeFacts = new PX4AirframeLoader(this, _vehicle->uas(), this);
    PX4AirframeLoader::loadAirframeMetaData();

Airframe XML 定义 SYS_AUTOSTART ID 与机型名称映射。新增 PX4 机架 需在 PX4 固件侧 airframes/ 添加,QGC 通过烧录包或在线同步 XML 自动更新列表。

步骤 5:FactGroup 扩展(遥测显示)

新传感器若通过 MAVLink 消息上报(非参数),在 Vehicle 或专用 XxxFactGroup 中解析消息并暴露 Fact,供 Fly 视图仪表板使用。例如 _distanceSensorFactGroup_battery1FactGroup

7.2.5 APM 传感器与机型差异

APM 的 APMAutoPilotPlugin::vehicleComponents()vehicleType + 参数存在性 动态组装:

  • 直升机:APMHeliComponent
  • 潜水器:APMSubFrameComponentAPMLightsComponent
  • 相机:APMCameraComponent(检测 CAM1_TYPE 等)
  • ESP8266 WiFi:ESP8266Component
79:80:src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc 复制代码
            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 外设类型:

  1. USBBoardInfo.json 增加 boardClass(如 RTK GPS
  2. LinkManager 自动连接逻辑中增加对应处理

7.2.7 Custom 定制示例

custom-example/ 展示最小定制路径:

24:28:custom-example/src/FirmwarePlugin/CustomFirmwarePluginFactory.cc 复制代码
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.h board 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

58:77:src/FirmwarePlugin/FirmwarePluginManager.cc 复制代码
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 等功能。

Vehicle 收消息前:

683:683:src/Vehicle/Vehicle.cc 复制代码
    if (!_firmwarePlugin->adjustIncomingMavlinkMessage(this, &message)) {

返回 false丢弃该消息(用于过滤重复 STATUSTEXT 等)。

Vehicle 发消息前:

2000:2000:src/Vehicle/Vehicle.cc 复制代码
    _firmwarePlugin->adjustOutgoingMavlinkMessage(this, link, &message);

APM 入站适配(典型):

487:514:src/FirmwarePlugin/APM/APMFirmwarePlugin.cc 复制代码
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 兼容要点:

  1. 组件识别 :通过 HEARTBEAT 的 autopilot 字段维护 _ardupilotComponentMap,仅对 ArduPilot 组件做方言转换
  2. STATUSTEXT 严重级别 :旧版 APM 使用非标准 severity 编码,_adjustSeverity() 映射到 MAV_SEVERITY 标准值
  3. PARAM_VALUE :参数名可能带 @ 后缀或索引差异,_handleIncomingParamValue 规范化
  4. RC_CHANNELS vs RC_CHANNELS_RAW:合并处理不同版本消息
  5. 出站 PARAM_SET_handleOutgoingParamSet 处理 APM 参数名/类型差异

PX4 入站适配:

503:516:src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc 复制代码
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 映射表:

25:51:src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc 复制代码
    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)

45:52:src/FirmwarePlugin/FirmwarePlugin.h 复制代码
    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:

54:67:src/FirmwarePlugin/FirmwarePlugin.h 复制代码
    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 二维索引:

50:61:src/MissionManager/MissionCommandTree.cc 复制代码
        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 中 override missionCommandOverrides()

7.3.7 地理围栏 / Rally / Follow Me

  • GeoFenceManager / RallyPointManager:基类 MAVLink 通用,Plugin 提供 supported() 与格式差异
  • FollowMe:PX4 支持 Follow Me 模式字符串;APM 部分版本通过 Plugin 扩展

7.3.8 编译期协议裁剪

96:99:src/VehicleSetup/FirmwareUpgradeController.cc 复制代码
#if !defined(NO_ARDUPILOT_DIALECT)
    _downloadArduPilotManifest();
#endif

NO_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 Custom QGCCorePlugin + 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、ArduPilot manifest.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 示例提供了不修改主干的定制路径。

相关推荐
Agent手记2 小时前
制造业生产流程自动化,Agent需要具备哪些能力?深度拆解2026工业级智能体落地范式与核心架构
大数据·人工智能·ai·架构·自动化
玖釉-2 小时前
下一个排列:从字典序到原地算法的完整推导
数据结构·c++·windows·算法
IronMurphy2 小时前
【算法五十】62. 不同路径
算法
影寂ldy2 小时前
C#一维数组
算法
Yunzenn3 小时前
深度分析字节最新研究cola-DLM 第 07 章:推理流水线逐行拆解 —— 从 prompt 到生成文本
人工智能·驱动开发·深度学习·chatgpt·架构·prompt·github
过期动态3 小时前
【LeetCode 热题 100】移动零
java·数据结构·算法·leetcode·职场和发展·rabbitmq
颖火虫盟主4 小时前
Linux 系统分层架构:从硬件通电到 systemd 进程管理
linux·运维·架构
计算机安禾4 小时前
【算法分析与设计】第10篇:下界理论与NP完全性初步
大数据·人工智能·算法
水木流年追梦5 小时前
大模型入门-大模型分布式训练2
开发语言·分布式·python·算法·正则表达式·prompt