Skip to main content
Version : 3.5.x

Protocole WebSocket

Le canal de simulation est une connexion WebSocket sur le port 10001. Il assure la boucle commande/état en temps réel entre votre application et le service.

Règle fondamentale : une seule 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 push hors bande. La fréquence dépend entièrement de votre cadence d'envoi.


Étape 1 — État des lieux initial (premier message du service)

À la connexion, le service envoie un aperçu complet contenant 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 :

BlocContientModifications
configInformations sur le micrologiciel, préréglages, base, montage, filtresRarement — uniquement en cas de modification explicite de la configuration
statePosition, vitesse, force, orientation, transformationsÀ chaque impulsion (haute fréquence)
statusPrêt, calibré, alimenté, en cours d'utilisationDe temps en temps (rarement)

Étape 2 — Envoyez votre première commande

Analysez l'inventaire initial pour trouver l'identifiant de votre appareil, puis renvoyez un message contenant votre profil de session, toute configuration initiale 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 ultérieures de l'état

Après le premier échange, le service envoie uniquement state + status (non config) à moins qu'une modification de configuration ne déclenche la transmission d'un instantané complet :

{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": {}, "cursor_velocity": {},},
"status": { "ready": true, "calibrated": true,}
}
]
}

Étape 4 — Répétez l'opération

Envoyez une commande → recevez une mise à jour de l'état. La boucle se poursuit à votre fréquence d'envoi.


configure contre commands

Chaque entrée de périphérique dans votre message sortant peut contenir deux mappages :

CarteObjectifPersévérance
configureParamètres ponctuels : préréglage, base, montage, filtres, configuration du moduleOn s'en souviendra jusqu'à ce que cela change
commandsContrôle par impulsion : force, position, couplesOn l'applique une fois, puis on l'oublie

Voir Configuration de la session pour consulter la liste complète des configure touches, et Commandes de contrôle pour le commands entrées.

set_transform est un cas particulier

set_transform vit sous commands mais est persistant — le service conserve la dernière valeur jusqu'à ce que vous en envoyiez une nouvelle. En effet, il est destiné à la navigation dans les scènes, où l'on transmet en continu les transformations pendant le déplacement de la caméra, mais où l'on souhaite que la dernière position soit conservée entre deux pressions.


Les execute drapeau

N'importe quel configure ou commands une entrée peut inclure "execute": false pour mettre en place le service analyser et valider la charge utile sans l'appliquer.

{
"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, Unity's JsonUtility) qui transmettent toujours tous les champs : définir les entrées inutilisées sur execute: false afin qu'ils ne remplacent pas la configuration réelle. La valeur par défaut est true — l'absence de drapeau signifie « appliquer normalement ».


Avertissements

Ne lancez pas de requête si vous êtes déjà en train d'envoyer des commandes

probe_position et probe_orientation sont des messages de maintien de connexion à des fins de surveillance uniquement pour les sessions qui n'envoient pas de commandes de contrôle (par exemple, Haply ). Si votre session envoie déjà set_cursor_force, set_cursor_position, etc., n'envoyez pas non plus de sondes — l'état de l'appareil figure déjà dans chaque réponse. Combiner les deux gaspille de la bande passante et peut entraîner session-probe-dropped événements.

Les touches inconnues sont ignorées sans avertissement

Si une commande semble ne produire aucun effet, le nom du champ est probablement incorrect. Le service ignore actuellement les clés JSON non reconnues sans générer d'erreur. Consultez les journaux du service et vérifiez les noms de champs par rapport à la référence de l'API. Il est prévu de modifier ce comportement dans une prochaine version.