09. Navigateur d'espace de travail WebSocket
Parcourez la position de l'espace de travail de l'appareil en temps réel en envoyant des commandes en continu set_transform sur le canal WebSocket. Le tutoriel utilise HTTP pour détecter la session et l'appareil (exactement comme le tutoriel 08), puis établit une connexion WebSocket pour transmettre les mises à jour de position à chaque cycle.
Cela illustre la différence entre deux opérations de transformation :
| Opération | Tutoriel | Utilisation typique |
|---|---|---|
configure.mount — transformation de montage persistante | 08 | Définie une seule fois (ou rarement) pour décrire la configuration physique de l'appareil |
set_transform — transformation continue de l'espace de travail | 09 (ce tutoriel) | Également persistante, mais pouvant être transmise en continu à chaque cycle pour permettre une navigation en temps réel dans l'espace de travail |
Ces deux commandes sont disponibles via HTTP et WebSocket, et toutes deux sont persistantes : le service enregistre la dernière valeur que vous avez envoyée. La différence réside dans l'objectif et la fréquence de mise à jour : configure.mount est optimisée pour des mises à jour peu fréquentes (installation physique), tandis que set_transform est optimisée pour une diffusion en continu à haute fréquence (navigation dans la scène).
Utilisez set_transform lorsque la position de l'espace de travail doit suivre un élément qui évolue au fur et à mesure de l'exécution : suivre un mouvement de la main, animer un décalage procédural ou permettre à un opérateur de déplacer l'espace de travail virtuel en temps réel.
Pris séparément, configure.mount et set_transform semblent produire le même effet, mais ils sont imbriqués : dans le pipeline de coordonnées, la transformation de l'espace de travail est appliquée par-dessus le montage (device → basis → mount → workspace → application). Voir Montage et espace de travail pour l'ensemble du pipeline.
Cas d'utilisation
- Navigation en temps réel dans l'espace de travail. Déplacez l'espace de travail du curseur de l'appareil (la zone délimitée couverte par l'effecteur) sans interrompre l'expérience haptique.
- Alignement piloté par un opérateur. Demandez à une personne, depuis un deuxième terminal, de maintenir les touches fléchées enfoncées pour décaler l'espace de travail pendant que l'application haptique principale est en cours d'exécution — cette fonction est utile pour l'étalonnage sur le poste de travail lors d'une session en direct.
- Déplacement procédural de l'espace de travail. Contrôlez la position de l'espace de travail à partir d'un script (réactif au son, basé sur la physique, etc.) en envoyant à chaque cycle des corrections de transformation ne portant que sur la position.
Prérequis
Le tutoriel 09 nécessite une session WebSocket active — un client disposant déjà d’ Inverse3 , dans une boucle haptique en cours d’exécution. Le tutoriel 09 se connecte ensuite à cette session et décale son espace de travail en temps réel.
Ouvrez l'Haply Hub et lancez la démo Orb. Elle ouvre une session haptique persistante que vous pouvez cibler immédiatement :
./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"
La scène Orb affiche une sphère au centre de l'espace de travail — déplacer l'espace de travail à l'aide du tutoriel n° 09 déplace l'ensemble de la scène en temps réel, ce qui vous offre un retour visuel instantané.
Tout autre tutoriel (du 01 au 07) qui exécute une boucle haptique fonctionne également. Lancez-le dans un premier terminal, puis démarrez le tutoriel 09 dans un deuxième terminal et laissez-le explorer la session de manière interactive.
Utilisation
# 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
Commandes
- Python
- C++
Maintenez une touche enfoncée pour vous déplacer en continu. Relâchez-la pour vous arrêter.
| Touche | Action |
|---|---|
→ / ← | +X / −X |
↑ / ↓ | +Y / −Y |
Page Up / Page Down | +Z / −Z |
= / - | Augmenter / réduire la vitesse de navigation |
0 | Réinitialiser l'espace de travail à son état d'origine |
H | Afficher l'aide |
Esc | Lâcheur (Ctrl+C (ça fonctionne aussi) |
Ligne par ligne : saisissez la commande, puis appuyez sur ENTRÉE.
| Commande | Action |
|---|---|
x+[N] / x-[N] | Régler la vitesse X à ±N mm/trame (x+ (utilise uniquement la vitesse par défaut actuelle) |
y+[N] / y-[N] | Régler la vitesse Y à ±N mm/trame |
z+[N] / z-[N] | Régler la vitesse Z à ±N mm/trame |
s+[N] / s-[N] | Régler la vitesse par défaut à ±N mm/trame |
stop | Remettre tous les compteurs à zéro |
reset | Remettre la vitesse à zéro et revenir au point de départ |
h | Afficher l'aide |
Appuyez sur Ctrl+C (ou Ctrl+D / EOF) pour quitter.
Fonctionnement
Étape 1 — HTTP : identification de la session et de l'appareil
Le tutoriel réutilise les mêmes fonctions utilitaires discover_session() / discover_device() que le tutoriel 08 : GET /sessions (ou GET /sessions/<selector> avec --session), puis GET /devices (ou utilisation directe de --device). Les deux fonctions acceptent les mêmes options en ligne de commande, avec un texte SESSION_HELP identique : un sélecteur issu du tutoriel 00 ou 08 fonctionne ici sans modification.
Étape 2 — Session WebSocket, négociation dès le premier message
Le tutoriel ouvre un WebSocket vers ws://localhost:10001. Au seul premier message reçu, il envoie l'enregistrement du profil de session :
{
"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}}}}}]
}
Les cases suivantes ne sont pas cochées session — uniquement le tableau de commande inverse3 est envoyé.
Étape 3 — set_transform à chaque tick
set_transform accepte une transformation partielle — uniquement les champs que vous souhaitez modifier. Ce tutoriel n'envoie que la position ; la rotation et l'échelle conservent leurs valeurs par défaut de la session (celles définies par configure.mount, le cas échéant).
{
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0.02, "y": 0.0, "z": 0.01}}}}}]
}
La position s'ajuste tick par tick. À environ 1 kHz, le service réapplique set_transform à chaque tick (ordre zéro), de sorte que l'espace de travail reste à la dernière position envoyée.
set_transform ou configure.mountCes deux commandes enregistrent une transformation persistante par session, mais la transformation de l'espace de travail s'effectue par-dessus le montage dans le pipeline (voir Montage et espace de travail). Pendant la diffusion du tutoriel n° 09 set_transform À chaque tick, chaque nouvelle trame WebSocket remplace la transformation de l'espace de travail diffusée précédemment ; ainsi, tout autre client qui diffuse set_transform vers le même instrument sera écrasée au tick suivant. configure.mount est indépendant et conserve sa valeur. En pratique, choisissez un canal par type de problème : le montage pour la configuration physique, set_transform pour la navigation en temps réel.
Modèle de threads (C++)
Le tutoriel C++ utilise deux threads qui partagent un compteur de position :
| Fil de discussion | Rôle |
|---|---|
| Fil de discussion principal | Lit std::getline(std::cin, ...), analyse les jetons, met à jour nav_vel[] et default_step |
| Thread de rappel WebSocket | A fait avancer nav_pos[] avec nav_vel[] * dt, sérialiser set_transform et l'envoie |
std::mutex nav_mutex protège nav_pos[], nav_vel[] et default_step. L'horodatage last_tick et l'indicateur first_ws_msg sont des fonctions locales au niveau de l'appel WS et ne nécessitent pas de 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
};
Source
Le tutoriel 09 est installé localement avec le SDK — consultez tutorials/09-haply-inverse-ws-remote-control/ dans le répertoire d'installation du service.
Voir aussi : commande set_transform · Sessions — négociation dès le premier message · Montage et espace de travail · Sélecteurs · Tutoriel 08 — Configuration HTTP à distance · Tutoriel 07 — Base et montage