Aller directement au corps du texte

05. Contrôle de position

set_cursor_positionÀ l'aide de la commande Inverse3 , déplacez le curseur dans la direction de la position cible. Les modèles d'interaction varient selon la langue. Le C++ utilise des cibles aléatoires ponctuelles, tandis que Python utilise un système de déplacement continu via le clavier.

Contenu pédagogique :

  • Pour le contrôle du mode de localisation set_cursor_position Mode d'emploi
  • Deux modèles d'interaction pour une même commande de base
  • Limiter (clamp) la position cible à l'intérieur de la sphère de l'espace de travail — Minverse utilise un rayon plus petit qu'Inverse3
  • Configurer les paramètres par défaut de l'espace de travail afin que le point d'origine soit situé au centre de celui-ci

Flux de travail​

C++ (modèle à cibles aléatoires)​

  1. les entrées clavier saisies ligne par ligne via stdin (n, +, -, q) lance un thread d'entrée en arrière-plan chargé de lire [ce contenu].
  2. Ouvre un WebSocket. Dans la première trame d'état : Profil de sessionen l'enregistrant et configure.preset: arm_front_centeredConfigurez le paramètre. Générez une première cible aléatoire à l'intérieur de la sphère (échantillonnage par rejet, rayon de 0,08 m).
  3. À chaque étape, concernant l'objectif actuel set_cursor_position La commande est envoyée. Le curseur suit la cible en douceur — le service limite la fréquence d'envoi (rate-limit) et effectue une interpolation.
  4. L'utilisateur n Une fois la saisie effectuée, appuyez sur ENTER pour que le thread de saisie génère une nouvelle cible aléatoire. + / -pour régler la vitesse, et, qet se termine par.

Python (modèle de déplacement par pression)​

  1. Ouvre un WebSocket. Dans la première trame d'état : status.calibratedvérifie et, si l'appareil n'a pas encore été calibré, en informe l'utilisateur.
  2. config.typeLisez le texte pour sélectionner le rayon de l'espace de travail (minverse = 0,04 m, sinon = 0,10 m).
  3. Profil de sessionen l'enregistrant et configure.preset: arm_front_centeredConfigurez .
  4. À chaque frappe, l'état du clavier (W/A/S/D/Q/E) et, le long de chaque axe enfoncé, SPEEDUne fois la position cible mise à jour, serrer l'élément à l'intérieur de l'espace de travail et set_cursor_positionest transmis. RLorsque vous appuyez sur ce bouton, la cible est réinitialisée au point de départ.

Paramètres​

NomValeur par défaut (C++)Valeur par défaut (Python)Utilisation
workspace_radius / RADIUS_INVERSE30.08 m0.10 m (Inverse3) / 0.04 m (Minverse)Rayon du cercle cible
speed_step / SPEED0.01 / Appuyer sur0.00005 m / ticIntervalle de déplacement par interaction
PRINT_EVERY_MS—100Limitation de la télémétrie (Python)
Profil de sessionco.haply.inverse.tutorials:position-controlidentiqueHaply Utilisé par le Hub à des fins d'identification
Vérification de l'étalonnage (Python)

La mutation en Python se produit dès la première trame d'état status.calibratedvérifie si l'appareil est calibré et, s'il ne l'est pas, en informe l'utilisateur. La version C++ part du principe que le calibrage est déjà terminé.

Champ « État de lecture »​

  • data.inverse3[0].device_id — Utilisé pour la génération de commandes
  • data.inverse3[0].state.cursor_position — Télémétrie
  • (Python, uniquement pour la première image) data.inverse3[0].config.type — Sélectionnez le rayon : Inverse3 ou Minverse
  • (Python, uniquement pour la première image) data.inverse3[0].status.calibrated — Si la valeur est « false », envoyer une notification à l'utilisateur

Émission et réception​

Flux de travail de communication​

  • **C++** exécute un thread stdin en arrière-plan afin de std::atomic<float> La valeur cible est enregistrée, et le thread WebSocket lit cette valeur à chaque tick. n Une fois la saisie effectuée, appuyez sur ENTER : le thread de saisie génère alors une nouvelle cible aléatoire, et qSi vous cliquez sur ce bouton, les deux threads seront arrêtés.
  • PythonIl s'agit d'une approche asynchrone à thread unique : la boucle WebSocket interroge l'état du clavier à chaque tick et positionIl le met à jour directement.

La charge utile de l'API inverse est identique. Lors du premier tick, le profil de session et configure.presetCeci est inclus, et dans les ticks suivants, set_cursor_position... sont les seules à être incluses.

Il s'agit d'une boucle asynchrone unique. Interrogation du clavier (handle_keys) est exécuté en ligne à chaque tick, sans utiliser de thread distinct. config.typeet status.calibratedn'est lue qu'une seule fois dans 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))
Programme d'installation du SDK inclus

Le tutoriel 05 est également installé localement avec le SDK. Dans le répertoire d'installation du service, sous le dossier tutorials/05-haply-inverse-position-control/Vous pouvez le consulter ici.

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

Documents connexes : Commandes de contrôle (set_cursor_position) · Montage et espace de travail (préréglage) · Type (vec3) · Tutoriel n° 6 (Combiné)