Aller au contenu principal

07. Base et montage : terrain d'essai

Pilotez de manière interactive la transformation de montage de l'appareil et explique comment configure.basis, configure.preset et configure.mount fonctionnent ensemble au niveau du protocole. Conserve un plan 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é vers le haut selon l'axe Y)
  • 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é par le 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 sur une touche envoie exactement un message de configuration
  • (C++ Glaze) modélisation de champs mutuellement exclusifs avec std::optional

Flux de travail​

  1. Dès le 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 la valeur 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. À l'étape suivante : créez un bloc configure.mount avec une transformation dont rotation est un quaternion unitaire (composition Z puis X des angles de tangage et de lacet actuels). Omettez preset — les deux s'excluent mutuellement au niveau du protocole.
  5. La touche de réinitialisation (R) annule le remplacement ; la configuration suivante revient à preset.

Paramètres​

NomDéfautRôle
BASIS"XZY"Permutation des axes — repère d'application avec l'axe Y orienté 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 plancher fixe (Y de l'application)
STIFFNESS1000 N/mConstante de rigidité du sol
MOUNT_STEP_DEG10°Rotation par simple pression sur une touche
PRINT_EVERY_MS200Limitation du débit de télémétrie

Commandes​

ToucheAction
W / SFaire pivoter le montage de ±10° autour de l'axe +X de l'appareil (tangage)
A / DFaire pivoter le montage de ±10° autour de l'axe +Z de l'appareil (lacet)
RRéinitialiser le montage — revenir au préréglage
HAfficher les commandes
QLâcheur
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. Appuyez sur R réactive preset lors de la configuration suivante, retire mount.

Différents modèles de saisie

Les variantes en C++ lisent les entrées ligne par ligne à partir d'un flux d'exécution stdin en arrière-plan (appuyez sur ENTRÉE après chaque lettre). Python utilise le module keyboard pour la détection des touches en temps réel dans la boucle asynchrone principale — pas besoin de la touche 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 identique pour toutes les variantes ; les différences notables concernent la manière dont chacune construit l'embranchement mutuellement exclusif mount / preset et la manière dont le fil d'entrée signale le fil WebSocket.

Boucle asynchrone unique avec interrogation 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 (transformation) · Tutoriel 04 (Bonjour Floor)