Zum Hauptinhalt springen

Simulationskanal

Überblick​

Der Simulationskanal ist ein bidirektionaler WebSocket-Kanal mit hoher Übertragungsrate, der zum Austauschvon Gerätestatusinformationen und zum Senden von Sitzungs- oderGerätebefehlen verwendet wird.

Standard-URL: ws://localhost:10001

Der Port kann in den Einstellungen geändert werden.

Rahmenvertrag (wichtig):

  • Wenn sich ein Client anmeldet, sendet der Dienst eine erste Bestandsmeldung mit der vollständigen Liste der Geräte.
  • Anschließend sendet der Server für jede vom Client empfangene Nachricht genau eine Statusaktualisierungsnachricht.
  • Jede Statusaktualisierung enthält den Status (und den Status) aller Geräte.
Module

Auf dieser Seite werden das Protokoll und die grundlegenden Befehle des Simulationskanals beschrieben.

Zusätzliche Module oder Funktionen können das System mit eigenen Befehlen und/oder Statusfeldern ergänzen und erweitern. Diese sind separat im Abschnitt „Module“ dokumentiert.

Protokollregeln​

Eine Antwort per Nachricht vom Kunden​

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

Das bedeutet:

  • Wenn Sie einen aktuellen Überblick über den Status der Geräte benötigen, müssen Sie einen Befehl senden (einen Sitzungsbefehl, einen Abfragebefehl oder einen Gerätebefehl).
  • Der Kanal funktioniert als Schleife, die durch die Nachrichten des Clients getaktet wird („Tick“).

Befragung ohne Gewaltanwendung (Erkundungsbefehle)​

Wenn Sie die Zustandsänderungen beobachten möchten, ohne Kräfte anzuwenden oder die Simulationsparameter zu ändern, verwenden Sie die Abfragebefehle:

  • probe_position gießen inverse3
  • probe_orientation für die Verse-Griffe

Abfragebefehle enthalten keine Steuerdaten; sie erzwingen lediglich die Abfrage der Geräteinformationen, sodass die Positions- und Orientierungsdaten bei der nächsten Statusaktualisierung auf dem neuesten Stand sind.

Möglicherweise benötigen Sie die Befehle für Umfragen gar nicht.

Simulationssitzungen, die bereits Steuerbefehle senden (set_cursor_force, set_cursor_position, usw.) haben pas Es müssen Abfragebefehle gesendet werden – der Gerätestatus ist immer im Antwort-Frame enthalten. Die Abfragebefehle sind für Sitzungen bestimmt nur zu Überwachungszwecken (z. B. „ Haply -Hub“), die den Status des Geräts abfragen müssen, ohne es zu steuern.

Konfiguration und Status​

  • Die Botschaft vonErstanlageverzeichnis umfasst die Felder config, state et status des Geräts.
  • Beiträge von Statusaktualisierung Zu den regulären Feldern gehören state et status des Geräts.

Wenn Sie erneut einen Snapshot einschließlich der Konfiguration benötigen, verwenden Sie session.force_render_full_state.

configure et commands​

Gerätemeldungen unterstützen zwei separate Wörterbücher: configure et commands. Sie haben unterschiedliche Aufgaben:

WörterbuchRolleFrequenz
configureEinmalige dauerhafte Konfiguration: Voreinstellungen, Basis, Montage, Filter, ModulparameterEinmalige Sendung oder im Falle einer Änderung
commandsPro Zyklus, nicht permanent: Kraft, Position, DrehmomenteMuss bei jedem Zyklus gesendet werden

Die Einträge aus commands (set_cursor_force, set_cursor_position, set_angular_torques, set_angular_position) werden angewendet einmal pro Zyklus und werden nicht gespeichert -- Wenn Sie die Signale nicht mehr senden, hört die Wirkung sofort auf und das Gerät kehrt in den Ruhezustand zurück. Verwenden Sie configure für alles, was von einem Zyklus zum nächsten bestehen bleiben soll, ohne zurückgesetzt zu werden.

Anmerkung
set_transform bildet eine Ausnahme

set_transform befindet sich unter commands, aber er ist anhaltend -- Der Dienst speichert die zuletzt gesendete Transformation, bis Sie eine neue senden. Sie sind nicht nicht verpflichtet es in jedem Zyklus zu senden. Da seine Funktion jedoch die Navigation der Kamera oder der Szene ist, ist die Übertragung im Takt der Zyklen (beispielsweise eine Transformation pro Bild, wenn der Benutzer die Szene verschiebt) die erwartete Vorgehensweise für eine Navigation mit kontinuierlicher Bewegung.

Koordinatensysteme​

Haply verwenden standardmäßig ein rechtshändiges Koordinatensystem, bei dem die Z-Achse nach oben zeigt.

