ROS 2 — 메시지 타입
토픽·서비스·액션이 운반하는 '타입'의 정체. struct처럼 생긴 데이터 모양 정의가 .msg 파일이다.
토픽·서비스·액션을 다룰 때 자꾸 “이름 + 타입” 이라는 표현이 나왔다. 토픽 이름은 /camera/image, 타입은 sensor_msgs/msg/Image 같이. 그런데 “타입” 이 정확히 뭔지는 짚지 않았다.
이번 글에서 그 정체를 본다. 한 줄로 — 메시지가 운반할 데이터의 모양 정의 다.
1. 메시지 = 구조화된 데이터의 모양
자율주행 로봇이 모터에게 “앞으로 1m/s, 오른쪽으로 0.5rad/s로 돌면서 가라” 라는 명령을 보낸다고 해보자. 이 명령에 필요한 정보는:
- 직선 속도: x, y, z 방향
- 회전 속도: x, y, z 축
이 6개 숫자를 한 묶음으로 묶은 게 메시지다. ROS에는 이걸 위해 정해진 표준 메시지가 있다 — geometry_msgs/Twist.
Twist 메시지의 타입 정의(.msg 파일) 는 이렇게 생겼다:
geometry_msgs/Vector3 linear
geometry_msgs/Vector3 angular
해석:
linear라는 필드가 있고, 타입은Vector3(벡터 — x/y/z 세 숫자)angular라는 필드도 같은Vector3타입
Vector3 자체도 메시지 타입이라서, 그 정의를 또 보면:
float64 x
float64 y
float64 z
float64(64비트 부동소수점 — 소수점 있는 숫자) 세 개. 즉 Twist 메시지는 실제로 6개의 숫자 묶음이다.
이게 “타입” 의 정체다. 구조화된 데이터의 모양 정의 — 어떤 필드가 있고 각 필드가 어떤 자료형인지를 명시한 schema. (C 언어 struct, Python dataclass와 비슷한 개념.)
2. 메시지 안에 메시지가 들어간다 (중첩)
위에서 봤듯이 Twist 안에 Vector3 가 들어가 있다. 이렇게 메시지가 다른 메시지를 포함할 수 있다.
그림으로 보면:
큰 cream 박스(Twist) 안에 두 개의 lavender 박스(linear, angular)가 들어 있고, 각 lavender 박스 안에 float64 필드 3개씩.
자주 만나는 다른 중첩 예시:
Pose=Point(위치 x, y, z) +Quaternion(방향 x, y, z, w)PoseStamped=Header(시간·좌표계 정보) +PoseImage=Header+ 해상도(height,width) + 픽셀 배열
복잡한 데이터도 작은 메시지의 조합으로 깔끔하게 표현된다.
3. 표준 메시지 패키지
ROS에는 대부분의 로봇이 공통으로 쓰는 데이터를 위한 표준 메시지 패키지가 있다. 직접 정의할 필요 없이 import해서 쓰면 된다.
| 패키지 | 다루는 데이터 | 대표 타입 |
|---|---|---|
std_msgs | 기본 자료형 | String, Int32, Float64, Bool |
geometry_msgs | 기하 (위치·방향·속도) | Twist, Pose, PoseStamped, Point |
sensor_msgs | 센서 | Image, LaserScan, Imu, NavSatFix(GPS) |
nav_msgs | 자율주행 | OccupancyGrid(지도), Path, Odometry(주행거리) |
visualization_msgs | 시각화 | Marker, MarkerArray (RViz 표시용) |
자율주행 로봇이 평소 쓰는 것:
- 카메라 →
sensor_msgs/Image - 라이다 →
sensor_msgs/LaserScan - GPS →
sensor_msgs/NavSatFix - 모터 명령 →
geometry_msgs/Twist - 현재 위치 추정 →
nav_msgs/Odometry
표준 타입은 다른 ROS 시스템과 말이 통하는 공용어다. 새 카메라 노드를 가져와도 sensor_msgs/Image 로 발행하기만 하면 알고리즘 노드는 그대로 받을 수 있다.
4. 메시지 타입 이름의 구조
자세히 보면 geometry_msgs/Twist, sensor_msgs/msg/Image 같은 형식이 보인다. 이건:
[패키지 이름] / msg / [메시지 이름]
- 패키지 이름 — 어느 패키지에 속하는지 (
geometry_msgs) msg— 이게 메시지 타입이라는 표시 (서비스는srv, 액션은action)- 메시지 이름 — 패키지 안에서의 이름 (
Twist)
가끔 줄여서 geometry_msgs/Twist 라고 쓰는데, 정식은 geometry_msgs/msg/Twist.
5. 커스텀 메시지
표준 패키지에 없는 데이터를 다루려면 직접 정의한다. 자율주행 로봇만의 “주행 모드” 정보를 표현하고 싶다면 — 패키지 my_robot_msgs/msg/DrivingMode.msg:
string mode_name # "주행", "주차", "비상정지"
float64 max_speed_mps
bool obstacle_detected
이 .msg 파일을 만들고 빌드하면, 다른 노드들이 my_robot_msgs/msg/DrivingMode 타입으로 토픽·서비스·액션을 만들 수 있다.
원칙: 표준에 있으면 표준 쓰기, 없을 때만 직접 정의. 표준 타입은 다른 도구·라이브러리(RViz, rosbag 등)가 자동으로 인식하기 때문.
6. .msg / .srv / .action 관계
세 종류의 파일이 있었는데, 셋의 관계를 그림으로 정리하면:
.msg— 메시지 1개의 모양 정의.srv— 메시지 2개를 묶음 (Request + Response).action— 메시지 3개를 묶음 (Goal + Feedback + Result)
.srv 파일 형식:
# Request (요청에 들어가는 데이터)
string mode_name
---
# Response (응답에 들어가는 데이터)
bool success
string message
위/아래를 --- 로 가른다.
.action 파일 형식:
# Goal (목표)
geometry_msgs/Pose target_pose
---
# Result (최종 결과)
bool success
float64 total_distance
---
# Feedback (진행 알림)
geometry_msgs/Pose current_position
float64 distance_remaining
세 부분을 --- 두 줄로 가른다.
결국 타입 시스템의 단위는 .msg — 토픽, 서비스, 액션 모두 .msg 위에서 조합되는 셈.
7. 직접 보기 — ros2 interface 명령
타입 정의를 명령어로 직접 볼 수 있다.
$ ros2 interface show geometry_msgs/msg/Twist
# Twist 메시지 정의를 그대로 출력함
$ ros2 interface list
# 시스템에 설치된 모든 메시지 타입 목록
$ ros2 topic type /cmd_vel
geometry_msgs/msg/Twist
# /cmd_vel 토픽이 운반하는 메시지 타입
한 줄로 박아둘 것
- “타입”의 정체 — 메시지가 운반할 데이터의 모양 정의 (struct 같은 schema)
- 메시지는 중첩될 수 있다 —
Twist안에Vector3,Pose안에Point와Quaternion이 들어가는 식 - 표준 메시지 패키지 —
std_msgs/geometry_msgs/sensor_msgs/nav_msgs등. 가급적 표준을 쓴다 - 타입 이름은
패키지/msg/이름형식 — 예:geometry_msgs/msg/Twist .msg가 단위,.srv/.action은 조합 — 서비스 = msg 2개 묶음, 액션 = msg 3개 묶음