Simulationskanal
Zusammenfassung
Der Simulationskanal ist ein hochfrequenter, bidirektionaler WebSocket-Kanal, der zum Austauschvon Gerätestatusinformationenund zum Senden vonBefehlen für die Sitzung oder das Gerätverwendet wird.
Standard-URL: ws://localhost:10001
Der Port kann in den Einstellungen geändert werden.
Kernvereinbarungen (wichtig):
- Sobald sich ein Client verbindet, sendet der Dienst eine „Initial Inventory“-Nachricht, die eine vollständige Liste aller Geräte enthält.
- Anschließend sendet der Server für jede vom Client empfangene Nachricht genau eine „State Update“-Nachricht.
- Jeder „State Update“-Bericht enthält den Zustand (und den Status)allerGeräte.
Auf dieser Seite werdendas Kernprotokollund die Befehle des Simulationskanals erläutert.
Zusätzliche Module und Funktionen können das System durch die Registrierung eigener Befehle und Statusfelder erweitern. Diese werden im Abschnitt „Module“ einzeln erläutert.
Regeln des Protokolls
Eine Antwort pro Client-Nachricht
Der Dienst sendet fürjedevom Client empfangene Nachricht eine „State Update“-Nachricht, die den StatusallerGeräte enthält.
Das bedeutet Folgendes:
- Wenn Sie einen aktuellen Snapshot des Gerätestatus benötigen, müssen Sie einebeliebige Nachricht (Sitzungsbefehl, Abfragebefehl oder Gerätebefehl) senden.
- Dieser Kanal funktioniert wie eine durch Client-Nachrichten gesteuerte „Tick“-Schleife.
Abfragen ohne Spannungsanlegung (Probe-Befehl)
Wenn Sie Zustandsänderungen überwachen möchten, ohne eine Kraft aufzubringen oder Simulationsparameter zu ändern, verwenden Sie bitte den Befehl „probe“:
inverse3fürprobe_position- Für den Verse Grip
probe_orientation
Der Probe-Befehl enthält keine Befehlsdaten, sondern fordert lediglich die Übermittlung von Geräteinformationen an. Dadurch werden die Daten zu Position und Ausrichtung beim nächsten „State Update“ auf den aktuellen Stand gebracht.
Steuerbefehle (set_cursor_force、set_cursor_position In Simulationssitzungen, in denen bereits (u. a.) gesendet wurden, werden Probe-Befehle gesendetDas ist nicht notwendig.. Der Status des Geräts ist stets im Antwort-Frame enthalten. Der Probe muss den Status des Geräts abfragen, ohne das Gerät in Betrieb zu nehmen,Nur zur Überwachungist für Sitzungen (z. B. „ Haply Hub“) vorgesehen.
Einstellungen und Status
- Anfangsbestand In der Nachricht steht: „Das Gerät“
config、state、statusgehört dazu. - Normalerweise Aktuelles aus dem Bundesstaat In der Nachricht steht: „Das Gerät“
stateundstatusgehört dazu.
Falls Sie erneut einen Snapshot einschließlich der Einstellungen erstellen müssen,session.force_render_full_state Bitte verwenden Sie dies.
configure und commands Der Unterschied
Gerätemeldungen sind,configure und commands Es werden zwei separate Karten unterstützt. Beide dienen unterschiedlichen Zwecken:
| Karte | Zweck | Sendehäufigkeit |
|---|---|---|
configure | Einmalig festzulegende, dauerhafte Konfiguration: Voreinstellungen, Basis, Montage, Filter, Moduleinstellungen | Einmalig oder bei Änderungen versenden |
commands | Nicht persistente Befehle pro Takt: Kraft, Position, Drehmoment | Muss bei jedem Tick gesendet werden |
commands Einträge darin (set_cursor_force、set_cursor_position、set_angular_torques、set_angular_position) ist,Wird bei jedem Klick einmal angewendet und nicht gespeichert.。Wird die Übertragung beendet, tritt die Wirkung sofort nicht mehr ein, und das Gerät kehrt in den Ruhezustand zurück. Für Elemente, die über einen Tick hinweg beibehalten werden sollen, ohne dass eine erneute Übertragung erforderlich ist, gilt:configure Bitte verwenden Sie dies.
set_transform Das ist ein Sonderfall.set_transform は commands wird darunter platziert, aberdauerhaft. Der Dienst behält die zuletzt gesendete Transformation bei, bis eine neue Transformation gesendet wird. Bei jedem Tick wird gesendetDas ist nicht nötig.. Da der Zweck jedoch in der Navigation durch die Kamera bzw. die Szene besteht, ist das Streaming mit der Tick-Rate (z. B. das Senden einer Transformation pro Frame, wenn der Benutzer die Szene schwenkt) das erwartete Nutzungsmuster bei der Navigation durch kontinuierliche Bewegungen.
Koordinatensystem
Haply verwendet standardmäßig das Z-Up-Koordinatensystem mit rechter Hand.
Zwei „configure“-Einträge beeinflussen die Art und Weise, wie Koordinaten interpretiert und zurückgegeben werden:
session.configure.basis: Die Zuordnung zwischen den Koordinaten von „ Haply “ und dem Koordinatensystem der Anwendung wird geändert (siehe unten Grundlage (siehe dort).inverse3[*].configure.preset: Wählen Sie eine benannte Werkseinstellung aus, um den Ursprung des Arbeitsbereichs festzulegen (Beispiel:arm_front_centeredは(0, 0, 0)(in der Mitte des Arbeitsbereichs platzieren). Weitere Informationen finden Sie im Abschnitt „Configure“ für das jeweilige Gerät.
Nachrichtenformat
In diesem Abschnitt werden die übergeordneten Hüllstrukturen von Nachrichten sowie die verschiedenen Nachrichtentypen erläutert. Ein vollständiges Beispiel finden Sie im weiteren Verlauf dieses Dokuments.
Gerätegruppe
Die Nachrichten werden auf oberster Ebene nach Gerätetyp gruppiert (Beispiel: inverse3、verse_grip、wireless_verse_grip). Die Schlüssel der einzelnen Gerätetypen entsprechen den gerätespezifischen Objekt-Arrays.
Anfangsbestand (Server → Client)
Diese Nachricht wird unmittelbar nach dem Aufbau der WebSocket-Verbindung einmal gesendet.
Jeder Eintrag enthält Folgendes:
device_idconfigstatestatus
Siehe: Beispiel: Nutzlast des Anfangsbestands
Status-Update (Server → Client)
Es wird pro Client-Nachricht einmal gesendet.
Jeder Eintrag enthält Folgendes:
device_idstatestatus
Siehe: Beispiel: Nutzdaten der Statusaktualisierung
Hüllkurve des Sitzungsbefehls (Client → Server)
Ein Sitzungsbefehl ist eine Aktion, die auf die aktuelle Verbindung bzw. Sitzung angewendet wird undnicht gerätespezifisch ist.
{
"session": {
"<command_name>": {
"...": "..."
}
}
}
Hüllkurve für Gerätebefehle (Client → Server)
Gerätebefehle werden als Array unter dem Schlüssel für den Gerätetyp gesendet, wobei in einer einzigen Nachricht Befehle an ein oder mehrere Geräte gesendet werden können. Der Eintrag für jedes Gerät lautet:configure Karte und commands Beide Karten werden unterstützt.
{
"<device_type>": [
{
"device_id": "<id>",
"configure": {
"<config_key>": { "...": "..." }
},
"commands": {
"<command_name>": { "...": "..." }
}
}
]
}
Um Befehle an mehrere Geräte desselben Typs zu senden, können Sie mehrere Einträge in eine Nachricht aufnehmen.
commands Es handelt sich um ein Wörterbuch, das mehrere Befehle für ein einzelnes Gerät enthalten kann. Allerdings ist pro Befehlstyp nur ein Eintrag zulässig.
execute Feld
Alle „command“- oder „configure“-Einträge sind optional. "execute" Boolescher Wert (Standardwert ist true) werden entgegengenommen."execute": false Wenn diese Option aktiviert ist, werden die Einträge zwar analysiert, aber nicht angewendet. Dies gilt für reflektionsbasierte Serializer, die stets alle Felder ausgeben (z. B. Unity JsonUtility) ist dabei hilfreich.
"set_cursor_force": { "execute": false, "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
Befehlsreferenz
Sitzung
Zwangsweise Darstellung des vollständigen Zustands
Fordern Sie einen Momentaufnahme des Zustands und der Konfiguration aller Geräte an.
{
"session": {
"force_render_full_state": {}
}
}
Aufbau der Sitzung
Persistente Konfigurationen auf Sitzungsebene sind session.configure wird über … gesendet. Dies ist auf Geräteebene configure Es folgt dem Muster der Karte.
Profil
Legen Sie den Namen des Sitzungsprofils fest. Dieser Name wird vom „ Haply -Hub“ verwendet, um die Simulation zu erkennen und die gerätespezifischen Einstellungen für die jeweilige App zu speichern.
{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
Basis (Sitzungsebene)
Hier wird die Basiszuordnung für die gesamte Sitzung festgelegt. Die Basiszuordnung gibt an, wie die Koordinaten von „Haply “ in das Koordinatensystem der Anwendung umgewandelt werden. Nach der Konfiguration werden alle Gerätestatuswerte in dieser Basis zurückgegeben, und alle zu sendenden Werte werden ebenfalls in dieser Basis interpretiert.
Die Permutationszeichenfolge wird auf der Grundlage des rechtshändigen Koordinatensystems mit der Z-Achse nach oben (Haply ) dargestellt.X、Y、Z in dieser Reihenfolge, gegebenenfalls + oder - wird vorangestellt. Beispiel:
XYZ、ZYX、+Y-Z+X、X-ZYYZXist die AnwendungYaber rechts von „ Haply “,Zaber in Richtung von „ Haply “,XDas bedeutet, dass es sich um die Aufwärtsrichtung von „ Haply “ handelt.
Beispiel für die linke Hand und die nach oben gerichtete Z-Achse (Unreal,X-YZ):
{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
session.set_basis Migration vonherkömmliche session.set_basis und session.configure.basis Inzwischen wurden die Regeln für die Vorzeichen der Achsen geändert. Permutationen, die mit den alten Befehlen funktioniert haben, erzeugen mit den neuen Befehlen unter Umständen eine umgekehrte Transformation. Kehren Sie die Vorzeichen der Achsen bei Bedarf um (Beispiel:X-ZY は XZ-Y wird).
Befehle, die für alle Geräte gelten
Probing (alle Geräte)
Mit dem Abtastbefehl können Sie die aktuellen Positions- und Orientierungsdaten abfragen, ohne Kräfte anzulegen oder andere Änderungen an der Simulation vorzunehmen.
- inverse3:
probe_position - Verse Grip(
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)
Konfigurieren Sie die Arbeitsbereichsumsetzung des Geräts (Umwandlung vom Geräteraum in den Anwendungsraum).
andere commands Im Gegensatz zu einem Eintrag,set_transform はdauerhaft. Der Dienst behält den zuletzt gesendeten Wert bei, bis der nächste Wert gesendet wird. Es ist nicht erforderlich, bei jedem Tick einen Wert zu senden; da der Dienst jedoch für Kameras und die Navigation in Szenen vorgesehen ist, wird bei kontinuierlichen Bewegungen davon ausgegangen, dass die Daten mit der Tick-Rate gestreamt werden (Beispiel: Während der Benutzer die Szene schwenkt, wird pro Bild eine Transformation gesendet).
{
"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“ sind bei der Konvertierung rotation Nur die Inhaltsstoffe entfalten ihre Wirkung. Da der Griff lediglich die Körperhaltung erfasst,position や scale Es gibt nichts, was vergrößert, verkleinert oder verschoben werden könnte.position und scale Das Feld wird ausschließlich akzeptiert, um die Konsistenz des Schemas mitInverse3 zu gewährleisten (und wird auch unverändert in den Snapshot zurückgegeben), und hat den Wert (position = {0,0,0}、scale = {1,1,1})zu verwenden, ist die übliche Vorgehensweise.
Inverse3 Gerät konfigurieren
Konfigurations-Einträge sind configure Sie werden über die Karte gesendet. Diese sind dauerhaft. Bitte senden Sie sie einmalig oder sobald sich die Werte ändern.
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。
Basis (auf Geräteebene)
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"basis": { "permutation": "ZXY" }
}
}
]
}
Halterung
Konfigurieren Sie die Mount-Konvertierung für das Gerät.mount innerhalb von transform Bitte achten Sie auf 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 }
}
}
}
}
]
}
BefehlAuf der Seite (vom Client zum Server) wird die Konvertierung in einen Wrapper eingeschlossen:"mount": { "transform": { ... } }。
SchnappschussAuf der Seite (vom Server zum Client) ergibt sich eine flache Struktur:"mount": { "position": {...}, "rotation": {...}, "scale": {...} }。
Dies ist beabsichtigt. Die Befehle verwenden einen einheitlichen Wrapper, während Snapshots die Konvertierung direkt serialisieren. Achten Sie darauf, das Format des Snapshots nicht in die Nutzlast des Befehls zu kopieren.
Dämpfung
Steuert die gleichmäßige Dämpfung und/oder die richtungsabhängige Dämpfung. Es muss mindestens ein Feld angegeben werden.
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"damping": { "scalar": 0.5 }
}
}
]
}
Sie können die Dämpfung entweder für eine bestimmte Richtung oder für beide Richtungen gleichzeitig einstellen:
"damping": { "scalar": 0.5, "vector": { "x": 0.0, "y": 1.0, "z": 0.0 } }
Force Gate
Stellen Sie den Dämpfungsfaktor (0,0 bis 1,0) des Force Gate ein.
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"force_gate": { "gain": 0.3 }
}
}
]
}
Inverse3 Befehl
inverse3 Um einen Befehl an das Gerät zu senden,inverse3 Unter dem Schlüssel, passend device_id die entsprechenden Einträge enthalten. Der Befehl gilt pro Tick und muss bei jedem Tick erneut gesendet werden, um seine Gültigkeit aufrechtzuerhalten.
Wenn Sie einen Befehl an ein Gerät senden möchten:
{
"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
}
}
}
}
]
}
Einstellung der Cursorposition
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"position": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
Einstellungen für die Cursor-Stä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 des Winkeldrehmoments
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_torques": {
"torques": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}
Konfiguration von Verse Grip
Die Geräte „Verse Grip“ und „Wireless Verse Grip“ sindpreset、basis、mount Diesbezüglich gilt dasselbe wie unterInverse3 configure Unterstützt die Taste.
Erweiterung „Verse Grip“
set_extension_data Der Befehl ist Teil des erweiterten Protokolls von „Verse Grip“, das bei Versionen des Griffs zum Einsatz kommt, die das Board-Erweiterungsprotokoll implementieren.
Einstellungen für die Griff-Erweiterungsdaten
Unterstützte Datenlänge:
- Upstream (Client → Gerät): maximal 20 Byte.
- Downstream (Gerät → Client): maximal 12 Byte.
state.extension_datawird als „State Update“-Meldung zurückgegeben.
Datenspezifikationen:
- 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
]
}
}
}
]
}
Beispiel
Beispiel: Nutzlast des Anfangsbestands
Sobald eine WebSocket-Verbindung hergestellt ist, sendet der Dienst eine Nachricht mit einer vollständigen Liste der Geräte. Die erste Nachricht lautet wie folgt: JSON hat folgende Form:
{
"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 die Statusaktualisierung
Der Dienst sendet für jede empfangene Nachricht eine Statusaktualisierungsnachricht, die den Status aller Geräte enthält.
Wenn Sie den Zustand des Geräts erfahren möchten, müssen Sie vorab eine Nachricht senden (z. B. Abtastbefehle oder Kraftwerte, auch wenn der Wert Null ist). Dies ist besonders wichtig, wenn Sie das Gerät als Eingangsquelle (z. B. zur Positionsverfolgung) verwenden, ohne eine Kraft aufzubringen.
Statusaktualisierungsmeldungen sind die folgenden JSON hat folgende Form:
{
"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
}
}
]
}