Unitree Isaac Sim 기반 XR Teleoperation WebSocket 오류 문의

안녕하세요.

현재 Unitree 기반 Isaac Sim 5.1 환경에서 Meta Quest 3를 이용한 XR Teleoperation 시뮬레이션 테스트를 진행 중인데, Virtual Reality 진입 시 WebSocket 연결이 끊기는 문제가 있어 기술 지원을 요청드립니다.

현재 구성은 아래와 같습니다.

  • 시뮬레이션: Isaac Sim 5.1 / unitree_sim_isaaclab

  • XR Teleoperation: unitreerobotics/xr_teleoperate v1.5 기준

  • XR 기기: Meta Quest 3

  • Python 환경: conda tv_sim, Python 3.10

  • 주요 패키지:

    • vuer==0.0.60

    • aiohttp==3.10.5

  • GPU 서버 IP: 192.168.123.2

실행 명령은 아래와 같습니다.

# Isaac Sim 실행
conda activate unitree_sim_env
cd ~/unitree_sim_isaaclab

python sim_main.py \
  --enable_cameras \
  --task Isaac-PickPlace-Cylinder-G129-Inspire-Joint \
  --enable_inspire_dds \
  --robot_type g129
# XR Teleoperation 실행
conda activate tv_sim
cd ~/xr_teleoperate_sim/teleop

python3 teleop_hand_and_arm.py \
  --input-mode=hand \
  --arm=G1_29 \
  --ee=inspire_dfx \
  --sim \
  --img-server-ip=192.168.123.2
  1. Isaac Sim 화면은 정상적으로 실행되며, 로봇과 환경이 표시됩니다.

  2. https://192.168.123.2:8012/?ws=wss://192.168.123.2:8012 VR Meta Quest 3 내 웹 브라우저에서 접속 시 WebSocket 연결은 정상적으로 이루어집니다.

  3. 하지만 Meta Quest 3에서 Virtual Reality 버튼을 누르는 순간 WebSocket 연결이 끊기며 오류가 발생합니다. 오류 내용은 이미지로 첨부드리겠습니다.

    https://192.168.123.2:8012/?ws=wss://192.168.123.2:8012`` 진입 시,websocketconnected가 보이나 Virtual Reality 버튼 클릭 시 disconnected 되며 끊겨 버립니다.

안녕하세요, 위고로보틱스 기술지원팀입니다.

상황은 **Vuer(웹 기반 시각화 도구)**와 Meta Quest 3 사이의 WebXR 세션 충돌 또는 네트워크 보안 정책으로 인해 발생하는 전형적인 현상입니다. 해당 시스템을 안정화하기 위한 단계별 해결 방법을 정리해 드립니다.


1. SSL/HTTPS 인증서 및 혼합 콘텐츠 설정

