09. WebSocket 工作区导航器
set_transform 通过 WebSocket 通道流式传输命令,从而使设备能够 实时显示工作区位置 进行探索。本教程将基于 HTTP 探索会话和设备(教程 08(与……完全相同的方式),随后打开 WebSocket 连接,以便在每个时间步长发送位置更新。
下表展示了两种转换运算之间的区别:
| 运算 | 教程 | 一般用途 |
|---|---|---|
configure.mount — 永久挂载转换 | 08 | 为说明设备的物理安装,需进行一次(或极少)设置 |
set_transform — 永久工作区转换 | 09(本教程) | 虽然也是永久性的,但可以每帧进行流式传输,以便实时浏览工作区 |
这两个命令都 HTTP 和 WebSocket 可在该环境中使用,两者均可 永久的是的。该服务会记住上次发送的值。这两个命令的区别在于用途和更新频率。 configure.mount虽然它针对不频繁的更新(物理设置)进行了优化,但, set_transform该功能专为高频流媒体播放(场景跳转)进行了优化。
当需要追踪工作区原点在运行时发生变化的对象时 set_transform请使用该功能。例如,在追踪手部动作、通过动画实现程序化偏移,或让操作员实时微调虚拟工作区时,均可使用该功能。
从个别情况来看 configure.mount哇 set_transform虽然看起来效果相同,但这两个值 亲子关系是。坐标管道(device → basis → mount → workspace → application) 中的工作区转换即挂载 上面 适用。整个管道是 挂载与工作区请参阅。
用例
- 实时工作空间导航。在不中断触觉场景的情况下,移动设备的光标工作空间(末端执行器能够到达的边界区域)。
- 由操作员主导的对齐。在主触觉应用运行期间,允许另一位用户在第二台终端上按方向键来移动工作区。这在实时会话中对进行用户级工作台校准非常有用。
- 基于流程的工作区运动。每帧发送仅包含位置信息的变换补丁,以通过脚本(如音频响应型、基于物理的脚本等)驱动工作区的位置。
先决条件
教程 09 需要一个活跃的 WebSocket 会话。也就是说,必须是一个正在运行的、在触觉循环中使用 Inverse3 的客户端。教程 09 会连接到该会话,然后实时移动工作区。
Haply 请打开Hub并运行Orb演示程序。随后将打开一个可立即指定目标的持久性触觉会话:
./09-haply-inverse-ws-remote-control --session co.haply.hub::demo-orb
python 09-haply-inverse-ws-remote-control.py --session "co.haply.hub::demo-orb"
“Orb”场景会在工作区原点处渲染一个球体。将工作区移动到教程 09 所在位置时,整个场景会实时移动,从而提供即时视觉反馈。
其他关于运行 Haptic Loop 的教程(01 – 07)也都正常工作。请先在一个终端中启动这些教程,然后在第二个终端中运行教程 09,以便以交互方式浏览该会话。
使用方法
# Discover session interactively, use first detected device
./09-haply-inverse-ws-remote-control
python 09-haply-inverse-ws-remote-control.py
# Target the Haply Hub Orb demo directly
./09-haply-inverse-ws-remote-control --session co.haply.hub::demo-orb
python 09-haply-inverse-ws-remote-control.py --session "co.haply.hub::demo-orb"
# Target a session directly, specify device
./09-haply-inverse-ws-remote-control --session :my_profile:0 --device A14
python 09-haply-inverse-ws-remote-control.py --session "#42" --device A14
操作方法
- Python
- C++
按住按键即可连续移动。松开按键即停止。
| 键 | 动作 |
|---|---|
→ / ← | +X / −X |
↑ / ↓ | +Y / −Y |
Page Up / Page Down | +Z / −Z |
= / - | 提高/降低搜索速度 |
0 | 将工作区重置为初始状态 |
H | 显示帮助 |
Esc | 结束 (Ctrl+C(也称为) |
这是逐行输入模式。输入命令后,请按 ENTER 键。
| 命令 | 动作 |
|---|---|
x+[N] / x-[N] | 将X轴速度设置为±N毫米/帧(x+(只需输入即可使用当前默认速度) |
y+[N] / y-[N] | 将Y速度设置为±N毫米/帧 |
z+[N] / z-[N] | 将Z轴速度设置为±N毫米/帧 |
s+[N] / s-[N] | 将基本速度调整为±N mm/帧 |
stop | 将所有速度设置为0 |
reset | 将速度设置为0,并返回原点 |
h | 显示帮助 |
如需退出,请按Ctrl+C(或 Ctrl+D / EOF)。
工作原理
第1步 — HTTP会话与设备识别
本教程是 教程 08与……相同 discover_session() / discover_device() 重复使用助手。 GET /sessions(或 --session与……一起使用 GET /sessions/<selector>) 调用后, GET /devices调用或 --device直接使用。这两个辅助函数是相同的 SESSION_HELP 它会接收与文本相同的 CLI 标志,教程 00 或 08 中的选择器在此处也能直接使用,无需修改。
第2步 — WebSocket 会话,首次消息握手
本教程是 ws://localhost:10001通过 WebSocket 建立连接。 仅针对首次收到的消息 发送会话配置文件信息:
{
"session": {"configure": {"profile": {"name": "co.haply.inverse.tutorials:ws-remote-control"}}},
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0, "y": 0, "z": 0}}}}}]
}
此后,在Tik上 session省略, inverse3 仅传输命令数组。
第3步 — 每次点击 set_transform 执行
set_transform银 部分转换允许这样做。也就是说,只需指定要更改的字段即可。本教程仅传输位置,而旋转和缩放则采用会话默认值(如果已设置的话 configure.mount (命令中指定的值)将保持不变。
{
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0.02, "y": 0.0, "z": 0.01}}}}}]
}
位置以 tick 为单位累积。在约 1 kHz 的频率下,该服务每 tick 都会 set_transform重新应用该操作(零阶保持)。因此,工作区将保持在最后传输的位置。
set_transform和 configure.mount的区别这两个命令都会按会话存储永久转换,但在管道中,工作区转换会挂载 上面 被放置(挂载与工作区 (参见)。教程 09 每帧都会 set_transform在流式传输期间,每当收到新的 WebSocket 帧时,之前流式传输的工作区转换都会被替换。因此,在同一台设备上 set_transform正在流式传输该内容的其他客户端将在下一个时钟周期被覆盖。 configure.mount是独立的,并保持其自身的值。在实际操作中,请为每个关注点选择一个通道。物理设置请使用“挂载”,实时浏览请使用 set_transform使用。
线程模型(C++)
该 C++ 教程使用了两个共享位置累加器的线程:
| 主题 | 角色 |
|---|---|
| 主线程 | 读取输入(std::getline(std::cin, ...)),令牌解析, nav_vel[] 以及 default_step 更新 |
| WebSocket 回调线程 | nav_vel[] * dt 使用该值 nav_pos[]并推进, set_transform将其序列化后传输 |
std::mutex nav_mutex是 nav_pos[], nav_vel[], default_step进行保护。 last_tick 时间戳和 first_ws_msg 由于标志(flag)是仅限于 WS 回调范围内的局部变量,因此不需要互斥锁。
ws.onmessage = [&](const std::string &) {
float pos_snap[3];
{
std::lock_guard<std::mutex> lk(nav_mutex);
for (int i = 0; i < 3; ++i) nav_pos[i] += nav_vel[i] * 0.001f; // mm/frame → m
for (int i = 0; i < 3; ++i) pos_snap[i] = nav_pos[i];
}
// build and send set_transform with pos_snap
};
源代码
教程 09 会随 SDK 一起安装在本地。位于服务安装目录下的 tutorials/09-haply-inverse-ws-remote-control/请在……处查看。
相关文档: set_transform 命令 · 会话 — 首次消息握手 · 挂载与工作区 · 选择器 · 教程 08 — HTTP 远程配置 · 教程 07 — Basis 和挂载