跳转至主要内容

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. 每个周期发送一条命令 set_cursor_position 指向当前目标。光标会平滑地跟随目标——该服务会限制数据流速并对位置进行插值。
  4. 当用户输入时 n 然后是“ENTRÉE”,输入线程会生成一个新的随机目标。 + / - 调整速度; q 退出。

Python(保持位移模型)​

  1. 打开 WebSocket。在收到第一个状态帧时,请检查 status.calibrated — 如果设备尚未校准,则向用户显示提示。
  2. 请阅读 config.type 选择工作区的半径(minverse = 0.04 米,其他所有值 = 0.10 米)。
  3. 保存 会话配置文件 并设置 configure.preset: arm_front_centered.
  4. 在每个循环中:查询键盘状态(W/A/S/D/Q/E),将目标从 SPEED 沿每个插入的轴线,将其限制在工作空间的球体内,然后发送 set_cursor_position. R 将目标重置为原点。

参数​

Nom默认值(C++)默认值(Python)角色
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-control完全相同支持在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 — 如果该值为假,则向用户显示一条提示信息

发送与接收​

报告安排​

  • C++ 运行一个后台进程,该进程读取标准输入并写入目标 std::atomic<float> ; WebSocket 线程会在每个循环中读取这些数据。在 n 然后是 ENTRÉE,输入线程会生成一个新的随机目标;在 q,两个儿子停了下来。
  • Python 这是异步且单线程的——WebSocket循环在每个周期都会查询键盘状态并更新 position 直接。

Inverse-API 的有效载荷与之相同:第一个循环传输会话配置文件,并且 configure.preset,而后续周期仅运输 set_cursor_position.

独特的异步循环。键盘查询(handle_keys) 在每个循环周期中直接在循环内执行——无需执行线程。 config.type et 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(综合)