Zwei Konfigurationsparameter beeinflussen die Art und Weise, wie Koordinaten interpretiert und zurückgegeben werden:

  • session.configure.basis : Passt die Zuordnung zwischen den Koordinaten von „ Haply “ und dem Koordinatensystem Ihrer Anwendung an (siehe Basis (siehe unten).
  • inverse3[*].configure.preset : Wählt eine benannte Werkseinstellung aus, die den Ursprung des Arbeitsbereichs festlegt (z. B. arm_front_centered Ort (0, 0, 0) in der Mitte des Arbeitsbereichs). Siehe Abschnitt „Gerätespezifische Konfiguration“.

Nachrichtenformate​

In diesem Abschnitt werden der allgemeine Aufbau und die wichtigsten Nachrichtentypen beschrieben. Vollständige Beispiele finden Sie weiter unten in diesem Dokument.

Gerätegruppen​

Die Meldungen sind auf der ersten Ebene nach Gerätetyp gruppiert (z. B. inverse3, verse_grip, wireless_verse_grip). Jeder Schlüssel vom Typ „Gerät“ entspricht einem Array von Objekten, wobei pro Gerät ein Objekt vorhanden ist.

Erstbestandsaufnahme (Server → Client)​

Wird einmalig gesendet, unmittelbar nach dem Aufbau einer WebSocket-Verbindung.

Jeder Eintrag umfasst:

  • device_id
  • config
  • state
  • status

Siehe: Beispiel: Nutzlast des Anfangsbestands

Statusaktualisierung (Server → Client)​

Wird einmal pro vom Client empfangener Nachricht gesendet.

Jeder Eintrag umfasst:

  • device_id
  • state
  • status

Siehe: Beispiel: Nutzlast für die Statusaktualisierung

Sitzungsbefehls-Umschlag (Client → Server)​

Sitzungsbefehle sind Aktionen, die sich auf die aktuelle Verbindung oder Sitzung beziehen und nicht gerätespezifisch sind.

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

Auftrags-Enveloppe (Client → Server)​

Die Gerätebefehle werden unter dem Schlüssel des Gerätetyps in Form einer Tabelle gesendet, wodurch Befehle an ein oder mehrere Geräte in einer einzigen Nachricht gesendet werden können. Jeder Geräteeintrag unterstützt jeweils ein Wörterbuch configure und ein Wörterbuch commands.

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

Sie können mehrere Einträge einfügen, um mehrere Geräte desselben Typs in einer einzigen Nachricht zu steuern. Beachten Sie, dass commands ist ein Wörterbuch, das mehrere Befehle für ein und dasselbe Gerät enthalten kann, jedoch nur einen pro Befehlstyp.

Das Feld execute​

Jeder Befehls- oder Konfigurations-Eingang akzeptiert einen booleschen Wert "execute" optional (standardmäßig true). Legen Sie fest "execute": false damit die Eingabe analysiert wird, ohne angewendet zu werden. Dies ist nützlich für auf Reflexion basierende Serializer (z. B. Unity JsonUtility), die stets alle Felder aussenden.

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

Bestellnummern​

Sitzung​

Die vollständige Darstellung des Berichts erzwingen​

Fordere eine Momentaufnahme aller Gerätestatus und -konfigurationen an.

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

Sitzungskonfiguration​

Die dauerhafte Konfiguration auf Sitzungsebene wird über session.configure. Es folgt dem gleichen Prinzip wie das Wörterbuch configure auf Geräteebene.

Profil​

Legt den Namen des Sitzungsprofils fest, das von „ Haply Hub“ verwendet wird, um die Simulation zu erkennen und die anwendungsspezifischen Geräteeinstellungen beizubehalten.

{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
Grundstufe (Niveau „Session“)​

Legt die Basiskoordinatentransformation für die gesamte Sitzung fest. Diese Transformation beschreibt, wie die Koordinaten von Haply in das Koordinatensystem Ihrer Anwendung umgewandelt werden; sobald sie definiert ist, werden alle Gerätestatus in diesem Bezugssystem zurückgegeben und alle von Ihnen gesendeten Werte werden darin interpretiert.

Die Permutationskette wird in Bezug auf das rechtshändige Koordinatensystem mit Z nach oben wie folgt ausgedrückt Haply : eine Permutation von X, Y, Z, gegebenenfalls mit dem vorangestellten + ou de -. Beispiele:

  • XYZ, ZYX, +Y-Z+X, X-ZY
  • YZX bedeutet, dass Ihr Y entsprechen der Geraden von Haply, Ihre Z vor Haply und Ihr X Oben auf Haply.

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

{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
Achtung
Migration aus session.set_basis

Die Konvention für die Vorzeichen der Achsen hat sich gegenüber dem früheren Befehl geändert session.set_basis et session.configure.basis. Eine Permutation, die mit dem alten Befehl funktionierte, kann mit dem neuen Befehl zu einer umgekehrten Transformation führen – kehren Sie in diesem Fall gegebenenfalls die Vorzeichen der Achsen um (z. B. X-ZY wird XZ-Y).

Bedienelemente aller Geräte​

Umfrage (alle Geräte)​

Verwenden Sie die Abfragebefehle, um aktuelle Informationen zu Position und Ausrichtung abzufragen, ohne Kräfte oder andere Änderungen an der Simulation vorzunehmen.

  • inverse3 : probe_position
  • Verse-Griffe (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": {}
}
}
]
}

