QGC 中修改原生 Android 串口 BUG 实操
一、QGC 原生 Android 串口实现的问题
原始 QGC 在 Android 平台下的串口实现,采用的是 Java + JNI 的方式:
- 由 Java 层 使用 Android USB Host API 枚举并打开 USB 串口设备
- 通过 JNI 注册 Native 方法
- 将串口数据以回调的形式传递到 C++ / Qt 层
该实现方式适用于 USB 转串口设备,但在实际工程中存在明显局限:
该方案无法操作系统中已存在的普通串口设备(如
/dev/ttyS* **、** /dev/ttyUSB* **、** /dev/ttyACM* )
在以下场景中尤为明显:
- 工控 / 定制 Android 系统
- 无人机遥控器内置 Android
- 已由内核直接生成 tty 设备节点的串口
- 需要高实时性、多串口并发的地面站应用
因此,原生 QGC 的 Android 串口方案在工程实践中存在适配不足的问题。
二、采用类 Linux 的原生 POSIX 串口方案
为解决上述问题,本次对 QGC 串口底层进行了修改,放弃 Java / JNI 串口路径 ,改为采用 类 Linux 的原生 POSIX 串口实现方式。
该方案通过以下机制直接操作串口设备:
open():打开系统设备文件termios/termios2:配置串口参数(波特率、数据位、校验位等)ioctl():支持非标准波特率及底层控制QSocketNotifier:将串口 fd 集成进 Qt 事件循环
核心特征如下:
直接操作系统设备文件(
/dev/tty*),完全绕过 Java 层,仅在 C++ / Qt 层完成串口通信。
该实现本质上是 Qt Unix 平台(Linux / Android)通用的 QSerialPortPrivate 实现,具备良好的稳定性与扩展性。
三、新串口实现的核心代码
新串口方案中,串口设备的打开方式如下:
cpp
int flags = O_NOCTTY | O_NONBLOCK;
flags |= O_RDWR; // 或 O_RDONLY / O_WRONLY
descriptor = ::open(systemLocation.toLocal8Bit().constData(), flags);
该代码直接获取串口设备的 文件描述符(fd) ,后续所有串口读写与事件监听均围绕该 fd 进行。
四、在 QGC 中的具体操作
为保证兼容性和可切换性,本次修改通过 宏控制 的方式,在原生 QGC 串口方案与新方案之间进行切换。
1️⃣ 在 QGCCommon.pri 中增加宏定义
cpp
DEFINES += GENERAL_SERIAL_ENABLE
用于启用新的通用串口实现。

2️⃣ 在 main.cc 中屏蔽原有 Android JNI 串口逻辑
原生 QGC 会在启动时注册 Java 串口的 Native 方法,需在启用新方案时将其屏蔽:
cpp
#ifndef GENERAL_SERIAL_ENABLE
#if !defined(NO_SERIAL_LINK)
QSerialPort::setNativeMethods();
#endif
#endif
启用 GENERAL_SERIAL_ENABLE 后,QGC 将不再走 Java / JNI 串口路径。

3️⃣ 替换 libs 目录下的 qtandroidserialport 库
- 删除原有
qtandroidserialport实现 - 替换为修改后的串口底层代码
该步骤确保 Android 平台下统一使用 POSIX 串口实现。

链接: https://ug.link/dxp4800-d1e0/filemgr/share-download/?id=b904d94c152c4b33b34b702501a0c7f3
具体替换的文件在这里,无需关心

五、实测
远传融创中 S1/S2 遥控器地面站软件中串口截图:

QGC 实测版本: v4.1.3 、Stable_v4.4