本文へスキップ
バージョン: 3.5.x

06. 組み合わせ(Inverse3 Wireless VerseGrip)

2つのデバイスを使ったチュートリアル:グリップを向け、ボタンを押し続けると、Inverse3 がその方向に移動します。カーソルは球形の作業領域内に固定されています。

学習内容:

  • 同じステートフレーム内で2種類のデバイスを読み取る(inverse3 そして wireless_verse_grip)
  • グリップの向きをその 四元数 (ローカル +Y (軸)
  • 使用して set_cursor_position カーソルを計算された目標地点へと移動させる
  • ターゲットを安全な作業領域内に固定する —Minverse Inverse3よりも半径を小さくMinverse
  • 設定 ワークスペースのプリセット (arm_front_centered)そのため、原点がリーチの中央に位置するように

ワークフロー

  1. 両方のデバイスをご覧ください:
    • C++ バリアントのクエリ GET /devices 起動時にHTTP経由で接続し、キャリブレーションのプロンプトを表示して、ENTERキーの入力待ちを行う。
    • Pythonは、最初のWebSocketステートフレームから両方のデバイスIDを読み取ります。
  2. を登録する セッションプロファイル そして設定する configure.preset: arm_front_centered 最初のメッセージにおいて(ワンショット・ハンドシェイク)。
  3. 各ティックごとに:グリップの orientation そして buttons.{a, b} 状態。
  4. モーションボタンを長押しした場合、グリップの世界座標系における方向を計算する(R(q) · ĵ — 回転させた単位(+Y軸))を、スケール係数で補正した目標位置に累積する SPEED.
  5. 対象をワークスペースの球体内に固定し、以下を通じて送信します set_cursor_position.
  6. (Pythonのみ)デバイスの球の半径を調整する config.typeminverse = 0.04 m、それ以外はすべて = 0.10 m。

パラメータ

名称デフォルト目的
SPEED0.01 m/tickボタンを押している間のモーションステップ
RADIUS_INVERSE30.10 mInverse3 Inverse3x のワークスペースクランプ半径
RADIUS_MINVERSE0.04 mMinverse のワークスペースクランプ半径Minverse Python のみ — C++ ではハードコーディングMinverse 0.10)
PRINT_EVERY_MS200テレメトリースロットル
セッションプロファイル名co.haply.inverse.tutorials:combinedHaply 上でこのシミュレーションを特定します
実行する前にキャリブレーションを行ってください
  • Inverse3 を行わせます(またはグリップをインクウェルに置き、LEDが点灯したままになるのを待ちます)。
  • インク壺からグリップを取り外してください。
  • AまたはBボタンを押したままグリップを回すと、カーソルがグリップの向いている方向へ移動します。

状態フィールドを読み取る

ティックごとの状態フレームから:

  • data.inverse3[0].state.cursor_positionvec3
  • data.wireless_verse_grip[0].state.orientationquaternion
  • data.wireless_verse_grip[0].state.buttons.{a, b, c} — ブール値
  • (Python、最初のフレームのみ) data.inverse3[0].config.type —Inverse3 Minverse を選択
  • (Python、最初のフレームのみ) data.inverse3[0].status.calibrated — falseの場合、ユーザーに確認を求める

送信/受信

四元数から方向への変換式(回転 +Y によって R(q)) および sphere clamp は古典的な線形代数の手法です — ソースファイルを参照してください。Inverse-API 側はハンドシェイクとティックごとの処理です set_cursor_position.

単一の非同期ループ。Pythonは最初のステートフレームから両方のデバイスIDを読み取り、ハンドシェイクでプロファイルと configure.preset: arm_front_centered 最初の 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))

出典: Python·C++·C++ Glaze

関連: 制御コマンド (set_cursor_position)型 (quaternion, vec3)マウントとワークスペース(プリセット)チュートリアル 03(ワイヤレス VG)チュートリアル 05(位置制御)