云卓 G20 遥控器 Android 开发实录:从 USB 设备到读取摇杆/按键通道值

云卓 G20 遥控器 Android 开发实录:从 USB 设备到读取摇杆/按键通道值

设备:云卓(Skydroid)G20 无人机地面遥控器

目标:在电脑上读取插上 USB 的"遥控器"的摇杆(遥杆)与按键值,并写一个 App 测试

前言

最近拿到一个"遥控器",插上电脑 USB 后 lsusb 显示的是 18d1:4e11 Google Inc. Nexus One------这不是手柄,而是 Android 设备的 adb 接口 。顺着这条线,我把这个设备从头摸了一遍:它其实是 云卓 G20 无人机遥控器(地面端),内置 Android 13 系统,本身就可以装 App、跑 SDK。

本文记录完整的探索过程与踩坑经验,包括:

  • 如何确认设备身份;
  • 为什么摇杆/按键没有注册成 Linux 输入设备;
  • 如何找到云卓私有服务与串口链路;
  • 如何用官方 RCSDK 读取 16 通道实时值(摇杆/按键/开关/波轮);
  • 接收机网口(图传)在 SDK 中的对应 API。

一、插上 USB 的"遥控器"到底是什么?

先用 lsusb 看设备:

bash 复制代码
$ lsusb
Bus 003 Device 009: ID 18d1:4e11 Google Inc. Nexus One

18d1:4e11 是经典 Android adb 设备的 VID/PID(Google 注册表里叫 Nexus One,实际是 adb 接口通用的名字)。所以它不是普通 HID 手柄,而是一台安卓设备。

再确认 adb:

bash 复制代码
$ adb devices -l
[设备序列号]   device usb:3-4 product:bengal_515 model:Bengal_for_arm64 device:bengal_515

二、先看说明书:这是云卓 G20

对应的是用户提供的手册《云卓-G20 使用说明书 V1.0》,提取 PDF 文本后确认:

项目 内容
产品 云卓 G20 遥控器(无人机地面端)
系统 Android 13(64 位),高通 6nm 8 核(Bengal)
屏幕 7 寸 1920x1200
通道数 16 通道
输入 左摇杆 X1/Y1、右摇杆 X2/Y2、L1/L2/R1/R2/H/B1/B2、三档开关、波轮(云台俯仰)、SPAY 播撒键、CAMERA 拍照键
接口 TYPE-C、USB(升级口)、SIM 卡槽
接收机 GR01(网口×1、PWM02=通道911、SBUS+数传)或 G12 RX(网口×1、PWM01=通道910、SBUS+数传)

关键点:手册第 8 页"设备助手→舵量查看"就是看实时通道值的,说明通道数据一定可以通过某种接口拿到。


三、确认设备身份(adb)

bash 复制代码
adb -s [设备序列号] shell getprop | grep -iE 'ro.product|ro.build.version'

输出确认:

复制代码
[ro.build.version.release]: [13]
[ro.build.version.sdk]: [33]
[ro.product.cpu.abi]: [arm64-v8a]
[ro.product.model]: [Bengal for arm64]

与手册完全一致:Android 13 / API 33 / arm64。


四、找摇杆数据:为什么 getevent 找不到?

一般游戏手柄/遥控器在 Android 里是 /dev/input/eventX 输入设备,可以直接 getevent。但这里:

bash 复制代码
$ adb shell getevent -pl
add device 1: /dev/input/event4   "bengal-idp-snd-card Button Jack"   (音量/媒体键)
add device 2: /dev/input/event3   "bengal-idp-snd-card Headset Jack"  (耳机)
add device 3: /dev/input/event2   "SITRONIX"                           (触摸屏)
add device 4: /dev/input/event0   "qpnp_pon"                           (电源键)
add device 5: /dev/input/event1   "gpio-keys"                          (返回键)

没有摇杆、没有 L1/R1 等按键! 说明摇杆/按键由云卓私有链路处理,不是标准 input 子系统。

继续排查,发现了云卓的系统应用和服务:

bash 复制代码
$ adb shell ps -A | grep -i sky
system  com.skydroid.rc_daemon     # 遥控器守护进程
system  com.skydroid.rcservice     # 遥控器服务 (RCService)
$ adb shell getprop | grep -i mcu
[vendor.mcu.rc_service]: [true]

五、逆向系统 App:找到 rcsdk 与串口线索

把三个云卓 APK 拉回电脑分析:

bash 复制代码
adb pull /system/app/rcserivce/rcserivce.apk      # RCService (210KB)
adb pull /system/app/rcdaemon/rcdaemon.apk        # 守护进程 (62KB)
adb pull /data/app/.../com.skydroid.devicetool/base.apk  # 设备助手 (19MB)

