Zum Hauptinhalt springen
Version: 3.5.x

WebSocket-Protokoll

Der Simulationskanal ist eine WebSocket-Verbindung auf Port 10001. Er überträgt den Echtzeit-Befehls-/Zustandsaustausch zwischen Ihrer Anwendung und dem Dienst.

Grundregel: eine Antwort pro Nachricht

Der Dienst sendet genau eine Statusaktualisierung für jede Nachricht, die er von Ihrem Client erhält:

Es gibt keine Abfrage, kein Abonnement und keine Push-Benachrichtigungen außerhalb des Datenkanals. Der Rhythmus richtet sich voll und ganz nach Ihrer Sendefrequenz.


Schritt 1 – Erstbestandsaufnahme (erste Nachricht vom Dienst)

Bei der Verbindung sendet der Dienst eine vollständiger Überblick mit config, state, und status für jedes erkannte Gerät:

{
"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 haben unterschiedliche Aktualisierungsfrequenzen:

BlockEnthältÄnderungen
configFirmware-Informationen, Voreinstellungen, Basis, Halterung, FilterSelten – nur bei einer expliziten Konfigurationsänderung
statePosition, Geschwindigkeit, Kraft, Ausrichtung, TransformationenBei jedem Tick (Hochfrequenz)
statusBereit, kalibriert, Stromversorgung, in GebrauchGelegentlich (selten)

Schritt 2 – Senden Sie Ihren ersten Befehl

Analysieren Sie die anfängliche Bestandsaufnahme, um Ihre Geräte-ID zu ermitteln, und senden Sie anschließend eine Nachricht zurück, die Ihr Sitzungsprofil, etwaige Anfangskonfigurationen und/oder einen Steuerbefehl enthält:

{
"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 Statusaktualisierungen

Nach dem ersten Austausch sendet der Dienst nur state + status (nein config) es sei denn, eine Konfigurationsänderung löst einen vollständigen Snapshot-Push aus:

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

Schritt 4 – Wiederholen

Befehl senden → Statusaktualisierung empfangen. Der Zyklus läuft mit Ihrer Sendefrequenz weiter.


configure vs commands

Jeder Geräteeintrag in Ihrer ausgehenden Nachricht kann zwei Zuordnungen enthalten:

KarteZweckBeharrlichkeit
configureEinmalige Einstellungen: Voreinstellung, Basis, Halterung, Filter, ModulkonfigurationSo lange gespeichert, bis es geändert wird
commandsSteuerung pro Takt: Kraft, Position, DrehmomenteEinmal auftragen, dann vergessen

Siehe Sitzungskonfiguration die vollständige Liste der configure Tasten und Steuerbefehle für die commands Einträge.

set_transform ist ein Sonderfall

set_transform lebt in commands aber ist anhaltend — Der Dienst behält den letzten Wert bei, bis Sie einen neuen senden. Der Grund dafür ist, dass er für die Szenennavigation gedacht ist, bei der Sie während der Kamerabewegung Transformationen streamen, aber möchten, dass die letzte Position zwischen den Tastendrücken beibehalten wird.


Die execute Flagge

Beliebig configure oder commands Ein Eintrag kann Folgendes enthalten "execute": false um den Dienst analysieren und validieren die Nutzlast, ohne sie anzuwenden.

{
"inverse3": [{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front", "execute": true },
"damping": { "scalar": 0.0, "execute": false }
}
}]
}

Dies ist nützlich für reflexionsbasierte Serializer (z. B. Unity's JsonUtility) die immer alle Felder ausgeben: Unbenutzte Einträge auf execute: false damit sie die eigentliche Konfiguration nicht überschreiben. Die Standardeinstellung ist true — Wenn die Option weggelassen wird, bedeutet dies „normal anwenden“.


Warnhinweise

Führe keine Abfrage durch, wenn du bereits Befehle sendest

probe_position und probe_orientation sind reine Überwachungs-Keepalives für Sitzungen, die keine Steuerbefehle senden (z. B. Haply ). Wenn Ihre Sitzung bereits set_cursor_force, set_cursor_positionusw., schick nicht auch noch Sonden — Der Gerätestatus ist bereits in jeder Antwort enthalten. Beides zu vermischen verschwendet Bandbreite und kann dazu führen, dass session-probe-dropped Veranstaltungen.

Unbekannte Schlüssel werden stillschweigend ignoriert

Wenn ein Befehl keine Wirkung zu zeigen scheint, ist der Feldname wahrscheinlich falsch. Der Dienst ignoriert derzeit unbekannte JSON-Schlüssel ohne Fehlermeldung. Überprüfen Sie die Dienstprotokolle und vergleichen Sie die Feldnamen mit der API-Referenz. Dieses Verhalten soll in einer zukünftigen Version geändert werden.