QGroundControl 固件插件架构深度解析:FirmwarePlugin、AutoPilotPlugin 与 QGCCorePlugin 扩展机制

原创2026-10-02 19:24:31674 阅读
文章标签:无人机智能硬件

QGroundControl 固件插件架构深度解析:FirmwarePlugin、AutoPilotPlugin 与 QGCCorePlugin 扩展机制

导读

本文以 QGroundControl(QGC)开发者文档 Plugin Architecture 为骨架,深入剖析这套跨平台地面站如何通过插件架构隔离各飞控固件(PX4、ArduPilot 等)之间的实现差异,避免核心代码退化为遍布 if/then/else 的固件分支。读完本文,你将掌握 FirmwarePlugin、AutoPilotPlugin、QGCCorePlugin 三大插件的职责边界与关键接口,理解工厂注册与单例管理机制,并能从源码层面看清如何为一种新固件或一套自定义商业产品接入 QGC。

一、为什么 QGC 需要插件架构

MAVLink 协议虽然为无人机通信定义了标准报文格式,但协议中大量细节留给固件开发者自行解释:

  • 同一任务在不同固件上的实现路径不同:例如切换到某个飞行模式、执行 RTL 返航,不同固件发出的报文序列与模式编码并不一致;
  • 各固件只实现 MAVLink 命令集的子集:QGC 需要针对每个固件判断哪些 MAV_CMD 可用;
  • 配置与参数集完全不在协议覆盖范围内:所有与飞机装机、参数设置相关的代码天然固件相关,任何引用具体参数名的代码也固件相关。

如果地面站把所有固件的差异逻辑堆进一套代码里,最终必然退化成"根据当前固件散落各处的 if/then/else"式的泥潭。QGC 的选择是用插件架构把固件特有代码与固件无关的通用代码彻底隔离。

从源码结构看,这一思路贯穿整个仓库:通用逻辑(MAVLink 收发、任务规划、航图渲染等)位于 src/Vehicle、src/Comms 等目录,而固件相关内容被收敛到 src/FirmwarePlugin 与 src/AutoPilotPlugins 两个目录中,各自只负责"这一个固件栈特有"的实现。

三大插件的职责划分

插件 职责 核心头文件
FirmwarePlugin 为 MAVLink 中"未被标准化"的部分提供统一接口,是唯一的固件栈专用代码存放地 src/FirmwarePlugin/FirmwarePlugin.h
AutoPilotPlugin 为"Vehicle Setup(飞机设置)"提供用户界面 src/AutoPilotPlugins/AutoPilotPlugin.h
QGCCorePlugin 以标准接口暴露 QGC 应用本身(与飞机无关)的功能,供自定义构建裁剪功能集 src/API/QGCCorePlugin.h

这套架构同样服务于自定义构建(Custom Build):厂商可以在标准 QGC 之上做更深度的定制,这正是 QGCCorePlugin 存在的主要原因(详见第五节)。

二、FirmwarePlugin:固件特有逻辑的统一接口

FirmwarePlugin 是所有固件栈插件的基类。其类注释明确写明了设计约束(见 FirmwarePlugin.h):

这是 QGroundControl 中唯一允许存放固件栈特定代码的位置,其余源码对通用 mavlink 实现保持通用。基类实现支持通用 mavlink 固件,覆写基类虚函数即可创建自己的固件插件。

基类默认返回的"通用实现"覆盖 MAVLink 规范中的标准行为,各固件插件只需覆写与自身有差异的部分,这极大降低了接入新固件的成本。以下按功能域展开核心接口。

2.1 能力声明:isCapable 与能力位掩码

固件差异首先体现在"能做什么"上。基类用一组位掩码描述可选能力(见 FirmwarePlugin.h):

enum FirmwareCapabilities {
    SetFlightModeCapability =              1 << 0, ///< 支持 setFlightMode
    PauseVehicleCapability =               1 << 1, ///< 支持当前位置悬停/暂停
    GuidedModeCapability =                 1 << 2, ///< 支持引导模式指令
    OrbitModeCapability =                  1 << 3, ///< 支持环绕模式
    TakeoffVehicleCapability =             1 << 4, ///< 支持起飞
    ROIModeCapability =                    1 << 5, ///< 支持兴趣点 ROI(Fly 引导与 Plan 创建)
    ChangeHeadingCapability =              1 << 6, ///< 支持原地改变航向
    GuidedTakeoffCapability =              1 << 7, ///< 支持引导起飞
    VTOLMulticopterTakeoffCapability =     1 << 8, ///< VTOL 在保持多旋翼模式下支持 MAV_CMD_NAV_TAKEOFF
};

