주요 콘텐츠로 건너뛰기
버전: 3.5.x

07. 베이시스 & 마운트 놀이터

장치의 기능을 대화형으로 제어합니다 마운트 변환 그리고 어떻게 하는지 보여줍니다 configure.basis, configure.presetconfigure.mount 와이어에서 함께 작업합니다. 수평 바닥을 고정시켜 두어, 구성 명령어에 대한 상호작용의 초점이 유지되도록 합니다.

배울 내용:

  • 설정 기초 순열 ("XZY" → Y-up 적용 프레임)
  • 선택하기 사전 설정 (arm_front) 및 해당 설정이 무엇을 구성하는지 이해하는 것
  • 실행 시점에 회전 쿼터니언을 사용하여 마운트 재정의하기 (키보드 제어)
  • 상호 배제 법칙: mount 그리고 preset 같은 곳에 공존할 수 없다 장치 구성 블록
  • 단편 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-up 적용 프레임
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 서로 배타적이다

이 서비스는 장치 구성 두 가지를 모두 포함하는 블록. 사용자가 마운트를 재정의하면, 튜토리얼에서는 preset 이후의 모든 configure 단계에서. 누르면 R 다시 활성화 preset 다음 configure 및 drops 시 mount.

다양한 입력 모델

C++ 변형은 백그라운드 stdin 스레드에서 줄 단위로 입력을 읽습니다(각 문자를 입력한 후 Enter 키를 누르세요). Python은 keyboard 메인 비동기 루프에서 실시간 키 폴링을 수행하는 패키지 — 엔터 키를 누를 필요가 없습니다. 동일한 키, 동일한 명령어입니다.

상태 필드 읽기

발신자 data.inverse3[i].state:

  • cursor_position.yvec3, 바닥 관통 깊이를 계산하는 데 사용됨
  • 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))

출처: Python · C++ · C++ Glaze

관련 기사: 기저 순열 · 마운트 및 작업 공간 · 장치 구성 · 제어 명령어 (set_cursor_force) · 유형 (변환) · 튜토리얼 04 (Hello Floor)