☰
QGroundControl 虚拟摇杆(Virtual Joystick)使用指南:屏幕拇指摇杆原理、配置与源码解析
2026/10/15 6:49:03 网站建设 项目流程
  • 无人机
  • 智能硬件

【免费下载链接】qgroundcontrol

Cross-platform ground control station for drones (Android, iOS, Mac OS, Linux, Windows)

项目地址:https://gitcode.com/gh_mirrors/qg/qgroundcontrol
点击查看免费下载

QGroundControl(QGC)内置了屏幕虚拟摇杆(Virtual Joystick),允许用户在没有任何物理遥控设备的情况下,通过触摸屏上的拇指摇杆(thumbsticks)直接操控载具。本文基于 docs/zh/qgc-user-guide/settings_view/virtual_joystick.md 展开,讲解该功能的启用方法、三个关联设置项的作用,并结合仓库源码说明虚拟摇杆从触摸输入到 MAVLink 指令的完整数据链路,帮助读者既会配置、也懂原理。

功能概述与适用场景

虚拟摇杆是 QGroundControl 针对平板、手机等触屏设备设计的"屏幕内置遥控器"。启用后,Fly View(飞行视图)底部会叠加显示两枚拇指摇杆垫,用户直接用手指拖拽即可发送滚转(roll)、俯仰(pitch)、偏航(yaw)与油门(thrust)指令。

从源码结构看,该功能的定位与物理摇杆并存互补:

  • 虚拟摇杆面向触屏设备的临时、轻量操控场景,无需任何外设即可起飞前的低速验证或演示操控;
  • 若需要精细操控,官方建议改用 USB 摇杆/游戏手柄(Joystick 模块)或 RC 遥控发射器。

需要特别强调的是:虚拟摇杆的操控精度和灵敏度低于 RC 遥控发射器,因为其指令经由 MAVLink 链路传输(而非独立的 RC 链路),存在链路延迟与量化误差。这一点在文档的提示信息中已明确说明,用户在飞行前应充分评估风险。

启用虚拟摇杆

启用操作非常简单,全部在应用程序设置中完成:

  1. 从顶部工具栏选择Q图标;
  2. 打开应用程序设置(Application Settings);
  3. 确保停留在常规(General)选项卡;
  4. 勾选虚拟游戏杆(Virtual joystick)复选框。

启用后回到 Fly View,即可看到屏幕底部出现两枚摇杆垫(左侧为油门摇杆,右侧为姿态摇杆)。该选项默认关闭(default: false),其配置项定义于 src/Settings/App.SettingsGroup.json:

{ "name": "virtualJoystick", "shortDesc": "Displays an on-screen virtual joystick in the Fly view for manual vehicle control.", "type": "bool", "default": false, "label": "Virtual Joystick", "keywords": "joystick,virtual stick" }

对应的 C++ 设置工厂声明位于 src/Settings/AppSettings.h 与 src/Settings/AppSettings.cc,运行时由QGroundControl.settingsManager.appSettings.virtualJoystick访问。

在界面层,Fly View 通过 FlyViewWidgetLayer.qml 中的Loader动态加载 src/FlyView/VirtualJoystick.qml:

Loader { id: virtualJoystickMultiTouch source: "qrc:/qml/QGroundControl/FlyView/VirtualJoystick.qml" active: _virtualJoystickEnabled && !(_activeVehicle ? _activeVehicle.usingHighLatencyLink : false) property bool _virtualJoystickEnabled: QGroundControl.settingsManager.appSettings.virtualJoystick.rawValue }

从这段代码可以推断两个重要的隐藏约束:虚拟摇杆仅在非高延迟链路上显示(usingHighLatencyLink为真时不激活),且视频全屏时会自动隐藏(visible条件中的!QGroundControl.videoManager.fullScreen)。

两个进阶设置项:油门回中与左手模式

除了总开关,QGroundControl 还提供两个与虚拟摇杆强相关的进阶选项,它们同样定义在 src/Settings/App.SettingsGroup.json,并在 src/AppSettings/pages/FlyView.SettingsUI.json 的 "Virtual Joystick" 分组中展示(仅在总开关开启时可用,enableWhen: "virtualJoystickOn"):

