Zum Haupttext springen

Simulationskanal

Übersicht​

Der Simulationskanal ist ein hochfrequenter, bidirektionaler WebSocket-Kanal, der zum Austausch von Gerätestatusinformationensowie zur Übertragung von Sitzungs- oder Gerätebefehlen verwendet wird.

Standard-URL: ws://localhost:10001

Der Port kann in den Einstellungen geändert werden.

Kernbestimmungen (wichtig):

  • Wenn sich ein Client verbindet, sendet der Dienst eine erste Inventarnachrichtmit einer vollständigen Liste aller Geräte.
  • Seitdem sendet der Server für jede vom Client empfangene Nachricht genau eine Statusaktualisierungsnachricht.
  • Jede Statusaktualisierung enthält den Status (sowie die Statusinformationen) aller Geräte.
Modul

Auf dieser Seite werden die wichtigsten Protokolle und Befehle des Simulationskanals dokumentiert.

Zusätzliche Module/Funktionen können das System durch die Registrierung eigener Befehle und/oder Statusfelder erweitern. Diese sind im Abschnitt „Module“ separat dokumentiert.

Protokollregeln​

Eine Antwort pro Client-Nachricht​

Der Dienst sendet für jede vom Client empfangene Nachricht eine Statusaktualisierungsnachricht, die den Status aller Geräte enthält.

Das bedeutet Folgendes:

  • Wenn Sie einen aktuellen Snapshot des Gerätestatus benötigen, müssen Sie unbedingt einen Befehl(Sitzungsbefehl, Probe-Befehl oder Gerätebefehl) senden.
  • Dieser Kanal funktioniert wie eine durch Client-Nachrichten angesteuerte „Tick“-Schleife.

Abfragen ohne Kraftanwendung (Probe-Befehl)​

Verwenden Sie den Befehl „probe“, um Zustandsänderungen zu beobachten, ohne Kräfte anzulegen oder Simulationsparameter zu ändern:

  • inverse3im Fall von probe_position
  • Im Fall des „Verse Grip“ probe_orientation

Der „Probe“-Befehl enthält keine Befehlsdaten, sondern erzwingt eine Abfrage der Geräteinformationen, damit die Positions- und Richtungsdaten bei der nächsten Statusaktualisierung auf dem neuesten Stand sind.

Möglicherweise ist kein Probe-Befehl erforderlich.

