Aller au contenu principal

07. Base et montage : terrain d'essai

Pilote de manière interactive la transformation de montage de l'appareil et montre comment configure.basis, configure.preset et configure.mount fonctionnent ensemble au niveau du protocole. Conserve un sol horizontal fixe afin que le point d'intérêt interactif reste sur les commandes de configuration.

Ce que vous apprendrez :

  • Définir une permutation de base ("XZY" → repère d'application orienté Y vers le haut)
  • Choisir un préréglage (arm_front) et comprendre ce qu'il configure
  • Remplacer le montage à l'exécution par un quaternion de rotation (piloté au clavier)
  • La règle d'exclusion mutuelle : mount et preset ne peuvent pas coexister dans le même bloc de configuration de l'appareil
  • Sémantique ponctuelle de configure : chaque pression de touche envoie exactement un message de configuration
  • (C++ Glaze) modélisation de champs mutuellement exclusifs avec std::optional

Flux de travail​

  1. Au premier message : envoyez le profil de session, configure.basis: "XZY" et configure.preset: arm_front. Commencez à envoyer set_cursor_force pour le sol fixe.
  2. À chaque cycle : lisez Y du curseur, calculez force_y = max(0, (floor_pos - y) * stiffness) et envoyez-la.
  3. Lorsque l'utilisateur appuie sur une touche de rotation du montage, définissez pending_configure = true.
  4. Au cycle suivant : construisez un bloc configure.mount avec une transformation dont rotation est un quaternion unitaire (composition Z puis X du tangage / lacet courants). Omettez preset — les deux sont mutuellement exclusifs au niveau du protocole.
  5. La touche de réinitialisation (R) efface le remplacement ; la configuration suivante revient à preset.

Paramètres​

NomDéfautRôle
BASIS"XZY"Permutation des axes — repère d'application orienté Y vers le haut
DEVICE_PRESET / DEVICE_CONFIG_PRESET"arm_front"Préréglage nommé — origine à la base de l'appareil
FLOOR_POS_Y0.0 mPlan du sol fixe (Y de l'application)
STIFFNESS1000 N/mConstante de raideur du sol
MOUNT_STEP_DEG10°Rotation par pression de touche
PRINT_EVERY_MS200Limitation du débit de télémétrie

Commandes​

ToucheAction
W / SFaire pivoter le montage de ±10° autour de +X de l'appareil (tangage)
A / DFaire pivoter le montage de ±10° autour de +Z de l'appareil (lacet)
RRéinitialiser le montage — revenir au préréglage
HAfficher les commandes
QQuitter
mount et preset sont mutuellement exclusifs

Le service rejette un bloc de configuration de l'appareil qui contient les deux. Une fois que l'utilisateur a remplacé le montage, le tutoriel omet preset de chaque configuration suivante. Appuyer sur R réactive preset lors de la configuration suivante et retire mount.

Modèles de saisie différents

Les variantes C++ lisent la saisie ligne par ligne dans un fil d'exécution stdin en arrière-plan (appuyez sur ENTRÉE après chaque lettre). Python utilise le paquet keyboard pour la scrutation des touches en temps réel dans la boucle asynchrone principale — pas besoin d'ENTRÉE. Mêmes touches, mêmes commandes.

Champs d'état lus​

À partir de data.inverse3[i].state :

  • cursor_position.y — vec3, utilisé pour calculer la pénétration dans le sol
  • current_cursor_force — signalé pour la télémétrie

Envoi / réception​

La structure de la charge utile est la même pour toutes les variantes ; les différences notables concernent la façon dont chacune construit l'embranchement mutuellement exclusif mount / preset et la façon dont le fil d'entrée signale le fil WebSocket.

Boucle asynchrone unique avec scrutation des touches en temps réel via le paquet keyboard. pending_configure est un indicateur global défini par les gestionnaires de touches et réinitialisé chaque fois qu'un bloc configure est envoyé.

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))
Fourni avec le programme d'installation du SDK

Le tutoriel 07 est également installé localement avec le SDK — consultez tutorials/07-haply-inverse-basis-and-mount/ dans le répertoire d'installation du service.

Source : Python · C++ · C++ Glaze

Voir aussi : Permutation de base · Montage et espace de travail · Configuration de l'appareil · Commandes de contrôle (set_cursor_force) · Types (transform) · Tutoriel 04 (Hello Floor)