주요 내용으로 이동

07. 베이스 & 마운트 훈련장

장치를 대화형 방식으로 구동하는 마운트 변환, 그리고 시연 configure.basis、configure.preset 와 configure.mount 통신 메시지 수준에서 어떻게 협업할 것인가. 일정한 기준을 유지하여 상호작용의 초점을 항상 configure 명령어에 두도록 한다.

다음 내용을 배우게 됩니다:

  • 설정 basis 축 변환("XZY" → Y축을 기준으로 한 응용 좌표계)
  • 선택 사전 설정(arm_front), 그리고 어떤 내용이 구성되는지 이해해야 합니다
  • 실행 중에 (키보드로 제어되는) 쿼터너리를 회전시켜 마운트를 덮어쓰기
  • 상호 배타 규칙:mount 와 preset 동시에 같은 곳에 나타날 수 없다 장비 구성 블록 내에서
  • 일회용 configure 의미: 키를 누를 때마다 configure 메시지를 하나만 전송합니다.
  • (C++ Glaze) 사용 std::optional 상호 배타적 필드의 모델링

업무 흐름​

  1. 첫 번째 메시지를 받았을 때: 보내기 세션 프로필、configure.basis: "XZY" 그리고 configure.preset: arm_front。지면을 고정하기 위해 지속적으로 전송을 시작합니다 set_cursor_force。
  2. 매 틱마다: 커서의 Y 좌표를 읽어들이고, 계산한다 force_y = max(0, (floor_pos - y) * stiffness) 그리고 전송합니다.
  3. 사용자가 마운트 회전 버튼을 누르면, pending_configure = true 위치 지정.
  4. 다음 틱에서: 다음을 생성합니다. configure.mount 블록, 그 변환된 rotation 단위 사원수(현재 피치각/요각에 따라 Z축, X축 순으로 합성). 생략 preset——이 두 가지는 통신 프로토콜에서 상호 배타적이다.
  5. 재설정 버튼(R) 덮어쓰기 설정을 지웁니다. 다음 configure 명령을 실행하면 다시 preset。

매개변수​

명칭기본값용도
BASIS"XZY"축 변환 — Y축을 기준으로 한 응용 좌표계
DEVICE_PRESET / DEVICE_CONFIG_PRESET"arm_front"이름이 지정된 프리셋 — 원점은 기기 받침대에 위치
FLOOR_POS_Y0.0 m고정 지면 평면 (응용 좌표계의 Y축)
STIFFNESS1000 해당 없음지면 스프링 상수
MOUNT_STEP_DEG10°버튼을 누를 때마다의 회전 각도
PRINT_EVERY_MS200원격 측정 스로틀 간격

제어​

버튼작업
W / S장비 주위로 +X축(상하) 방향으로 ±10° 회전
A / D장비 주위로 +Z축(요) 방향으로 ±10° 회전
R마운트 재설정——기본값으로 복원
H표시 제어 키
Q종료
mount 와 preset 상호 배타

서비스는 두 가지를 모두 포함하는 경우 이를 거부합니다. 장비 구성 블록. 사용자가 mount를 덮어쓰면, 이 튜토리얼에서는 이후의 모든 configure 단계에서 해당 내용을 생략합니다. preset. 누르세요 R 그 후, 다음 configure 단계에서 다시 활성화됩니다. preset 그리고 제거하고 mount。

다양한 입력 모드

C++ 변형은 백그라운드 stdin 스레드에서 줄 단위로 입력을 읽습니다(각 문자를 입력한 후 ENTER 키를 눌러야 함). 반면 Python은 메인 비동기 루프에서 keyboard 키를 실시간으로 순차적으로 확인하므로 ENTER 키를 누를 필요가 없습니다. 키가 같으면 명령도 동일합니다.

읽은 상태 필드​

출처: data.inverse3[i].state:

  • cursor_position.y — vec3, 지면을 관통하는 깊이를 계산하는 데 사용됨
  • current_cursor_force — 원격 측정 데이터 전송용

보내기 / 받기​

각 변형의 로드 구조는 동일하며, 진정한 차이는 각 변형이 상호 배타적인 요소를 어떻게 구성하는지에 있다. mount / preset 브랜치, 그리고 입력 스레드가 WebSocket 스레드에 어떻게 알리는지.

단일 비동기 루프를 통해 keyboard 패키지에 대해 실시간 키 입력 폴링을 수행합니다.pending_configure 전역 플래그로, 키 처리 함수에 의해 설정되며, 매번 전송될 때마다 configure 블록이 끝난 후 지우십시오.

async with websockets.connect(URI) as websocket:
while True:
msg = await websocket.recv()
data = json.loads(msg)

if first_message:
first_message = False
device_id = data["inverse3"][0]["device_id"]
# Handshake: profile + basis + preset
request_msg = {
"session": {"configure": {"profile": {"name": SLUG}}},
"inverse3": [{
"device_id": device_id,
"configure": build_configure_block(first_handshake=True),
# -> {"basis": {"permutation": "XZY"},
# "preset": {"preset": "arm_front"}}
}],
}
else:
handle_key_inputs() # may set pending_configure = True (classic, not shown)

y = data["inverse3"][0]["state"]["cursor_position"]["y"]
force_y = 0.0 if y > FLOOR_POS_Y else (FLOOR_POS_Y - y) * STIFFNESS

entry = {
"device_id": device_id,
"commands": {"set_cursor_force":
{"vector": {"x": 0.0, "y": force_y, "z": 0.0}}},
}
if pending_configure:
entry["configure"] = build_configure_block(first_handshake=False)
# -> {"mount": {...}} OR {"preset": {...}} (never both)
pending_configure = False

request_msg = {"inverse3": [entry]}

await websocket.send(json.dumps(request_msg))
SDK 설치 프로그램과 함께 제공됩니다

튜토리얼 07도 SDK와 함께 로컬에 설치됩니다. 서비스 설치 디렉터리에서 확인해 주세요. tutorials/07-haply-inverse-basis-and-mount/。

소스 코드: Python · C++ · C++ Glaze

관련 내용: Basis 축 변환 · 마운트 및 작업 공간 · 장비 구성 · 제어 명령(set_cursor_force) · 유형 (변환) · 튜토리얼 04 (Hello Floor)