メインコンテンツまでスキップ

04. Hello Floor

最初の触覚エフェクトです。カーソルが押し込まれると押し返す仮想の水平な床を作ります。力は単純なペナルティばね(stiffness × penetration_depth)で、set_cursor_force を介して Z 方向に適用されます。

このチュートリアルで学べること:

  • set_cursor_force を使用して、ペナルティばねの力を適用する
  • cursor_position を読み取り、リアルタイムで力を計算する
  • (Python)ワークスペースプリセット(arm_front_centered)を設定し、原点がワークスペースの中心に来るようにする
  • (Python)keyboard パッケージを使い、床の高さとばね定数をキーボードで対話的に調整する

ワークフロー​

  1. ws://localhost:10001 に対して WebSocket を開き、最初の状態フレームを待ちます。
  2. 最初のフレームで、セッションプロファイルを登録します。Python 版は、さらに configure.preset: arm_front_centered を送信し、原点がワークスペースの中央に来るようにします。C++ 版は、デバイスで既に有効になっている設定をそのまま使用します。
  3. 毎フレーム、cursor_position.z を読み取り、force_z = max(0, (floor_pos - z) * stiffness) を計算して、set_cursor_force コマンドとして送信します。
  4. 以降のティックでは力のコマンドのみを送信します。セッションプロファイルは一回限りのハンドシェイクです。
  5. (Python)各ティックでキーボードの矢印キーもポーリングし、floor_pos と stiffness をリアルタイムに更新します。

パラメータ​

名前デフォルト用途
floor_pos0.10 m仮想の床の平面の Z 座標
stiffness1000 N/mばね定数(1 mm の食い込みで 1 N)
PRINT_EVERY_MS100–200テレメトリの間引き間隔
セッションプロファイル名co.haply.inverse.tutorials:hello-floorHaply Hub でこのシミュレーションを識別します
対話操作(Python のみ)

Python 版は keyboard パッケージを使用します(Linux では管理者権限が必要です):

  • ↑ / ↓ — 床の平面を上げる / 下げる
  • ← / → — ばね定数を下げる / 上げる
  • R — デフォルトにリセットする
力の拡張

サービスのティックでは、力は加算されます。デバイスに送信される前に、複数の発生源からの力が合計されます。このようなチュートリアルは、他の力の生成元とどちらもブロックすることなく共存できます。

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

data.inverse3[i].state から読み取ります:

  • cursor_position.z — vec3。食い込み深さの計算に使用します
  • current_cursor_force — テレメトリ用に報告されます

送信 / 受信​

各ティックでカーソルの Z を読み取り、force_z = max(0, (floor_pos - z) * stiffness) を計算して、set_cursor_force を送信します。最初の送信メッセージには(すべての版で)セッションプロファイルも含まれ、Python 版では configure.preset: arm_front_centered も含まれます。

単一の非同期ループです。最初のフレームでのハンドシェイクにはプロファイルと configure.preset が含まれ、floor_pos = 0.1 がワークスペースの中心座標に揃うようにします。

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 + preset (one-shot)
request_msg = {
"session": {"configure": {"profile": {"name": "co.haply.inverse.tutorials:hello-floor"}}},
"inverse3": [{
"device_id": device_id,
"configure": {"preset": {"preset": "arm_front_centered"}}
}]
}
else:
# Per tick: compute force along Z, send set_cursor_force
z = data["inverse3"][0]["state"]["cursor_position"]["z"]
force_z = 0.0 if z > floor_pos else (floor_pos - z) * stiffness
request_msg = {
"inverse3": [{
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": 0.0, "z": force_z}}}
}]
}

await websocket.send(json.dumps(request_msg))
SDK インストーラーに同梱

チュートリアル 04 も SDK と一緒にローカルへインストールされています。サービスのインストールディレクトリ配下の tutorials/04-haply-inverse-hello-floor/ を参照してください。

ソース: Python · C++ · C++ Glaze

関連: 制御コマンド (set_cursor_force) · マウントとワークスペース(プリセット) · 型 (vec3) · セッション · チュートリアル 07(Basis & Mount)