任何界面层调用前都应通过 isCapable(vehicle, capabilities) 询问固件能力,而不是自行假设。例如 APM 系列在 APMFirmwarePlugin.h 中覆写了 isCapable,并定义了自身的模式编码常量 APMCustomMode(见 APMFirmwarePlugin.h):

enum Mode : uint32_t {
    AUTO      = 3,
    GUIDED    = 4,
    RTL       = 6,
    SMART_RTL = 21
};

这类"自定义模式数值"正是各固件实现差异的典型代表——同一个概念(RTL 返航)在不同固件里是不同数值,QGC 通过插件把这些数值映射成统一的人类可读名称。

2.2 飞行模式:字符串与 base/custom mode 的双向映射

飞行模式是固件差异最密集的区域。基类提供一组接口(FirmwarePlugin.h):

  • flightModes(vehicle):返回 Fly 视图下拉框可用的模式列表;
  • flightMode(base_mode, custom_mode):把 HEARTBEAT 报文中的 base_mode/custom_mode 翻译为可读、可语音播报的模式名;
  • setFlightMode(flightMode, &base_mode, &custom_mode):反向把模式名编码回 SET_MODE 报文;
  • 一系列命名模式查询:pauseFlightMode()、missionFlightMode()、rtlFlightMode()、landFlightMode()、takeOffFlightMode()、stabilizedFlightMode()、gotoFlightMode()、followFlightMode() 等,它们为上层 UI(RTL 按钮、起飞按钮、Follow Me 等)提供"这个固件的返航模式叫什么"的答案。

APM 插件直接在基类上覆写这些方法,并把常见模式名固化为常量(见 APMFirmwarePlugin.h):

const QString _guidedFlightMode  = tr("Guided");
const QString _rtlFlightMode     = tr("RTL");
const QString _smartRtlFlightMode= tr("Smart RTL");
const QString _autoFlightMode    = tr("Auto");

此外基类通过 _updateFlightModeList() 与 _addNewFlightMode()(FirmwarePlugin.h)维护内部 FlightModeList 与 FlightModeCustomModeMap 映射表,FirmwareFlightMode 结构体(FirmwarePlugin.h)承载模式名、标准模式、自定义模式、是否可被设置、是否高级模式、适用机型等完整信息。

2.3 引导模式指令(Guided Mode Commands)

引导模式是一系列"指挥飞机去某处/做某事"的接口,基类在 FirmwarePlugin.h 中声明了完整集合:

  • setGuidedMode(vehicle, guidedMode):进入/退出引导模式;
  • pauseVehicle(vehicle):原地悬停(支持引导模式的固件进入引导模式,否则回 Loiter);
  • guidedModeRTL(vehicle, smartRTL) / guidedModeLand(vehicle) / guidedModeTakeoff(vehicle, takeoffAltRel);
  • guidedModeGotoLocation(vehicle, gotoCoord, forwardFlightLoiterRadius):飞往指定坐标(高度忽略,沿用当前高度);
  • guidedModeChangeHeading(vehicle, headingCoord)、guidedModeROI(vehicle, roiCenterCoord, relativeAltitudeMeters);
  • guidedModeChangeAltitude(vehicle, altitudeChange, pauseVehicle)、guidedModeChangeGroundSpeedMetersSecond(...)、guidedModeChangeEquivalentAirspeedMetersSecond(...);
  • minimumTakeoffAltitudeMeters() 默认返回 3.048(即 10 英尺),maximumHorizontalSpeedMultirotorMetersSecond() 等速度限制接口默认返回 NAN 表示"未获取到"。

基类还提供带校验重试的保护性实现供子类复用:_armVehicleAndValidate()、_setFlightModeAndValidate()、_sendROICommand()(FirmwarePlugin.h),APM 插件即通过这些组合出带校验的引导指令流程。

2.4 MAVLink 消息钩子:adjustIncoming/adjustOutgoing

固件对 MAVLink 规范的差异化解释,最终要在报文层面兜底。FirmwarePlugin 提供双向消息钩子,让"通用代码保持 mavlink 通用"成为可能(FirmwarePlugin.h):

/// 任何 mavlink 消息被 Vehicle 处理之前调用,插件可调整消息特征
virtual bool adjustIncomingMavlinkMessage(Vehicle* vehicle, mavlink_message_t* message) { return true; }

