09. WebSocket Workspace-Navigator
Navigieren Sie die Workspace-Position eines Geräts in Echtzeit, indem Sie set_transform-Befehle über den WebSocket-Kanal streamen. Das Tutorial verwendet HTTP, um Session und Gerät zu ermitteln (genau wie Tutorial 08), und öffnet anschließend eine WebSocket-Verbindung, um bei jedem Tick Positionsaktualisierungen zu senden.
Dies veranschaulicht den Unterschied zwischen zwei Transformationsoperationen:
| Operation | Tutorial | Typische Verwendung |
|---|---|---|
configure.mount — persistente Mount-Transformation | 08 | Einmal (oder selten) setzen, um die physische Montage des Geräts zu beschreiben |
set_transform — persistente Workspace-Transformation | 09 (dieses) | Ebenfalls persistent, kann aber bei jedem Tick für die Echtzeit-Navigation im Workspace gestreamt werden |
Beide Befehle sind über HTTP und WebSocket verfügbar, und beide sind persistent — der Dienst merkt sich den zuletzt gesendeten Wert. Der Unterschied liegt in Zweck und Aktualisierungsrate: configure.mount ist für seltene Aktualisierungen optimiert (physische Einrichtung), während set_transform für hochfrequentes Streaming (Szenennavigation) optimiert ist.
Verwenden Sie set_transform, wenn der Workspace-Ursprung einer Größe folgen soll, die sich zur Laufzeit ändert, etwa einer Hand, einem animierten prozeduralen Versatz oder einer Bedienperson, die den virtuellen Workspace live verschiebt.
Für sich genommen scheinen configure.mount und set_transform denselben Effekt zu erzeugen, sie sind aber hierarchisch verknüpft: Die Workspace-Transformation wird in der Koordinaten-Pipeline auf den Mount angewendet (device → basis → mount → workspace → application). Die vollständige Pipeline finden Sie unter Mount & Workspace.
Anwendungsfälle
- Live-Navigation im Workspace. Verschieben Sie den Cursor-Workspace des Geräts (den Begrenzungsbereich, den der Endeffektor erreichen kann), ohne die haptische Szene anzuhalten.
- Vom Bediener gesteuerte Ausrichtung. Lassen Sie eine Person in einem zweiten Terminal die Pfeiltasten gedrückt halten, um den Workspace zu verschieben, während die haptische Hauptanwendung läuft — nützlich für die Kalibrierung am jeweiligen Arbeitsplatz während einer laufenden Session.
- Prozedurale Workspace-Bewegung. Steuern Sie die Workspace-Position aus einem Skript heraus (audiogesteuert, physikbasiert usw.), indem Sie bei jedem Tick reine Positions-Transform-Patches senden.
Voraussetzungen
Tutorial 09 benötigt eine aktive WebSocket-Session, also einen Client, dessen Inverse3 bereits in einer laufenden haptischen Schleife aktiv ist. Tutorial 09 hängt sich dann an diese Session an und verschiebt deren Workspace live.
Öffnen Sie Haply Hub und starten Sie die Orb-Demo. Sie öffnet eine persistente haptische Session, die Sie sofort ansprechen können:
./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"
Die Orb-Szene rendert eine Kugel im Ursprung des Workspace — wenn Sie den Workspace mit Tutorial 09 verschieben, verschiebt sich die gesamte Szene in Echtzeit, sodass Sie sofortiges visuelles Feedback erhalten.
Jedes andere Tutorial (01 – 07), das eine haptische Schleife ausführt, funktioniert ebenfalls. Starten Sie es in einem Terminal und starten Sie anschließend Tutorial 09 in einem zweiten Terminal, damit es die Session interaktiv erkennt.
Verwendung
# 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
Steuerung
- Python
- C++
Halten Sie eine Taste gedrückt, um sich kontinuierlich zu bewegen. Loslassen, um anzuhalten.
| Taste | Aktion |
|---|---|
→ / ← | +X / −X |
↑ / ↓ | +Y / −Y |
Page Up / Page Down | +Z / −Z |
= / - | Navigationsgeschwindigkeit erhöhen / verringern |
0 | Workspace auf den Ursprung zurücksetzen |
H | Hilfe anzeigen |
Esc | Beenden (Ctrl+C funktioniert ebenfalls) |
Zeilenbasiert — Befehl eingeben und anschließend ENTER drücken.
| Befehl | Aktion |
|---|---|
x+[N] / x-[N] | X-Geschwindigkeit auf ±N mm/Frame setzen (ohne Zahl verwendet x+ die aktuelle Standardgeschwindigkeit) |
y+[N] / y-[N] | Y-Geschwindigkeit auf ±N mm/Frame setzen |
z+[N] / z-[N] | Z-Geschwindigkeit auf ±N mm/Frame setzen |
s+[N] / s-[N] | Standardgeschwindigkeit um ±N mm/Frame anpassen |
stop | Alle Geschwindigkeiten auf null setzen |
reset | Geschwindigkeit auf null setzen und zum Ursprung zurückkehren |
h | Hilfe anzeigen |
Drücken Sie Ctrl+C (oder Ctrl+D / EOF), um das Programm zu beenden.
Funktionsweise
Schritt 1 — HTTP-Session- und Geräteerkennung
Das Tutorial verwendet dieselben Hilfsfunktionen discover_session() / discover_device() wie Tutorial 08: GET /sessions (oder GET /sessions/<selector> mit --session), danach GET /devices (oder direkt --device verwenden). Beide Hilfsfunktionen akzeptieren dieselben CLI-Flags mit identischem SESSION_HELP-Text — ein Selektor aus Tutorial 00 oder 08 funktioniert hier unverändert.
Schritt 2 — WebSocket-Session, Handshake bei der ersten Nachricht
Das Tutorial öffnet eine WebSocket-Verbindung zu ws://localhost:10001. Nur bei der ersten empfangenen Nachricht sendet es die Registrierung des Session-Profils:
{
"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}}}}}]
}
Nachfolgende Ticks lassen session weg — gesendet wird nur das Befehls-Array inverse3.
Schritt 3 — set_transform pro Tick
set_transform akzeptiert eine partielle Transformation, also nur die Felder, die Sie ändern möchten. Dieses Tutorial sendet ausschließlich die Position; Rotation und Skalierung bleiben auf den Session-Standardwerten (den Werten, die gegebenenfalls durch configure.mount gesetzt wurden).
{
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0.02, "y": 0.0, "z": 0.01}}}}}]
}
Die Position summiert sich Tick für Tick. Mit etwa 1 kHz wendet der Dienst set_transform bei jedem Tick erneut an (Zero-Order-Hold), sodass der Workspace dort bleibt, wohin Sie ihn zuletzt verschoben haben.
set_transform vs configure.mountBeide Befehle speichern pro Session eine persistente Transformation. Die Workspace-Transformation liegt in der Pipeline jedoch auf dem Mount (siehe Mount & Workspace). Solange Tutorial 09 bei jedem Tick set_transform streamt, ersetzt jeder neue WebSocket-Frame die zuvor gestreamte Workspace-Transformation. Ein anderer Client, der set_transform an dasselbe Gerät streamt, wird daher beim nächsten Tick überschrieben. configure.mount ist davon unabhängig und behält seinen Wert. In der Praxis sollten Sie pro Anliegen einen Kanal wählen: Mount für die physische Einrichtung, set_transform für die Live-Navigation.
Threading-Modell (C++)
Das C++-Tutorial verwendet zwei Threads, die sich einen Positionsakkumulator teilen:
| Thread | Rolle |
|---|---|
| Haupt-Thread | Liest std::getline(std::cin, ...), parst Tokens, aktualisiert nav_vel[] und default_step |
| WebSocket-Callback-Thread | Schreibt nav_pos[] um nav_vel[] * dt fort, serialisiert set_transform und sendet |
std::mutex nav_mutex schützt nav_pos[], nav_vel[] und default_step. Der Zeitstempel last_tick und das Flag first_ws_msg sind lokal im WS-Callback und benötigen keinen Mutex.
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
};
Quelle
Tutorial 09 wird lokal mit dem SDK installiert — Sie finden es unter tutorials/09-haply-inverse-ws-remote-control/ im Installationsverzeichnis des Dienstes.
Verwandte Themen: Befehl set_transform · Sitzungen — Handshake mit der ersten Nachricht · Mount & Workspace · Selektoren · Tutorial 08 — HTTP-Remote-Konfiguration · Tutorial 07 — Basis & Mount