本文へスキップ

07. ベース&マウント プレイグラウンド

デバイスの 単位変換を対話形式で制御し、 configure.basis, configure.preset, configure.mountこれらは、ワイヤプロトコルレベルでどのように連携して動作するかを示しています。対話型フォーカスが「configure」コマンドに留まるよう、水平なベースを維持します。

学習内容:

  • 基底順列 設定 ("XZY" → Y軸上方向(アプリケーションフレーム))
  • プリセット(arm_front)選択およびそのプリセットが構成する内容を理解する
  • 回転クォータニオンを使用した実行時のマウントの再定義(キーボード入力に基づく)
  • 相互排他ルール: mountわあ presetのような デバイスの設定 同じブロック内に同時に存在することはできません
  • 1回限り configure 動作:キーを押すたびに、configureメッセージが正確に1回送信されます
  • (C++ Glaze) std::optionalを用いた相互排他的なフィールドモデリング

ワークフロー​

  1. 最初のメッセージを受け取ると セッションプロファイル, configure.basis: "XZY", configure.preset: arm_frontを送信します。固定床用として set_cursor_force 送信を開始します。
  2. 各マティックごとにカーソルのY座標を読み取り、 force_y = max(0, (floor_pos - y) * stiffness)を計算して送信します。
  3. ユーザーがマウント回転キーを押すと pending_configure = trueに設定します。
  4. 次のティックで rotationこの単位クォータニオン(現在のピッチ/ヨーをZ→Xの順で合成したもの)である変換を含む configure.mount ブロックを構成します。 presetは省略します。これら2つのフィールドは、ワイヤ上では相互に排他的です。
  5. リセットキー(R)はオーバーライドを解除します。次回のconfigureでは再び presetを使用します。

パラメータ​

名前デフォルト値用途
BASIS"XZY"軸の順列— Y軸上方向のアプリケーションフレーム
DEVICE_PRESET / DEVICE_CONFIG_PRESET"arm_front"名前付きプリセット— 原点はデバイスベース
FLOOR_POS_Y0.0 m固定床面(アプリケーションY)
STIFFNESS1000 単位なし床のばね定数
MOUNT_STEP_DEG10°キー入力ごとの回転角度
PRINT_EVERY_MS200テレメトリー・スロットル

制御​

キー動作
W / Sデバイス+X軸(ピッチ)を基準に、マウントを±10°回転させる
A / Dデバイス+Z軸(ヨー)を基準に、マウントを±10°回転させる
Rマウントのリセット — プリセットに戻す
Hコントロールキーの表示
Q終了
mountわあ presetは互いに排他的です

このサービスは、両方のフィールドを含む デバイスの設定 ブロックを拒否します。ユーザーがマウントを再定義した場合、チュートリアルではその後のすべての configure において presetを省略します。 Rをクリックすると、次のconfigureで presetこれが再び使用され、 mountは除外されます。

入力モデルの違い

C++の変形版は、バックグラウンドのstdinスレッドで行単位の入力を読み取ります(文字を入力するたびにEnterキーを押します)。Pythonはメインの非同期ループで keyboard パッケージを使用してリアルタイムでキー入力をポーリングするため、ENTERキーを押す必要はありません。キーとコマンドは同じです。

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

data.inverse3[i].stateから読み取る値:

  • cursor_position.y — vec3. 床の貫通量を計算するために使用します。
  • current_cursor_force — テレメトリ用として報告されます。

送信 / 受信​

ペイロードの構造は、すべてのバリエーションで同じです。違いは、各バリエーションが互いに排他的であるという点です。 mount / preset ブランチを構成する方法と、入力スレッドがWebSocketスレッドにシグナルを送信する方法です。

単一の非同期ループ内で keyboard パッケージを使用して、リアルタイムのキー入力をポーリングします。 pending_configureは、キーハンドラによって設定されるグローバルフラグであり、 configure ブロックが送信されるたびに初期化されます。

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"]
# Handshake: profile + basis + preset
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": build_configure_block(first_handshake=True),
# -> {"basis": {"permutation": "XZY"},
# "preset": {"preset": "arm_front"}}
}],
}
else:
handle_key_inputs() # may set pending_configure = True (classic, not shown)

y = data["inverse3"][0]["state"]["cursor_position"]["y"]
force_y = 0.0 if y > FLOOR_POS_Y else (FLOOR_POS_Y - y) * STIFFNESS

entry = {
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": force_y, "z": 0.0}}},
}
if pending_configure:
entry["configure"] = build_configure_block(first_handshake=False)
# -> {"mount": {...}} OR {"preset": {...}} (never both)
pending_configure = False

request_msg = {"inverse3": [entry]}

await websocket.send(json.dumps(request_msg))
SDKインストーラーに同梱されています

チュートリアル 07 は、SDK とともにローカルにもインストールされます。サービスのインストールディレクトリ内の tutorials/07-haply-inverse-basis-and-mount/で閲覧できます。

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

関連項目: Basisの順列 ・ マウント&ワークスペース ・ デバイスの構成 ・ 制御コマンド (set_cursor_force) ・ タイプ (transform) ・ チュートリアル 04(Hello Floor)