/// 任何 mavlink 消息发送给飞机之前调用(必须线程安全)
virtual void adjustOutgoingMavlinkMessageThreadSafe(Vehicle* vehicle, LinkInterface* outgoingLink, mavlink_message_t* message) {}

adjustIncomingMavlinkMessage 返回 false 可丢弃该消息。以 APM 为例,插件在 APMFirmwarePlugin.h 覆写了这两个方法,内部处理心跳、状态文本、参数值、RC 通道等报文的固件差异(见私有方法 _handleIncomingHeartbeat、_handleIncomingStatusText、_handleIncomingParamValue 等,APMFirmwarePlugin.h)。

2.5 任务命令差异:supportedMissionCommands 与命令覆盖文件

各固件实现不同的 MAVLink 命令子集,插件通过两个接口收敛差异(FirmwarePlugin.h):

  • supportedMissionCommands(vehicleClass):返回支持的任务命令列表,空列表表示全部支持;
  • missionCommandOverrides(vehicleClass):返回指定机型对应的任务命令 JSON 覆盖文件名,VehicleClassGeneric 表示请求适用于所有机型的覆盖。

仓库中实际存在这些覆盖文件,例如 PX4 与 APM 各有一套按机型拆分的 JSON(均位于对应插件目录下):

src/FirmwarePlugin/PX4/PX4-MavCmdInfoCommon.json
src/FirmwarePlugin/PX4/PX4-MavCmdInfoFixedWing.json
src/FirmwarePlugin/PX4/PX4-MavCmdInfoMultiRotor.json
src/FirmwarePlugin/PX4/PX4-MavCmdInfoRover.json
src/FirmwarePlugin/PX4/PX4-MavCmdInfoSub.json
src/FirmwarePlugin/PX4/PX4-MavCmdInfoVTOL.json
src/FirmwarePlugin/APM/APM-MavCmdInfoCommon.json
...(APM 目录下同构的 6 个文件)

这些 JSON 与通用 UI 信息文件(src/MissionManager/MavCmdInfoCommon.json 等)配合,构成"同一命令在不同固件上的参数含义与 UI 呈现差异"的声明式描述。

2.6 参数名重映射:应对跨版本改名

固件在版本迭代中会重命名参数,QGC 为此在 FirmwarePlugin 中内建了参数重映射机制(FirmwarePlugin.h):

  • remapParamNameMap_t:new_name -> old_name 单版本映射;
  • remapParamNameMinorVersionRemapMap_t:按固件 minor 版本索引的重映射表;
  • remapParamNameMajorVersionMap_t:按固件 major 版本索引的完整结构;
  • 对外接口 paramNameRemapMajorVersionMap() 与 remapParamNameHigestMinorVersionNumber(majorVersion)。

按头文件注释,调用方始终使用最新参数名,ParameterManager::_remapParamNameToVersion() 会从已知最高 minor 版本向飞机实际固件版本反向遍历重映射表逐步换算;若需绕过重映射(例如要按具体新旧名字判断是否存在以决定单位换算),可在参数名前加 noremap. 前缀。以注释中的例子说明:remapV4_0["TUNE_MIN"] = "TUNE_LOW" 表示 TUNE_LOW 在 4.0 版本改名为 TUNE_MIN。

2.7 其他常用覆写点

