03. Drahtloses Drucken mit VerseGrip
Entsprichtdem ModusausTutorial 02, gilt jedoch für den kabellosen VerseGrip – im Streaming-Modus wurden die Tasten (A/B/C) und der Akkustand hinzugefügt.
Du wirst Folgendes lernen:
- Das für das drahtlose Gerät spezifische Statusfeld auslesen:
buttons.{a,b,c}、battery_level、hall - wird
probe_orientationMechanismus zur Aufrechterhaltung der Lebensfähigkeit als unabhängiger Beobachter - Handshake-Modus mit nur einer ersten Nachricht, wie inTutorial 02
Arbeitsablauf
- Öffnen bis
ws://localhost:10001WebSocket und warte auf den ersten Status-Frame. - von
wireless_verse_gripDen ersten „VerseGrip“ aus dem Array abrufendevice_id。 - Verwendung Sitzungsprofil Erstellen Sie eine Anfrage und fügen Sie für jedes Gerät Folgendes hinzu:
probe_orientationAnweisung zur Kinderbetreuung. - Anfrage senden, dann entfernen
sessionFeld – es handelt sich lediglich um einen einmaligen Handshake. - In jedem folgenden Frame werden die Quaternionen in Euler-Winkel umgewandelt und die gedrosselten Telemetriedaten, einschließlich des Tastenstatus und des Ladezustands der Batterie, ausgegeben. In jedem Zyklus wird erneut ein Keep-Alive-Befehl gesendet.
Parameter
| Bezeichnung | Standardwert | Verwendungszweck |
|---|---|---|
URI | ws://localhost:10001 | URL des WebSocket-Simulationskanals |
PRINT_EVERY_MS | 100 | Drosselung der Konsolenausgabe |
| Name des Sitzungsprofils | co.haply.inverse.tutorials:print-wireless-verse-grip | Diese Simulation im „ Haply Hub“ kennzeichnen |
Die Transformation erfolgt in der intrinsischen Z-X-Y-Reihenfolge (Gierung → Nickung → Rollung), wobei als Koordinatensystem +X right, +Y forward, +Z up。Bitte nichtVerwendung glm::eulerAngles——Es folgt unterschiedlichen Konventionen, weshalb hier ein falsches Ergebnis ausgegeben wird. In allen drei Sprachversionen werden dieselben mathematischen Berechnungen durchgeführt; die Formeln finden Sie im Quellcode.
probe_orientationprobe_orientation Nur in deiner SitzungkeineDies ist nur nützlich, wenn Sie Befehle an Inverse3 senden. Sobald Sie Befehle (Kraft, Position, Drehmoment usw.) an Inverse3 senden, übermittelt der Dienst automatisch in jedem Status-Frame die entsprechenden VerseGrip-Richtungsdaten – ohne dass eine Erkennung erforderlich ist. Verwenden Sie dies nur in eigenständigen Greiferüberwachungstools wie in diesem Tutorial. probe_orientation。
Gelesene Statusfelder
Aus data.wireless_verse_grip[0].state:
orientation—quaternion(w, x, y, z)hall— Messwerte des Hall-Sensors vom Typ „Integer“buttons.a、buttons.b、buttons.c— Boolesche Wertebattery_level— Gleitkommazahlen (0,0 – 1,0)transform.rotation— Drehung des Arbeitsraums (quaternion); Position und Skalierung sind für Geräte, die nur eine Ausrichtung haben, nicht anwendbar und werden daher niemals ausgegeben
Wenn transform.rotation entspricht der Einheitsquaternion {w:1,x:0,y:0,z:0} In diesem Fall wird das Feld weggelassen. Bitte geben Sie beim Auslesen einen Standardwert an. Aktivieren serialization/explicit_fields Dieses Feld kann jederzeit empfangen werden.
Senden / Empfangen
undTutorial 02hat dieselbe Struktur, nur dass wireless_verse_grip Gerätearray. WebSocket empfängt kontinuierlich Status-Frames und sendet Handshake-Informationen sowie probe_orientation Keep-Alive-Befehl; die erste Nachricht enthält das Sitzungsprofil, alle folgenden Frames enthalten lediglich den Keep-Alive-Befehl.
- 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
Stark typisierte Strukturen. Hinweis button_state ist explizit benannt (und nicht buttons), um eine Verdeckung zu vermeiden wvg_state auf buttons Felder – Glaze ordnet Felder anhand ihrer Namen zu, daher können die Typnamen der Strukturen beliebig festgelegt werden.
// 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
Befehlszeilenargumente (Python)
Die Python-Version akzeptiert dieselben zwei Parameter wieTutorial 01:
--full——Die ursprüngliche JSON-Datenlast soll in formatierter Form ausgegeben werden, nicht als einzeilige Zusammenfassung.--query-config——Bei jedem Ausfahrzyklus erneut einspritzensession.force_render_full_state, sodass jedes EinzelbildconfigBlöcke und nicht nur Zustandsinkremente.
--query-config Das ist besonders nützlich für den kabellosen VerseGrip, da config Der Block enthält neben den üblichen Konfigurationsfeldern auch WVG-spezifische sub_type Feld (stylus / prototype / ruko / kingfisher(neu in Version 3.5). Ausführen python 03-haply-inverse-print-wireless-verse-grip.py --full --query-config Man kann dies in Echtzeit beobachten config.sub_type Zusammen mit den anderen Konfigurationswerten aktualisieren.
In der C++-Version stehen diese Parameter nicht zur Verfügung.
Das Tutorial 03 wird ebenfalls zusammen mit dem SDK lokal installiert – bitte im Installationsverzeichnis des Dienstes unter tutorials/03-haply-inverse-print-wireless-verse-grip/ dort suchen.
Quellcode: Python · C++ · C++ Glaze
Verwandte Themen: Tutorial 02 (VG mit Kabel) · Typ (Quaternionen) · Steuerbefehl (probe_orientation) · WebSocket-Protokoll