09. WebSocket 工作区导航器
通过 WebSocket 通道 set_transform 通过流式传输命令,设备的实时导航至工作区位置可以。在本教程中,我们将使用 HTTP 来检测会话和设备(教程08 (方法与上述完全相同)。随后,打开 WebSocket,并每隔一个 tick 发送一次位置更新。
这展示了两种转换操作之间的区别:
| 操作 | 教程 | 典型应用 |
|---|---|---|
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中移动工作区时,整个场景会实时随之移动,因此可以立即获得视觉反馈。
其他执行触觉循环的教程(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 mm/帧 |
z+[N] / z-[N] | 将Z轴速度设置为 ±N mm/帧 |
s+[N] / s-[N] | 将既定速度调整为 ±N 毫米/帧 |
stop | 将所有速度设为零 |
reset | 将速度设为零,并返回原点 |
h | 显示帮助 |
按下Ctrl+C(或 Ctrl+D / EOF)即可退出。
运作机制
步骤 1 — 检测 HTTP 会话和设备
本教程旨在,教程08 与……相同 discover_session() / discover_device() 将复用该辅助函数。首先 GET /sessions(--session 若要指定时 GET /sessions/<selector>),接着 GET /devices(或 --device (直接使用)进行调用。这两个辅助函数都使用相同的 CLI 标志和相同的 SESSION_HELP 为了接收文本,您可以在这里继续使用教程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}}}}}]
}
在随后的 tick 中 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 和 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 标志是 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 — 底座与安装座