03. Wireless VerseGrip drucken
Das gleiche Schema wie in Tutorial 02, jedoch für einen kabellosen VerseGrip – fügt dem gestreamten Status die Tasten (A/B/C) und den Akkustand hinzu.
Was Sie lernen werden:
- Auslesen von drahtlos-spezifischen Statusfeldern:
buttons.{a,b,c},battery_level,hall - Verwendung von
probe_orientationals eigenständiger Keepalive-Beobachter - Das gleiche Handshake-Muster, bei dem nur die erste Nachricht gesendet wird, wie in Tutorial 02
Arbeitsablauf
- Öffne einen WebSocket zu
ws://localhost:10001und auf den ersten Status-Frame warten. - Entscheiden Sie sich für den ersten kabellosen VerseGrip
device_idaus demwireless_verse_gripArray. - Erstellen Sie eine Anfrage mit dem Sitzungsprofil und pro Gerät
probe_orientationKeepalive. - Sende die Anfrage und entferne anschließend das
sessionFeld – es handelt sich um einen einmaligen Handshake. - Wandle in jedem nachfolgenden Frame das Quaternion in Euler-Winkel um und gib die gedrosselte Telemetriedaten aus, einschließlich der Tastenstatus und des Akkustands. Sende das Keepalive bei jedem Tick erneut.
Parameter
| Name | Standard | Zweck |
|---|---|---|
URI | ws://localhost:10001 | WebSocket-URL des Simulationskanals |
PRINT_EVERY_MS | 100 | Drosselung der Konsolenausgabe |
| Name des Sitzungsprofils | co.haply.inverse.tutorials:print-wireless-verse-grip | Identifiziert diese Simulation im Haply |
Die Umrechnung erfolgt im Anwendungsbezugssystem nach dem intrinsischen Z-X-Y-Schema (Gieren → Nicken → Rollen) +X right, +Y forward, +Z up. Nicht Verwendung glm::eulerAngles — Es folgt einer anderen Konvention und wird hier falsch angezeigt. Alle drei Sprachvarianten verwenden dieselbe mathematische Formel; die Formel findest du im Quellcode.
probe_orientation tatsächlich benötigt wirdprobe_orientation ist nur dann sinnvoll, wenn deine Sitzung nicht Senden Sie einen beliebigen Befehl an einen Inverse3. Sobald Sie einen Befehl an einen Inverse3 senden Inverse3 Kraft, Position, Drehmoment ...), überträgt der Dienst automatisch die Ausrichtung des gekoppelten VerseGrip in jedem Zustandsframe – ganz ohne Sensor. Verwenden Sie probe_orientation nur für eigenständige Tools zur Griffüberwachung wie in diesem Tutorial.
Statusfelder gelesen
Von data.wireless_verse_grip[0].state:
orientation—quaternion(w, x, y, z)hall— Ganzzahliger Messwert des Hall-Sensorsbuttons.a,buttons.b,buttons.c— Boolesche Wertebattery_level— float (0,0 – 1,0)
Senden / Empfangen
Gleiche Form wie Tutorial 02, nur mit dem wireless_verse_grip Gerätearray. Die WebSocket-Schleife empfängt einen Status-Frame und sendet den Handshake zurück + probe_orientation Keepalive; die erste ausgehende Nachricht enthält das Sitzungsprofil, alle nachfolgenden Frames enthalten nur das Keepalive.
- Python
- C++ (nlohmann)
- C++ (Glaze)
Einzelne asynchrone Schleife.
async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)
if first_message:
first_message = False
device_id = data["wireless_verse_grip"][0]["device_id"]
request_msg = {
"session": {"configure": {"profile": {
"name": "co.haply.inverse.tutorials:print-wireless-verse-grip"}}},
"wireless_verse_grip": [{
"device_id": device_id,
"commands": {"probe_orientation": {}} # empty — keepalive
}]
}
await websocket.send(json.dumps(request_msg))
request_msg.pop("session", None) # one-shot handshake
ws.onmessage = [&](const std::string &msg) {
const json data = json::parse(msg);
if (first_message) {
first_message = false;
device_id = data["wireless_verse_grip"][0].at("device_id").get<std::string>();
request_msg = {
{"session", {{"configure", {{"profile",
{{"name", "co.haply.inverse.tutorials:print-wireless-verse-grip"}}}}}}},
{"wireless_verse_grip", json::array({
{{"device_id", device_id},
{"commands", {{"probe_orientation", json::object()}}}},
})},
};
}
ws.send(request_msg.dump());
request_msg.erase("session"); // one-shot handshake
};
ws.open("ws://localhost:10001");
while (std::cin.get() != '\n') {} // block main thread
Typisierte Strukturen. Hinweis button_state wird explizit genannt (nicht buttons), um zu vermeiden, dass der buttons Feld aktivieren wvg_state — Glaze ordnet Felder anhand ihres Namens zu, sodass der Name des Strukturtyps frei gewählt werden kann.
// Struct models
struct quat { float w{1.0f}, x{}, y{}, z{}; };
struct button_state { bool a{}, b{}, c{}; };
struct wvg_state {
quat orientation{};
uint8_t hall{};
button_state buttons{};
float battery_level{};
};
struct wvg_device { std::string device_id; wvg_state state; };
struct devices_message { std::vector<wvg_device> wireless_verse_grip; };
struct probe_orientation_cmd {}; // empty object on the wire
struct commands_message {
std::optional<session_cmd> session; // one-shot — omitted when unset
std::vector<device_commands> wireless_verse_grip;
};
// Send / receive
ws.onmessage = [&](const std::string &msg) {
devices_message data{};
if (glz::read<glz_settings>(data, msg)) return;
if (first_message) {
first_message = false;
request_msg.session = session_cmd{ /* profile = print-wireless-verse-grip */ };
device_commands dc{ .device_id = data.wireless_verse_grip[0].device_id };
dc.commands.probe_orientation = probe_orientation_cmd{};
request_msg.wireless_verse_grip.push_back(std::move(dc));
}
std::string out_json;
(void)glz::write_json(request_msg, out_json);
ws.send(out_json);
request_msg.session.reset(); // one-shot handshake
};
ws.open("ws://localhost:10001");
while (std::cin.get() != '\n') {} // block main thread
Quelle: Python · C++ · C++ Glaze
Siehe auch: Anleitung 02 (Wired VG) · Typen (Quaternionen) · Steuerbefehle (probe_orientation) · WebSocket-Protokoll