Skip to main content
Version : 3.5.x

05. Contrôle de position

Déplace le Inverse3 vers une position cible via set_cursor_position. Le modèle d'interaction varie selon la langue — Le C++ utilise des cibles aléatoires ponctuelles, tandis que Python utilise un déplacement continu commandé par le clavier.

Ce que vous apprendrez :

  • Utilisation de set_cursor_position pour la régulation en mode position
  • Deux modèles d'interaction différents pour une même commande sous-jacente
  • Fixation de la cible sur une sphère de l'espace de travail — Minverse un rayon plus petit qu'Inverse3
  • Définir un préréglage d'espace de travail pour que l'origine se trouve au centre de l'espace de travail

Flux de travail

C++ (modèle à cible aléatoire)

  1. Lancer un thread d'entrée en arrière-plan qui lit les frappes stockées dans le tampon de ligne (n, +, -, q) à partir de l'entrée standard.
  2. Ouvrez le WebSocket. Lors de la première trame d'état, enregistrez le profil de session et définir configure.preset: arm_front_centered. Générer la première cible aléatoire à l'intérieur d'une sphère (échantillonnage par rejet, rayon de 0,08 m).
  3. À chaque tick, envoyer un set_cursor_position commande vers la cible actuelle. Le curseur la suit en douceur : le service applique une limitation de débit et effectue une interpolation.
  4. Lorsque l'utilisateur tape n + ENTRÉE : le thread d'entrée génère une nouvelle cible aléatoire. + / - régler la vitesse ; q quitte.

Python (modèle « tenir pour déplacer »)

  1. Ouvrez le WebSocket. Dans la première trame d'état, vérifiez status.calibrated — demander à l'utilisateur de procéder au calibrage si l'appareil n'est pas encore calibré.
  2. Lire config.type pour choisir le rayon de l'espace de travail (minverse = 0,04 m, sinon = 0,10 m).
  3. Enregistrer le profil de session et définir configure.preset: arm_front_centered.
  4. À chaque itération : vérifier l'état du clavier (W/A/S/D/Q/E), mettre à jour la position cible en SPEED le long de chaque axe enfoncé, fixer à la sphère de travail, puis envoyer set_cursor_position. R réinitialise la cible à l'origine.

Paramètres

NomPar défaut (C++)Par défaut (Python)Objectif
workspace_radius / RADIUS_INVERSE30.08 m0.10 m (Inverse3) / 0.04 m (Minverse)Rayon de la sphère cible
speed_step / SPEED0.01 / presse0.00005 m / tickÉtape par interaction
PRINT_EVERY_MS100Accélérateur de télémétrie (Python)
Profil de sessionco.haply.inverse.tutorials:position-controlidemIdentifie dans Haply
Vérification de l'étalonnage (Python)

Les vérifications de la variante Python status.calibrated à partir du premier cadre d'état et demande à l'utilisateur de procéder à l'étalonnage si l'appareil n'est pas encore étalonné. La variante C++ part du principe que l'étalonnage est déjà terminé.

Champs d'état lus

  • data.inverse3[0].device_id — pour la création de la commande
  • data.inverse3[0].state.cursor_position — télémétrie
  • (Python, première image uniquement) data.inverse3[0].config.type — sélectionne Minverse « Inverse3 Minverse
  • (Python, première image uniquement) data.inverse3[0].status.calibrated — demande à l'utilisateur si la valeur est fausse

Envoyer / recevoir

Processus de communication

  • C++ exécute un thread stdin en arrière-plan qui écrit std::atomic<float> cibles ; le thread WebSocket les lit à chaque tick. Sur n + ENTER : le thread de saisie génère une nouvelle cible aléatoire ; sur q, les deux fils ont été fermés.
  • Python fonctionne en asynchrone à un seul thread : la boucle WebSocket interroge l'état du clavier à chaque itération et met à jour position directement.

Les charges utiles de l'API inverse sont identiques : le premier tick contient le profil de session + configure.preset, les ticks suivants ne portent que set_cursor_position.

Boucle asynchrone unique. Interrogation du clavier (handle_keys) s'exécute en ligne à chaque itération — sans threads. config.type et status.calibrated sont lues une seule fois à partir de la première trame d'état.

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"]
radius = get_workspace_radius(data["inverse3"][0].get("config", {}))
# Handshake: profile + preset (one-shot)
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": {"preset": {"preset": "arm_front_centered"}},
}],
}
else:
# Per tick: update position from keyboard (classic polling, not shown), send command
position = handle_keys(position, radius)
request_msg = {
"inverse3": [{
"device_id": device_id,
"commands": {"set_cursor_position": {"position": position}},
}],
}

await websocket.send(json.dumps(request_msg))

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

À lire également : Commandes de contrôle (set_cursor_position) · Montage et espace de travail (préréglages) · Types (vec3) · Tutoriel 06 (Combiné)