Zum Hauptinhalt springen

WebSocket-Protokoll

Der Simulationskanal ist eine WebSocket-Verbindung auf Port 10001. Er überträgt den Echtzeit-Zyklus aus Befehlen und Zuständen 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 empfängt:

Es gibt kein Polling, kein Abonnement und keinen Out-of-Band-Push. Der Takt wird vollständig durch Ihre Sendefrequenz bestimmt.


Schritt 1 – Erste Bestandsaufnahme (erste Nachricht vom Dienst)​

Beim Verbindungsaufbau sendet der Dienst einen vollständiger Snapshot 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 weisen unterschiedliche Aktualisierungsfrequenzen auf:

BlockEnthältÄnderungshäufigkeit
configFirmware-Info, Voreinstellung, Basis, Montage, FilterSelten, nur bei einer expliziten Konfigurationsänderung
statePosition, Geschwindigkeit, Kraft, Orientierung, TransformationenBei jedem Tick (hohe Frequenz)
statusBereit, kalibriert, Stromversorgung, in GebrauchGelegentlich (geringe Häufigkeit)

Schritt 2 – Ersten Befehl senden​

Analysieren Sie die anfängliche Bestandsaufnahme, um Ihre Geräte-ID zu ermitteln. Senden Sie anschließend eine Nachricht, die Ihr Sitzungsprofil, eventuelle 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 Zustandsaktualisierungen​

Nach dem ersten Austausch sendet der Dienst nur noch state + status (ohne 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​

Senden Sie einen Befehl → Sie erhalten eine Statusaktualisierung. Die Schleife läuft mit Ihrer Sendefrequenz weiter.


configure vs. commands​

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

KarteZweckPersistenz
configureEinmalige Einstellungen: Voreinstellung, Basis, Montage, Filter, ModulkonfigurationWird bis zur Änderung gespeichert
commandsSteuerung pro Tick: Kraft, Position, DrehmomenteMan wendet es einmal an und vergisst es danach

Die vollständige Liste der configure-Den Schlüssel finden Sie unter Sitzungskonfiguration, und die commands-Einträge unter Steuerbefehle.

Hinweis
set_transform ist ein Sonderfall

set_transform gehört zu commands, ist aber anhaltend — Der Dienst behält den letzten Wert bei, bis Sie einen neuen senden. Das liegt daran, dass er für die Szenennavigation gedacht ist: Sie streamen Transformationen während einer Kamerabewegung, möchten aber, dass die letzte Position zwischen den Eingaben erhalten bleibt.


Die Flagge execute​

Jeder Eintrag configure oder commands kann "execute": false enthalten, damit der Dienst die Nutzlast parst und validiert, 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 Reflection-basierte Serializer (z. B. JsonUtility in Unity), die stets alle Felder ausgeben: Setzen Sie ungenutzte Einträge auf execute: false, damit sie keine tatsächliche Konfiguration überschreiben. Der Standardwert ist true — Wird das Flag weggelassen, bedeutet dies „normal anwenden“.


Warnungen​

Senden Sie keine Testdaten, wenn Sie bereits Befehle senden

probe_position und probe_orientation sind reine Überwachungs-Keepalives für Sitzungen, die keine Steuerbefehle senden (z. B. „ Haply -Hub“). Wenn Ihre Sitzung bereits set_cursor_force, set_cursor_position usw. sendet, Bitte senden Sie keine weiteren Proben — Der Gerätezustand ist ohnehin in jeder Antwort enthalten. Beides gleichzeitig verschwendet Bandbreite und kann session-probe-dropped-Ereignisse auslösen.

Unbekannte Schlüssel werden stillschweigend ignoriert

Wenn ein Befehl keine Wirkung zu zeigen scheint, ist der Feldname wahrscheinlich falsch. Der Dienst ignoriert unbekannte JSON-Schlüssel derzeit 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.