メインコンテンツへ移動

シミュレーション用水路

概要​

シミュレーションチャネルは、デバイスの状態を交換したり、セッションやデバイスへのコマンドを送信したりするために使用される、高頻度の双方向WebSocketチャネルです。

デフォルトのURL: ws://localhost:10001

ポート番号は設定画面で変更可能です。

基本契約(重要):

  • クライアントが接続すると、サービスはデバイスの完全なリストを含む初期インベントリメッセージを送信します。
  • その後、サーバーはクライアントから受信した各メッセージに対して、正確に1つの ステータス更新メッセージを送信します。
  • 各ステータス更新には、すべてのデバイスのステータス(および状態)が含まれています。
モジュール

このページでは、シミュレーションチャネルのプロトコルと基本的なコマンドについて解説しています。

追加のモジュールや機能により、独自のコマンドやステータスフィールドを追加して、システムを拡張することができます。これらについては、「モジュール」のセクションで別途説明されています。

プロトコルの規則​

顧客からのメッセージによる回答​

このサービスは、クライアントから受信した各メッセージに対して、すべてのデバイスの状態を含む状態更新メッセージを送信します。

つまり、これは次のような意味になります:

  • デバイスの最新の状態を把握したい場合は、何らかのコマンド(セッションコマンド、ポーリングコマンド、またはデバイスコマンド)を送信する必要があります。
  • このチャネルは、クライアントからのメッセージによってタイミング(「ティック」)が制御されるループとして機能します。

非暴力的な尋問(探りを入れるための指示)​

力を加えたりシミュレーションのパラメータを変更したりせずに、状態の変化を観察したい場合は、プローブコマンドを使用してください:

  • probe_position 注ぐ inverse3
  • probe_orientation Verseグリップ用

ポーリングコマンドにはコマンドデータは含まれておらず、単にデバイスの情報を照会するように強制するものです。これにより、次回のステータス更新時に位置および姿勢のデータが最新の状態になります。

アンケート機能は必要ないかもしれません

すでに制御コマンドを送信しているシミュレーションセッション(set_cursor_force, set_cursor_position、など)は pas ポーリングコマンドを送信する必要がある――応答フレームには常にデバイスの状態が含まれている。ポーリングコマンドはセッション向けのものである 監視のみ (例:Haply Hub)など、デバイスを制御することなく、その状態を照会する必要があるもの。

設定と状態​

  • からのメッセージ初期棚卸し フィールドを含みます config, state et status 本機の。
  • からのメッセージ ステータスの更新 定期的な項目には、以下のフィールドが含まれます state et status 本機の。

設定情報を含むスナップショットを再度必要とする場合は、以下を使用してください。 session.force_render_full_state.

configure et commands​

デバイスメッセージでは、2つの異なる辞書がサポートされています: configure et commands. それぞれの役割は異なります:

辞書役割周波数
configure一時的な永続設定:プリセット、ベース、マウント、フィルター、モジュールの設定単発の送付、または変更があった場合
commandsサイクルごと、非持続的:力、位置、モーメント各サイクルごとに送信する必要があります

「」の項目 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軸が上向きの 右利き座標系を使用します。