Bereits ausgeführte Steuerbefehle (set_cursor_force, set_cursor_position Simulationssitzungen, die (u. a.) übertragen, können Probe-Befehle senden Das ist nicht nötig. -- Der Gerätestatus ist stets in den Antwort-Frames enthalten. Der Probe muss den Gerätestatus abfragen, ohne das Gerät anzusteuern. Nur zur Überwachung Dies ist für eine Sitzung (z. B. „ Haply Hub“) vorgesehen.

Aufbau und Zustand​

  • Anfangsbestand In der Meldung wird das Gerät config, state, statusgehört dazu.
  • Allgemeines Status-Update In der Meldung wird das Gerät stateWow statusgehört dazu.

Falls Sie erneut einen Snapshot einschließlich der Konfiguration benötigen, session.force_render_full_stateVerwenden Sie .

configureWow commands​

Gerätemeldungen sind configureWow commandsunterstützt zwei separate Karten. Die beiden Karten dienen unterschiedlichen Zwecken:

KarteVerwendungszweckÜbertragungshäufigkeit
configureEinmalige, dauerhafte Einstellungen: Voreinstellungen, Basis, Montage, Filter, ModuleinstellungenBei einmaliger Übertragung oder bei Übertragung nach einer Änderung
commandsPro Takt angewendete nicht-permanente Größen: Kraft, Position, DrehmomenteMuss bei jedem Takt unbedingt übertragen werden

commandsder Eintrag (set_cursor_force, set_cursor_position, set_angular_torques, set_angular_position) ist Wird einmal pro Klick angewendet und nicht gespeichert. -- Wird die Übertragung unterbrochen, erlischt der Effekt sofort und das Gerät kehrt in den Ruhezustand zurück. Zu den Elementen, die über mehrere Ticks hinweg beibehalten werden müssen, ohne dass erneut übertragen wird, gehören configureVerwenden Sie .

Anmerkung
set_transformDas ist ein Ausnahmefall.

set_transform은 commandsgehört zwar dazu, aber dauerhaft– Der Dienst behält die zuletzt übermittelte Transformation bei, bis eine neue Transformation gesendet wird. Es ist nicht erforderlich, bei jedem Tick eine Transformation zu senden. Da der Zweck jedoch die Kamera- bzw. Szenennavigation ist, entspricht das Streaming im Tick-Rhythmus (z. B. das Senden einer Transformation pro Frame, wenn der Benutzer sich in der Szene bewegt) dem zu erwartenden Nutzungsmuster bei der Navigation durch fortlaufende Bewegungen.

Koordinatensystem​

Das Standardkoordinatensystem von Haply ist ein Rechtshänder-Koordinatensystemmit Z-Achse nach oben.

Es gibt zwei Konfigurationsoptionen, die sich auf die Art und Weise auswirken, wie Koordinaten interpretiert und zurückgegeben werden:

  • session.configure.basis : Ändert die Zuordnung zwischen den Koordinaten von „ Haply “ und dem Koordinatensystem der Anwendung (siehe unten Grundlage (siehe dort).
  • inverse3[*].configure.preset : Wählen Sie eine benannte Werkseinstellung aus, in der der Ursprung des Arbeitsbereichs festgelegt ist (z. B. arm_front_centeredist (0, 0, 0)(in der Mitte des Arbeitsbereichs platzieren). Siehe den Abschnitt „Configure“ für das jeweilige Gerät.

Nachrichtenformat​

In diesem Abschnitt werden die übergeordneten Envelopes und Nachrichtentypen erläutert. Ein vollständiges Beispiel finden Sie weiter hinten in diesem Dokument.

Gerätegruppe​

Die Meldungen werden auf oberster Ebene nach Gerätetyp gruppiert (z. B.: inverse3, verse_grip, wireless_verse_grip). Jeder Gerätetyp-Schlüssel wird einem Array von gerätespezifischen Objekten zugeordnet.

Anfänglicher Bestand (Server → Client)​

Die Übertragung erfolgt einmalig unmittelbar nach dem Aufbau der WebSocket-Verbindung.

Jeder Punkt umfasst Folgendes:

  • device_id
  • config
  • state
  • status

Siehe: Beispiel: Payload für den Anfangsbestand

Statusaktualisierung (Server → Client)​

Es wird bei jeder Client-Nachricht einmal gesendet.

Jeder Punkt umfasst Folgendes:

  • device_id
  • state
  • status

Siehe: Beispiel: Payload für Statusaktualisierung

Sitzungsbefehl-Hüllkurve (Client → Server)​

Der Befehl „Session“ gilt für die aktuelle Verbindung bzw. Sitzung und wird nicht geräteabhängig ausgeführt.

{
"session": {
"<command_name>": {
"...": "..."
}
}
}

Befehlshüllkurve (Client → Server)​

Da Gerätebefehle als Array unter dem Gerätetyp-Schlüssel übertragen werden, können Befehle mit einer einzigen Nachricht an ein oder mehrere Geräte gesendet werden. Jeder Geräteeintrag ist configure Karte und commands Alle Karten werden unterstützt.

{
"<device_type>": [
{
"device_id": "<id>",
"configure": {
"<config_key>": { "...": "..." }
},
"commands": {
"<command_name>": { "...": "..." }
}
}
]
}

Sie können mehrere Elemente in eine Nachricht einfügen, um Befehle an mehrere Geräte desselben Typs zu senden. commandsist ein Wörterbuch, das zwar mehrere Befehle für ein bestimmtes Gerät enthalten kann, jedoch pro Befehlstyp nur einen einzigen.

execute Feld​

Alle Befehle oder Konfigurationsoptionen sind optional. "execute" Boolesche Werte (Standardwert true) erhält. "execute": falseWenn diese Option aktiviert ist, werden die Elemente lediglich geparst, aber nicht angewendet. Dies gilt für reflektionsbasierte Serialisierer, die stets alle Felder ausgeben (z. B. Unity JsonUtility) ist nützlich.

"set_cursor_force": { "execute": false, "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }

Befehlsübersicht​

Sitzung​

Erzwungenes Rendern des gesamten Zustands​

Fordern Sie einen Momentaufnahme aller Gerätestatus und -konfigurationen an.

{
"session": {
"force_render_full_state": {}
}
}

Sitzung „Configure“​

Permanente Konfigurationen auf Sitzungsebene sind session.configurewird übertragen. Dies geschieht auf Geräteebene configure Es folgt genau dem Kartenmuster.

Profil​

Legen Sie einen Namen für das Sitzungsprofil fest. Dieser Name wird von „ Haply Hub“ verwendet, um die Simulation zu identifizieren und die app-spezifischen Geräteeinstellungen beizubehalten.

{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
Basis (auf Sitzungsebene)​

Legt die Basiszuordnung für die gesamte Sitzung fest. Die Basiszuordnung beschreibt, wie Koordinaten aus dem Koordinatensystem „ Haply “ in das Koordinatensystem der Anwendung umgewandelt werden. Nach Festlegung dieser Zuordnung werden alle nachfolgenden Gerätestatuswerte in dieser Basis zurückgegeben, und alle übertragenen Werte werden ebenfalls auf Basis dieser Basis interpretiert.

Permutationszeichenfolgen werden auf der Grundlage des rechten Koordinatensystems von Haply bzw. des Z-up-Koordinatensystems dargestellt. X, Y, Zist eine Permutation von und optional + oder - Sie können ein Symbol voranstellen. Hier ein Beispiel:

  • XYZ, ZYX, +Y-Z+X, X-ZY
  • YZXist der des Benutzers Y Die Achse befindet sich rechts von Haply, Z Die Achse befindet sich an der Vorderseite des Haply, X Das bedeutet, dass die Achse auf den oberen Teil von Haply zeigt.

Beispiel für ein linkshändiges Koordinatensystem mit Z-Achse nach oben (Unreal, X-YZ):

{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
Warnung
Veraltete Befehle session.set_basisMigration von

Regeln für die Vorzeichenangabe bei Achsen sind veraltete Befehle session.set_basisNeuer Befehl in session.configure.basiswurde geändert. Permutationen, die mit dem bisherigen Befehl funktionierten, können mit dem neuen Befehl zu einer umgekehrten Transformation führen. Kehren Sie gegebenenfalls das Vorzeichen der Achse um (z. B.: X-ZYist XZ-Ywird).

Alle Gerätebefehle​

Probing (alle Geräte)​

Um die aktuellen Positions- und Ausrichtungsdaten abzufragen, ohne Kraft- oder sonstige Simulationsänderungen anzuwenden, verwenden Sie den Befehl „Probing“.

  • inverse3: probe_position
  • Verse-Griff(verse_grip, wireless_verse_grip): probe_orientation
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"probe_position": {}
}
}
],
"verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
],
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
]
}