가장 흔한 원인은 브라우저의 보안 정책입니다. Meta Quest 3의 브라우저는 보안되지 않은 WebSocket(ws://)이나 유효하지 않은 SSL 인증서가 포함된 wss:// 연결을 VR 모드에서 차단하는 경우가 많습니다.

  • 해결 방법: * https 대신 http로 접속하여 테스트해 보세요. (예: http://192.168.123.2:8012)
    • 반대로 https 사용 시, 브라우저 주소창 왼쪽의 설정 아이콘을 눌러 ‘보안되지 않은 콘텐츠 허용’ 또는 '인증서 예외’를 확실히 승인했는지 확인하세요.
    • vuer 실행 시 --cert--key 옵션을 사용하여 정식 또는 유효한 자체 서명 인증서를 적용해야 할 수도 있습니다.

2. 패키지 버전 호환성 체크 (vueraiohttp)

게시글에 명시된 vuer==0.0.60aiohttp==3.10.5 조합에서 특정 핸드셰이크 오류가 보고된 바 있습니다.

  • 해결 방법: * vuer 라이브러리를 최신 버전으로 업데이트하거나, 안정화된 버전인 0.0.55 내외로 재설치하여 테스트해 보세요.
    • pip install --upgrade vuer 명령어를 통해 최신 WebXR 통신 규격이 반영되었는지 확인하십시오.

3. MTU 및 네트워크 대역폭 확인

VR 모드로 진입하면 컨트롤러 데이터뿐만 아니라 이미지/포인트 클라우드 스트리밍 데이터가 급증합니다. 이때 패킷 크기가 네트워크 장비의 허용 한도(MTU)를 넘으면 연결이 즉시 끊깁니다.

  • 해결 방법:
    • teleop_hand_and_arm.py 실행 시 --img-server-ip 외에 이미지 해상도나 FPS를 낮추는 옵션을 추가하여 부하를 줄여보세요.
    • 공유기의 5GHz 대역을 사용 중인지 확인하고, PC와 Meta Quest 3가 동일한 서브넷에 있는지 다시 점검하십시오.

4. Isaac Sim 및 Isaac Lab 설정 확인

Isaac Sim 5.1과 unitree_sim_isaaclab 사이에서 카메라 렌더링 리소스를 과하게 점유할 때 WebSocket 응답이 밀리면서 타임아웃이 발생할 수 있습니다.

  • 해결 방법: * sim_main.py 실행 시 --enable_cameras를 끄고 먼저 VR 접속이 유지되는지 테스트해 보세요.
    • 만약 카메라 없이 접속이 유지된다면, GPU 메모리 부족이나 렌더링 병목이 원인입니다.

5. 방화벽 및 포트 개방

포트 8012 외에도 데이터 전송을 위한 추가 포트가 차단되어 있을 수 있습니다.

  • 해결 방법:
    • 서버(Ubuntu)에서 sudo ufw disable을 통해 일시적으로 방화벽을 끄고 테스트하여 네트워크 정책 문제인지 확인하십시오.

[!TIP]
로그 확인이 최우선입니다. > Meta Quest 3 내의 브라우저에서 chrome://inspect 또는 edge://inspect 기능을 사용하여 원격 디버깅을 시도해 보세요. VR 버튼을 누를 때 콘솔에 발생하는 구체적인 JavaScript 오류 메시지(Auth Error, Protocol Error, Timeout 등)를 확인하면 훨씬 정확한 해결이 가능합니다.

현재 진행 중인 프로젝트에서 가장 먼저 vuer 버전 변경브라우저 보안 예외 설정을 시도해 보시는 것을 추천드립니다! 추가로 궁금한 점이 있으신가요?

  1. 접속 주소에서 http로 테스트했으나 정상 동작하지 않았습니다. 기본 브라우저와 Wolvic 브라우저 모두 인증서 보안 허용은 진행했습니다.

  2. vuer는 최신 버전 기준으로도 문제가 발생했습니다. vuer 0.0.55 안정 버전으로 맞추려고도 했으나, 다른 패키지들과 충돌이 발생하여 전체 의존성 변경이 필요한 상황이라 추가 진행은 하지 않았습니다.

  3. MTU는 1500으로 확인되었고, Quest 3와 GPU 서버는 5GHz 대역 및 동일 서브넷 환경에서 테스트했습니다.
    또한 teleop_hand_and_arm.py에는 FPS나 이미지 해상도를 낮추는 실행 옵션이 별도로 보이지 않았습니다.

  4. sim_main.py 실행 시 --enable_cameras 옵션을 제거하면 환경 생성이 실패하게 됩니다. 이 옵션은 기본적으로 필요한 것으로 보입니다.

  5. Ubuntu 방화벽을 비활성화한 상태에서도 동일하게 문제가 발생했습니다.

추가로 Meta Quest 3 VR 기기 내 Wolvic 웹 브라우저 환경에서, teleop_hand_and_arm.py 실행 시 --input-mode=controller로 실행하면 컨트롤러를 쥐고 팔을 움직였을 때 어느 정도 동작하는 것으로 보입니다.
하지만 --input-mode=hand로 실행하면 초기 자세는 잡히는 것 같으나, 이후 텔레오퍼레이션이 정상적으로 이어지지 않습니다.

현재 저희가 사용하는 환경은 아래와 같습니다.

  • aiohappyeyeballs: 2.6.1
  • aiohttp: 3.13.5
  • aiohttp-cors: 0.8.1
  • vuer: 0.0.40
  • xr_teleoperation: v1.0

위 환경에서 테스트 해보시는 것을 추천드립니다.

isaac sim은 5.1 버전이실까요?

이 페이지에 있는 2.2 :key: Generate Certificate Files 과정은 다 거치셨을까요?

감사합니다. 말씀 주신 버전으로 xr_teleoperate 버전을 1.0v로 낮췄더니 성공할 수 있었습니다.

다만, 한가지 더 궁금한 점이 있습니다.

현재 로봇 팔과 Inspire hand 손가락 제어는 Isaac Sim 상에서 정상적으로 동작합니다.
다만 VR에서 보는 카메라 스트리밍 화면에 지연이 있습니다.
제가 움직이면 Isaac Sim 화면에서는 비교적 자연스럽게 따라오는데, VR 화면에서는 약간 버퍼가 걸린 것처럼 한 박자 늦게 따라와서 실시간 원격 조작이 어렵습니다.

이러한 지연을 개선해보려고 아래 항목들을 수정해봤습니다.

  1. xr_teleoperate 쪽
  • teleop_hand_and_arm.py 실행 시 --frequency 90 옵션 사용
  • robot_control/robot_arm.py
    • self.arm_velocity_limit 값을 20.0 → 30.0으로 변경
  • robot_control/robot_hand_inspire.py
    • Inspire_Controller 클래스의 fps 값을 100.0 → 150.0으로 변경
  1. unitree_sim_isaaclab 쪽
  • tools/shared_memory_utils.py
    • MultiImageWriter 클래스에서 카메라 이미지를 shared memory에 쓰는 최소 간격 변경
    • self._min_interval_sec 값을 1.0 / 50.0 → 1.0 / 100.0으로 변경

위 수정 후 Isaac Sim 상의 움직임은 더 자연스럽고 빨라진 것처럼 보입니다.
하지만 VR에서 보는 카메라 화면은 여전히 약간 늦게 따라옵니다.

이 경우 VR 스트리밍 지연을 줄이려면 어느 부분을 우선적으로 수정해야 할까요?

전반적으로 VR 상에서 카메라 화면이 끊기면서 부자연스럽게 나오나요? 부드럽고 빠르게 성능을 높일 수 있는 방법을 알려주시면

감사드리겠습니다.

지금까지 만지신 파라미터들은 로봇 제어 루프(arm velocity, hand fps, teleop frequency) 위주라 카메라 스트리밍 지연에는 거의 영향이 없습니다. 영상 파이프라인은 별도 라인이에요.

영상 파이프라인 구조 먼저

Isaac Sim 렌더링 (GPU)
  ↓ GPU→CPU readback   ← ① 큰 비용
shared memory write
  ↓
image_server.py (cv2.imencode JPEG)   ← ② CPU 인코딩
  ↓ ZMQ PUB
Vuer 백엔드 (WebSocket)   ← ③ TCP/HoL blocking
  ↓ Wi-Fi
Quest 3 브라우저 디코드
  ↓
WebXR 텍스처 업로드 → 합성   ← ④ Quest GPU

지연이 누적되는 지점은 ①②③④인데, 사용자가 “느리게 따라옴” 정도로 느낀다면 보통 ②+③ 조합이 8할입니다.

우선순위별 개선 포인트

1순위: ZMQ 프레임 누적 차단 (효과 큼, 작업 5분)

xr_teleoperate/image_server/image_server.py(또는 동등 파일)의 PUB 소켓에 다음을 추가하세요.

socket.setsockopt(zmq.SNDHWM, 1)
socket.setsockopt(zmq.CONFLATE, 1)

CONFLATE는 큐에 미전송 프레임이 쌓이면 최신 한 장만 남기고 폐기합니다. 이게 없으면 네트워크 jitter 발생 시 오래된 프레임이 큐에 쌓여 지연이 누적되는데, 사용자가 묘사한 "한 박자 늦음"의 전형적인 원인이에요. 수신단(Vuer 쪽)에도 RCVHWM=1, CONFLATE=1 적용.

2순위: JPEG 인코딩 부하 감소 (효과 매우 큼)

image_server.py에서 cv2.imencode('.jpg', img, ...) 호출부 찾으세요. 일반적으로:

# 기본값이 95인 경우가 많음 - 너무 높음
cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 60])

