본문으로 바로 가기

시뮬레이션 채널

개요​

시뮬레이션 채널은 장치 상태를 교환하고 세션 또는 장치 명령을 전송하는 데 사용되는 고주파 양방향 WebSocket 채널입니다.

표준 URL: ws://localhost:10001

이 포트는 설정에서 변경할 수 있습니다.

기본 행동 수칙 (중요):

  • 클라이언트가 연결되면 서비스는 전체 장치 목록이 포함된 초기 인벤토리 메시지를 전송합니다.
  • 그 후 서버는 클라이언트로부터 수신한 각 메시지에 대해 정확히 하나의 상태 업데이트 메시지를 전송합니다.
  • 각 상태 업데이트에는 모든 기기의 상태(및 상태 정보)가 포함됩니다.
모듈

이 페이지에서는 시뮬레이션 채널의 핵심 프로토콜 과 해당 명령어에 대해 설명합니다.

추가 모듈 또는 기능을 통해 시스템에 사용자 정의 명령어 및/또는 상태 필드를 확장하고 등록할 수 있습니다. 이에 대한 내용은 ‘모듈’ 섹션에 별도로 설명되어 있습니다.

의사록 작성 규칙​

클라이언트 메시지당 하나의 응답​

이 서비스는 클라이언트가 수신한 각 메시지에 대해 모든 기기의 상태가 포함된 상태 업데이트 메시지를 전송합니다.

이는 다음과 같은 의미입니다:

  • 장치 상태에 대한 최신 스냅샷이 필요한 경우, 세션 명령, 조회 명령 또는 장치 명령 중 하나를 전송해야 합니다.
  • 이 채널은 클라이언트 메시지에 의해 제어되는 “틱” 루프와 같은 방식으로 작동합니다.

힘을 가하지 않는 폴링 (쿼리 명령어)​

힘을 가하거나 시뮬레이션 매개변수를 변경하지 않고 상태 변화를 관찰하려면 쿼리 명령어를 사용하십시오:

  • probe_position für inverse3
  • probe_orientation Verse Grips용

쿼리 명령어에는 명령 데이터가 포함되어 있지 않으며, 다음 상태 업데이트 메시지에서 위치 및 방향 데이터가 최신 상태로 유지될 수 있도록 장치 정보를 조회하도록만 합니다.

쿼리 명령어가 필요하지 않을 수도 있습니다

이미 제어 명령을 전송하고 있는 시뮬레이션 세션 (set_cursor_force, set_cursor_position 등), ~할 필요가 없다 쿼리 명령어 전송 – 응답 프레임에는 항상 장치 상태가 포함됩니다. 쿼리 명령어는 다음 용도로 사용됩니다. 순수한 모니터링 회의 (예: Haply Hub)와 같이, 장치를 제어하지 않고도 장치 상태를 조회해야 하는 경우입니다.

구성 대 상태​

  • 죽다 초기 재고 내역이 포함된 메시지 포함 config, state 그리고 status 기기의.
  • 정규 주별 최신 정보-뉴스 포함 state 그리고 status 기기의.

설정이 포함된 스냅샷이 다시 필요하시면 다음을 사용하십시오. session.force_render_full_state.

configure vs. commands​

기기 알림은 두 가지 별개의 매핑을 지원합니다: configure 그리고 commands. 이들은 각기 다른 용도로 사용됩니다:

매핑Zweck빈도
configure일회성, 영구 설정: 프리셋, 기본 설정, 장착, 필터, 모듈 설정한 번만 보내거나 변경 사항이 있을 때
commandsPro Tick, 비지속적: 힘, 위치, 토크매 틱마다 전송되어야 함

다음 항목들 commands (set_cursor_force, set_cursor_position, set_angular_torques, set_angular_position)가 틱당 한 번 적용되며 저장되지 않음 – 신호를 더 이상 전송하지 않으면 효과가 즉시 종료되고 기기가 대기 모드로 돌아갑니다. 다음을 사용하십시오. configure 여러 틱에 걸쳐 유지되어야 하며, 다시 전송되지 않아야 하는 모든 항목에 대해.

