Aller au contenu principal

06. Ensemble (Inverse3 + Wireless VerseGrip)

Tutoriel à deux appareils : pointez la poignée et maintenez un bouton enfoncé pour déplacer le curseur Inverse3 dans cette direction. Le curseur est confiné à l'intérieur d'un espace de travail sphérique.

Ce que vous apprendrez :

  • Lire deux types d'appareils dans la même trame d'état (inverse3 et wireless_verse_grip)
  • Retirer la pièce de guidage de la poignée de son emplacement quaternion (axe local +Y)
  • Utiliser set_cursor_position pour déplacer le curseur vers une cible calculée
  • Limiter la cible à une sphère de l'espace de travail sécurisé — Minverse utilise un rayon plus petit que Inverse3
  • Définir un préréglage de l'espace de travail (arm_front_centered) afin que l'origine soit située au centre de la portée

Déroulement​

  1. Détecter les deux appareils :
    • Les variantes C++ interrogeant GET /devices via HTTP au démarrage, puis affichent une invite de calibrage et attendent que l'utilisateur appuie sur la touche Entrée.
    • Python lit les identifiants des deux appareils à partir de la première trame d'état de WebSocket.
  2. Enregistrez le profil de session et définissez configure.preset: arm_front_centered dans le premier message (prise de contact unique).
  3. À chaque cycle, lisez l'orientation de la poignée et l'état de buttons.{a, b}.
  4. Si un bouton de déplacement est enfoncé, calculez la direction de la poignée dans l'espace du monde (R(q) · ĵ — l'axe unitaire +Y pivoté), multipliez-la par SPEED puis ajoutez-la à la position cible.
  5. Limitez la cible à l'intérieur de la sphère de l'espace de travail et envoyez-la via set_cursor_position.
  6. (Python uniquement) Adaptez le rayon de la sphère en fonction du config.type de l'appareil — minverse = 0,04 m, tout le reste = 0,10 m.

Paramètres​

NomValeur par défautRôle
SPEED0.01 m/cycleAucun déplacement tant qu'un bouton est enfoncé
RADIUS_INVERSE30.10 mRayon de contrainte de l'espace de travail pour Inverse3 / Inverse3x
RADIUS_MINVERSE0.04 mRayon de contrainte de l'espace de travail pour Minverse (Python uniquement — C++ corrigé) 0.10 (en dur)
PRINT_EVERY_MS200Limitation du débit de télémétrie
Nom du profil de sessionco.haply.inverse.tutorials:combinedIdentifiez cette simulation dans le Hub Haply
Calibrer avant l'exécution
  • Laissez- Inverse3 -se calibrer automatiquement (ou posez la poignée sur l'encrier et attendez que la LED reste allumée en continu).
  • Retirez la poignée de l'encrier.
  • Maintenez la touche A ou B enfoncée et faites pivoter la poignée : le curseur se déplace dans la direction vers laquelle pointe la poignée.

Champs d'État lus​

À partir de la trame d'état de chaque cycle :

  • data.inverse3[0].state.cursor_position — vec3
  • data.wireless_verse_grip[0].state.orientation — quaternion
  • data.wireless_verse_grip[0].state.buttons.{a, b, c} — booléens
  • (Python, première trame uniquement) data.inverse3[0].config.type — sélectionne le rayon de Inverse3 ou celui de Minverse
  • (Python, première trame uniquement) data.inverse3[0].status.calibrated — invite l'utilisateur à effectuer un étalonnage si la valeur est erronée

Envoi et réception​

Le calcul de la direction à partir du quaternion (rotation de +Y par R(q)) et la contrainte à la sphère relèvent de l'algèbre linéaire classique — consultez les fichiers source. Du côté de l'API Inverse, il s'agit de la prise de contact initiale et de set_cursor_position à chaque cycle.

Boucle asynchrone unique. Python lit les identifiants des deux appareils à partir de la première trame d'état ; la prise de contact joint le profil et configure.preset: arm_front_centered au premier set_cursor_position.

async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)

if first_message:
first_message = False
inverse3_id = data["inverse3"][0]["device_id"]
grip_id = data["wireless_verse_grip"][0]["device_id"]
radius = get_workspace_radius(data["inverse3"][0].get("config", {}))

# Handshake: profile + preset + first position command
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": inverse3_id,
"configure": {"preset": {"preset": "arm_front_centered"}},
"commands": {"set_cursor_position": {"position": position}},
}],
}
else:
# Per tick: update position from grip pointing direction (classic math, not shown), send
request_msg = {
"inverse3": [{
"device_id": inverse3_id,
"commands": {"set_cursor_position": {"position": position}},
}],
}

await websocket.send(json.dumps(request_msg))
Inclus avec le programme d'installation du SDK

Le tutoriel n° 6 est également installé localement avec le SDK — consultez tutorials/06-haply-inverse-combined/ dans le répertoire d'installation du service.

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

Voir aussi : Commandes de contrôle (set_cursor_position) · Types (quaternion, vec3) · Montage et espace de travail (préréglages) · Tutoriel n° 3 (VG sans fil) · Tutoriel 05 (contrôle de position)