Umrechnung festlegen (alle Geräte)​

Legt die Arbeitsbereichstransformation (vom Gerätebereich zum Anwendungsbereich) für ein Gerät fest.

Im Gegensatz zu den anderen Einträgen in commands, set_transform est anhaltend -- Der Dienst behält den zuletzt gesendeten Wert bei, bis Sie einen neuen senden. Es ist nicht erforderlich, ihn in jedem Zyklus zu senden; da seine Funktion die Steuerung der Kamera oder der Szene ist, entspricht die Übertragung im Takt der Zyklen jedoch der erwarteten Vorgehensweise für eine kontinuierliche Bewegung (z. B. eine Transformation pro Bild, während der Benutzer 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 Geräten „Verse Grip“ und „Wireless Verse Grip“ gilt dies nur für die Komponente rotation Die Transformation hat eine Auswirkung – der Griff überträgt lediglich die Ausrichtung, es muss also nichts skaliert oder verschoben werden, um position ou scale. Die Felder position et scale werden (und in den Snapshot zurückgeschrieben) ausschließlich akzeptiert, um die Konsistenz des Schemas mit Inverse3 zu gewährleisten; sie sollten auf ihren Identitätswerten belassen werden (position = {0,0,0}, scale = {1,1,1}) ist die gängige Praxis.

Gerätekonfiguration Inverse3​

Die Konfigurationsdaten werden an das Wörterbuch gesendet configure. Sie sind dauerhaft gespeichert – senden Sie sie einmalig oder bei Änderungen.

Voreinstellung​

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

Verfügbare Werte: device_defaults, arm_front, arm_front_centered, led_front, led_front_centered, custom.

Basis (Geräteebene)​

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

Montage​

Legt die Montage-Transformation des Geräts fest. Beachten Sie die Hüllkurve. transform innerhalb von mount.

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

Die Seite Bestellung (Client-zu-Server) umfasst die Transformation: "mount": { "transform": { ... } }. Die Seite sofort (Server zu Client) ist ausgefallen: "mount": { "position": {...}, "rotation": {...}, "scale": {...} }. Diese Entscheidung ist bewusst getroffen worden – Befehle verwenden einen einheitlichen Wrapper, während Snapshots die Transformation direkt serialisieren. Achten Sie darauf, die Struktur des Snapshots nicht in eine Befehlsnutzlast zu kopieren.

Abschreibung​

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

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

Sie können auch eine gerichtete Dämpfung festlegen oder beides gleichzeitig:

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

Türöffner​

Legt den Dämpfungsfaktor des Krafttors fest (0,0 bis 1,0).

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

Bestellungen Inverse3​

So senden Sie Befehle an ein Gerät inverse3, fügen Sie einen Eintrag mit einem device_id entsprechend dem Schlüssel inverse3. Die Befehle werden in jedem Zyklus gesendet und müssen in jedem Zyklus erneut gesendet werden, um aktiv zu bleiben.

Ein einzelnes Gerät steuern:

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

Mehrere Geräte in einer einzigen Nachricht steuern:

{
"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
}
}
}
}
]
}

Die Position des Cursors festlegen​

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

Die Stärke des Cursors festlegen​

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

Winkelposition festlegen​

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

Winkelmomente definieren​

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

Verse Grip: Konfigurieren​

Die Geräte „Verse Grip“ und „Wireless Verse Grip“ unterstützen dieselben Schlüssel configure que Inverse3 pour preset, basis et mount.

Verse Grip erweitert​

Die Bestellung set_extension_data ist Teil des erweiterten Verse-Grip-Protokolls und wird mit den Griffvarianten verwendet, die das Kommunikationsprotokoll zur Kartenerweiterung implementieren.

Ermitteln der Abmessungen des Griffs​

Unterstützte Datentypen:

  • Bis zu 20 Oktette in Richtung Server (Client → Gerät).
  • Bis zu 12 Oktette in Richtung Client (Gerät → Client), die in der „State Update“-Nachricht in folgender Form zurückgesendet werden: state.extension_data.

Angaben zu den Daten:

  • Länge des Arrays: 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
]
}
}
}
]
}

Beispiele​

Beispiel: Nutzlast bei der Erstanlage​

Der Dienst sendet eine Nachricht mit der vollständigen Liste der Geräte, sobald eine WebSocket-Verbindung hergestellt ist. Die erste Nachricht entspricht dem folgenden Format JSON Weiter:

{
"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: Nutzlast – Statusaktualisierung​

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

Wenn Sie den Status der Maschine abfragen möchten, müssen Sie ihr zuvor eine Nachricht senden (z. B. einen Abfragebefehl oder einen Kraftwert, auch wenn die Werte Null sind). Dies ist besonders wichtig, wenn Sie Geräte als Eingangsquellen verwenden (z. B. zur Positionsüberwachung), ohne Kräfte auszuüben.

Die „State Update“-Nachricht entspricht dem Format JSON Weiter:

{
"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
}
}
]
}