WebSocket-Protokoll
Der Simulationskanal ist eine WebSocket-Verbindung über Port 10001. Dieser Kanal überträgt die Echtzeit-Befehls- und Status-Schleife zwischen der Anwendung und dem Dienst.
Grundregel: Eine Antwort pro Nachricht
Der Dienst sendet für jedevom Client empfangene Nachricht genau eine Statusaktualisierung:
Es gibt weder Polling noch Abonnements noch Push-Benachrichtigungen außerhalb des Bandbreitenbereichs. Der Aktualisierungsrhythmus hängt ausschließlich von der Übertragungshäufigkeit des Clients ab.
Schritt 1 – Erstinventar (die erste Nachricht des Dienstes)
Sobald die Verbindung hergestellt ist, führt der Dienst für alle erkannten Geräte folgende Schritte durch: config, state, statuseinschließlich Gesamtübersichtübermittelt:
{
"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": []
}
Die drei Blöcke werden in unterschiedlichen Abständen aktualisiert:
| Block | Lieferumfang | Änderungshäufigkeit |
|---|---|---|
config | Firmware-Informationen, Voreinstellungen, Basis, Halterung, Filter | Selten – nur bei expliziten Konfigurationsänderungen |
state | Position, Geschwindigkeit, Kraft, Richtung, Umrechnung | Matik (Hochfrequenz) |
status | Bereit, kalibriert, Stromversorgung, in Betrieb | gelegentlich (selten) |
Schritt 2 – Übertragung des ersten Befehls
Analysieren Sie den Anfangsbestand, um die Geräte-ID zu ermitteln, und senden Sie anschließend eine Nachricht mit dem Sitzungsprofil, der Anfangskonfiguration und/oder Steuerbefehlen zurück:
{
"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 } }
}
}
]
}
Schritt 3 – Nachfolgende Statusaktualisierung
Nach dem ersten Austausch wird der Dienst, sofern keine vollständige Snapshot-Übertragung aufgrund von Konfigurationsänderungen erfolgt, state + statusEs werden nur (config (Ausgenommen):
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": { … }, "cursor_velocity": { … }, … },
"status": { "ready": true, "calibrated": true, … }
}
]
}
Schritt 4 – Wiederholung
Befehlsübertragung → Empfang einer Statusaktualisierung. Der Zyklus wird entsprechend der Übertragungsgeschwindigkeit fortgesetzt.
configureWow commandsDer Unterschied
Jeder Geräteeintrag in der gesendeten Nachricht kann die folgenden beiden Zuordnungen enthalten:
| Karte | Verwendungszweck | Beständigkeit |
|---|---|---|
configure | Einmalige Einstellungen: Voreinstellungen, Basis, Halterung, Filter, Moduleinstellungen | Bis zur Änderung beibehalten |
commands | Steuerung in Tick-Schritten: Kraft, Position, Drehmomente | Nach einmaliger Anwendung entsorgen |
configure Die vollständige Liste der Schlüssel finden Sie unter Aufbau der Sitzung을, commands Die Punkte sind SteuerbefehlSiehe dazu.
set_transformDas ist ein Ausnahmefall.set_transform은 commands Es befindet sich zwar unten, ist aber **persistent**. Der Dienst behält den letzten Wert bei, bis ein neuer Wert gesendet wird. Dies dient der Szenenerkundung, bei der die Kamera sich bewegt und gleichzeitig die Transformationswerte streamt, während die letzte Position zwischen den Eingaben beibehalten werden soll.
execute Flagge
configure oder commands unter dem Punkt "execute": falseWenn man dies einbezieht, wendet der Dienst die Nutzlast nicht an und Nur Syntaxanalyse und Validierung Wir führen dies durch.
{
"inverse3": [{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front", "execute": true },
"damping": { "scalar": 0.0, "execute": false }
}
}]
}
Dies bedeutet, dass stets alle Felder ausgegeben werden. Reflexionsbasierter Serializer(Beispiel: In Unity JsonUtility) nützlich. Nicht verwendete Elemente sind execute: falseStellen Sie dies so ein, dass die tatsächliche Konfiguration nicht überschrieben wird. Der Standardwert lautet trueWenn das Flag weggelassen wird, wird es „normal angewendet“.
Warnung
probe_positionund probe_orientationEs handelt sich um eine reine Überwachungs-Keepalive-Nachricht für Sitzungen, die keine Steuerbefehle senden (z. B. „ Haply Hub“). Wenn die Sitzung bereits set_cursor_force, set_cursor_position wenn man den Rücken zukehrt Bitte senden Sie die Sonde nicht mit.. Der Gerätestatus ist bereits in allen Antworten enthalten. Wenn man beides zusammen verwendet, wird Bandbreite verschwendet und session-probe-dropped Es kann zu einem Ereignis kommen.
Wenn der Befehl scheinbar keine Wirkung zeigt, ist der Feldname höchstwahrscheinlich falsch. Der Dienst ignoriert derzeit nicht erkannte JSON-Schlüssel, ohne einen Fehler auszugeben. Überprüfen Sie das Dienstprotokoll und vergewissern Sie sich anhand der API-Referenz, dass der Feldname korrekt ist. Dieses Verhalten wird sich in zukünftigen Versionen ändern.