跳转至主要内容

05. 位置控制

通过以下方式控制Inverse3 的光标: set_cursor_position 到目标位置。 交互模型因编程语言的不同而有所差异 — C++ 使用一次性随机目标位置,而 Python 采用连续的、由键盘控制的移动方式。

您将学到:

  • 使用 set_cursor_position 用于位置模式下的控制
  • 针对同一底层命令的两种不同交互模型
  • 将目标限制在工作空间球体内——Minverse 使用的半径比Inverse3
  • 设置工作空间预设,使原点位于工作空间中心

流程​

C++(随机目标模型)​

  1. 启动一个后台输入线程,用于处理按行缓冲的键盘输入(n, +, -, q) 从标准输入(stdin)读取。
  2. 打开 WebSocket。在收到第一个状态帧时,注册 会议简介 并设置 configure.preset: arm_front_centered. 在一个球体内部生成第一个随机目标(拒绝采样,半径 0.08 米)。
  3. 每次 tick 时发送一个 set_cursor_position-向当前目标发送指令。光标会平稳地跟随它——该服务会限制速率并进行插值。
  4. 如果用户 n + 按下 ENTER 键时,输入线程会生成一个新的随机目标。通过 + / - 请调整速度; q 结束程序。

Python(长按即可移动的模型)​

  1. 打开 WebSocket。在第一个状态帧时进行检查 status.calibrated — 如果设备尚未校准,请提示用户进行校准。
  2. 请阅读 config.type aus,用于确定工作空间的半径(minverse = 0.04 米,其余所有数值 = 0.10 米)。
  3. 请注册该 会议简介 并设置 configure.preset: arm_front_centered.
  4. 每次时钟脉冲:查询键盘状态(W/A/S/D/Q/E),目标位置偏移 SPEED 沿每个按下的轴进行更新,限制在工作空间球体内,并 set_cursor_position 发送。 R 将目标重置为初始值。

参数​

名称默认值(C++)默认值(Python)Zweck
workspace_radius / RADIUS_INVERSE30.08 m0.10 m (Inverse3) / 0.04 m (Minverse)目标球的半径
speed_step / SPEED0.01 / 按键0.00005 m / 勾选每次交互的步长
PRINT_EVERY_MS—100遥测限速(Python)
会议简介co.haply.inverse.tutorials:position-controlgleich在Haply Hub中识别
校准测试(Python)

Python 版本会进行检查 status.calibrated 在第一个状态帧时,如果设备尚未校准,则会提示用户进行校准。C++ 版本则假设校准已经完成。

已读取的状态字段​

  • data.inverse3[0].device_id — 用于创建该命令
  • data.inverse3[0].state.cursor_position — 遥测
  • (Python,仅在第一帧) data.inverse3[0].config.type — 在Inverse3 半径和Minverse 半径之间进行选择
  • (Python,仅在第一帧) data.inverse3[0].status.calibrated — 如果该值为 false,则提示用户

发送 / 接收​

沟通流程​

  • C++ 运行一个后台 stdin 线程,该线程 std::atomic<float>-Ziele 负责写入数据;WebSocket 线程在每次 tick 时读取这些数据。在 n + 按下 ENTER 键后,输入线程会生成一个新的随机目标;当 q 这两个线程都将被终止。
  • Python 它是单线程且异步的——WebSocket 的循环会在每次 tick 时查询键盘状态并进行更新 position direkt.

Inverse-API 的有效数据完全相同:第一个数据点包含会话配置文件 + configure.preset,以下时间戳仅包含 set_cursor_position.

单个异步循环。键盘检测(handle_keys) 在每个 tick 时都会内联执行——无需线程。 config.type und status.calibrated 将从第一个状态帧中一次性读取。

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

if first_message:
first_message = False
device_id = data["inverse3"][0]["device_id"]
radius = get_workspace_radius(data["inverse3"][0].get("config", {}))
# Handshake: profile + preset (one-shot)
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": {"preset": {"preset": "arm_front_centered"}},
}],
}
else:
# Per tick: update position from keyboard (classic polling, not shown), send command
position = handle_keys(position, radius)
request_msg = {
"inverse3": [{
"device_id": device_id,
"commands": {"set_cursor_position": {"position": position}},
}],
}

await websocket.send(json.dumps(request_msg))
包含在 SDK 安装程序中

教程 05 会随 SDK 一起在本地安装——您可以在以下位置找到它: tutorials/05-haply-inverse-position-control/ 位于该服务的安装目录中。

来源: Python·C++·C++ Glaze

另见: 控制命令 (set_cursor_position) · 剪辑与工作区(预设) · 类型 (vec3) · 教程 06(综合)