품질 95→60으로 낮추면 인코딩 시간과 대역폭이 절반 이하로 떨어지고 VR 시야각에서는 화질 차이가 거의 보이지 않습니다. 50까지도 실용적입니다.

3순위: 카메라 해상도 (효과 매우 큼)

unitree_sim_isaaclab의 카메라 설정에서 해상도 확인하세요. G1 inspire hand 시연 기준으로 한쪽 눈 640×480 정도면 충분합니다. 1280×720 이상이면 readback과 인코딩 모두 비례해서 느려집니다. VR 시야에서는 어차피 작게 보여서 1080p가 의미 없어요.

4순위: 네트워크 경로 (간과되기 쉬움)

  • Quest 3는 반드시 5GHz 또는 Wi-Fi 6 6GHz에 연결. 2.4GHz면 거의 확정적으로 끊김/지연
  • PC와 Quest가 동일 AP, 동일 서브넷, 가능하면 PC는 유선 연결
  • 같은 라우터라도 mesh hop 거치면 RTT 5~20ms씩 추가됨
  • 회사망의 Multi-AP 환경이면 격리된 단독 AP 권장

지표로는 Quest 3에서 PC로 ping해서 RTT가 연속 측정 시 max 10ms 이하여야 합니다. spike가 50ms+이면 Wi-Fi 채널 간섭.