Konvertierungseinstellungen (alle Geräte)​

Richtet die Arbeitsbereichsumwandlung des Geräts (vom Geräteraum in den Anwendungsraum) ein.

Andere commands Im Gegensatz zu den Punkten set_transform은 dauerhaftDas heißt, der Dienst behält den zuletzt gesendeten Wert bei, bis ein neuer Wert gesendet wird. Es ist nicht erforderlich, bei jedem Tick einen Wert zu senden, doch da es sich um die Kamera-/Szenenführung handelt, ist es bei kontinuierlichen Bewegungen üblich, mit der Tick-Frequenz zu streamen (z. B. wird bei jeder Bildwiederholrate eine Transformation gesendet, während sich der Benutzer durch die Szene bewegt).

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_transform": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
Verse-Griff / kabelloser Verse-Griff

Bei den Modellen „Verse Grip“ und „Wireless Verse Grip“ beträgt die Umwandlung rotation Nur die Komponenten wirken. Da dieser Griff ausschließlich die Richtungsinformationen berücksichtigt, positionIna scaleEs gibt keine Objekte, die angepasst oder verschoben werden könnten. position sowie scale Das Feld ist ausschließlich zur Wahrung der Konsistenz mit dem Schema „ Inverse3 “ zulässig (und wird auch in Snapshots unverändert zurückgegeben) und enthält den Wert „1“ (position = {0,0,0}, scale = {1,1,1}) ist die übliche Vorgehensweise.

Inverse3 Gerät konfigurieren​

Die Bestandteile sind configure An die Karte senden. Da dieser Eintrag dauerhaft ist, sollte er nur einmal gesendet werden oder nur dann, wenn sich der Wert ändert.

Voreinstellungen​

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
}
}
]
}

Mögliche Werte: device_defaults, arm_front, arm_front_centered, led_front, led_front_centered, custom.

Grundlagen (Geräteebene)​

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"basis": { "permutation": "ZXY" }
}
}
]
}

Halterung​

Die Gerätehalterungsumwandlung wird eingerichtet. mount im Inneren transform Bitte achten Sie auf den Rapper.

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"mount": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
Asymmetrie des Mount-Schemas

Befehl Die Seite (vom Client zum Server) verpackt die Konvertierung: "mount": { "transform": { ... } }. Momentaufnahme Die Seite (vom Server zum Client) weist eine flache Struktur auf: "mount": { "position": {...}, "rotation": {...}, "scale": {...} }. Dies ist beabsichtigt. Der Grund dafür ist, dass „command“ einen integrierten Wrapper verwendet, während „snapshot“ die Transformation direkt serialisiert. Achten Sie darauf, das „snapshot“-Format nicht in die „command“-Nutzlast zu kopieren.

