Protocole WebSocket
Le canal de simulation est une connexion WebSocket sur le port 10001. Il assure la transmission en temps réel de la boucle de commandes et d'états entre votre application et le service.
Règle de base : une réponse par message
Le service envoie exactement une mise à jour d'état pour chaque message qu'il reçoit de votre client :
Il n'y a ni interrogation, ni abonnement, ni notification « hors bande ». La cadence est entièrement déterminée par votre fréquence d'émission.
Étape 1 — État des lieux initial (premier message du service)
Lors de l'établissement de la connexion, le service envoie un instantané complet mit config, state et status pour chaque appareil détecté :
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"config": {
"type": "inverse3",
"port": "COM12",
"device_info": { "major_version": 7, "minor_version": 4, "id": "049D", "device_type": 4, "uuid": "…" },
"extended_device_id": "…",
"extended_firmware_version": "…",
"gravity_compensation": { "enabled": true, "scaling_factor": 1.0 },
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": { "enabled": true },
"home_return": { "enabled": false },
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0.0 }
}
},
"state": {
"cursor_position": { "x": 0.0, "y": -0.12, "z": 0.15 },
"cursor_velocity": { "x": 0.0, "y": 0.0, "z": 0.0 },
"angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"angular_velocity": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"body_orientation": { "w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_force": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_angular_torques": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"current_angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"control_domain": "cartesian",
"control_mode": "idle",
"transform": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"transform_velocity": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 0, "y": 0, "z": 0 } }
},
"status": {
"calibrated": true,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
Ces trois blocs ont des fréquences de mise à jour différentes :
| Bloc | Contient | Fréquence des modifications |
|---|---|---|
config | Informations sur le micrologiciel, Préréglage, Base, Montage, Filtre | Rarement, uniquement en cas de modification explicite de la configuration |
state | Position, vitesse, force, orientation, transformations | À chaque impulsion (haute fréquence) |
status | Prêt, calibré, alimenté, en cours d'utilisation | De temps en temps (faible fréquence) |
Étape 2 — Envoyer la première commande
Analysez l'état des lieux initial pour trouver l'identifiant de votre appareil. Envoyez ensuite un message contenant votre profil de session, les éventuelles configurations initiales et/ou une commande de contrôle :
{
"session": {
"configure": {
"profile": { "name": "co.haply.inverse.tutorials:hello-floor" }
}
},
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
},
"commands": {
"set_cursor_force": { "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
}
}
]
}
Étape 3 — Mises à jour d'état ultérieures
Après le premier échange, le service n'envoie plus que state + status (sans config), sauf si une modification de configuration déclenche un transfert complet de l'instantané :
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": { … }, "cursor_velocity": { … }, … },
"status": { "ready": true, "calibrated": true, … }
}
]
}
Étape 4 — Répéter
Envoyez une commande → Vous recevrez une mise à jour de l'état. La boucle continue de fonctionner à votre fréquence d'émission.
configure contre commands
Chaque entrée relative à un appareil dans votre message sortant peut contenir deux cartes :
| Carte | Objet | Persistance |
|---|---|---|
configure | Réglages uniques : préréglages, réglages de base, montage, filtres, configuration des modules | Sera conservé jusqu'à ce qu'il soit modifié |
commands | Commande par impulsion : force, position, couples | On l'utilise une fois, puis on l'oublie |
La liste complète des configure-Vous trouverez les clés sous Configuration de session, et la commands- Entrées sous Commandes de contrôle.
set_transform est un cas particulierset_transform fait partie de commands, mais c'est persistant — Le service conserve la dernière valeur jusqu’à ce que vous en envoyiez une nouvelle. En effet, son rôle est de permettre la navigation entre les scènes : vous transmettez les transformations en continu pendant un déplacement de caméra, mais vous souhaitez que la dernière position soit conservée entre deux entrées.
Le drapeau execute
Chaque entrée configure ou commands peut "execute": false contenues afin que le service puisse traiter la charge utile analysé et validé, sans les mettre en pratique.
{
"inverse3": [{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front", "execute": true },
"damping": { "scalar": 0.0, "execute": false }
}
}]
}
Cela est utile pour Sérialiseurs basés sur la réflexion (par exemple JsonUtility dans Unity), qui affichent toujours tous les champs : définissez les entrées inutilisées sur execute: false, afin qu'ils ne remplacent pas une configuration existante. La valeur par défaut est true — Si l'indicateur n'est pas spécifié, cela signifie « application normale ».
Avertissements
probe_position et probe_orientation Il s'agit de simples messages de maintien de connexion destinés à la surveillance des sessions qui n'envoient aucune commande de contrôle (par exemple, le concentrateur « Haply »). Si votre session est déjà set_cursor_force, set_cursor_position etc., envoie, N'envoyez pas d'échantillons supplémentaires — L'état de l'appareil est de toute façon indiqué dans chaque réponse. Faire les deux en même temps gaspille de la bande passante et peut session-probe-dropped- Déclencher des événements.
Si une commande semble ne produire aucun effet, c'est probablement que le nom du champ est incorrect. Le service ignore actuellement les clés JSON inconnues sans afficher de message d'erreur. Vérifiez les journaux du service et comparez les noms de champs avec la documentation de l'API. Ce comportement devrait être modifié dans une prochaine version.