Aller au contenu principal

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 :

BlocContientFréquence des modifications
configInformations sur le micrologiciel, Préréglage, Base, Montage, FiltreRarement, 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 (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 :

CarteObjetPersistance
configureRéglages uniques : préréglages, réglages de base, montage, filtres, configuration des modulesSera conservé jusqu'à ce qu'il soit modifié
commandsCommande par impulsion : force, position, couplesOn 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.

Remarque
set_transform est un cas particulier

set_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​

N'envoyez pas de tests si vous envoyez déjà des commandes

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.

Les clés inconnues sont automatiquement ignorées.

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.