Atlas Robotics
ROS2 CommunicationCơ bản

Message trong ROS2 là gì? Cấu trúc dữ liệu chuẩn hoá

Atlasbot · 16/8/2026 · 11 phút đọc

Message trong ROS2 là gì? Cấu trúc dữ liệu chuẩn hoá
Từ file .msg tới class trong code

Một topic không truyền "dữ liệu chung chung" — nó truyền đúng một kiểu message cố định, được định nghĩa tường minh trước khi biên dịch. Đây là lý do publisher viết bằng C++ và subscriber viết bằng Python vẫn hiểu đúng dữ liệu của nhau: cả hai cùng dùng chung một định nghĩa message, chỉ khác ngôn ngữ sinh code.

Khái niệm chính

Message được khai báo trong file .msg — cú pháp cực đơn giản, mỗi dòng là kiểu_dữ_liệu tên_trường:

# geometry_msgs/Twist.msg
Vector3 linear
Vector3 angular
# geometry_msgs/Vector3.msg
float64 x
float64 y
float64 z

Message có thể lồng nhau — Twist chứa hai Vector3 bên trong, mỗi Vector3 lại có 3 trường số thực. Các kiểu cơ bản có sẵn: int32, float64, string, bool, bool[] (mảng)... đủ để ghép thành hầu hết cấu trúc dữ liệu robot cần.

Message được biên dịch thành class thật

Khi build package, công cụ sinh code của ROS2 tự động đọc file .msg và sinh ra class tương ứng trong từng ngôn ngữ (Python, C++) — không cần viết tay struct/class thủ công, và không sợ hai bên định nghĩa lệch nhau vì cả hai cùng sinh ra từ một nguồn .msg duy nhất.

Tóm lại: File .msg là "hợp đồng" mô tả hình dạng dữ liệu — publisher và subscriber dù viết bằng ngôn ngữ nào cũng phải tuân theo đúng hợp đồng đó, đảm bảo không bao giờ hiểu sai cấu trúc dữ liệu của nhau.

Nguyên lý hoạt động

Twist.msg (định nghĩa)
       ↓  biên dịch lúc build (rosidl)
  Python: geometry_msgs.msg.Twist
  C++:    geometry_msgs::msg::Twist
       ↓
   Dùng trong code như một class/struct bình thường

Tạo và điền dữ liệu vào một message trong Python:

from geometry_msgs.msg import Twist

msg = Twist()
msg.linear.x = 0.2    # truy cập trường lồng nhau như thuộc tính object
msg.angular.z = 0.1
publisher.publish(msg)

Xem cấu trúc đầy đủ của bất kỳ kiểu message nào (kể cả message từ package của người khác) mà không cần mở file .msg thủ công:

ros2 interface show geometry_msgs/msg/Twist

Kiến thức kỹ thuật

Công thức

Kích thước message khi truyền qua mạng ước lượng bằng tổng kích thước từng trường, cộng thêm overhead đóng gói (CDR, xem mục Register/Bit/Byte):

Kích thước message ≈ Σ(kích thước từng trường) + overhead CDR

VD: Twist (2 × Vector3, mỗi Vector3 = 3 × float64)
= 2 × (3 × 8 byte) + overhead ≈ 48 byte + ~20 byte overhead ≈ ~68 byte

Con số này giải thích trực tiếp phần "kích thước 1 message" đã dùng ở công thức băng thông trong bài Topic — message càng nhiều trường lồng nhau, càng tốn băng thông khi publish tần suất cao.

Thông số

Kích thước byte của các kiểu dữ liệu nguyên thuỷ trong .msg — dùng đúng kiểu vừa đủ giúp tiết kiệm băng thông khi thiết kế message tuỳ chỉnh:

KiểuKích thước
int8 / uint8 / bool1 byte
int16 / uint162 byte
int32 / uint32 / float324 byte
int64 / uint64 / float648 byte
stringĐộ dài thay đổi (4 byte lưu độ dài + nội dung thực tế)

Register / Bit / Byte

