シミュレーション・チャンネル
概要
シミュレーション・チャネルは、デバイスの状態を交換したり、セッションやデバイスのコマンドを送信したりするために使用される、高頻度の双方向WebSocketチャネルです。
デフォルトのURL: ws://localhost:10001
設定でポートを変更できます。
基本契約(重要):
- クライアントが接続すると、サービスはデバイスの完全なリストを含む初期インベントリメッセージを送信します。
- その後、サーバーはクライアントから受信したメッセージごとに、正確に1つの ステート更新メッセージを送信します。
- 各「ステータス更新」には、すべてのデバイスの状態(およびステータス)が含まれています。
このページでは、Simulation Channelのプロトコルとコマンドの基本について解説しています。
追加のモジュールや機能は、独自のコマンドや状態フィールドを登録してシステムを拡張することができます。これらは「モジュール」のセクションで別途説明されています。
プロトコル規則
クライアントメッセージ1件につき1つの応答
このサービスは、クライアントから受信したメッセージ1件につき、すべてのデバイスの状態を含む1つの「State Update」メッセージを送信します。
これはつまり、
- デバイスの最新の状態を確認したい場合は、何らかのコマンド(セッションコマンド、プローブコマンド、またはデバイスコマンド)を送信する必要があります。
- このチャネルは、クライアントからのメッセージによって駆動される「ティック」ループのように動作します。
力を加えないポーリング(プローブコマンド)
力を加えたりシミュレーションパラメータを変更したりせずに状態の変化を観察したい場合は、プローブコマンドを使用してください:
probe_position~のためにinverse3probe_orientationVerseグリップ用
プローブコマンドにはコマンドデータが含まれておらず、単にデバイス情報の照会を強制するだけであるため、次のステート更新時には位置・姿勢データが最新の状態になります。
すでに制御コマンドを送信しているシミュレーションセッション(set_cursor_force, set_cursor_position(など)を行う ではない プローブコマンドを送信する必要があります。デバイスの状態は常に応答フレームに含まれています。プローブは、 監視専用 デバイスを制御することなく、デバイスの状態をポーリングする必要があるセッション(例:Haply )。
構成と状態
- について 初期在庫 メッセージにはデバイスが含まれています
config,stateそしてstatus. - 通常 州の最新情報 メッセージにはデバイスが含まれます
stateそしてstatus.
設定情報を含むスナップショットを再度必要とする場合は、次のコマンドを使用してください session.force_render_full_state.
configure 対 commands
デバイスメッセージは、2つの別々のマップをサポートしています: configure そして commands. これらはそれぞれ異なる目的を果たします:
| 地図 | 目的 | 周波数 |
|---|---|---|
configure | ワンショット永続設定:プリセット、ベース、マウント、フィルター、モジュール設定 | 1回送信、または変更時に送信 |
commands | 1ティックごと、非永続的:力、位置、トルク | 毎ティック送信する必要があります |
「」内の項目 commands (set_cursor_force, set_cursor_position, set_angular_torques, set_angular_position)が適用される 1ティックごとに1回実行され、保存されない -- 送信を停止すると、その効果は直ちに解除され、デバイスはアイドル状態に戻ります。使用方法 configure 再送信されることなく、ティックをまたいで保持される必要があるものすべてに対して。
set_transform は特殊なケースですset_transform ~の下に住んでいる commands しかし、それは 持続的な — このサービスは、
新しい変換を送信するまで、最後に送信した変換を保持します。あなたは ~する 毎ティック送信する。とはいえ、その目的はカメラ/シーンのナビゲーションであるため、
ティックレートでストリーミングすること(例えば、ユーザーがシーンをパンした際に
1フレームにつき1回のトランスフォーム)が、連続的な動きのナビゲーションにおける想定される使用パターンである。
座標系
Haply 、デフォルトでZ軸が上向きの右利き座標系がHaply 。
座標の解釈と返却方法に影響を与える設定項目は2つあります:
session.configure.basis:Haply の座標系との対応関係を変更します(詳細は 基礎 (以下)。inverse3[*].configure.preset: ワークスペースの原点(例:arm_front_centeredputs(0, 0, 0)(ワークスペースセンターにて)。各デバイスの「設定」セクションを参照してください。
メッセージ形式
このセクションでは、概要的なエンベロープとメッセージの種類について説明します。具体的な例については、このドキュメントの後半で紹介します。
デバイスグループ
メッセージは最上位レベルでデバイスタイプごとにグループ化されます(例: inverse3, verse_grip, wireless_verse_grip). 各デバイスタイプのキーは、デバイスごとのオブジェクトの配列に対応付けられています。
初期インベントリ(サーバー → クライアント)
WebSocket接続が確立された直後に1回送信されます。
各項目には以下の内容が含まれます:
device_idconfigstatestatus
参照:例:初期在庫ペイロード
ステータス更新(サーバー → クライアント)
クライアントからのメッセージごとに1回送信されます。
各項目には以下の内容が含まれます:
device_idstatestatus
セッションコマンドのエンベロープ(クライアント→サーバー)
セッションコマンドは、現在の接続/セッションに適用されるアクションであり、特定のデバイスに依存するものではありません。
{
"session": {
"<command_name>": {
"...": "..."
}
}
}
デバイスコマンドのエンベロープ(クライアント → サーバー)
デバイスコマンドは、デバイスタイプキーの下に配列として送信されるため、1つのメッセージで1つ以上のデバイスにコマンドを送信することができます。各デバイスエントリは、 configure 地図と commands 地図。
{
"<device_type>": [
{
"device_id": "<id>",
"configure": {
"<config_key>": { "...": "..." }
},
"commands": {
"<command_name>": { "...": "..." }
}
}
]
}
1つのメッセージに複数のエントリを含めることで、同じ種類の複数のデバイスを制御することができます。
なお、 commands これは辞書であり、特定のデバイスに対して複数のコマンドを含めることができますが、コマンドの種類ごとに1つだけ指定できます。
について execute フィールド
すべてのコマンドまたは設定項目では、オプションとして "execute" ブール値(デフォルト true). 設定 "execute": false エントリを解析するが、適用はしない。これは、リフレクションベースのシリアライザ(例:Unity)で役立つ。 JsonUtility) 常にすべてのフィールドを出力するもの。
"set_cursor_force": { "execute": false, "vector": { "x": 0.0, "y": 0.0, "z": 0.0 } }
コマンドリファレンス
セッション
状態全体を強制レンダリング
すべてのデバイスの状態と設定のスナップショットを取得してください。
{
"session": {
"force_render_full_state": {}
}
}
セッションの設定
セッションレベルの永続設定は、以下を通じて送信されます session.configure. これはデバイスレベルの configure マップパターン。
プロフィール
セッションプロファイル名を設定します。これは、Haply シミュレーションを識別し、アプリごとのデバイス設定を保持するために使用されます。
{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
ベース(セッションレベル)
セッション全体の基底マッピングを設定します。基底マッピングは、 Haply アプリケーションの座標系にどのように変換されるかを定義します。 設定後は、すべてのデバイス状態がその基底で返され、送信するすべての値も その基底に基づいて解釈されます。
この順列文字列は、Haply右利き/Z軸上向きの
座標系を基準として表される――つまり、 X, Y, Z、必要に応じて前に
+ または -. 例:
XYZ,ZYX,+Y-Z+X,X-ZYYZXつまり、あなたのYHaply言う通りなら、あなたのZHaply、あなたのXHaply番だ。
左利き用Zアップの例(Unreal、 X-YZ):
{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
session.set_basis旧バージョンと新バージョンでは、軸と記号の規則が変更されました session.set_basis そして
session.configure.basis. 以前のコマンドでは正しく動作していた置換が、
新しいコマンドでは逆の変換結果を生じることがあります。必要に応じて軸の符号を反転させてください(例: X-ZY ~になる XZ-Y).
すべてのデバイスのコマンド
プロービング(すべてのデバイス)
プローブコマンドを使用して、力を加えたりその他のシミュレーション変更を行ったりすることなく、最新の位置・姿勢情報を取得します。
- inverse3:
probe_position - ヴァース・グリップ(
verse_grip,wireless_verse_grip):probe_orientation
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"probe_position": {}
}
}
],
"verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
],
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"probe_orientation": {}
}
}
]
}
変形を設定(すべてのデバイス)
デバイスのワークスペース変換(デバイス空間からアプリケーション空間へ)を設定します。
他のものと違って commands エントリ、 set_transform は 持続的な — この
サービスは、新しい値が送信されるまで、最後に送信された値を保持します。毎ティック送信する必要は
ありませんが、その目的がカメラやシーンのナビゲーションであるため、
連続的な動きを実現するには、ティックレートでストリーミングすることが推奨される使用パターンです
(例:ユーザーがシーンをパンする際、1フレームにつき1回のトランスフォーム更新)。
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_transform": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
VerseグリップおよびWireless Verseグリップについては、 rotation 変換の
この要素が影響を及ぼす――グリップは向きのみを報告するため、
何も position または scale 拡大縮小または位置を調整する。 position そして
scale これらのフィールドは、Inverse3とのスキーマの一貫性を保つためだけに受け入れられ(スナップショットに反映されます)。これらをID値のままにしておくと
(position = {0,0,0}, scale = {1,1,1})が一般的な慣行です。
Inverse3 設定
設定エントリは configure map。これらは永続的です――一度送信するか、変更があった際に送信します。
プリセット
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"preset": { "preset": "arm_front_centered" }
}
}
]
}
利用可能な値: device_defaults, arm_front, arm_front_centered, led_front, led_front_centered, custom.
基本(デバイスレベル)
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"basis": { "permutation": "ZXY" }
}
}
]
}
マウント
デバイスのマウント変換を設定します。注意: transform 内部のラッパー mount.
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"mount": {
"transform": {
"position": { "x": 0.0, "y": 0.0, "z": 0.0 },
"rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 },
"scale": { "x": 1.0, "y": 1.0, "z": 1.0 }
}
}
}
}
]
}
について コマンド side(クライアントからサーバーへ)が transform をラップします: "mount": { "transform": { ... } }.
その スナップショット (サーバーからクライアントへの)通信経路は単一です: "mount": { "position": {...}, "rotation": {...}, "scale": {...} }.
これは意図的な仕様です。コマンドは統一されたラッパーを使用しますが、スナップショットは変換結果を直接シリアライズします。スナップショットのシェイプをコマンドのペイロードにコピーしないよう注意してください。
減衰
均一減衰および/または方向性減衰を制御します。少なくとも1つのフィールドが必要です。
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"damping": { "scalar": 0.5 }
}
}
]
}
方向ごとの減衰を設定することも、両方を同時に設定することもできます:
"damping": { "scalar": 0.5, "vector": { "x": 0.0, "y": 1.0, "z": 0.0 } }
フォース・ゲート
フォースゲートの減衰利得を設定します(0.0~1.0)。
{
"inverse3": [
{
"device_id": "049D",
"configure": {
"force_gate": { "gain": 0.3 }
}
}
]
}
Inverse3
コマンドを送信するには inverse3 デバイスには、一致するエントリを含める device_id ~の下で inverse3 キー。コマンドは1ティックごとに有効であり、有効な状態を維持するには毎ティック送信し直す必要があります。
1つのデバイスを操作する:
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
1つのメッセージで複数のデバイスを操作する:
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
},
{
"device_id": "049E",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
カーソル位置の設定
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_position": {
"position": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
カーソルフォースの設定
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"x": 1.0,
"y": 2.0,
"z": 3.0
}
}
}
}
]
}
角度位置の設定
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_position": {
"angles": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}
角トルクを設定する
{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_angular_torques": {
"torques": {
"a0": 1.0,
"a1": 2.0,
"a2": 3.0
}
}
}
}
]
}
Verse Gripの設定
Verse GripおよびWireless Verse Gripは、同じ機能をサポートしています configure Inverse3 として preset, basisそして mount.
エクステンデッド・ヴァース・グリップ
について set_extension_data このコマンドは、Verseグリップ用の拡張プロトコルの一部であり、ボード拡張通信プロトコルを実装したグリップバージョンで使用されます。
セット・グリップ・エクステンション・データ
対応データ長:
- アップストリーム(クライアント→デバイス)は最大20バイト。
- ダウンストリーム(デバイス→クライアント)で最大12バイト。State Updateメッセージ内で以下のように返されます。
state.extension_data.
データ仕様:
- 配列の長さ:20バイト
- 値の範囲:各値は0~255
{
"wireless_verse_grip": [
{
"device_id": "049D",
"commands": {
"set_extension_data": {
"extension_data": [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
}
}
}
]
}
例
例:初期在庫ペイロード
WebSocketが接続されると、このサービスはデバイスの完全なリストを含むメッセージを送信します。最初のメッセージには以下の内容が含まれます JSON という形式をとっている:
{
"inverse3": [
{
"device_id": "04BA",
"config": {
"type": "inverse3",
"port": "COM13",
"device_info": {
"major_version": 7,
"minor_version": 1,
"id": "04BA",
"device_type": 4,
"uuid": "2D35F80DD9005F599B68F49944CB04BA"
},
"extended_device_id": "2D35F80DD9005F599B68F49944CB04BA",
"extended_firmware_version": "8C20FDC8010AA1E15AA133CDA2534874",
"gravity_compensation": {
"enabled": true,
"scaling_factor": 1
},
"handedness": "right",
"streaming_mode": "USB",
"torque_scaling": {
"enabled": true
},
"home_return": {
"enabled": false
},
"filters": {
"force_gate": { "gain": 0.3 },
"damping": { "scalar": 0 }
},
"preset": "defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"config": {
"type": "verse_grip",
"port": "COM3",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"config": {
"type": "wireless_verse_grip",
"port": "COM6",
"major_version": 1,
"minor_version": 4,
"hardware_version": 1,
"streaming_mode": "Radio",
"preset": "device_defaults",
"basis": { "permutation": "XYZ" },
"mount": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
}
},
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
]
}
例:ステータス更新ペイロード
このサービスは、受信したメッセージごとに、すべてのデバイスの状態を含む状態更新メッセージを1つ送信します。
マシンの状態を確認したい場合は、事前にメッセージ(例えば、プローブコマンドや力値など。値がゼロであっても構いません)を送信する必要があります。これは、力を加えることなくデバイスを入力ソース(位置追跡など)として使用する際に、特に重要です。
ステータス更新メッセージには以下の内容が含まれています JSON という形式をとっている:
{
"inverse3": [
{
"device_id": "04BA",
"state": {
"cursor_position": {
"x": 0.07842738,
"y": -0.14836666,
"z": 0.14297646
},
"cursor_velocity": {
"x": -0.011969013,
"y": 0.0012009288,
"z": -0.043197
},
"angular_position": {
"x": -69.31704,
"y": 137.62952,
"z": 19.832787
},
"angular_velocity": {
"x": 0,
"y": 0,
"z": 0
},
"body_orientation": {
"x": -0.01940918,
"y": 0.7026367,
"z": 0.00048828125,
"w": 0.7113037
},
"current_cursor_force": { "x": 0, "y": 0, "z": 0 },
"current_cursor_position": { "x": 0, "y": 0, "z": 0 },
"current_angular_torques": { "x": 0, "y": 0, "z": 0 },
"current_angular_position": { "x": 0, "y": 0, "z": 0 },
"control_domain": "cartesian",
"control_mode": "force",
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"calibrated": false,
"in_use": false,
"power_supply": true,
"ready": true,
"started": true
}
}
],
"verse_grip": [
{
"device_id": "61548",
"state": {
"button": false,
"hall": 0,
"orientation": {
"x": -0.5019531,
"y": 0.8632202,
"z": -0.048095703,
"w": -0.022338867
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"error": 0,
"ready": true
}
}
],
"wireless_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"connected": true,
"awake": true,
"ready": true
}
}
],
"custom_verse_grip": [
{
"device_id": "0",
"state": {
"battery_level": 0.816,
"battery_voltage": 3.77,
"buttons": {
"a": false,
"b": false,
"c": false
},
"hall": 16,
"orientation": {
"x": -0.019866943,
"y": -0.017486572,
"z": 0.05508423,
"w": -0.9963989
},
"extension_data": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"transform": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 1, "y": 1, "z": 1 }
},
"transform_velocity": {
"position": { "x": 0, "y": 0, "z": 0 },
"rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
"scale": { "x": 0, "y": 0, "z": 0 }
}
},
"status": {
"ready": true
}
}
]
}