Zum Hauptinhalt springen

07. Basis & Mount-Spielplatz

Steuert interaktiv die Montage-Transformation des Geräts und zeigt, wie configure.basis, configure.preset und configure.mount auf Protokollebene zusammenwirken. Es wird ein fester horizontaler Boden beibehalten, damit der interaktive Fokus auf den `configure`-Befehlen bleibt.

Was Sie lernen werden:

  • Festlegen einer Basispermutation ("XZY" → Anwendungsrahmen mit der Y-Achse nach oben)
  • Auswahl eines Voreinstellungen (arm_front) und nachvollziehen, was dadurch konfiguriert wird
  • Überschreiben des Mounts zur Laufzeit mit einem Rotationsquaternion (über die Tastatur gesteuert)
  • Das Prinzip der gegenseitigen Ausschließlichkeit: mount und preset können nicht gemeinsam im selben Block der Gerätekonfiguration vorkommen
  • Einmalige configure-Semantik: Jeder Tastendruck sendet genau eine „configure“-Nachricht
  • (C++ Glaze) Modellierung sich gegenseitig ausschließender Felder mit std::optional

Ablauf​

  1. Bei der ersten Nachricht: Senden Sie das Sitzungsprofil, configure.basis: "XZY" und configure.preset: arm_front. Beginnen Sie mit dem festen Boden set_cursor_force zu senden.
  2. Bei jedem Tick: Cursor-Y auslesen, force_y = max(0, (floor_pos - y) * stiffness) berechnen und versenden.
  3. Wenn der Benutzer eine Taste zur Wechselung der Einbindung drückt, setzen Sie pending_configure = true.
  4. Beim nächsten Tick erstellen Sie einen configure.mount-Block mit einer Transformation, deren rotation ein Einheits-Quaternion ist (Zusammensetzung aus Z und anschließend X aus dem aktuellen Pitch- und Yaw-Wert). Nehmen wir an, preset weg – die beiden schließen sich auf Protokollebene gegenseitig aus.
  5. Die Reset-Taste (R) hebt das Überschreiben auf; die nächste „configure“-Anweisung greift wieder auf preset zurück.

Parameter​

NameStandardZweck
BASIS"XZY"Achsenpermutation – Anwendungsrahmen mit der Y-Achse nach oben
DEVICE_PRESET / DEVICE_CONFIG_PRESET"arm_front"Benanntes Preset – Ursprung an der Gerätebasis
FLOOR_POS_Y0.0 mFeste Bodenebene (Anwendungs-Y)
STIFFNESS1000 k. A.Federkonstante des Bodens
MOUNT_STEP_DEG10°Drehung per Tastendruck
PRINT_EVERY_MS200Einschränkung der Telemetrie

Steuerung​

GeschmackAktion
W / SDas Gerät um ±10° um die +X-Achse drehen (Neigung)
A / DUm ±10° um die +Z-Achse des Geräts drehen (Yaw)
RMount zurücksetzen – zurück zum Preset
HSteuerung anzeigen
QBeenden
mount und preset schließen sich gegenseitig aus

Der Dienst lehnt eine Sperrung der Gerätekonfiguration ab, das beide enthält. Sobald der Benutzer den Mount überschreibt, lässt das Tutorial preset in jeder weiteren `configure`-Anweisung weggelassen. Durch Drücken von R wird preset bei der nächsten „configure“-Anweisung wieder aktiviert und mount verworfen.

Verschiedene Eingabemodelle

Die C++-Varianten lesen zeilenbasierte Eingaben in einem Hintergrund-stdin-Thread ein (nach jedem Buchstaben die Eingabetaste drücken). Python verwendet das Paket keyboard für die Echtzeit-Tastenabfrage in der asynchronen Hauptschleife – ENTER ist nicht erforderlich. Gleiche Tasten, gleiche Befehle.

Ausgelesene Zustandsfelder​

Aus data.inverse3[i].state:

  • cursor_position.y — vec3, wird zur Berechnung der Bodendurchdringung verwendet
  • current_cursor_force — wird für die Telemetrie gemeldet

Senden / Empfangen​

Die Struktur der Nutzlast ist in allen Varianten gleich; interessant sind die Unterschiede darin, wie jede Variante die sich gegenseitig ausschließenden Zweige mount / preset aufbaut und wie der Eingabe-Thread dem WebSocket-Thread ein Signal sendet.

Einzelne asynchrone Schleife mit Echtzeit-Tastenabfrage über das Paket keyboard. pending_configure ist ein globales Flag, das von den Tastaturhandlern gesetzt und jedes Mal zurückgesetzt wird, wenn ein configure-Block gesendet wird.

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["inverse3"][0]["device_id"]
# Handshake: profile + basis + preset
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": build_configure_block(first_handshake=True),
# -> {"basis": {"permutation": "XZY"},
# "preset": {"preset": "arm_front"}}
}],
}
else:
handle_key_inputs() # may set pending_configure = True (classic, not shown)

y = data["inverse3"][0]["state"]["cursor_position"]["y"]
force_y = 0.0 if y > FLOOR_POS_Y else (FLOOR_POS_Y - y) * STIFFNESS

entry = {
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": force_y, "z": 0.0}}},
}
if pending_configure:
entry["configure"] = build_configure_block(first_handshake=False)
# -> {"mount": {...}} OR {"preset": {...}} (never both)
pending_configure = False

request_msg = {"inverse3": [entry]}

await websocket.send(json.dumps(request_msg))
Im SDK-Installationsprogramm enthalten

Tutorial 07 ist ebenfalls lokal mit dem SDK installiert – zu finden unter tutorials/07-haply-inverse-basis-and-mount/ im Installationsverzeichnis des Dienstes.

Quelle: Python · C++ · C++ Glaze

Verwandte Themen: Basispermutation · Halterung & Arbeitsbereich · Gerätekonfiguration · Steuerbefehle (set_cursor_force) · Typen (transformieren) · Tutorial 04 (Hallo Boden)