跳转至正文

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

操作方法​

按住按键即可连续移动。松开按键即停止。

键动作
→ / ←+X / −X
↑ / ↓+Y / −Y
Page Up / Page Down+Z / −Z
= / -提高/降低搜索速度
0将工作区重置为初始状态
H显示帮助
Esc结束 (Ctrl+C(也称为)

工作原理​

第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
};

源代码​

随SDK安装程序一起提供

教程 09 会随 SDK 一起安装在本地。位于服务安装目录下的 tutorials/09-haply-inverse-ws-remote-control/请在……处查看。

相关文档: set_transform 命令 · 会话 — 首次消息握手 · 挂载与工作区 · 选择器 · 教程 08 — HTTP 远程配置 · 教程 07 — Basis 和挂载