09. WebSocket 작업 공간 탐색기
WebSocket 채널을 통해 스트리밍 방식으로 전송함으로써 set_transform 명령, 실시간 내비게이션 기기의작업 공간 위치. 이 튜토리얼에서는 HTTP를 사용하여 세션과 기기를 탐지합니다( 튜토리얼 08 (완전히 동일함), 그런 다음 WebSocket을 열고 매 틱마다 위치 업데이트를 푸시합니다.
아래 표는 두 가지 변환 연산 간의 차이점을 보여줍니다:
| 작업 | 튜토리얼 | 대표적인 사용법 |
|---|---|---|
configure.mount — 마운트 변환의 영속화 | 08 | 장치의 물리적 설치 방식을 설명하기 위해 한 번만 설정(또는 극히 드물게 변경)합니다. |
set_transform — 작업 공간 변환의 영속화 | 09(본 튜토리얼) | 마찬가지로 영구 저장되지만, 각 틱마다 스트리밍 방식으로 전송할 수 있어 실시간 작업 공간 탐색에 사용됩니다. |
두 명령어 모두 다음을 통해 실행할 수 있습니다. HTTP와 WebSocket 사용하며, 모두지속적인——서비스는 사용자가 마지막으로 전송한 값을 기억합니다. 두 가지의 차이점은 용도와 업데이트 빈도에 있습니다:configure.mount 저주파수 업데이트(물리적 설정)에 대해 최적화를 진행했으며, 반면 set_transform 고주파 스트리밍 전송(시나리오 내비게이션)에 대해 최적화를 실시했습니다.
작업 공간의 원점이 실행 중에 변화하는 객체를 따라가야 할 때는 다음을 사용하십시오. set_transform——예를 들어, 손의 움직임을 따라가거나, 프로그래밍된 변위를 애니메이션으로 표현하거나, 작업자가 가상 작업 공간을 실시간으로 미세 조정할 수 있도록 하는 것 등이 있습니다.
개별적으로 보면,configure.mount 와 set_transform 겉보기에는 같은 효과가 나타날 것 같지만, 이 둘 사이에는부자 관계: 좌표 파이프라인에서, 작업 공간 변환이 마운트에 적용됩니다.그 위(device → basis → mount → workspace → application). 전체 파이프라인은 다음을 참조하십시오. 마운트 및 작업 공간。
사용 사례
- 실시간 작업 공간 내비게이션. 탭틱 시나리오를 중단하지 않은 상태에서 모바일 기기의 커서 작업 공간(즉, 엔드 이펙터가 도달할 수 있는 포락선 영역)을 이동합니다.
- 운영자가 직접 제어하는 정렬. 다른 단말기의 사용자가 방향 키를 누르고 있는 동안, 메인 탭틸 앱이 실행 중일 때 작업 공간을 이동시킵니다. 실시간 세션 중에 각 사용자에 대해 데스크톱 보정을 수행하는 데 적합합니다.
- 프로그래밍 방식의 작업 공간 이동. 스크립트(오디오 구동, 물리 구동 등)를 통해 작업 공간 위치를 제어하며, 각 틱마다 위치 정보만 포함된 변환 패치만 전송합니다.
전제 조건
튜토리얼 09에서는실행 중인 WebSocket 세션이필요합니다. 즉, 실행 중인 탭틸 루프 내에 Inverse3 클라이언트가 이미 있어야 합니다. 튜토리얼 09에서는 이 세션에 연결하여 작업 공간을 실시간으로 이동시킵니다.
Haply Hub를열고 Orb 데모를 실행하세요. 그러면 지속적인 햅틱 세션이 열리며, 이를 즉시 대상으로 지정할 수 있습니다:
./09-haply-inverse-ws-remote-control --session co.haply.hub::demo-orb
python 09-haply-inverse-ws-remote-control.py --session "co.haply.hub::demo-orb"
Orb 장면은 작업 공간의 원점에 구체를 렌더링합니다. 튜토리얼 09 ‘작업 공간 이동’을 활용하면 전체 장면을 실시간으로 이동시켜 즉시 시각적 피드백을 얻을 수 있습니다.
촉각 루프를 실행하는 다른 모든 튜토리얼(01 – 07)에도 동일하게 적용됩니다. 먼저 한 터미널에서 이를 실행한 다음, 두 번째 터미널에서 튜토리얼 09를 실행하여 대화형 모드로 세션을 감지하도록 하세요.
사용법
# Discover session interactively, use first detected device
./09-haply-inverse-ws-remote-control
python 09-haply-inverse-ws-remote-control.py
# Target the Haply Hub Orb demo directly
./09-haply-inverse-ws-remote-control --session co.haply.hub::demo-orb
python 09-haply-inverse-ws-remote-control.py --session "co.haply.hub::demo-orb"
# Target a session directly, specify device
./09-haply-inverse-ws-remote-control --session :my_profile:0 --device A14
python 09-haply-inverse-ws-remote-control.py --session "#42" --device A14
제어
- 파이썬
- C++
특정 키를 누르고 있으면 계속 이동할 수 있으며, 손을 떼면 멈춥니다.
| 버튼 | 작업 |
|---|---|
→ / ← | +X / −X |
↑ / ↓ | +Y / −Y |
Page Up / Page Down | +Z / −Z |
= / - | 탐색 속도 높이기 / 낮추기 |
0 | 작업 공간을 원점으로 재설정 |
H | 도움말 보기 |
Esc | 종료(Ctrl+C (마찬가지로 유효함) |
행 단위 입력 — 입력 후 ENTER 키를 누르십시오.
| 명령 | 작업 |
|---|---|
x+[N] / x-[N] | X 축 속도를 ±N mm/프레임으로 설정 (직접 입력) x+ (이 경우 현재 기본 속도를 사용합니다) |
y+[N] / y-[N] | Y 방향 속도를 ±N mm/프레임으로 설정합니다. |
z+[N] / z-[N] | Z 축 속도를 ±N mm/프레임으로 설정합니다. |
s+[N] / s-[N] | 기본 속도를 ±N mm/프레임으로 조정 |
stop | 모든 속도를 0으로 설정 |
reset | 속도를 0으로 설정하고 원점으로 복귀 |
h | 도움말 보기 |
Ctrl+C(또는 Ctrl+D / EOF) 를눌러 종료합니다.
작동 원리
1단계 — HTTP 세션 및 장치 탐지
이 튜토리얼에서는 재사용과 튜토리얼 08 같은 discover_session() / discover_device() 보조 함수: 먼저 실행 GET /sessions(만약 지정된 경우 --session, 이면 GET /sessions/<selector>), 그 다음 다음을 실행합니다. GET /devices(또는 직접 사용) --device). 두 보조 함수는 동일한 명령줄 인수를 받아들이며, 또한 SESSION_HELP 텍스트가 완전히 일치합니다. 튜토리얼 00 또는 08에 나오는 선택기는 수정할 필요 없이 여기에서 바로 사용할 수 있습니다.
2단계 — WebSocket 세션과 첫 번째 메시지의 핸드셰이크
이 튜토리얼에서는 다음을 가리키는 ws://localhost:10001 WebSocket.첫 번째 메시지를 수신했을 때만,이때 세션 구성 등록 정보를 전송합니다:
{
"session": {"configure": {"profile": {"name": "co.haply.inverse.tutorials:ws-remote-control"}}},
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0, "y": 0, "z": 0}}}}}]
}
후속 틱은 생략합니다. session 필드——전송 전용 inverse3 명령어 배열.
3단계 — 각 틱마다 set_transform
set_transform 수락부분 변환——수정하고자 하는 필드만 포함하면 됩니다. 이 튜토리얼에서는 위치만 전송하며, 회전 및 확대/축소 값은 세션의 기본값을 유지합니다(즉, configure.mount (설정된 값이 있는 경우).
{
"inverse3": [{"device_id": "...", "commands": {"set_transform": {"transform": {"position": {"x": 0.02, "y": 0.0, "z": 0.01}}}}}]
}
위치는 틱마다 누적됩니다. 약 1 kHz에서 서비스는 매 틱마다 다시 적용됩니다. set_transform(0차 유지)이므로 작업 공간은 마지막으로 푸시한 위치 그대로 유지됩니다.
set_transform 와 configure.mount 의 차이두 명령어 모두 각 세션에 대해 하나의 영구 변환을 저장하지만, 파이프라인에서는 작업 공간 변환이 마운트된 위치에 있습니다.그 위(참조: 마운트 및 작업 공간). 튜토리얼 09에서는 매 틱마다 스트리밍 방식으로 전송할 때 set_transform 이때, 새로운 WebSocket 프레임 하나하나가 이전에 스트리밍으로 전송된 작업 공간 변환을 대체하게 됩니다. 따라서 동일한 장치로 스트리밍되는 다른 어떤 것도 set_transform 의 클라이언트는 다음 틱에서 덮어쓰게 됩니다.configure.mount 서로 독립적이며, 그 값을 변함없이 유지합니다. 실제 사용 시, 각 역할 유형별로 하나의 채널을 선택합니다: 물리적 설정을 위한 마운트,set_transform 실시간 내비게이션에 사용됩니다.
스레드 모델 (C++)
이 C++ 튜토리얼에서는 두 개의 스레드가 하나의 위치 누적기를 공유하는 방법을 다룹니다:
| 스레드 | 직무 |
|---|---|
| 메인 스레드 | 읽기 std::getline(std::cin, ...), 토큰 분석, 업데이트 nav_vel[] 와 default_step |
| WebSocket 콜백 스레드 | 사용 nav_vel[] * dt 추진 nav_pos[], 직렬화 set_transform 그리고 보내기 |
std::mutex nav_mutex 보호 nav_pos[]、nav_vel[] 와 default_step。last_tick 타임스탬프와 first_ws_msg `mark`는 WS 콜백의 지역 변수이므로, 뮤트릭스 잠금이 필요하지 않습니다.
ws.onmessage = [&](const std::string &) {
float pos_snap[3];
{
std::lock_guard<std::mutex> lk(nav_mutex);
for (int i = 0; i < 3; ++i) nav_pos[i] += nav_vel[i] * 0.001f; // mm/frame → m
for (int i = 0; i < 3; ++i) pos_snap[i] = nav_pos[i];
}
// build and send set_transform with pos_snap
};
소스 코드
튜토리얼 09는 SDK와 함께 로컬에 설치되어 있으므로, 서비스 설치 디렉터리 내의 tutorials/09-haply-inverse-ws-remote-control/ 에서 검색하세요.
관련 내용: set_transform 명령 · 세션 — 첫 번째 메시지 핸드셰이크 · 마운트 및 작업 공간 · 선택기 · 튜토리얼 08 — HTTP 원격 구성 · 튜토리얼 07 — Basis와 마운트