참고 사항
set_transform 는 특수한 경우입니다

set_transform 다음에 기재되어 있습니다 commands, 하지만 지속적인 – 이 서비스는 사용자가 새로운 변환을 보낼 때까지 가장 최근에 보낸 변환을 유지합니다. 사용자는 müssen 매 틱마다 전송하지는 않습니다. 하지만 이 데이터의 목적은 카메라 또는 장면 탐색에 있으므로, 틱 속도에 맞춰 스트리밍하는 것(예: 사용자가 장면을 훑어볼 때 프레임당 한 번의 변환)이 지속적인 이동 탐색에서 예상되는 사용 패턴입니다.

좌표계​

Haply 기본적으로 Z축이 위쪽을 향하는 우측 좌표계를 사용합니다.

좌표가 해석되고 반환되는 방식에는 다음 두 가지 구성 항목이 영향을 미칩니다:

  • session.configure.basis: Haply 좌표와 애플리케이션의 좌표계 간의 매핑을 변경합니다(참조: 기초 (아래 참조).
  • inverse3[*].configure.preset: 작업 영역의 기점을 정의하는 명명된 공장 구성을 선택합니다(예: arm_front_centered den Punkt (0, 0, 0) (작업 영역 중앙으로). 기기별 “Configure” 섹션을 참조하십시오.

뉴스 형식​

이 섹션에서는 상위 엔벨로프와 메시지 유형에 대해 설명합니다. 구체적인 예제는 이 문서의 뒷부분에서 다룰 예정입니다.

기기 그룹​

알림은 최상위 수준에서 기기 유형별로 그룹화됩니다(예: inverse3, verse_grip, wireless_verse_grip). 각 장치 유형 키는 해당 장치에 특화된 객체들이 포함된 배열에 매핑됩니다.

Inventar 초기화 (서버 → 클라이언트)​

WebSocket 연결이 수립된 직후 한 번 전송됩니다.

각 항목에는 다음 내용이 포함됩니다:

  • device_id
  • config
  • state
  • status

참조: 예시: 초기 인벤토리의 페이로드

상태 업데이트 (서버 → 클라이언트)​

각 클라이언트 메시지에 대해 한 번씩 전송됩니다.

각 항목에는 다음 내용이 포함됩니다:

  • device_id
  • state
  • status

참조: 예시: 상태 업데이트 페이로드

세션 명령어용 래퍼 (클라이언트 → 서버)​

세션 명령어는 현재 연결 또는 세션에 적용되며, 특정 기기에 국한되지 않는 작업입니다.

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

장치 명령용 래퍼 (클라이언트 → 서버)​

기기 명령은 기기 유형 키 아래에 배열 형태로 전송되므로, 단일 메시지를 통해 하나 이상의 기기에 명령을 전달할 수 있습니다. 각 기기 항목은 다음을 모두 지원합니다. configure-매핑뿐만 아니라 commands-할당.

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

동일한 유형의 여러 장치를 하나의 메시지로 제어하려면 여러 항목을 지정할 수 있습니다. 다음 사항에 유의하십시오. commands 사전은 하나의 사전을 의미하며, 특정 기기에 대해 여러 명령을 포함할 수 있지만, 명령 유형당 하나만 포함할 수 있습니다.

Das Feld execute​

모든 명령어나 configure 항목은 선택적인 부울 값을 허용합니다. "execute" (표준: true). Setzen Sie "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 좌표가 애플리케이션의 좌표계로 어떻게 변환되는지를 정의하며, 이 매핑이 설정된 후에는 모든 장치 상태가 이 기본 매핑을 기준으로 반환되고, 전송된 모든 값도 이 매핑을 기준으로 해석됩니다.

Haply 는 Z축이 위쪽을 향하는 오른손 좌표계를 기준으로 순열 문자열을 지정합니다. 이는 다음에서 유래한 순열입니다. X, Y, Z, 선택 사항이며 앞에 다음을 붙일 수 있음 + 또는 -. 예시:

  • XYZ, ZYX, +Y-Z+X, X-ZY
  • YZX 이는 귀하가 Y Haply 의 법적 입장과 일치하는, 귀하의 Z Haply 의 진행 방향과 귀하 X Haply 의 상승 추세선.

Z축이 위쪽을 향하는 왼손 좌표계의 예시 (언리얼, X-YZ):

{
"session": {
"configure": {
"basis": { "permutation": "X-YZ" }
}
}
}
경고
이동: session.set_basis

축 부호에 대한 관례는 구식인 session.set_basis 그리고 session.configure.basis 변경되었습니다. 기존 명령어에서는 정상적으로 작동하던 순열이, 새로운 명령어에서는 반전된 변환을 생성할 수 있습니다. 필요한 경우 축의 부호를 반전하십시오(예: X-ZY zu XZ-Y).

모든 기기에 적용되는 명령어​

테스트 (모든 기기)​

프로빙 명령을 사용하여 힘이나 기타 시뮬레이션 변경 사항을 적용하지 않고도 현재 위치 및 방향 정보를 조회하십시오.

  • inverse3: probe_position
  • Verse 그립 (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 지속적인 – 이 서비스는 사용자가 새로운 값을 전송할 때까지 마지막으로 전송된 값을 유지합니다. 매 틱마다 이 값을 전송할 필요는 없습니다. 하지만 이 서비스의 목적은 카메라 또는 장면 탐색이므로, 지속적으로 이동할 때는 틱 속도로 스트리밍하는 것이 예상되는 사용 패턴입니다(예: 사용자가 장면을 이동하는 동안 프레임당 한 번의 변환).

{
"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 또는 scale 크기를 조정하거나 이동할 수 있습니다. 필드 position 그리고 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": {...} }. 이는 의도된 동작입니다. 명령어는 일관된 래퍼를 사용하는 반면, 스냅샷은 변환 결과를 직접 직렬화합니다. 스냅샷 구조를 명령어 페이로드에 복사하지 않도록 주의하십시오.

감쇠​

균일한 감쇠 및/또는 방향에 따른 감쇠를 제어합니다. 필드는 최소 한 개 이상 입력해야 합니다.

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"damping": { "scalar": 0.5 }
}
}
]
}

