跳到主要内容

01. 打印 Inverse3

连接到仿真 WebSocket,并持续接收服务报告的第一个 Inverse3 的光标位置、速度和力的数据。

您将学到:

  • 建立 WebSocket 连接并接收初始的完整状态消息
  • 发送零力的 set_cursor_force 保活指令,使会话持续运行
  • 注册会话配置文件,以便 Haply Hub 识别您的仿真
  • 仅在第一条消息中进行握手的模式——首次发送后去掉 session/configure
  • 按部分更新语义读取工作空间的 transform(位置、旋转、缩放)
  • 将控制台输出限制在可读的频率

工作流程​

  1. 打开到 ws://localhost:10001 的 WebSocket。服务会立即推送一个完整状态帧,其中列出已连接的设备。
  2. 在收到第一帧时,选取第一个 Inverse3 的 device_id,并构建包含两部分的请求消息:
    • session.configure.profile.name —— 向Haply Hub注册该仿真。
    • 针对每个设备的 set_cursor_force 指令,力向量为零。服务将其用作保活信号——只要持续收到指令,服务就会持续发出状态帧。
  3. 将消息发回。在下一个周期之前去掉 session 字段——会话配置文件只是一次性握手;后续周期仅发送指令。
  4. 对之后的每一个状态帧:以约 10 Hz 的频率限速打印光标的 vec3 字段(位置、速度、力),并重新发送零力保活指令。

参数​

名称默认值用途
URIws://localhost:10001仿真通道 WebSocket 的 URL
PRINT_EVERY_MS100控制台输出限速
会话配置文件名称co.haply.inverse.tutorials:print-inverse3在 Haply Hub 中标识该仿真

读取的状态字段​

读取自 data.inverse3[0].state:

  • cursor_position、cursor_velocity、current_cursor_force —— 均为 vec3
  • transform —— 工作空间变换;为子对象,包含 position(vec3)、rotation(quaternion)和 scale(vec3)
部分更新语义

等于其单位默认值的子字段(position: {0,0,0}、rotation: {w:1,x:0,y:0,z:0}、scale: {1,1,1})为节省带宽,会从负载中省略。读取时务必提供默认值(例如在 C++ 中使用 .value("position", default_pos),在 Python 中使用 .get("position", default_pos))。若要始终接收每个字段,请启用 serialization/explicit_fields。

发送 / 接收​

WebSocket 循环:接收一个状态帧,构建并发回一个指令帧。第一个指令帧携带会话握手信息以及零力的 set_cursor_force 保活指令;此后每一帧仅携带保活指令(会话信息已去掉)。

单一异步循环——recv() → 构建指令 → send() → 重复。

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"]
request_msg = {
"session": {"configure": {"profile": {
"name": "co.haply.inverse.tutorials:print-inverse3"}}},
"inverse3": [{
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": 0.0, "z": 0.0}}},
}]
}

await websocket.send(json.dumps(request_msg))
request_msg.pop("session", None) # one-shot handshake

命令行参数(Python)​

Python 变体接受两个参数,用于更改教程的输出内容:

参数作用
--full以格式化方式输出每个状态帧中原始的 JSON 负载数据,而非单行摘要。便于了解服务会输出哪些字段。
--query-config在每个发出的周期重新注入 session.force_render_full_state: {},使服务在每一帧中都重新输出完整快照(包括 config 块——设备类型、固件、预设、安装方式、过滤器等)。若不使用该参数,config 仅在第一帧中出现,后续帧均为流式增量数据。

两个参数可以组合使用——python 01-haply-inverse-print-inverse3.py --full --query-config 会在每个周期输出包含可见 config 的完整 JSON 负载数据,在通过 Haply Hub 或 HTTP API 实时观察设置变化时非常实用。底层 WebSocket 命令请参阅 session.force_render_full_state。

C++ 变体不支持这些参数——它们始终只输出单行摘要,且 config 仅在第一帧中接收。

随 SDK 安装程序一同提供

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

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

相关内容: WebSocket 协议 · 控制命令(set_cursor_force) · 会话 · 类型(vec3)