PART 5 ROS 2 연동과 시뮬레이션 · 약 40분

20Isaac Sim · MuJoCo 시뮬레이션

Isaac Sim USD 모델과 MuJoCo 디지털 트윈으로 가상 텔레오퍼레이션·데이터 수집·Sim-to-Real 을 체험합니다.

왜 진짜 물리 시뮬레이터가 필요한가#

이 강좌의 시뮬레이터는 지금까지 아주 쓸모 있었습니다. 관절을 돌리고, IK 를 풀고, 궤적을 녹화했지요. 하지만 이 시뮬레이터는 기구학만 계산합니다. 중력도, 마찰도, 부딪힘의 반발도 없습니다. 큐브는 "그리퍼가 충분히 닫히고 TCP 가 가까우면 붙는다"는 단순 규칙으로 집힙니다.

실제 세상에서는 이런 일이 생깁니다.

  • 팔을 쭉 뻗으면 모터가 무게를 못 이겨 처집니다 (19장의 중력 토크).
  • 그리퍼가 블록을 너무 세게 쥐면 미끄러지거나 튕겨 나갑니다.
  • 빠르게 휘두르면 관절이 목표를 지나쳤다가 되돌아옵니다.

물리 시뮬레이터는 이런 현상을 계산해 줍니다. 실물을 망가뜨릴 걱정 없이 수천 번 실험하고, 정책 학습용 데이터를 쏟아낼 수 있습니다. reBot 생태계에서는 두 가지가 공식으로 준비되어 있습니다.

MuJoCoNVIDIA Isaac Sim
모델 형식MJCF (.xml)USD (.usda)
강점가볍고 빠른 접촉 물리, 브라우저 데모로도 체험 가능사실적 렌더링, 카메라 합성 데이터, GPU 대량 병렬
필요 장비일반 PC (온라인 데모는 브라우저만)NVIDIA RTX GPU (권장 RTX 3070 이상, VRAM 8GB+)
reBot 자료온라인 데모, MuJoCo Menagerie 모델Isaac Sim 위키, reBot-Isaacsim
CAD SolidWorks 조립품 URDF + STL 링크·관절·질량 이 강좌 시뮬레이터 URDF 그대로 (three.js) 기구학만 · 설치 없음 · 중력/마찰 없음 MuJoCo MJCF (.xml) · Menagerie 빠른 접촉 물리 · 온라인 데모 · CPU Isaac Sim USD (.usda) · urdf-usd-converter PhysX/Newton · 사실적 렌더 · RTX GPU 변환할 때마다 관절 이름·부호· 충돌 형상이 달라질 수 있으니 항상 원본과 대조합니다
세 시뮬레이터 모두 같은 CAD·URDF 에서 출발합니다. 형식이 바뀌는 지점마다 확인이 필요합니다.

설치 없이 — 온라인 MuJoCo 디지털 트윈#

공식 저장소 README 는 B601-RS MuJoCo 디지털 트윈을 브라우저에서 바로 체험할 수 있는 온라인 데모를 소개합니다. 처음 모델을 받는 데 시간이 조금 걸리며 Chrome 이나 Edge 를 권장합니다.

기능화면에서 찾을 것
구성 전환"Arm only" ↔ "AGV chassis"(이동 차체). AGV 는 WASD·화살표로 운전, Space 는 즉시 정지
TCP 조작"Enable TCP drag" 후 TCP 표식을 끌어 손끝 이동, Open/Close 로 그리퍼
카메라전역 오버헤드 카메라 + D405 손목 카메라, 나란히/위아래 보기
자동 데모빨강 큐브·파랑 블록·노랑 원기둥 중 골라 "Put away"(제자리 정리), "Stack"(쌓기)
접촉·힘접촉 개수, 그립 힘(Grip force), 관절 토크·오차 곡선
분해도"Disassemble" 로 부품을 펼치고, 부품을 눌러 조립·관절·재질 정보 보기
실습 — 물리가 있는 집기 관찰하기
  1. 온라인 데모를 열고 "Put away" 데모를 실행합니다.
  2. 데모가 도는 동안 Contacts and forces 패널을 보세요. 손가락이 블록에 닿는 순간 접촉 개수와 그립 힘이 어떻게 변하나요?
  3. 이번에는 강좌 시뮬레이터에서 큐브를 켜고 같은 동작(접근 → 닫기 → 들기)을 해 봅니다. 그립 힘이라는 개념이 있나요? 큐브는 언제 "붙나요"?
  4. 두 결과의 차이를 한 문장으로 적어 보세요. 그것이 "기구학 시뮬레이터"와 "물리 시뮬레이터"의 차이입니다.