방향에 따른 감쇠를 설정하거나 두 가지 방식을 동시에 적용할 수도 있습니다:

"damping": { "scalar": 0.5, "vector": { "x": 0.0, "y": 1.0, "z": 0.0 } }

포스 게이트​

Force Gate의 감쇠 이득을 설정합니다(0.0~1.0).

{
"inverse3": [
{
"device_id": "049D",
"configure": {
"force_gate": { "gain": 0.3 }
}
}
]
}

Inverse3-명령어​

명령을 ~에 보내려면 inverse3-장치를 전송하려면, 해당 항목에 맞는 항목을 추가하십시오. device_id 열쇠 아래에서 inverse3 hinzu. 명령은 틱(tick) 단위로 적용되며, 유효한 상태를 유지하려면 매 틱마다 다시 전송해야 합니다.

단일 장치 제어:

{
"inverse3": [
{
"device_id": "049D",
"commands": {
"set_cursor_force": {
"vector": {
"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
}
}
}
},
{
"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.

Verse Grip용 확장 프로토콜​

명령어 set_extension_data 이는 Verse Grips용 확장 프로토콜의 일부이며, 보드 확장 프로토콜을 구현하는 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
}
}
]
}

예시: 상태-업데이트-유틸리티​

이 서비스는 수신된 각 메시지에 대해 모든 기기의 상태가 포함된 상태 업데이트 메시지를 전송합니다.

시스템의 상태를 확인하려면, 먼저 시스템에 메시지를 전송해야 합니다(예: 프로빙 명령어나 힘 값 등, 값이 0인 경우에도 마찬가지입니다). 이는 힘을 가하지 않고 장치를 입력 소스로 사용하는 경우(예: 위치 추적)에 특히 중요합니다.

State 업데이트 메시지에는 다음과 같은 내용이 있습니다. 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
}
}
]
}