油门自动回中(Auto-Center Throttle)

  • 配置项:appSettings.virtualJoystickAutoCenterThrottle
  • 默认值:true
  • 作用:启用后,油门摇杆在手指松开时自动弹回中心位置(对应 0 油门中点),而非停留在当前输出位置。
{ "name": "virtualJoystickAutoCenterThrottle", "shortDesc": "Returns the throttle stick to center when released instead of holding position.", "type": "bool", "default": true, "label": "Auto-Center Throttle" }

该设置直接决定摇杆垫的yAxisReCenter行为,其物理含义在 src/QmlControls/JoystickThumbPad.qml 中有明确注释:true表示松开后回到中心,false表示松开后停在当前位置。从 src/FlyView/VirtualJoystick.qml 可以看到,初始油门值也依赖该选项:

property real leftYAxisValue: autoCenterThrottle ? height / 2 : height

即回中模式下油门初始值为高度中点(输出 0),非回中模式下初始值为底部(输出满油门位置),这与"非回中模式模拟自稳遥控器油门杆保持位置"的行为一致。

左手模式(Left-Handed Mode)

  • 配置项:appSettings.virtualJoystickLeftHandedMode
  • 默认值:false
  • 作用:启用后,摇杆布局左右互换,油门/偏航摇杆移到左侧,姿态摇杆移到右侧,适配左手操控习惯。
{ "name": "virtualJoystickLeftHandedMode", "shortDesc": "Swaps the virtual joystick layout so throttle/yaw is on the left.", "type": "bool", "default": false, "label": "Left-Handed Mode" }

在 src/FlyView/VirtualJoystick.qml 中,左右两枚JoystickThumbPad的角色由该选项决定:左摇杆yAxisPositiveRangeOnly在非左手模式下且非 rover 机型时开启(油门仅输出正向区间),右摇杆始终回中;左手模式下两者对调,同时 src/FlyView/VirtualJoystick.qml 的发送逻辑也会交换左右摇杆的取值顺序。

屏幕摇杆的交互细节:轴值范围与回中逻辑

虚拟摇杆的核心交互组件是 src/QmlControls/JoystickThumbPad.qml(在 src/QmlControls/CMakeLists.txt 中注册)。其公开属性定义了输出协议,理解这些属性有助于把握虚拟摇杆的操控行为:

属性取值范围含义
xAxis[-1, 1]横轴输出,负值向左、正值向右
yAxis[-1, 1] 或 [0, 1]纵轴输出,负值向下、正值向上;yAxisPositiveRangeOnly为真时仅输出 [0, 1]
yAxisPositiveRangeOnlybool仅输出正区间(油门类摇杆用,避免向负方向输出)
yAxisReCenterbool松开后是否弹回中心(对应油门自动回中)
touchActivebool当前是否有手指按压在摇杆垫上

摇杆垫的坐标换算实现在calculateXAxis()/calculateYAxis()(src/QmlControls/JoystickThumbPad.qml):将拇指位置按摇杆垫尺寸归一化,映射到 [-1, 1](或油门模式的 [0, 1])。同时它还处理了界面缩放场景——resize()与reCenter()(src/QmlControls/JoystickThumbPad.qml)会在窗口尺寸变化时保留当前 Y 轴输出、重排摇杆位置,避免飞行中因布局重排导致指令突变。

