대상: ROS로 자율주행 로봇을 개발하거나, 센서·제어 노드 간의 데이터 흐름을 이해하고 싶은 개발자
환경: Ubuntu 20.04 + ROS Noetic (Melodic 동일)
적용 예시: 차륜형 이동 로봇 (differential drive, Ackermann 등)
1. 문제/주제 요약
ROS 기반 모바일 로봇을 처음 다루면 아래와 같은 의문이 생깁니다:
cmd_vel은 어디서 오고, 누가 구독하나?odom은 어떻게 계산되고, 어디에 쓰이는가?tf트리와odom,base_link의 관계는?- LiDAR, IMU 등 센서 데이터는 어디로 연결되는가?
이 글에서는 기본적인 ROS 모바일 로봇 시스템 구조를 한눈에 정리합니다.
RViz나 시뮬레이터(Gazebo)에서 동작을 이해하기 전, 이 흐름을 정확히 아는 것이 중요합니다.
2. ROS 모바일 로봇의 핵심 구성도
ROS에서 차륜형 로봇의 일반적인 데이터 흐름은 다음과 같습니다:
┌────────────────────┐
│ Navigation │ ← move_base / path planner
│ (cmd_vel publisher)│
└─────────┬──────────┘
│
▼
┌────────────────────┐
│ Base Controller │ ← 실제 모터 명령 제어
│ (cmd_vel subscriber│
│ odom publisher) │
└─────────┬──────────┘
│
│ odometry data (/odom)
▼
┌────────────────────┐
│ Localization / TF │ ← odom → base_link 변환
└─────────┬──────────┘
│
│ sensor data (/scan, /imu)
▼
┌────────────────────┐
│ Sensors (Lidar, │
│ IMU, Camera 등) │
└────────────────────┘
3. 주요 토픽 및 역할 정리
| 토픽 이름 | 발행자(pub) | 구독자(sub) | 설명 |
|---|---|---|---|
/cmd_vel | teleop, move_base | 로봇 하위 제어 노드 | 로봇 속도 명령 (geometry_msgs/Twist) |
/odom | 로봇 제어 노드 | localization, EKF 등 | 로봇의 이동 추정 (nav_msgs/Odometry) |
/tf | 각 센서 및 로봇 프레임 노드 | RViz, TF listener | 좌표계 간 변환 관계 |
/scan | LiDAR 드라이버 | SLAM, obstacle detection | 거리 센서 데이터 (sensor_msgs/LaserScan) |
/imu/data | IMU 드라이버 | EKF, localization | 관성 센서 데이터 (sensor_msgs/Imu) |
4. 토픽 흐름 상세 분석
(1) cmd_vel — 속도 명령 (Velocity Command)
- 메시지 타입:
geometry_msgs/Twist - 단위: m/s, rad/s
rostopic echo /cmd_vel
출력 예시:
linear:
x: 0.2
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.5
발행자(Publisher)
teleop_twist_keyboardmove_base- 자율주행 알고리즘
구독자(Subscriber)
- 모터 제어 노드 (예:
diff_drive_controller,ackermann_steering_controller)
💡 로봇의 실제 움직임은 이
cmd_vel명령을 받아 속도 제어기로 전달되는 것으로 시작됩니다.
(2) odom — 주행 거리 및 자세 추정 (Odometry)
- 메시지 타입:
nav_msgs/Odometry - 주로 엔코더 기반 계산
rostopic echo /odom
출력 예시:
pose:
pose:
position: {x: 1.23, y: 0.45, z: 0.0}
orientation: {x: 0, y: 0, z: 0.382, w: 0.924}
twist:
twist:
linear: {x: 0.1, y: 0.0, z: 0.0}
angular: {x: 0.0, y: 0.0, z: 0.1}
발행자(Publisher)
- 로봇 베이스 제어 노드 (예:
diff_drive_controller,wheel_odom_node)
구독자(Subscriber)
robot_localization(EKF 필터)amcl(지도 기반 위치 추정)- RViz (로봇 위치 표시)
⚙️
odom은 로봇 내부 기준에서 계산된 상대 위치입니다.
외부 지도 좌표와 연결하려면map → odom변환이 추가로 필요합니다.
(3) tf — 좌표계 변환 관계
TF는 ROS에서 모든 센서, 로봇 부품의 위치 관계를 관리합니다.
예시 프레임 트리:
map
└── odom
└── base_link
├── laser
└── imu_link
주요 변환:
| 변환 | 의미 | 생성 노드 |
|---|---|---|
odom → base_link | 로봇 주행 이동량 | odometry node |
base_link → laser | 센서 장착 위치 | static_transform_publisher |
map → odom | 지도 기반 위치 보정 | localization node (예: amcl) |
시각화:
rosrun tf view_frames
evince frames.pdf
💡 TF 관계가 잘못 설정되면 RViz에서 센서와 로봇이 엉뚱한 위치에 나타납니다.
(4) sensor — LiDAR, IMU, Camera
- LiDAR:
/scan(sensor_msgs/LaserScan) - IMU:
/imu/data(sensor_msgs/Imu) - Camera:
/camera/image_raw,/camera_info
센서 데이터는 SLAM, Localization, Obstacle Detection 등 상위 노드에서 사용됩니다.
예시:
rostopic echo /scan | head
→ 거리값 배열이 출력
RViz에서 시각화:
rosrun rviz rviz
- LaserScan:
/scan - TF:
odom → base_link → laser
5. 전체 데이터 흐름 요약
[ teleop / move_base ] → /cmd_vel → [ motor controller ]
↓
publishes
↓
/odom
↓
[ localization ]
↓
/tf tree
↓
[ sensors (LiDAR, IMU) ]
↓
/scan, /imu/data
즉, 명령(cmd_vel) → 이동(odom) → 위치(tf) → 센서 피드백(sensor)의 닫힌 루프 구조로 동작합니다.
6. 자주 하는 실수 & 디버깅 팁
| 증상 | 원인 | 해결 방법 |
|---|---|---|
| RViz에서 로봇이 안 보임 | TF 프레임 불일치 | fixed_frame을 odom으로 맞추기 |
/odom이 안 뜸 | 하위 제어 노드 미실행 | controller_manager list로 노드 확인 |
/cmd_vel 발행해도 움직이지 않음 | 구독자 없음 | rostopic info /cmd_vel로 확인 |
/scan은 뜨는데 RViz에서 안 보임 | frame_id mismatch | 센서 launch 파일에서 frame_id 수정 |
| Localization 오차 누적 | map → odom 보정 없음 | amcl 또는 ekf_localization 추가 |
7. 정리
| 구성 요소 | 주요 역할 | 핵심 토픽 |
|---|---|---|
| 제어 명령 | 속도 지시 | /cmd_vel |
| 주행 추정 | 오도메트리 계산 | /odom |
| 좌표계 변환 | 프레임 관계 관리 | /tf |
| 센서 피드백 | 외부 정보 제공 | /scan, /imu/data 등 |
📌 요약
- ROS 모바일 로봇의 기본 루프는
cmd_vel → odom → tf → sensor순환 구조 cmd_vel: 제어 명령,odom: 이동 결과,tf: 좌표계 연결,sensor: 외부 피드백- 각 노드는 퍼블리셔-서브스크라이버 패턴으로 연결되어 있고, RViz에서 모두 시각화 가능