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.
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_positiongießeninverse3probe_orientationfü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.
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,stateetstatusdes Geräts. - Beiträge von Statusaktualisierung Zu den regulären Feldern gehören
stateetstatusdes 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örterbuch | Rolle | Frequenz |
|---|---|---|
configure | Einmalige dauerhafte Konfiguration: Voreinstellungen, Basis, Montage, Filter, Modulparameter | Einmalige Sendung oder im Falle einer Änderung |
commands | Pro Zyklus, nicht permanent: Kraft, Position, Drehmomente | Muss 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.
set_transform bildet eine Ausnahmeset_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_centeredOrt(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_idconfigstatestatus
Siehe: Beispiel: Nutzlast des Anfangsbestands
Statusaktualisierung (Server → Client)
Wird einmal pro vom Client empfangener Nachricht gesendet.
Jeder Eintrag umfasst:
device_idstatestatus
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-ZYYZXbedeutet, dass IhrYentsprechen der Geraden von Haply, IhreZvor Haply und IhrXOben auf Haply.
Beispiel für ein linkshändiges Koordinatensystem mit Z nach oben (Unreal, X-YZ) :
{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
session.set_basisDie 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 }
}
}
}
}
]
}
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 }
}
}
}
}
]
}
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
}
}
]
}