WebSocket-Protokoll
Der Simulationskanal ist eine WebSocket-Verbindung auf Port 10001. Er überträgt die Steuerungs- und Statusschleife in Echtzeit 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 weder eine Abfrage (Polling) noch ein Abonnement noch einen spontanen Versand außerhalb des Kanals. Die Frequenz wird vollständig durch Ihre Sendehäufigkeit bestimmt.
Schritt 1 – Erstaufnahme (erste Nachricht des Dienstes)
Bei der Verbindung sendet der Dienst eine vollständige Momentaufnahme Behälter config, state
et 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 Aktualisierungsraten:
| Block | Inhalt | Änderungen |
|---|---|---|
config | Informationen zu Firmware, Voreinstellungen, Basis, Halterung, Filtern | Selten – nur bei einer expliziten Konfigurationsänderung |
state | Position, Geschwindigkeit, Kraft, Ausrichtung, Transformationen | Bei jedem Zyklus (hohe Frequenz) |
status | Bereit, kalibriert, Stromversorgung, in Gebrauch | Gelegentlich (selten) |
Schritt 2 – Senden Sie Ihre erste Bestellung ab
Analysieren Sie den Anfangszustand, um die ID Ihres Geräts zu ermitteln, und senden Sie anschließend eine Nachricht mit Ihrem Sitzungsprofil, allen Anfangskonfigurationen und/oder einem Steuerbefehl 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 Statusaktualisierungen
Nach dem ersten Austausch sendet der Dienst nur noch state + status (ohne
config), es sei denn, eine Konfigurationsänderung löst die Übertragung eines vollständigen Snapshots aus:
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": { … }, "cursor_velocity": { … }, … },
"status": { "ready": true, "calibrated": true, … }
}
]
}
Schritt 4 – Wiederholen Sie den Vorgang
Senden Sie einen Befehl → erhalten Sie eine Statusaktualisierung. Dieser Kreislauf wiederholt sich in dem von Ihnen festgelegten Sendeintervall.
configure ou commands
Jeder Geräteeintrag in Ihrer ausgehenden Nachricht kann zwei Wörterbücher enthalten:
| Wörterbuch | Rolle | Beharrlichkeit |
|---|---|---|
configure | Einzelne Einstellungen: Voreinstellung, Basis, Halterung, Filter, Modulkonfiguration | Werden bis zur Änderung gespeichert |
commands | Prüfung bei jedem Zyklus: Kraft, Position, Drehmomente | Einmal angebracht, dann vergessen |
Siehe Sitzungskonfiguration für die
vollständige Liste der Schlüssel von configure, und Steuerbefehle für
die Vorspeisen von commands.
set_transform bildet eine Ausnahmeset_transform befindet sich unter commands, aber sie ist dauerhaft — Der Dienst
behält den letzten Wert bei, bis ein neuer gesendet wird. Dies liegt daran, dass seine Funktion
die Navigation innerhalb der Szene ist: Sie übermitteln die Transformationen kontinuierlich während der Kamerabewegungen, möchten aber, dass die letzte Position zwischen zwei Tastendrücken beibehalten wird.
Der Indikator execute
Jeder Eintrag configure ou commands kann umfassen "execute": false damit der
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 }
}
}]
}
Das ist nützlich für die Reflexionsbasierte Serialisierer (zum Beispiel, JsonUtility (de Unity)
die immer alle Felder ausgeben: Legen Sie die nicht verwendeten Eingaben auf execute: false damit sie
die tatsächliche Konfiguration nicht überschreiben. Der Standardwert ist true — Wird der Indikator weggelassen, bedeutet dies
„normal anwenden“.
Warnhinweise
probe_position et probe_orientation sind Keepalive-Nachrichten, die ausschließlich der Überwachung dienen, und zwar für
Sitzungen, die keine Steuerbefehle senden (z. B. „ Haply Hub“). Wenn Ihre Sitzung bereits set_cursor_force, set_cursor_positionusw., Schickt bitte auch keine Sonden — Der Gerätestatus ist bereits in jeder Antwort enthalten.
Beides zu kombinieren verschwendet Bandbreite und kann Ereignisse auslösen. session-probe-dropped.
Wenn ein Befehl keine Wirkung zu zeigen scheint, ist der Feldname wahrscheinlich falsch. Der Dienst ignoriert derzeit nicht erkannte JSON-Schlüssel, ohne einen Fehler auszugeben. Sehen Sie sich die Protokolle des Dienstes an und überprüfen Sie die Feldnamen in der API-Referenz. Dieses Verhalten wird sich in einer kommenden Version ändern.