跳到主要内容

06. 组合(Inverse3 + 无线 VerseGrip)

双设备教程:将握把指向某个方向并按住按钮,即可驱动 Inverse3 光标沿该方向移动。光标被限制在球形工作空间内。

你将学到:

  • 在同一状态帧中读取两种设备类型(inverse3 和 wireless_verse_grip)
  • 从握把的 四元数(局部 +Y 轴)中提取指向方向
  • 使用 set_cursor_position 将光标驱动至计算得出的目标位置
  • 将目标限制在安全的球形工作空间内——Minverse 使用的半径小于 Inverse3
  • 设置 工作空间预设(arm_front_centered),使原点位于可达范围的中心

工作流程​

  1. 发现两台设备:
    • 启动时,C++ 的各个变体通过 HTTP 查询 GET /devices,随后打印校准提示并等待按下 ENTER 键。
    • Python 从第一个 WebSocket 状态帧中读取两台设备的 ID。
  2. 在第一条消息中注册 会话配置文件,并设置 configure.preset: arm_front_centered(一次性握手)。
  3. 每个周期:读取握把的 orientation 以及 buttons.{a, b} 状态。
  4. 若按住运动按钮,则计算握把在世界坐标系中的方向(R(q) · ĵ,即旋转后的单位 +Y 轴),并按 SPEED 缩放后累加到目标位置上。
  5. 将目标限制在工作空间球体内,并通过 set_cursor_position 发送。
  6. (仅 Python)根据设备的 config.type 调整球体半径——minverse 为 0.04 m,其他所有类型为 0.10 m。

参数​

名称默认值用途
SPEED0.01 m/周期按住按钮时的每步运动距离
RADIUS_INVERSE30.10 mInverse3 / Inverse3x 的工作空间限制半径
RADIUS_MINVERSE0.04 mMinverse 的工作空间限制半径(仅适用于 Python —— C++ 中硬编码为 0.10)
PRINT_EVERY_MS200遥测输出节流间隔
会话配置文件名称co.haply.inverse.tutorials:combined在 Haply Hub 中标识此模拟
运行前先校准
  • 让 Inverse3 自行校准(或将握把放在墨水盒上,并等待 LED 常亮)。
  • 将握把从墨水盒上取下。
  • 按住 A 或 B 并转动握把——光标将沿握把指向的方向移动。

读取的状态字段​

从每个周期的状态帧中读取:

  • data.inverse3[0].state.cursor_position — vec3
  • data.wireless_verse_grip[0].state.orientation — quaternion
  • data.wireless_verse_grip[0].state.buttons.{a, b, c} — 布尔值
  • (Python,仅第一帧)data.inverse3[0].config.type —— 用于选择 Inverse3 或 Minverse 的半径
  • (Python,仅第一帧)data.inverse3[0].status.calibrated —— 若为 false,则提示用户

发送 / 接收​

四元数到方向的计算(用 R(q) 旋转 +Y)以及球体限制都是经典的线性代数运算,详见源文件。Inverse API 部分由握手过程以及每个周期的 set_cursor_position 调用组成。

单一异步循环。Python 从第一个状态帧中读取两台设备的 ID;握手过程将配置文件 + configure.preset: arm_front_centered 附加到第一次 set_cursor_position 调用中。

async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)

if first_message:
first_message = False
inverse3_id = data["inverse3"][0]["device_id"]
grip_id = data["wireless_verse_grip"][0]["device_id"]
radius = get_workspace_radius(data["inverse3"][0].get("config", {}))

# Handshake: profile + preset + first position command
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": inverse3_id,
"configure": {"preset": {"preset": "arm_front_centered"}},
"commands": {"set_cursor_position": {"position": position}},
}],
}
else:
# Per tick: update position from grip pointing direction (classic math, not shown), send
request_msg = {
"inverse3": [{
"device_id": inverse3_id,
"commands": {"set_cursor_position": {"position": position}},
}],
}

await websocket.send(json.dumps(request_msg))
随 SDK 安装程序一同提供

教程 06 也会随 SDK 一同安装在本地——请在服务安装目录下的 tutorials/06-haply-inverse-combined/ 中查找。

源代码: Python · C++ · C++ Glaze

相关内容: 控制命令(set_cursor_position) · 类型(quaternion、vec3) · 安装与工作空间(预设) · 教程 03(无线 VG) · 教程 05(位置控制)