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.
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 vonprobe_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.
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
stateWowstatusgehö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:
| Karte | Verwendungszweck | Übertragungshäufigkeit |
|---|---|---|
configure | Einmalige, dauerhafte Einstellungen: Voreinstellungen, Basis, Montage, Filter, Moduleinstellungen | Bei einmaliger Übertragung oder bei Übertragung nach einer Änderung |
commands | Pro Takt angewendete nicht-permanente Größen: Kraft, Position, Drehmomente | Muss 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 .
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_idconfigstatestatus
Siehe: Beispiel: Payload für den Anfangsbestand
Statusaktualisierung (Server → Client)
Es wird bei jeder Client-Nachricht einmal gesendet.
Jeder Punkt umfasst Folgendes:
device_idstatestatus
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-ZYYZXist der des BenutzersYDie Achse befindet sich rechts von Haply,ZDie Achse befindet sich an der Vorderseite des Haply,XDas 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" }
}
}
}
session.set_basisMigration vonRegeln 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 }
}
}
}
}
]
}
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 }
}
}
}
}
]
}
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
}
}
]
}