WebSocketプロトコル
シミュレーションチャネルは、ポート 10001 でのWebSocket 接続です。このチャネルは、アプリケーションとサービス間のリアルタイムなコマンド/ステータスループを伝達します。
基本ルール:メッセージ1件につき返信1件
このサービスは、クライアントから受信した各メッセージに対して、正確に1つの状態更新を送信します:
ポーリングも、サブスクリプションも、帯域外プッシュもありません。更新の頻度は、もっぱらクライアントの送信頻度によって決まります。
ステップ1 — 初期インベントリ(サービスの最初のメッセージ)
接続されると、サービスは検出されたすべてのデバイスに対して config, state, statusを含む 全体のスナップショットを送信します:
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"config": {
"type": "inverse3",
"port": "COM12",
"device_info": { "major_version": 7, "minor_version": 4, "id": "049D", "device_type": 4, "uuid": "…" },
"extended_device_id": "…",
"extended_firmware_version": "…",
"gravity_compensation": { "enabled": true, "scaling_factor": 1.0 },
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": { "enabled": true },
"home_return": { "enabled": false },
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0.0 }
}
},
"state": {
"cursor_position": { "x": 0.0, "y": -0.12, "z": 0.15 },
"cursor_velocity": { "x": 0.0, "y": 0.0, "z": 0.0 },
"angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"angular_velocity": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"body_orientation": { "w": 1.0, "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_force": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_cursor_position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"current_angular_torques": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"current_angular_position": { "a0": 0.0, "a1": 0.0, "a2": 0.0 },
"control_domain": "cartesian",
"control_mode": "idle",
"transform": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 1, "y": 1, "z": 1 } },
"transform_velocity": { "position": { "x": 0, "y": 0, "z": 0 }, "rotation": { "w": 1, "x": 0, "y": 0, "z": 0 }, "scale": { "x": 0, "y": 0, "z": 0 } }
},
"status": {
"calibrated": true,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [],
"wireless_verse_grip": []
}
3つのブロックは、更新頻度がそれぞれ異なります:
| ブロック | 内容 | 変更頻度 |
|---|---|---|
config | ファームウェア情報、プリセット、ベース、マウント、フィルター | まれに — 明示的な構成変更が行われた場合のみ |
state | 位置、速度、力、方向、変換 | マティック(高頻度) |
status | 準備完了、校正済み、電源供給中、使用中 | たまに(頻度は低い) |
ステップ2 — 最初のコマンドの送信
初期インベントリを解析してデバイス ID を特定した後、セッションプロファイル、初期設定、および/または制御コマンドを含むメッセージを再送信してください:
{
"session": {
"configure": {
"profile": { "name": "co.haply.inverse.tutorials:hello-floor" }
}
},
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
},
"commands": {
"set_cursor_force": { "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
}
}
]
}
ステップ3 — その後の状況の更新
最初の交換後は、構成の変更によってフルスナップショットのプッシュが発生しない限り、サービスは state + status送信のみ行います(config (除く):
{
"session_id": 7,
"inverse3": [
{
"device_id": "049D",
"state": { "cursor_position": { … }, "cursor_velocity": { … }, … },
"status": { "ready": true, "calibrated": true, … }
}
]
}
ステップ4 — 繰り返し
コマンドの送信 → ステータス更新の受信。このループは、送信速度に応じて継続されます。
configureわあ commandsの違い
送信するメッセージの各デバイス項目には、次の 2 つのマップが含まれる場合があります:
| マップ | 用途 | 持続性 |
|---|---|---|
configure | 1回限りの設定:プリセット、ベース、マウント、フィルター、モジュール設定 | 変更されるまで維持する |
commands | ティック単位での制御:力、位置、トルク | 一度適用された後は廃棄する |
configure キーの完全な一覧は セッションの構成を、 commands 項目は 制御コマンドを参照してください。
set_transformこれは例外的なケースですset_transformは commands 以下に示す通り、これは**持続型(persistent)**です。サービスは、新しい値が送信されるまで最後の値を維持します。これは、カメラが移動している間、変換値をストリーミングしつつも、入力の合間に最後の位置を維持したいというシーン探索の用途に用いられるためです。
execute フラグ
configure または commands 項目に "execute": falseを含めると、サービスはペイロードを適用せずに 構文解析と検証のみ 実行します。
{
"inverse3": [{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front", "execute": true },
"damping": { "scalar": 0.0, "execute": false }
}
}]
}
これは、すべてのフィールドを常に出力する リフレクションベースのシリアライザ(例:Unityの JsonUtility)に役立ちます。使用しない項目は execute: falseに設定し、実際の構成を上書きしないようにしてください。デフォルト値は trueまた、フラグを省略した場合は「通常通り適用」されます。
警告
probe_positionと probe_orientationこれは、制御コマンドを送信しないセッション(例:Haply Hub)向けの、監視専用のキープアライブメッセージです。セッションがすでに set_cursor_force, set_cursor_position ~を送っているなら プローブは同梱しないでください. デバイスの状態はすでにすべての応答に含まれています。この2つを併用すると、帯域幅が無駄になり、 session-probe-dropped イベントが発生する可能性があります。
コマンドがまったく効果がないように見える場合は、フィールド名が間違っている可能性が高いです。サービスは、現在認識されていない JSON キーをエラーを返さずに無視します。サービスのログを確認し、API リファレンスでフィールド名が正しいかどうかを検証してください。この動作は、今後のバージョンで変更される予定です。