本文へスキップ

06. 統合サンプル(Inverse3 +ワイヤレスVerseGrip)

2つのデバイスを使用するチュートリアルです。グリップを希望する方向に向けた状態でボタンを押し続けると、Inverse3 のカーソルがその方向に移動します。カーソルの移動範囲は球形のワークスペース内に制限されます。

学習内容:

  • 同じ状態フレーム内で2種類のデバイスを読み取る (inverse3 および wireless_verse_grip)
  • クォータニオングリップが指す方向を抽出する(ローカル +Y おめでとう)
  • set_cursor_positionを使用して計算された目標地点にカーソルを移動させる
  • 目標地点を安全な作業領域内に限定する — MinverseはInverse3よりも小さい半径を使用します
  • 原点が到達範囲の中央に位置するように ワークスペースのプリセット (arm_front_centered) の設定

ワークフロー​

  1. 2つのデバイスを検索:
    • C++ バージョンは起動時にHTTP経由で GET /devicesを照会した後、補正に関する案内メッセージを表示し、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.typeこれに基づき、円の半径を調整します — minverseは 0.04 m、それ以外は 0.10 m です。

パラメータ​

名前デフォルト値用途
SPEED0.01 m/ティックボタンを押している間の移動間隔
RADIUS_INVERSE30.10 mInverse3 / Inverse3xの作業領域の制限半径
RADIUS_MINVERSE0.04 mMinverseの作業領域の制限半径(Pythonのみ — C++は 0.10(固定)
PRINT_EVERY_MS200テレメトリ出力周期の制限
セッションプロファイル名co.haply.inverse.tutorials:combinedHaply Hubでこのシミュレーションを識別するための値
実行前に補正する
  • Inverse3に自動補正を行わせるか(あるいは、グリップをインクウェルの上に置き、LEDが点灯状態になるまでお待ちください)。
  • グリップをインク壺から取り外してください。
  • A または B ボタンを押したままグリップを回転させてください。カーソルは、グリップが指し示す方向に沿って移動します。

読み取り状態フィールド​

各ティックごとに送信されるステートフレームから、以下の値を読み取ります:

  • 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} — ブール値
  • (Python、最初のフレームのみ) data.inverse3[0].config.type — 「Inverse3」と「Minverse 」の半径のうち、いずれか一方を選択します
  • (Python、最初のフレームのみ) data.inverse3[0].status.calibrated — 値が false の場合は、ユーザーに通知します

送信 / 受信​

クォータニオンから方向を求める計算(R(q)で +Y(回転演算)および球内部の制限処理は、典型的な線形代数演算です。詳細については、ソースファイルを参照してください。Inverse API 側では、ハンドシェイクおよびティックごとに呼び出される set_cursor_positionで構成されています。

単一の非同期ループで構成されています。Pythonは最初のステートフレームから2つのデバイスIDを読み取ります。ハンドシェイクでは、最初の set_cursor_position 呼び出しにプロファイルと configure.preset: arm_front_centeredを添付いたします。

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))
SDKインストーラーに含まれる

チュートリアル 06 は、SDK とともにローカルにもインストールされます — サービスのインストールディレクトリ内の tutorials/06-haply-inverse-combined/ フォルダ内でご確認いただけます。

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

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