OmniGraph로 ROS2와 잇기
시뮬레이터 안의 로봇이 LiDAR 점군을 /scan 토픽으로 내보내고, 외부의 /cmd_vel 명령을 받아 바퀴를 굴리려면, 시뮬레이터와 ROS2 사이에 다리가 필요합니다. Isaac Sim에서 그 다리를 놓는 방법이 OmniGraph(Action Graph) 입니다.
노드를 이어 만드는 데이터 흐름
OmniGraph는 "비주얼 컴퓨트 그래프"입니다 — 박스(노드)를 선으로 이어 데이터 흐름을 만듭니다. 센서를 토픽으로 발행하는 건 보통 세 노드의 체인입니다.
도식 렌더링 중…
같은 패턴으로 여러 센서·인터페이스를 잇습니다.
| 그래프 | 역할 |
|---|---|
LiDAR → /scan | 거리 점군 발행 |
Camera → /image_raw | 영상 발행 |
IMU → /imu/data | 관성 발행 |
Clock → /clock | 시뮬 시간 발행 |
/cmd_vel → DifferentialController | 명령 → 바퀴 |
각 그래프는 "발화(tick) → 읽기(Isaac Read*) → 발행(ROS2 Publish*)"이라는 동일한 골격을 가집니다. 이 골격을 알면 새 센서를 잇는 일이 "노드 세 개 잇기"로 단순해집니다.
자주 막히는 함정 — 외부 명령 수신
발행(publish)은 위 패턴으로 잘 됩니다. 그런데 외부 ROS2 노드(예: Nav2)가 보낸 /cmd_vel을 받는 쪽에서 자주 막힙니다.
⚠️ OmniGraph의 Twist 구독 노드로 외부 명령을 못 받는 경우 — 그래프의 cmd_vel 구독 노드가 시뮬 내부 그래프 간 통신엔 되지만, 외부 ROS2 노드가 발행한 메시지는 못 받는 상황이 있습니다. 이럴 땐 그래프 구독 대신 별도 ROS2 클라이언트(rclpy) 버퍼로 받아 적용하는 경로가 안정적입니다. "발행은 OmniGraph, 외부 명령 수신은 별도 구독자"로 나눠 두면 디버깅이 쉽습니다.
이 함정은 "내 토픽은 잘 나가는데 왜 명령이 안 먹지?"의 단골 원인입니다 — 발행 경로와 수신 경로가 다르다는 걸 모르면 한참 헤맵니다.
왜 그래프인가
코드로 직접 ROS2 노드를 짜도 되는데 왜 비주얼 그래프일까요? 씬의 일부로 저장되고, 로봇 에셋과 함께 따라다니기 때문입니다. 로봇 USD에 센서 그래프가 붙어 있으면, 그 로봇을 어떤 환경에 스폰하든 토픽 발행이 그대로 따라옵니다 — 매니페스트 한 장으로 로봇을 추가하는 플랫폼 철학과 잘 맞습니다.
한 줄 정리
📌 OmniGraph는 "발화 → Isaac 읽기 → ROS2 발행" 노드 체인으로 센서를 토픽으로 내보낸다(LiDAR/카메라/IMU/clock). 발행은 매끄럽지만 외부 ROS2 명령 수신은 별도 구독자 경로가 필요할 수 있다 — 발행/수신 경로가 다르다는 걸 기억하라.
