跳转至正文

WebSocket 协议

模拟通道是端口 10001 上的WebSocket 连接。该通道用于在应用程序和服务之间传输实时命令/状态循环。

核心规则:一条消息对应一个响应​

该服务针对从客户端接收到的每条消息,都会发送且仅发送一次状态更新:

没有轮询、没有订阅、也没有带外推送。更新周期完全由客户端的发送频率决定。


第1步 — 初始库存(服务的首条消息)​

连接成功后,该服务将针对所有已检测到的设备 config, state, status包括……在内的 完整快照发送:

{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"config": {
"type": "inverse3",
"port": "COM12",
"device_info": { "major_version": 7, "minor_version": 4, "id": "049D", "device_type": 4, "uuid": "…" },
"extended_device_id": "…",
"extended_firmware_version": "…",
"gravity_compensation": { "enabled": true, "scaling_factor": 1.0 },
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": { "enabled": true },
"home_return": { "enabled": false },
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0.0 }
}
},
"state": {
"cursor_position": { "x": 0.0, "y": -0.12, "z": 0.15 },
"cursor_velocity": { "x": 0.0, "y": 0.0, "z": 0.0 },
"angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"angular_velocity": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"body_orientation": { "w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_force": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_angular_torques": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"current_angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"control_domain": "cartesian",
"control_mode": "idle",
"transform": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"transform_velocity": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 0, "y": 0, "z": 0 } }
},
"status": {
"calibrated": true,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}

这三个区块的更新频率各不相同:

区块包含内容变更频率
config固件信息、预设、基线、安装、滤光片很少见——仅在明确更改结构时
state位置、速度、力、方向、转换每秒(高频)
status就绪、已校准、电源已接通、正在使用中偶尔(低频)

第2步 — 发送第一个命令​

请解析初始库存以查找设备 ID,然后重新发送包含会话配置文件、初始配置和/或控制命令的消息:

{
"session": {
"configure": {
"profile": { "name": "co.haply.inverse.tutorials:hello-floor" }
}
},
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
},
"commands": {
"set_cursor_force": { "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
}
}
]
}

第3步 — 后续状态更新​

在首次交换之后,除非因配置变更而触发全局快照推送,否则该服务将 state + status仅传输(config (除外):

{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": { … }, "cursor_velocity": { … }, … },
"status": { "ready": true, "calibrated": true, … }
}
]
}

第4步 — 重复​

发送命令 → 接收状态更新。该循环将根据传输速度持续进行。


configure哇 commands的区别​

发送消息中的每个设备条目可能包含以下两种映射:

地图用途持久性
configure一次性设置:预设、基准、安装、滤镜、模块设置在变更前保持不变
commands步进控制:力、位置、转矩使用一次后丢弃

configure 密钥的完整列表如下: 会话配置을, commands 项目是 控制命令请参阅。

笔记
set_transform这属于例外情况

set_transform银 commands 虽然位于下方,但它是**持久型(persistent)**。该服务会在发送新值之前保留上一个值。这是因为该场景用于场景探索,在相机移动时需要一边流式传输变换值,一边在两次输入之间保持上一个位置。


execute 标志​

configure 或者 commands 在项目中 "execute": false如果包含该内容,则服务不会应用有效载荷, 仅限语法分析和验证 执行。

{
"inverse3": [{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front", "execute": true },
"damping": { "scalar": 0.0, "execute": false }
}
}]
}

这会始终输出所有字段 基于反射的序列化器(例如:Unity的 JsonUtility) 很有用。不使用的项目是 execute: false请将其设置为,以免覆盖实际配置。默认值为 true此外,如果省略该标志,则会“正常应用”。


警告​

如果已经发送了命令,请不要发送探针

probe_position和 probe_orientation这是专用于不发送控制命令的会话(例如:Haply Hub)的监控专用保持活动消息。如果会话已经 set_cursor_force, set_cursor_position 如果正背对着…… 请勿随附探针. 设备状态已包含在所有响应中。同时使用这两者会浪费带宽,并且 session-probe-dropped 可能会发生该事件。

未知键将被无错误地忽略

如果命令似乎没有任何效果,那么很可能是字段名称有误。该服务会无提示地忽略当前无法识别的 JSON 键。请检查服务日志,并核对API 参考文档中字段名称是否正确。此行为将在未来版本中进行更改。