基类还包含大量实用虚函数,可按需覆写:

  • 参数元数据与离线编辑:loadParameterMetaData()、offlineEditingParamFile()、adjustMetaData()、_internalParameterMetaDataFile();APM 目录下的 Copter.OfflineEditing.params、Plane.OfflineEditing.params、Rover.OfflineEditing.params、Sub.OfflineEditing.params,以及 PX4 的 V1.4.OfflineEditing.params、PX4ParameterFactMetaData.json 即对应的离线参数/元数据资源;
  • 家点与任务序号:sendHomePositionToVehicle()——通用栈默认 false(不发送第一个家点项并调整序号,这是 mavlink 规范默认行为),而 APM 覆写为 true(见 APMFirmwarePlugin.h);
  • 遥测与界面元素:toolIndicators()、vehicleImageOpaque()(默认 /qmlimages/vehicleArrowOpaque.svg)、expandedToolbarIndicatorSource();
  • 相机与云台:createCameraManager()、createCameraControl()、hasGimbal();
  • 电量消耗估算:batteryConsumptionData()(输出 mAh、悬停电流、巡航电流);
  • 版本检查:checkIfIsLatestStable()、versionCompare()、_getLatestVersionFileUrl()、_versionRegex()(APM 用正则 " V(<a href="https://link.gitcode.com/i/75470a9b0b681bf4ffe0469f2e3c2d7a" target="_blank">0-9,\\.]*)$" 提取固件版本号,见 [APMFirmwarePlugin.h);
  • 遥控器与摇杆:defaultJoystickTXMode()(默认 2)、supportsRadio()、supportsJSButton()、supportsThrottleModeCenterZero()、supportsNegativeThrust();
  • 高级机型判定:multiRotorCoaxialMotors()、multiRotorXConfig()。

此外 FirmwarePluginInstanceData(FirmwarePlugin.h)以 CommandSupportedResult(SUPPORTED/UNSUPPORTED/UNKNOWN)为每条 MAV_CMD 缓存"该固件是否支持"的探测结果,避免对自动驾驶仪进行多余往返探测——APM 的实现见 APMFirmwarePlugin.h。

三、插件工厂与注册机制:固件插件如何被找到

FirmwarePlugin 是接口,真正决定"当前飞机用哪个插件"的是工厂 + 注册表 + 单例管理器三层机制。

3.1 FirmwarePluginFactory:按固件/机型产出插件

FirmwarePluginFactory 定义了两个纯虚函数(src/FirmwarePlugin/FirmwarePluginFactory.h):

virtual FirmwarePlugin *firmwarePluginForAutopilot(MAV_AUTOPILOT autopilotType, MAV_TYPE vehicleType) = 0;
virtual QList<QGCMAVLink::FirmwareClass_t> supportedFirmwareClasses() const = 0;

每个固件栈提供一个工厂实现。以 PX4 为例(src/FirmwarePlugin/PX4/PX4FirmwarePluginFactory.cc),工厂声明只支持 FirmwareClassPX4,并在收到 MAV_AUTOPILOT_PX4 类型请求时惰性创建单例插件实例:

FirmwarePlugin* PX4FirmwarePluginFactory::firmwarePluginForAutopilot(MAV_AUTOPILOT autopilotType, MAV_TYPE /*vehicleType*/)
{
    if (autopilotType == MAV_AUTOPILOT_PX4) {
        if (!_pluginInstance) {
            _pluginInstance = new PX4FirmwarePlugin();
        }
        return _pluginInstance;
    }
    return nullptr;
}

APM 工厂则更进一步,为不同机型分别维护单例实例(_arduCopterPluginInstance、_arduPlanePluginInstance、_arduRoverPluginInstance、_arduSubPluginInstance,见 src/FirmwarePlugin/APM/APMFirmwarePluginFactory.h),对应 ArduCopter / ArduPlane / ArduRover / ArduSub 四类插件。

FirmwarePluginFactoryRegister(src/FirmwarePlugin/FirmwarePluginFactory.h)是全局注册表,各工厂通过 registerPluginFactory() 在启动阶段登记自己。

3.2 FirmwarePluginManager:统一查询入口与通用回退

FirmwarePluginManager 是全局单例(Q_GLOBAL_STATIC,见 src/FirmwarePlugin/FirmwarePluginManager.cc),对外提供:

  • supportedFirmwareClasses():汇总所有已注册工厂支持的固件类,并总是追加 FirmwareClassGeneric;
  • singleFirmwareSupport() / singleVehicleSupport():判断"只支持单一固件 / 单一固件单一机型",自定义产品据此裁剪 UI;
  • firmwarePluginForAutopilot(MAV_AUTOPILOT, MAV_TYPE):核心分发逻辑(FirmwarePluginManager.cc):
FirmwarePlugin *FirmwarePluginManager::firmwarePluginForAutopilot(MAV_AUTOPILOT firmwareType, MAV_TYPE vehicleType)
{
    FirmwarePluginFactory *const factory = _findPluginFactory(firmwareType);
    FirmwarePlugin *plugin = nullptr;
    if (factory) {
        plugin = factory->firmwarePluginForAutopilot(firmwareType, vehicleType);
    }
    if (!plugin) {
        if (!_genericFirmwarePlugin) {
            _genericFirmwarePlugin = new FirmwarePlugin(this);   // 通用回退
        }
        plugin = _genericFirmwarePlugin;
    }
    return plugin;
}

关键设计:任何未知/未登记的固件类型都会回退到基类 FirmwarePlugin 的通用实现(支持 mavlink 通用固件),保证新固件接入时系统"至少可用",而不是崩溃或拒绝连接。_findPluginFactory 遍历注册表按 supportedFirmwareClasses() 匹配工厂(FirmwarePluginManager.cc)。

整体调用链可归纳为:

飞机 HEARTBEAT(autopilot type)
  → FirmwarePluginManager::firmwarePluginForAutopilot()
    → FirmwarePluginFactoryRegister 注册表
      → 对应 FirmwarePluginFactory::firmwarePluginForAutopilot()
        → 返回(缓存)单例 FirmwarePlugin 子类
          → 找不到则回退基类 FirmwarePlugin 通用实现

四、AutoPilotPlugin:Vehicle Setup 界面的固件差异层

FirmwarePlugin 解决"与飞机通信"的固件差异,而"飞机装机设置(Vehicle Setup)"的界面差异由 AutoPilotPlugin 承担。它是抽象基类(src/AutoPilotPlugins/AutoPilotPlugin.h),类注释同样声明"这是 AutoPilot 特有代码唯一允许存在的位置"。

其核心概念是 VehicleComponent(设置页上的一个个组件,如传感器校准、电源、遥控器、飞行模式、安全、摇杆、电调等),对外暴露两个属性:

Q_PROPERTY(QVariantList vehicleComponents ...)  ///< VehicleComponent 对象列表
Q_PROPERTY(bool setupComplete ...)              ///< false: 尚有组件需要设置

关键接口(src/AutoPilotPlugins/AutoPilotPlugin.h):

  • KnownVehicleComponent 枚举:KnownRadioVehicleComponent(遥控器)、KnownFlightModesVehicleComponent(飞行模式)、KnownSensorsVehicleComponent(传感器)、KnownSafetyVehicleComponent(安全)、KnownPowerVehicleComponent(电源)、KnownJoystickVehicleComponent(摇杆)、KnownESCVehicleComponent(电调)、UnknownVehicleComponent(固件自定义组件);
  • vehicleComponents()(纯虚):返回该固件可用的组件列表;
  • prerequisiteSetup(component):返回必须先完成设置的前置组件名,用于驱动"校准完成才能进行下一步"的向导流程;
  • knownVehicleComponentAvailable() / findKnownVehicleComponent():查询与定位已知组件;
  • parametersReadyPreChecks():参数首次就绪时的预检查钩子,覆写必须调用基类。

setupComplete 由 _recalcSetupComplete() 槽位根据各组件状态自动重算(src/AutoPilotPlugins/AutoPilotPlugin.h)。具体固件的实现分散在 src/AutoPilotPlugins/APM、src/AutoPilotPlugins/PX4 目录中,每个目录都包含对应的设置组件类与 QML 界面(例如 PX4 目录下含 38 个 qml、16 个 cc/h 文件),同时可复用 src/AutoPilotPlugins/Common 中的通用组件。

五、QGCCorePlugin:应用级扩展点与自定义构建

前两个插件解决"固件差异",QGCCorePlugin 解决"应用整体如何被定制"——它暴露与飞机无关的 QGC 自身功能,供自定义构建调整功能集。头文件注释(src/API/QGCCorePlugin.h)明确指出:它是针对"需要整体修改 QGC"的自定义构建的扩展点,按固件类型变化的行为应放 FirmwarePlugin,而它负责 UI 页面、航图项、工具栏指示器、视频管线、任务文件钩子等应用级行为。

5.1 主要扩展接口

  • 页面与设置:analyzePages()(Analyze 菜单项)、defaultSettings()、overrideSettingsGroupVisibility()(控制设置组显隐)、registerCustomSettings()(注册自定义设置组,使生成页面可通过 QGroundControl.settingsManager.<accessor> 引用)、adjustSettingMetaData()(修改设置元数据与用户可见性);
  • UI 行为:createQmlApplicationEngine() / destroyQmlApplicationEngine()(介入 QML 引擎创建与销毁,可加 import 路径或往 context 注入对象)、createRootWindow()、paletteOverride()(覆盖 QGC 调色板配色)、createVideoReceiver() / createVideoSink() / releaseVideoSink()(替换视频管线组件);
  • 任务文件钩子:preSaveToJson() / postSaveToJson()、preSaveToMissionJson() / postSaveToMissionJson()、preLoadFromJson() / postLoadFromJson()(在计划文件保存/解析前后注入自定义内容);
  • 计划功能扩展:complexMissionItemNames() + createComplexMissionItem()(注册内置之外的复杂任务项,内置类型为 Survey、CorridorScan、StructureScan、FixedWingLanding、VTOLLanding)、planCreators()(新增"新建计划"入口);
  • 界面数据:toolBarIndicators()(非飞机相关的工具栏指示器)、customMapItems()(向 FlightMap 注入自定义 QmlComponentInfo 项)、firstRunPromptStdIds() / firstRunPromptCustomIds()(首次运行引导页,自定义 ID 从 kFirstRunPromptIdsFirstCustomId = 10000 起,标准 ID kInitialSetupPromptId = 3);
  • 版本检查:stableVersionCheckFileUrl()(默认 mainline 指向 QGC 稳定版文件,自定义构建默认返回空以关闭检查)、stableDownloadUrl();
  • 消息监听:mavlinkMessage()(观察所有经过车辆的 mavlink 流量,返回 false 可阻止处理)。

5.2 自定义构建实例:custom-example

仓库自带完整的自定义构建样例 custom-example,其 README(custom-example/README.md)说明了构建方式:清空构建目录 → 把 custom-example 重命名为 custom → 在该目录下构建 QGC(配合 cmake/CustomOverrides.cmake 启用 QGC_CUSTOM_BUILD)。

样例演示的四类定制正是 QGCCorePlugin 的典型用法:

  • 隐藏多数飞机设置(面向整机销售的商业产品):把大部分装机流程交给厂商预配置,界面更简洁,完整功能保留在 Advanced Mode;
  • 自定义品牌:自定义图片与配色,paletteOverride() 即为实现手段(见 custom-example/src/CustomPlugin.cc,样例为 window、text、button 等色板键逐一设置明暗两套色值);
  • 自定义界面:如用自研仪表组件替换标准 UI(见 FlyViewCustomLayer.qml、FlyViewToolStripActionList.qml);
  • 覆盖应用设置:隐藏用户不应改动的选项并调整默认值。

CustomPlugin 继承 QGCCorePlugin 并覆写的关键方法包括:构造函数中关闭高级 UI(_showAdvancedUI = false,CustomPlugin.cc);registerCustomSettings() 注册自定义设置组(CustomPlugin.cc);adjustSettingMetaData() 把离线编辑默认固件/机型固定为 PX4 + 多旋翼并隐藏对应设置项(CustomPlugin.cc)。其自定义固件插件骨架位于 custom-example/src/FirmwarePlugin,自定义设置 JSON 位于 custom-example/src/Settings。

六、插件机制运转总览与扩展要点

综合仓库源码,QGC 插件机制的完整运转流程可归纳为:

QGC 启动
  ├─ 各 FirmwarePluginFactory 通过 FirmwarePluginFactoryRegister 注册
  └─ 自定义构建: CustomPlugin(QGCCorePlugin) 在 QGCApplication 启动前注册
连接飞机
  ├─ HEARTBEAT → FirmwarePluginManager 按 autopilot/vehicle 分派插件(未识别回退通用)
  ├─ FirmwarePlugin 处理: 飞行模式映射 / 引导指令 / 消息调整 / 任务命令与参数元数据
  └─ AutoPilotPlugin 提供: Vehicle Setup 的 VehicleComponent 列表与设置向导
运行期
  ├─ QGCCorePlugin 定制: 页面 / 调色板 / 视频管线 / 计划文件 / 设置组
  └─ FirmwarePluginInstanceData 缓存各 MAV_CMD 支持状态,避免多余探测

若要为 QGC 接入一种新固件,从源码结构看最低成本的路径是:

  1. 在 src/FirmwarePlugin 下新建固件目录,继承 FirmwarePlugin 覆写飞行模式、引导指令、消息钩子、任务命令覆盖与参数元数据相关虚函数;
  2. 实现 FirmwarePluginFactory 子类并通过 FirmwarePluginFactoryRegister::registerPluginFactory() 注册(可参考 PX4FirmwarePluginFactory.cc 的单例写法);
  3. 在 src/AutoPilotPlugins 下实现 AutoPilotPlugin 子类与 VehicleComponent 集合,提供 Vehicle Setup 界面;
  4. 若产品形态特殊(如整机厂商),再继承 QGCCorePlugin 做应用级裁剪,直接套用 custom-example 的工程组织方式。

需要注意的边界约束:固件特有代码只能落在 FirmwarePlugin 与 AutoPilotPlugin 中,其余模块应保持 mavlink 通用;对外发消息的调整钩子(adjustOutgoingMavlinkMessageThreadSafe)必须线程安全;参数名始终使用最新名称,跨版本改名交给重映射表处理。

延伸阅读

登录后查看全文
qgroundcontrol