strings/javap 分析后得到关键信息:

  1. 设备助手(devicetool / Htool)内置了完整的 SDK :com.skydroid.rcsdk,里面有 comm/SerialPortcommon/button/ButtonHelpercommon/airlink/*(NetworkConfig、GLinkSkyDevice、ReceiverOptions 等),还有 libsky_serialport.so(JNI,实现 Java_com_skydroid_rcsdk_comm_SerialPort_open)------经典 android-serialport-api 模式。
  2. G20 通道参数 :assets/params_g20/default.json 里是 16 通道的映射表,min/mid/max = 105/150/195(舵量范围,单位不是 us,而是这个私有协议的数值)。
  3. rcservice 的 assets 里还有 Artosyn 图传链路相关二进制(daemondata_stream,ARP8030 图传芯片 SDK)。

六、动态抓日志:确认串口 /dev/ttyHS2

启动"设备助手"后抓 logcat(这就是网上说的"看日志比猜靠谱"):

bash 复制代码
adb logcat -c
adb shell am start -n com.skydroid.devicetool/com.skydroid.h12ptool.ui.activity.MainActivity
adb shell "logcat -d | grep -iE 'serial|ttyHS|rcsdk'"

结果:

复制代码
D serial_port: Opening serial port /dev/ttyHS2 with flags 0x2
D serial_port: open() fd = 86
D serial_port: Configuring serial port
D RCSDK_JNI: ar8030_helper_socket version:31  agrc 5
D RCSDK_JNI: -p 50002

结论:SDK 通过高通 HSUART /dev/ttyHS2 与遥控器 MCU 通信,读取 16 通道舵量/dev/ttyHS1/dev/ttyHS2 在本机权限是 777,普通 App 也能打开(SELinux 为 permissive)。


七、柳暗花明:官方 RCSDK 开源 Demo

正好官方源码在 Gitee:

集成要点(README 原文语义):

text 复制代码
1) 导入 rcsdk-v1.9.2.aar
2) 权限: <uses-permission android:name="android.permission.INTERNET"/>
3) 初始化: RCSDKManager.initSDK(this, SDKManagerCallBack)
4) 连接:   RCSDKManager.connectToRC()
5) 读通道: KeyManager.get(RemoteControllerKey.KeyChannels, callback)  // int[16]

注意(官方说明):

  • 摇杆杆量无法主动上报,GET 请求一次返回一次,推荐 ≥100ms 轮询一次;
  • 使用前务必停止设备助手/地面站,否则串口端口被占用导致连接失败。

八、最小测试 App(纯 Java,无 AndroidX)

为了快速验证,新建了最小工程 g20test(纯 Java + 官方 aar,不引入 AndroidX,离线也能构建):

核心代码 (MainActivity.java 片段):

java 复制代码
RCSDKManager.INSTANCE.initSDK(this, new SDKManagerCallBack() {
    @Override public void onRcConnected() { /* 已连接 */ }
    @Override public void onRcConnectFail(SkyException e) {}
    @Override public void onRcDisconnect() {}
});
RCSDKManager.INSTANCE.setMainThreadCallBack(true);
RCSDKManager.INSTANCE.connectToRC();

// 每 100ms 轮询一次(在 Handler 中)
KeyManager.INSTANCE.get(RemoteControllerKey.INSTANCE.getKeyChannels(),
    new CompletionCallbackWith<int[]>() {
        @Override public void onSuccess(int[] value) {
            // value 就是 16 个通道实时值
            Log.i("G20Test", "CH: " + Arrays.toString(value));
        }
        @Override public void onFailure(SkyException e) {}
    });

编译注意:RCSDK 是 Kotlin 写的,纯 Java 工程需手动引入 kotlin-stdlib;本机 Gradle 缓存有 kotlin-stdlib-1.9.20.jar,直接 files() 引用即可。


九、实测结果:16 通道实时值

安装运行后,logcat 实时输出(实测):

复制代码
CH: [1500, 1500, 1528, 1050, 1950, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1500, 1050, 1050]
CH04 1050 -> 1238 (Δ188) [摇杆/波轮]
CH04 1238 -> 1500 (Δ262) [摇杆/波轮]
CH04 1500 -> 1950 (Δ293) [摇杆/波轮]
  • 通道值范围:1050 ~ 1950,中心 1500 (与 params_g20/default.json 的 105/150/195 缩放一致,即放大 10 倍);
  • 摇杆/波轮:连续变化(如 CH04 从 1050 平滑到 1950);
  • 按键/开关:跳变(±500 级别,如 1050 ↔ 1950),三档开关是 1050/1500/1950 三态;
  • 截图确认界面正常显示 16 通道 + 事件日志。

结论:用一个 App + 官方 SDK,即可在 G20 上(或通过 adb 转发的 logcat 在电脑上)实时看到所有摇杆/按键/开关状态。


十、接收机与网口(图传)在 SDK 中的对应

10.1 手册怎么看

GR01 G12 RX
网络 网口×1(R±/T±) 网口×1(ETH0 TX±/RX±)
PWM PWM0~2 = 通道 9~11 PWM0~1 = 通道 9~10
飞控 SBUS 输出 + 数传 RX/TX SBUS + UART 数传
对频 长按对频按钮 短接 GND+KEY