Khi một message ROS2 được gửi qua mạng, nó không truyền dạng object ngôn ngữ (Python object, C++ struct) trực tiếp — nó được tuần tự hoá (serialize) thành một chuỗi byte theo chuẩn CDR (Common Data Representation), chuẩn mã hoá dữ liệu do DDS quy định. Giống hệt padding trong struct C đã nói ở chuyên mục Lập trình nhúng, CDR cũng áp dụng quy tắc căn chỉnh bộ nhớ (alignment) — một trường float64 (8 byte) trong message luôn bắt đầu ở offset chia hết cho 8 trong chuỗi byte tuần tự hoá, có thể chèn thêm byte đệm nếu trường trước đó không đủ căn chỉnh, hoàn toàn tương tự nguyên lý padding struct đã học.

Ứng dụng thực tế

Khi thiết kế message tuỳ chỉnh cho một robot cụ thể, gộp các trường liên quan chặt chẽ vào 1 message thay vì tách thành nhiều topic riêng lẻ thường hợp lý hơn — VD: 1 message BatteryStatus.msg gồm voltage, current, percentage, temperature publish chung 1 topic, thay vì 4 topic riêng biệt cho từng giá trị — giúp bên nhận luôn có đủ 4 giá trị đồng bộ tại cùng 1 thời điểm (cùng 1 message), tránh tình huống đọc voltage ở thời điểm này và current ở thời điểm khác rồi tính toán sai lệch do lệch thời gian giữa 2 lần đọc từ 2 topic riêng.

Ví dụ thực tế

$ ros2 interface show geometry_msgs/msg/Twist
Output:
# This expresses velocity in free space broken into its linear and angular parts.

Vector3  linear
	float64 x
	float64 y
	float64 z
Vector3  angular
	float64 x
	float64 y
	float64 z
$ ros2 topic type /cmd_vel
Output:
geometry_msgs/msg/Twist

ros2 interface show là cách tra cứu nhanh nhất cấu trúc đầy đủ của bất kỳ message nào (kể cả message lồng nhau nhiều tầng) mà không cần tìm và mở file .msg gốc trong source code — hữu ích khi làm việc với package của người khác không quen thuộc.

Lỗi thường gặp

  • Không rebuild sau khi sửa file .msg — code Python/C++ dùng class message cũ (đã sinh trước khi sửa) vẫn chạy được nhưng thiếu/thừa trường so với định nghĩa mới — luôn colcon build lại package chứa message sau mỗi lần sửa .msg.
  • Đặt tên trường trùng từ khoá dành riêng của ngôn ngữ — VD: đặt tên trường là class hoặc import (từ khoá Python) gây lỗi sinh code hoặc xung đột cú pháp khi dùng trong code Python.
  • Chọn kiểu số quá hẹp cho khoảng giá trị thực tế — giống lỗi tràn số đã nói ở chuyên mục Lập trình nhúng, dùng int8 cho giá trị có thể vượt quá 127 (VD: phần trăm pin tính sai đơn vị) gây tràn số âm thầm.
  • Phụ thuộc vòng tròn giữa 2 package message tuỳ chỉnh — package A định nghĩa message dùng kiểu từ package B, package B lại dùng kiểu từ package A — colcon không thể xác định thứ tự build hợp lệ, cần tái cấu trúc để loại bỏ phụ thuộc vòng tròn.

Kết luận

Message là "hợp đồng" định nghĩa hình dạng dữ liệu trao đổi giữa các node, được sinh tự động thành class cho từng ngôn ngữ từ 1 nguồn .msg duy nhất — đảm bảo tính nhất quán bất kể ngôn ngữ lập trình. Hiểu cách CDR tuần tự hoá message thành byte giúp lý giải chính xác chi phí băng thông đã tính ở bài Topic. Bài tiếp theo trong chuyên mục đi sâu hơn vào Service — cơ chế request-response, và cách nó được cài đặt từ Message + Topic bên dưới.

Message trong ROS2 là gì? Cấu trúc dữ liệu chuẩn hoá — Atlasbot