Skip to content

Latest commit

 

History

History
151 lines (112 loc) · 4.65 KB

File metadata and controls

151 lines (112 loc) · 4.65 KB

ControllerSDK 架构设计

本文档面向需要理解 ControllerSDK 内部架构或进行二次开发的开发者。

兼容性:ControllerSDK 仅支持山猫 M20 标配的云卓 G20 手柄,不兼容其他型号。


架构总览

ControllerSDK 是独立于 RobotSDK 及其底层协议栈的 Android Library:

Your App
    ↓
ControllerSDK  →  通过 rcsdk 直连手柄
    ↓
rcsdk-v1.9.1.aar  (云卓手柄 SDK,需自行获取)

模块职责

模块 职责
ControllerManager 单例入口,自动识别设备型号,管理手柄生命周期
RemoteControlBase 手柄抽象基类,定义通用 LiveData 和生命周期方法
YzG20ConnectUtils 云卓 G20 具体实现,摇杆/按键数据解析与归一化
JoystickData 摇杆数据模型,包含原始值与归一化值
PhysicalKeyBase 物理按键基类接口

模块关系

SimpleDemo
    └── ControllerSDK (api)
        └── rcsdk-v1.9.1.aar (external)

设计原则

  1. 设备自动识别ControllerManagerconnect() 时自动判断设备型号,无需手动指定
  2. 抽象基类RemoteControlBase 定义通用接口,不同手柄型号继承实现
  3. 响应式编程:状态通过 LiveData 实时推送,UI 被动更新
  4. 生命周期绑定onResume() / onPause() / disconnect() 与 Activity 生命周期对齐

核心类详解

ControllerManager

统一入口单例,负责根据设备类型自动选择对应的手柄实现。

object ControllerManager {
    fun init(application: Application)
    fun connect(context: Context, scope: LifecycleCoroutineScope, onException: ((Exception) -> Unit)? = null)
    fun disconnect()
    fun onResume()
    fun onPause()
    fun hasController(): Boolean
    fun needSendSoftEmergencyStopMessage(): Boolean
    fun setDeadzone(value: Float)

    val joystickDataLive: LiveData<JoystickData>?
    val physicalKeyStatesLive: LiveData<List<PhysicalKeyBase>?>?
    val d2dConnectStateLive: LiveData<Boolean>?
    val d2dSignalLive: LiveData<Int>?
    val softEmergencyStopLive: LiveData<Boolean>?
}

RemoteControlBase

手柄遥控抽象基类,定义手柄通用的 LiveData 输出和生命周期方法。

abstract class RemoteControlBase {
    var deadzone: Float = 0f                    // 摇杆死区归一化值(0~0.5)
    val physicalKeyStatesLive: FilterMutableLiveData<List<PhysicalKeyBase>?>
    val d2dConnectStateLive: FilterMutableLiveData<Boolean>
    val d2dSignalLive: FilterMutableLiveData<Int>
    val softEmergencyStopLive: FilterMutableLiveData<Boolean>
    val joystickDataLive: FilterMutableLiveData<JoystickData>

    abstract fun needSendSoftEmergencyStopMessage(): Boolean
    abstract fun connect(context: Context, scope: LifecycleCoroutineScope, onException: ((Exception) -> Unit)? = null)
    abstract fun disconnect()
    fun onResume()
    fun onPause()
}

JoystickData

摇杆数据模型,包含原始值与归一化值。

data class JoystickData(
    val leftX: Int = 0,        // 左摇杆 X 轴原始值(范围 1050~1950,中心 1500)
    val leftY: Int = 0,        // 左摇杆 Y 轴原始值
    val rightX: Int = 0,       // 右摇杆 X 轴原始值
    val rightY: Int = 0,       // 右摇杆 Y 轴原始值
    val leftXNorm: Float = 0f, // 左摇杆 X 轴归一化值(-1.0 ~ 1.0,应用死区后)
    val leftYNorm: Float = 0f, // 左摇杆 Y 轴归一化值
    val rightXNorm: Float = 0f,// 右摇杆 X 轴归一化值
    val rightYNorm: Float = 0f // 右摇杆 Y 轴归一化值
)

PhysicalKeyBase

物理按键基类接口,各手柄实现类定义具体的物理按键枚举。

interface PhysicalKeyBase {
    val name: String
}

云卓 G20 按键枚举(YzG20ConnectUtils.PhysicalKey):

按键 name
L1 G20_KEY_L1
L2 G20_KEY_L2
R1 G20_KEY_R1
R2 G20_KEY_R2
HOME G20_KEY_HOME
STOP(急停) G20_KEY_STOP
CAMERA G20_KEY_CAMERA
PUMP G20_KEY_PUMP

归一化与死区

摇杆原始值范围 [1050, 1950],中心 1500,半量程 450

normalizeWithDeadzone() 方法将原始值映射为归一化值:

  • 死区内(|raw - center| ≤ deadRadius):归一化值 = 0
  • 死区外负侧:线性映射到 [-1, 0)
  • 死区外正侧:线性映射到 (0, 1]

死区半径 = deadzone × 450。例如 deadzone = 0.1 时,原始值在 [1455, 1545] 范围内归一化值均为 0。


外部依赖

ControllerSDK 依赖外部库 rcsdk-v1.9.1.aar(云卓手柄 SDK),该文件不随本项目发布,需从云卓官方获取。