座標の解釈および返され方に影響を与える設定項目が2つあります:

  • session.configure.basis : `Haply ` の座標と、アプリケーションの座標系との対応関係を変更します(詳細は ベース (以下)。
  • inverse3[*].configure.preset : 指定された工場設定を選択し、ワークスペースの原点を設定します(例: arm_front_centered 場所 (0, 0, 0) (ワークスペースの中央)。各デバイスごとの設定に関するセクションを参照してください。

メッセージの形式​

このセクションでは、全体的な概要と、高レベルのメッセージの種類について説明します。完全な例については、このドキュメントの後半で紹介します。

機器グループ​

メッセージは、第1レベルでデバイスの種類ごとにグループ分けされています(例: inverse3, verse_grip, wireless_verse_grip). 各デバイスタイプのキーは、デバイスごとに1つずつ、オブジェクトの配列に対応しています。

初期インベントリ(サーバー→クライアント)​

WebSocket接続が確立された直後に、1回だけ送信されます。

各メニューには以下が含まれます:

  • device_id
  • config
  • state
  • status

参照:例:初期在庫の有効荷重

ステータスの更新(サーバー→クライアント)​

クライアントから受信したメッセージごとに1回送信されます。

各メニューには以下が含まれます:

  • device_id
  • state
  • status

参照:例:ステータス更新のペイロード

セッションコマンドのカプセル化(クライアント→サーバー)​

セッションコマンドとは、現在の接続またはセッションに適用されるアクションであり、特定のデバイスに固有のものではありません。

{
"session": {
"<command_name>": {
"...": "..."
}
}
}

デバイスコマンドのカプセル化(クライアント→サーバー)​

デバイスへのコマンドは、デバイスタイプをキーとする配列の形式で送信されるため、1つのメッセージ内で1台または複数のデバイスにコマンドを送信することが可能です。各デバイスのエントリは、辞書と configure そして辞書 commands.

{
"<device_type>": [
{
"device_id": "<id>",
"configure": {
"<config_key>": { "...": "..." }
},
"commands": {
"<command_name>": { "...": "..." }
}
}
]
}

1つのメッセージに複数の項目を含めることで、同じ種類の機器を複数台注文することができます。 なお、 commands これは、1つのデバイスに対して複数のコマンドを登録できる辞書ですが、コマンドの種類ごとに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 Hubがシミュレーションを識別し、各アプリケーション固有のデバイス設定を維持するために使用する、セッションプロファイル名を指定します。

{
"session": {
"configure": {
"profile": {
"name": "my_profile"
}
}
}
}
基礎(セッションレベル)​

セッション全体にわたる基本座標変換を定義します。この座標変換は、Haply の座標がアプリケーションの座標系にどのように変換されるかを記述するものです。 一度定義されると、デバイスのすべての状態はこの基本座標系に基づいて返され、送信するすべての値もこの基本座標系に基づいて解釈されます。

置換列は、Z軸を上とする右利き座標系において、Haply として表される。これは、 X, Y, Z、必要に応じてその前に + ou de -. 例:

  • XYZ, ZYX, +Y-Z+X, X-ZY
  • YZX これは、あなたの Y Haply の右側に相当します。あなたの Z Haply のフロント部分と、あなたの X Haply のトップページへ。

Z軸が上向きの左利きシステムの例(Unreal、 X-YZ) :

{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
ご注意
移行元 session.set_basis

以前のコマンドでは、軸の記号の規則が変更されました session.set_basis et session.configure.basis. 以前のコマンドでは正しく動作していた置換が、新しいコマンドでは逆の変換になってしまう場合があります。その場合は、必要に応じて軸の符号を反転させてください(例: X-ZY devient 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 est 持続的な -- このサービスは、新しい値が送信されるまで、最後に送信された値を保持します。毎サイクル送信する必要はありませんが、カメラやシーンの移動を制御する機能であるため、連続的な動きを実現するには、サイクルごとに値を配信することが推奨されます(例:ユーザーがシーンを移動させている間、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グリップ / ワイヤレスVerseグリップ

Verse grip および Wireless Verse grip については、コンポーネントのうち rotation この変換にはある効果があります――ハンドルは向きのみを伝達するため、拡大縮小や移動を行う必要は一切ありません。 position ou scale. フィールド position et scale これらは、Inverse3 とのスキーマの一貫性を確保するためだけに受け入れられ(スナップショットに反映されます)。これらの値をアイデンティティ値のままにしておく(position = {0,0,0}, scale = {1,1,1}) が標準的な慣行です。

デバイスの設定Inverse3​

設定エントリは辞書に送信されます configure. これらは継続的なものです――一度送信するか、変更があった場合に送信してください。

プリセット​

{
"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 }
}
}
}
}
]
}
組立図の非対称性

その側面 注文 (クライアントからサーバーへ)という処理が、この変換を包含しています: "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台のデバイスを操作するには:

{
"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 et mount.

Verse Grip 拡張版​

コマンド set_extension_data これは、カード拡張通信プロトコルを実装したグリップモデルで使用される、Verse Gripの拡張プロトコルの一部です。

ハンドルの拡張データを定義する​

対応しているデータ長:

  • 上流(クライアント→デバイス)方向で最大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
}
}
]
}

例:有効荷重の状態更新​

このサービスは、受信した各メッセージに対して、すべてのデバイスのステータスを含むステータス更新メッセージを送信します。

機械の状態を確認したい場合は、あらかじめ機械にメッセージ(例えば、センシングコマンドや力値など。値がゼロであっても構いません)を送信する必要があります。これは、力を加えることなく機器を入力源として使用する(例えば、位置追跡など)場合に特に重要です。

「State Update」メッセージは、所定の形式に準拠しています。 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
}
}
]
}