网口只用来接相机(图传),不接飞控:

  • 云卓相机(如 C10Pro)插接收机网口 → 设备助手"视频查看"直接看;
  • 第三方相机必须设网段 192.168.144.XXX,再用 RTSP 拉流;
  • 云卓相机默认 192.168.144.108,网关 192.168.144.11;
  • 遥控器开 USB 网络共享后,电脑连 192.168.43.1,Mission Planner 可走 TCP 5760(数传),VLC 可拉相机码流(图传)。

10.2 SDK 里对应的类/接口(rcsdk AAR 反编译确认)

SDK 成员 说明
common.airlink.GLinkSkyDevice 天空端设备枚举:GR01/GR02/GR03/TR01/YL20
common.airlink.NetworkConfig ip / gateway / mask 三字段(网口/网络配置)
common.airlink.ReceiverOptions baudRate + mode(接收机输出:SBUS/PPM/CBUS)
common.airlink.UartBaudRate B9600/B57600/B115200/B921600
AirLinkKey.KeyUart0BaudRate 接收机串口 0 波特率(支持 G12/G20/G30/G16)
AirLinkKey.KeySignalQuality / KeyRawSignalQuality 接收机信号质量(0-100%)及原始 JSON
AirLinkKey.KeyG12GetChan G12/G20 信道/频率/功率查询与设置
PipelineManager.createG12G20Pipeline() G12/G20 专用数传管道(UDP,需系统≥20250110)
PipelineManager.createUDPPipeline(本地端口,"192.168.144.10",远端端口) 自定义 UDP 管道
PayloadManager.getUDPPayload(PayloadType.C10PRO, 5000, "192.168.144.108", 5000) 云台相机控制(网口/UDP链路)
PayloadManager.getTCPPayload(PayloadType.C10, "192.168.144.108", 5000) C10 相机 TCP 控制

即:接收机网口 = 相机高清图传/控制链路,对应 PayloadManager + FPV 视频流;接收机串口/SBUS = 飞控控制链路,对应 PipelineManager 数传管道


十一、经验与踩坑总结

  1. 别把"遥控器"当 HID :云卓 G20 是安卓设备,先 adb devices 确认身份;摇杆/按键走私有 MCU 串口(实测 /dev/ttyHS2),不是 /dev/input
  2. 官方优先:有官方 SDK(基于 KeyManager 的 SET/GET/ACTION/LISTEN 模型)就不要自己读串口;
  3. GET 轮询 :KeyChannels 一次只能取一次值,轮询间隔 ≥100ms;
  4. 端口互斥 :设备助手/地面站不退出,SDK 连不上(启动前 am force-stop com.skydroid.devicetool);
  5. 纯 Java 工程 + Kotlin SDK :记得手动带 kotlin-stdlib;
  6. 构建加速 :Gradle 仓库加阿里云镜像(maven.aliyun.com/repository/public|google|gradle-plugin);
  7. 安卓 13/API 33 :本机 SDK 没有 android-32,用 compileSdk 33 + android.suppressUnsupportedCompileSdk=33 即可;
  8. 日志先行 :启动官方 App 抓 serial_port/RCSDK_JNI 日志,比纯猜快得多。

附录:常用命令

bash 复制代码
# 设备
adb devices -l
adb -s [设备序列号] shell getprop | grep -i model

# 输入设备(确认摇杆不在里面)
adb -s [设备序列号] shell getevent -pl

# 停止设备助手(释放串口)
adb -s [设备序列号] shell am force-stop com.skydroid.devicetool

# 安装/启动测试 App
adb -s [设备序列号] install -r app/build/outputs/apk/debug/app-debug.apk
adb -s [设备序列号] shell am start -n com.demo.g20test/.MainActivity
adb -s [设备序列号] logcat -s G20Test:*

# 官方 Demo
git clone https://gitee.com/skydroid/rcsdk-demo.git

本文基于云卓 G20 遥控器 + RCSDK v1.9.2 实测整理,仅供学习交流。

相关推荐
lxw202302711642 分钟前
k8s的pod管理
linux·容器·kubernetes
qetfw1 小时前
Debian Samba 与 OpenLDAP 统一认证配置
linux·debian
pengyu1 小时前
【Kotlin 协程修仙录 · 炼虚境 · 初阶】 | 虚空造物:Channel 基础与协程间通信的管道艺术
android·前端·kotlin
小强闯江湖1 小时前
ViewCompose:让原生 Android View 进入声明式时代
android·开源·kotlin
初願致夕霞2 小时前
《为什么公网访问不了内网?正向代理、内网穿透与 NAT 打洞一次说清》
linux·网络·tcp/ip·智能路由器
高磊20052 小时前
Kubernetes Pod 管理实战详解
linux·容器·kubernetes
喜欢吃燃面2 小时前
Linux网络编程深度解析:从Socket API到自定义协议设计
linux·网络·arm开发
苹果嘉尔121382 小时前
Linux系统编程——网络(TCP)
linux·运维·服务器
昌原的儿子LEO3 小时前
Linux进程知识点总结
linux·服务器·c语言·数据库