MuJoCo 모델 들여다보기 — mujoco_collision 의 의미#

17장에서 메시 폴더 중 mujoco_collision/ 이 따로 있던 것을 기억하나요? 물리 시뮬레이터에서 집기는 접촉 형상이 전부입니다. 손가락을 볼록 껍질 하나로 단순화하면, 손가락 안쪽 오목한 부분까지 "꽉 찬 덩어리"로 계산되어 블록이 실제보다 일찍 닿거나 손가락끼리 관통합니다. 그래서 공식 패키지는 손가락을 앞·중간·뒤 세 조각으로 나누고 캐리지·스토퍼까지 따로 둔 10조각을 MuJoCo 접촉용으로 제공합니다. README 의 경고 그대로 "완전한 손가락의 단일 convex hull 로 바꾸면 닫을 때 관통, 과도하게 큰 접촉면, 불안정한 파지가 다시 생길 수 있습니다."

reBot-Isaacsim 저장소의 mjcf/rebot_devarm/ 에는 MuJoCo Menagerie(DeepMind 가 관리하는 고품질 로봇 모델 모음)의 [seeed_rebot_devarm](https://github.com/google-deepmind/mujoco_menagerie/tree/da76818e269b82289eba39808e2fb91d679d6994/seeed_rebot_devarm) 모델이 복사되어 있고, README 가 그 설계를 자세히 설명합니다.

설계내용 (README 기준)
충돌 형상링크마다 8~12조각 볼록 분해(convex decomposition), 총 92개. 링크당 볼록 껍질 하나면 부피가 실제의 3.24배, 분해하면 1.89배
자기 충돌켜져 있음. 인접 링크 등 11쌍만 제외
구동기위치 구동기. 토크 한계 RS-06 36 N·m(관절 1~3), RS-00 14 N·m(관절 4~6) — 실물 펌웨어에서 읽은 값
그리퍼1:1 랙-피니언이라 두 손가락을 <equality joint> 로 묶음 (독립 자유도 아님)
중력 검증MuJoCo 의 중력 항과 Pinocchio g(q) 를 5개 자세에서 비교, 최대 차이 5.9e-6 N·m
xml
<joint name="joint2" type="hinge" range="-3.14 0" axis="0 0 -1" class="rs06"/>
...
<equality>
  <joint joint1="joint_left" joint2="joint_right" polycoef="0 1 0 0 0" .../>
</equality>
이 MJCF·USD 는 관절 약속이 다릅니다

위 발췌를 보면 RS 모델인데 joint2 범위가 -3.14 ~ 0 이고 손가락 이름이 joint_left/joint_right 입니다. 이 자산은 저장소의 이전 RS URDF(urdf/00-arm-rs_asm-v3)에서 만들어졌기 때문입니다. 현재 Rebot_Arm_description/RS 의 URDF(joint2 0 ~ 3.14, gripper_joint1/2)와 부호·이름이 다릅니다. 저장소 문서도 "응용 프로그램의 관절 부호 매핑을 적용하라"고 당부합니다. 시뮬레이터 사이에서 자세 값을 옮길 때는 반드시 각 모델 파일의 range·axis·이름을 대조하세요.

ROS 2 를 쓴다면 공식 작업공간의 rebotarm_mujoco_rs 패키지가 RS MuJoCo 모델을 ROS 에 붙여 줍니다. kinematic 모드는 ROS 관절 상태를 그대로 MuJoCo 에 복사하고, physics 모드는 PD 제어 + 중력 항으로 목표를 따라갑니다. 이 래퍼는 SocketCAN 을 열지 않으므로 실물 팔은 여전히 reBotArmController 하나만 제어합니다(18장).

bash
ros2 launch rebotarm_mujoco_rs mujoco_rs.launch.py \
  arm_namespace:=rebotarm_rs simulation_mode:=physics use_viewer:=true

Isaac Sim — USD 모델과 가상 텔레오퍼레이션#

준비물#

Isaac Sim 위키 기준 요구 사양입니다.

항목요구
Isaac Sim6.0.0 독립 실행 패키지
OSUbuntu 22.04 / 24.04 LTS (권장), 또는 Windows 11 + WSL2
GPUNVIDIA RTX, 권장 RTX 3070 이상, VRAM 8GB 이상, 드라이버 535 이상
RAM / 저장공간32GB 이상 / SSD 여유 100GB 이상

URDF 에서 USD 로#

Isaac Sim 은 USD(Universal Scene Description) 라는 장면 형식을 씁니다. reBot-Isaacsim 의 RS 자산(usd/RS-rebot-dev-arm/RS-rebot-dev-arm.usda)은 urdf-usd-converter 로 URDF 를 변환한 뒤, scripts/prep_asset.py 로 후처리한 결과입니다. 변환기만으로는 부족한 것을 스크립트가 채웁니다.

  1. 관절 8개에 구동기(drive) 와 검증된 게인·토크 한계를 붙입니다 (변환 직후 관절은 "기구학 전용"이라 힘이 없습니다).
  2. 충돌 형상을 혼합으로: 팔은 볼록 껍질, 그리퍼(gripper_end·좌우 손가락)는 볼록 분해.
  3. Isaac 로봇 스키마를 붙여 Gain Tuner 같은 도구가 로봇을 인식하게 합니다.

DM 자산은 usd/reBot_B601_DM/reBot_B601_DM.usda 에 있습니다. 변환 과정과 검증 결과(관절별 한계 유지 테스트, 중력 처짐 분석)는 저장소 docs/VALIDATION.md 에 기록되어 있어, 시뮬레이션 모델도 검증 대상이라는 좋은 예를 보여 줍니다.

송신부와 수신부 — 두 터미널 구조#

reBot-Isaacsim 은 수신부(Isaac Sim 안에서 관절을 움직임)와 송신부(관절각을 보냄)를 UDP 로 잇습니다.

text
터미널 2 (송신부)                         터미널 1 (수신부)
reBotArm_control_py uv 환경   ── UDP JSON ──▶  Isaac Sim 의 python
  gravity_joint_sender 등        127.0.0.1:5005   isaacsim_joint_receiver
json
{"sequence": 123, "timestamp": 1718000000.123,
 "joint_positions": [0.0, 0.1, 0.2, -0.1, 0.0, -0.02],
 "gripper_position": 0.05}
송신부하는 일실물 필요
isaacsim_joint_test_sender미리 정한 자세 사이를 천천히 오가며 통신 확인아니요
isaacsim_ik_senderx y z [r p y] 를 입력하면 IK 로 풀어 전송아니요 (IK 계산만)
isaacsim_traj_senderIK + 관절 공간 MIN_JERK 궤적으로 부드럽게아니요
gravity_joint_sender중력 보상 손잡이 모드: 실물 팔을 손으로 움직이면 Isaac Sim 의 팔이 60 Hz 로 따라옴예
joint_reader_senderReal-to-Sim: 다른 프로그램이 돌리는 실물 팔을 읽기만 해서 비춤예

gravity_joint_sender 가 바로 가상 텔레오퍼레이션입니다. 19장의 중력 보상(MIT + g(q))으로 실물 팔을 가볍게 만들어 리더 암처럼 쓰고, 그 관절각으로 가상 팔을 조종합니다. 저장소는 그리퍼를 떼고 손잡이를 단 개조 팔을 예로 듭니다.

bash
# 터미널 1 — 수신부를 먼저
cd reBotArm_Isaacsim
./run_isaacsim_receiver.sh

# 터미널 2 — 실물 없이 통신 확인
cd reBotArm_Isaacsim
uv run python isaacsim_joint_test_sender.py
위키와 저장소의 차이

위키 본문은 저장소 주소를 hopcan/reBot-Isaacsim 으로, 터미널 1 명령을 ${ISAACSIM_PYTHON_EXE} gravity_joint_sender.py 로 적고 있지만, 저장소 README 는 Seeed-Projects/reBot-Isaacsim 이고 수신부는 isaacsim_joint_receiver.py(run_isaacsim_receiver.sh)입니다. 또 실물 송신부를 쓰기 전에 python set_hw_rs.py 로 하드웨어 설정을 RS 로 맞추라고 안내합니다. 실행 전 저장소 README 의 최신 순서를 확인하세요.

실물 송신부를 쓸 때

gravity_joint_sender 와 joint_reader_sender 는 실제 CAN 버스(can0, 1 Mbps)에 붙습니다. SDK 의 example/9 중력 보상을 동시에 돌리지 마세요 — 버스를 서로 빼앗습니다. RS 는 48V 전원이고, 중력 보상 중인 팔도 토크가 켜져 있으니 비상 시 전원을 바로 끊을 수 있게 하세요.


Sim-to-Real 갭과 도메인 랜덤화#

시뮬레이션에서 완벽히 되던 동작이 실물에서는 어긋나는 현상을 Sim-to-Real 갭이라고 합니다. 원인은 "모델이 현실을 100% 담지 못한다"는 것입니다.

갭의 원천reBot 에서의 예
질량·관성URDF 질량 합 RS 6.01 kg vs 사양 약 6.7 kg (17장) — 케이블·나사 누락
마찰·백래시reBot-Isaacsim 측정: 실물 그리퍼 정지 마찰은 손가락 기준 13.6 N, 백래시 ±0.37 mm
구동기실물은 MIT 게인·전류 한계·통신 지연, 시뮬은 이상적 구동기
접촉접촉 형상 단순화, 마찰 계수 추정
센서카메라 노이즈·조명·색감, 엔코더 잡음

reBot-Isaacsim 의 docs/GRIPPER_RESIDUAL_MOTION.md 는 좋은 사례입니다. 팔을 휘두를 때 실물 그리퍼 손가락은 사실상 움직이지 않는데, 시뮬레이션에서는 8 Hz 로 휘두를 때 약 0.25 mm 흔들렸습니다. 구동기 강성을 16배 올려도 거의 그대로였고, 문서는 이것이 강성 문제가 아니라는 점을 측정으로 하나씩 확인해 나갑니다. 시뮬레이션의 차이는 추측이 아니라 측정으로 좁힌다는 태도를 배울 수 있습니다.

갭을 줄이는 두 가지 큰 전략은 다음과 같습니다 (일반론).

  1. 시스템 식별(system identification) — 실물을 측정해 모델 값을 맞춥니다. 19장의 tau_scale 조정, reBot-Isaacsim 의 마찰·강성 측정이 여기에 속합니다.
  2. 도메인 랜덤화(domain randomization) — 시뮬레이션의 질량·마찰·게인·조명·카메라 위치·물체 색을 에피소드마다 조금씩 무작위로 바꿔 학습시킵니다. 정책이 "정확히 이 세계"가 아니라 "이 근처의 여러 세계"에서 통하도록 배우면, 실물도 그 범위 안의 한 세계로 받아들여질 가능성이 커집니다.
Sim-to-Real VLA 코스

Seeed 는 NVIDIA Isaac 과 함께 Learning Physical AI — A Sim-to-Real VLA Pipeline with Seeed reBot Arm and NVIDIA Isaac 코스를 안내합니다. 시뮬레이션에서 데이터를 만들고 VLA(시각-언어-행동) 정책을 학습해 실물 reBot 에 옮기는 흐름입니다. 커리큘럼·가격 등 세부는 페이지에서 최신 정보를 확인하세요. 정책 학습 자체는 16장을 참고하세요.


세 시뮬레이터 비교#

항목강좌 브라우저 시뮬레이터MuJoCoIsaac Sim
계산기구학만 (FK·IK)강체 동역학 + 접촉강체 동역학 + 접촉 (PhysX / Newton)
중력·마찰·토크없음있음있음
집기단순 규칙(닫힘 + 근접 → 붙음)접촉 메시와 마찰로 계산접촉 메시와 마찰로 계산
카메라손목·스탠드 가상 카메라오버헤드·D405 손목 (데모)사실적 렌더링, 합성 데이터
모델공식 URDF (RS/DM 전환)MJCF (Menagerie 기반 RS)USD (RS·DM)
설치없음pip 또는 브라우저 데모RTX GPU + Isaac Sim 6.0
잘하는 일개념 학습, 관절·IK·궤적 연습, LeRobot 형식 녹화빠른 물리 실험, 파지 검증대규모 데이터 생성, 시각 정책, Sim-to-Real
못하는 일처짐·미끄러짐·충돌 반력사진 같은 렌더링가벼운 실행
실습 — "물리가 없으면 무엇을 놓칠까" 목록 만들기
  1. 시뮬레이터 Python 탭에서 아래를 실행해 팔을 최대한 앞으로 뻗었다가 접습니다.
python
arm.home()
for x in [0.30, 0.45, 0.60]:
    ok = arm.move_to(x, 0.0, 0.20, t=1.5)          # 위치만 맞추기
    print(x, "도달" if ok else "실패", [round(a, 1) for a in arm.get_joints()])
arm.home()
  1. 각 자세에서 실물이라면 어느 관절이 가장 힘들지(중력 토크가 클지) 예상해 적어 보세요. 19장의 결과와 비교합니다.
  2. 큐브를 켜고 arm.cube() 위치로 가서 arm.close() 한 뒤 들어 올려 보세요. 실물이나 MuJoCo 라면 어떤 이유로 실패할 수 있을지(미끄러짐, 손가락 관통, 블록 회전 등) 세 가지를 적습니다.
  3. 녹화 탭으로 이 동작을 LeRobot 형식으로 내보내 보세요. 이 데이터를 실물 정책 학습에 그대로 쓰면 어떤 갭이 생길까요?

녹화 탭 열기


정리#

  • 이 강좌 시뮬레이터는 기구학 전용이고, MuJoCo·Isaac Sim 은 중력·마찰·접촉을 계산하는 물리 시뮬레이터입니다.
  • 온라인 MuJoCo 디지털 트윈은 설치 없이 TCP 드래그, D405 손목 카메라, 정리·쌓기 데모, 접촉·힘 모니터를 제공합니다.
  • mujoco_collision 메시는 손가락을 여러 조각으로 나눈 세밀 접촉 형상으로, 하나의 볼록 껍질로 바꾸면 집기가 불안정해집니다.
  • Isaac Sim 자산은 URDF → urdf-usd-converter → 후처리(구동기·충돌·스키마)로 만든 USD 이고, reBot-Isaacsim 은 UDP 송신부/수신부 구조로 IK·궤적·중력 보상 텔레오퍼·Real-to-Sim 을 지원합니다.
  • 변환된 자산(MJCF·USD)은 관절 부호·이름이 현재 URDF 와 다를 수 있으니 항상 대조하세요.
  • Sim-to-Real 갭은 시스템 식별(측정으로 모델 맞추기)과 도메인 랜덤화(무작위로 흔들어 학습)로 줄입니다.

확인 문제#

  1. 강좌 브라우저 시뮬레이터로는 확인할 수 없고 MuJoCo 로는 확인할 수 있는 현상 두 가지를 쓰세요.
  2. 그리퍼 손가락의 MuJoCo 접촉 형상을 하나의 볼록 껍질로 단순화하면 어떤 문제가 생길 수 있나요?
  3. reBot-Isaacsim 에서 실물 없이 통신부터 확인하려면 어떤 송신부를 쓰나요? 수신부와 송신부 중 무엇을 먼저 켜나요?
  4. reBot-Isaacsim 의 RS MJCF 에서 joint2 범위가 -3.14 ~ 0 인 것을 보고 무엇을 조심해야 하나요?
  5. 도메인 랜덤화가 Sim-to-Real 갭을 줄이는 원리를 한 문장으로 설명하세요.
정답
  1. 예: 팔이 중력으로 처지는 것, 그리퍼가 블록을 쥘 때의 접촉 힘과 미끄러짐, 관절 토크, 충돌 반력.
  2. 손가락 안쪽까지 꽉 찬 덩어리로 계산되어 닫을 때 관통하거나 접촉면이 너무 커져 파지가 불안정해집니다.
  3. isaacsim_joint_test_sender.py 를 씁니다. **수신부(run_isaacsim_receiver.sh)를 먼저** 켜고 송신부를 켭니다.
  4. 현재 Rebot_Arm_description 의 RS URDF(joint2 0 ~ 3.14)와 부호 약속이 반대이므로, 자세 값을 옮길 때 부호 매핑을 적용하고 관절 이름(joint_left/right vs gripper_joint1/2)도 대조해야 합니다.
  5. 시뮬레이션 조건을 무작위로 바꿔 가며 학습하면 정책이 여러 세계에서 통하도록 배우므로, 실물도 그중 하나처럼 다룰 수 있게 됩니다.