跳转至主要内容

09. WebSocket 工作区浏览器

浏览 设备工作空间的实时位置 通过持续发送命令 set_transform 通过 WebSocket 通道。本教程使用 HTTP 来检测会话和设备(与 教程 08),然后建立一个 WebSocket 连接,用于在每个周期中传输位置更新。

这说明了两种转换操作之间的区别:

行动教程典型用法
configure.mount — 持久化编辑转换08仅需定义一次(或极少定义)即可描述设备的物理组装情况
set_transform — 工作区的持续转换09(本教程)同样是持久性的,但可以在每个循环中持续传输,以便在工作区中进行实时导航

这两项命令可通过以下方式使用: HTTP 和 WebSocket,而且这两者都是 常绿植物 : 该服务会记住您发送的最后一个值。两者的区别在于更新目的和更新频率: configure.mount 该方案针对更新频率较低的情况进行了优化(物理安装),而 set_transform 该功能针对高频流式传输(场景浏览)进行了优化。

请使用 set_transform 当工作区的起始位置需要跟随运行时发生变化的对象时:例如跟随一只手、实现过程化偏移动画,或者允许操作员实时移动虚拟工作区。

剪辑与工作空间是相互交织的

单独来看, configure.mount et set_transform 看似产生了相同的效果,但它们是 相互交错的 : 在坐标管道中,会应用工作空间变换 par-dessus 剪辑 (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 移动工作区会实时移动整个场景,从而为您提供即时视觉反馈。

任何其他执行触觉循环的教程(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:会话和设备的识别​

本教程复用了相同的辅助函数 discover_session() / discover_device() que le 教程 08 : GET /sessions (ou GET /sessions/<selector> avec --session),然后 GET /devices (或直接使用 --device). 这两个函数支持相同的命令行选项,其中包含一段文本 SESSION_HELP 完全相同:来自教程 00 或 08 的选择器在此处无需修改即可正常工作。

步骤 2 — WebSocket 会话,首次消息协商​

本教程会打开一个连接到 ws://localhost:10001. Au. 简体中文(大陆) 仅收到第一条消息, 它会发送会话配置文件的记录:

{
"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}}}}}]
}

以下项目未包含 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}}}}}]
}

该位置是逐个时钟周期累积而成的。在约 1 kHz 时,该服务会重新应用 set_transform 在每个时钟周期(保持零阶),使得工作区保持在最后发送的位置。

set_transform ou configure.mount

这两个命令都会为每个会话保存一个持久的转换,但工作区的转换会位于 par-dessus 管道中的编辑(参见 剪辑与工作区). 在教程09播放期间 set_transform 在每个时钟周期内,每个新的 WebSocket 帧都会替换之前广播的工作区转换;因此,任何其他正在广播的客户端 set_transform 针对同一设备的该订单将在下一个价格跳动时被覆盖。 configure.mount 它是独立的,并能保持其价值。实际上,应针对每个关注点选择一个通道:例如,物理配置使用“安装”通道, set_transform 用于实时导航。

线程模型(C++)​

该 C++ 教程使用了两个线程,它们共享一个位置累加器:

主题角色
线程主体Lit std::getline(std::cin, ...), 分析代币, 更新 nav_vel[] et default_step
WebSocket 回调线程推动进展 nav_pos[] avec nav_vel[] * dt, 序列化 set_transform 并将其发送

std::mutex nav_mutex protège nav_pos[], nav_vel[] et default_step. 时间戳 last_tick 以及该指标 first_ws_msg 它们在 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/ 在服务安装目录中。

另请参阅: commande set_transform · 会话——首次消息的协商 · 剪辑与工作区 · 选择器 · 教程 08 — 远程 HTTP 配置 · 教程 07 — 基础与组装