一个值得注意的细节是,虚拟摇杆启用期间会禁用地图的双指缩放(pinch-to-zoom):当任一摇杆垫处于按压状态时,FlyViewWidgetLayer.qml 通过Binding将pinchZoomDisabledByVirtualJoysticks置真,阻止PinchHandler抢占触摸事件(注释提及 issue #13450),保证摇杆拖拽不被地图手势干扰。

数据链路:从触摸输入到 MAVLink 指令

虚拟摇杆的发送循环由 src/FlyView/VirtualJoystick.qml 中的定时器驱动:

Timer { interval: 40 // 25Hz, same as real joystick rate running: QGroundControl.settingsManager.appSettings.virtualJoystick.value repeat: true onTriggered: { if (_activeVehicle && _initialConnectComplete) { leftHandedMode ? _activeVehicle.virtualTabletJoystickValue(leftStick.xAxis, leftStick.yAxis, rightStick.xAxis, rightStick.yAxis) : _activeVehicle.virtualTabletJoystickValue(rightStick.xAxis, rightStick.yAxis, leftStick.xAxis, leftStick.yAxis) } leftYAxisValue = leftStick.yAxis // We keep Y axis value from the throttle stick for using it while there is a resize } }

关键信息点:

  • 发送频率为 25 Hz(interval: 40ms),与真实摇杆的采样速率一致(见 src/Joystick 模块实现);
  • 仅在存在激活载具且初始连接完成(initialConnectComplete)后才发送,避免连接早期产生无效指令;
  • 总开关关闭时定时器自动停止(running绑定设置值)。

发送入口是Vehicle::virtualTabletJoystickValue(roll, pitch, yaw, thrust)(src/Vehicle/Vehicle.h、src/Vehicle/Vehicle.cc):

void Vehicle::virtualTabletJoystickValue(double roll, double pitch, double yaw, double thrust) { // The following if statement prevents the virtualTabletJoystick from sending values if the standard joystick is enabled bool isActiveVehicle = (MultiVehicleManager::instance()->activeVehicle() == this); bool joystickEnabled = isActiveVehicle && JoystickManager::instance()->activeJoystickEnabledForActiveVehicle(); if (!joystickEnabled) { sendJoystickDataThreadSafe( static_cast<float>(roll), static_cast<float>(pitch), static_cast<float>(yaw), static_cast<float>(thrust), 0, 0, // buttons NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN); // extension values } }

这里有一个重要的优先级约束:当物理摇杆(USB Joystick)已启用且作用于激活载具时,虚拟摇杆的输入会被丢弃,以避免双输入源互相冲突。

最终由Vehicle::sendJoystickDataThreadSafe()(src/Vehicle/Vehicle.cc)将 [-1, 1] 范围内的摇杆值乘以1000缩放系数,封装为 MAVLinkMANUAL_CONTROL消息(mavlink_msg_manual_control_pack_chan)通过主链路发送给飞控;若当前链路是高延迟链路(isHighLatency()),则直接返回不发送,与前面 FlyView 层隐藏摇杆的逻辑相互印证。整条链路可概括为:

手指触摸 → JoystickThumbPad 坐标归一化(xAxis/yAxis) → VirtualJoystick.qml 25Hz 定时器 → Vehicle::virtualTabletJoystickValue()(物理摇杆启用时拦截) → Vehicle::sendJoystickDataThreadSafe() → MAVLink MANUAL_CONTROL 消息 → 飞控

常见问题与使用建议

  • 为什么虚拟摇杆不如 RC 灵敏?因为指令以 25 Hz 的速率通过 MAVLink 数字链路传输,链路延迟、量化与包丢失风险都高于点对点 RC 模拟链路;需要高精度操控时应使用 RC 发射器或 USB 摇杆/游戏手柄。
  • 油门位置保持不住?检查Auto-Center Throttle设置——默认开启时松开即回中;若希望模拟"油门杆保持当前位置"的行为,将其关闭即可(JoystickThumbPad.qml 的yAxisReCenter对应此行为)。
  • 摇杆没有显示?确认三点:总开关已勾选、当前不是视频全屏状态、当前链路不是高延迟链路(FlyViewWidgetLayer.qml)。
  • 摇杆拖不动 / 地图缩放抢占?虚拟摇杆按压期间地图双指缩放会被自动禁用,属预期行为而非故障。
  • 虚拟摇杆与物理摇杆同时启用?物理摇杆优先:当物理摇杆已启用并作用于激活载具时,虚拟摇杆输出被忽略(Vehicle.cc)。

相关资源索引

  • 官方文档:virtual_joystick.md(本文主体来源)
  • 界面实现:src/FlyView/VirtualJoystick.qml、src/FlyView/FlyViewWidgetLayer.qml
  • 摇杆垫组件:src/QmlControls/JoystickThumbPad.qml
  • 设置项定义:src/Settings/App.SettingsGroup.json、src/Settings/AppSettings.h
  • 设置界面布局:src/AppSettings/pages/FlyView.SettingsUI.json
  • 指令发送:src/Vehicle/Vehicle.cc、src/Vehicle/Vehicle.cc
  • 物理摇杆替代方案:setup_view/joystick.md、src/Joystick、test/Joystick
  • 无人机
  • 智能硬件

【免费下载链接】qgroundcontrol

Cross-platform ground control station for drones (Android, iOS, Mac OS, Linux, Windows)

项目地址:https://gitcode.com/gh_mirrors/qg/qgroundcontrol
点击查看免费下载

相关推荐

上一篇:3步突破网易云音乐加密:NCM转换工具让付费音乐自由播放
下一篇:Wux Weapp 数据展示组件终极指南:列表、卡片与网格布局全解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询