5순위: Isaac Sim GPU→CPU readback

--enable_cameras로 활성화된 카메라가 RTX rendering으로 되어 있으면 GPU→CPU 복사 비용이 큽니다. unitree_sim_isaaclab의 카메라 설정에서:

  • 카메라 개수를 꼭 필요한 만큼만(보통 head 2개)
  • TiledCamera 사용 시 단일 readback으로 묶이는지 확인
  • 가능하면 pathtracing 대신 RaytracedLighting 또는 RasterizedLighting

사용자가 만진 항목 재평가

shared_memory_utils.py_min_interval_sec을 50→100Hz로 올린 건 읽기 측이 빠르지 않으면 무의미합니다. shared memory에 100Hz로 써도 image_server가 30Hz로 읽으면 70%는 버려져요. 오히려 writer 부하만 증가. 50Hz로 되돌리고, 대신 image_server의 송출 주기를 측정해보세요.

끊김(jitter) 여부 진단

"부드럽고 빠르게"를 동시에 원하시는데, 이 둘은 다른 문제입니다.

  • 느리게 따라옴 (latency): 파이프라인 깊이 → 위 1~3순위로 해결
  • 끊김/뚝뚝거림 (jitter): 프레임 도착 간격이 불균일 → 4순위 네트워크 + CONFLATE 옵션으로 해결

Quest 3 브라우저에서 chrome://inspect 원격 디버깅으로 Performance 탭 보시면 프레임 간격 히스토그램 나옵니다. 16.7ms(60fps)에 일정하게 몰려 있으면 jitter는 없는 거고, 30~100ms로 산포되어 있으면 네트워크 문제입니다.

가장 빠른 검증 순서

  1. JPEG quality 60으로 낮추기 (1줄 수정)
  2. ZMQ CONFLATE/HWM=1 추가 (2줄 수정)
  3. 카메라 해상도 절반으로 (config 1줄)
  4. Quest를 5GHz로 강제

이 4개만 해도 체감 지연이 절반 이하로 떨어지는 게 일반적입니다. 적용해보시고 그래도 남는 지연이 있으면 chrome://inspect의 Performance 캡처를 공유해주세요. 어느 단계가 병목인지 정확히 짚을 수 있습니다.

우선 말씀주신 4가지 전부 시도해봤는데 끊기는 현상은 여전한 것 같습니다.

혹시 실제로 하실 땐 VR 상에서는 스트리밍이 부드럽게 나오시는지, 어떻게 나오시는지 알 수 있을까요?

기본적으로 이렇게 살짝 느리게 끊겨서 보이는지 궁금합니다.

담당자 의견으로는 네트워크 상태에 영향을 많이 받았다고 합니다.
그리고 저희는 시뮬레이터가 아니라 G1 로봇에 바로 연결해서 텔레오퍼레이션 한 결과라 연구원님 상황과 차이가 있습니다.