Dämpfung​

Steuert die gleichmäßige Dämpfung und/oder die gerichtete Dämpfung. Mindestens ein Feld muss ausgefüllt werden.

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"damping": { "scalar": 0.5 }
}
}
]
}

Sie können entweder die Richtungsdämpfung einstellen oder beide Optionen gleichzeitig aktivieren:

"damping": { "scalar": 0.5, "vector": { "x": 0.0, "y": 1.0, "z": 0.0 } }

Krafttor​

Stellen Sie den Dämpfungsfaktor des Power-Gates (0,0–1,0) ein.

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"force_gate": { "gain": 0.3 }
}
}
]
}

Inverse3 Befehl​

inverse3 Um Befehle an das Gerät zu senden, inverse3 die unter dem Schlüssel übereinstimmenden device_identhält Einträge mit . Der Befehl wird bei jedem Tick angewendet und muss bei jedem Tick erneut gesendet werden, um den aktiven Status aufrechtzuerhalten.

Befehl an ein Gerät senden:

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}

Befehle mit einer einzigen Nachricht an mehrere Geräte senden:

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
},
{
"device_id": "049E",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}

Cursorposition festlegen​

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"position": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}

Einstellungen für die Cursorstärke​

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}

Einstellung der Winkelposition​

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_position": {
"angles": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}

Einstellung von Winkel und Drehmoment​

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_torques": {
"torques": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}

Verse Grip konfigurieren​

Verse Grip- und Wireless Verse Grip-Geräte sind preset, basis, mountin Bezug auf dasselbe, das bei Inverse3 verwendet wird configure Unterstützt Tastenbefehle.

Erweiterung „Verse Grip“​

set_extension_data Der Befehl ist Teil des Verse-Grip-Erweiterungsprotokolls und wird in Grip-Versionen verwendet, die das Board-Erweiterungskommunikationsprotokoll implementieren.

Einstellungen für erweiterte Griffdaten​

Unterstützte Datenlänge:

  • Upstream (Client → Gerät): maximal 20 Byte.
  • Downstream (Gerät → Client): maximal 12 Byte, und state.extension_dataEs wird zur Meldung „State Update“ zurückgekehrt.

Datenspezifikationen:

  • Array-Länge: 20 Byte
  • Wertebereich: Jeder Wert liegt zwischen 0 und 255
{
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"set_extension_data": {
"extension_data": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
}
}
}
]
}

Beispiel​

Beispiel: Nutzdaten für die Liste der anfänglichen Geräte​

Bei Herstellung einer WebSocket-Verbindung sendet der Dienst eine Nachricht, die die vollständige Geräteliste enthält. Die erste Nachricht lautet wie folgt: JSON Befolgen Sie das Format:

{
"inverse3": [
{
"device_id": "04BA",
"config": {
"type": "inverse3",
"port": "COM13",
"device_info": {
"major_version": 7,
"minor_version": 1,
"id": "04BA",
"device_type": 4,
"uuid": "2D35F80DD9005F599B68F49944CB04BA"
},
"extended_device_id": "2D35F80DD9005F599B68F49944CB04BA",
"extended_firmware_version": "8C20FDC8010AA1E15AA133CDA2534874",
"gravity_compensation": {
"enabled": true,
"scaling_factor": 1
},
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": {
"enabled": true
},
"home_return": {
"enabled": false
},
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0 }
},
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"config": {
"type": "verse_grip",
"port": "COM3",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"config": {
"type": "wireless_verse_grip",
"port": "COM6",
"major_version": 1,
"minor_version": 4,
"hardware_version": 1,
"streaming_mode": "Radio",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
]
}

Beispiel: Nutzdaten für Statusaktualisierung​

Der Dienst sendet für jede empfangene Nachricht jeweils eine Statusaktualisierungsnachricht, die den Status aller Geräte enthält.

Wenn Sie den Status des Geräts erfahren möchten, müssen Sie vorab eine Nachricht senden (z. B. einen Abtastbefehl oder einen Kraftwert, auch wenn der Wert 0 ist). Dies ist besonders wichtig, wenn Sie das Gerät als Eingangsquelle (z. B. zur Positionserfassung) verwenden, ohne Kraft auszuüben.

Status-Update-Meldungen lauten wie folgt JSON Befolgen Sie das Format:

{
"inverse3": [
{
"device_id": "04BA",
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
],
"custom_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"extension_data": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"ready": true
}
}
]
}