로봇의 블랙박스가 필요하다
로봇을 움직이다 보면 가장 답답한 순간은 문제가 지나간 뒤에 찾아온다. 방금 전까지 잘 가던 로봇이 갑자기 벽 쪽으로 기울어 갔다. RViz에서는 LiDAR 점들이 잠깐 사라진 것 같았다. /cmd_vel은 분명 멈춤 명령을 보낸 것 같은데 바퀴는 한 박자 늦게 반응했다. 그런데 그 순간은 이미 지나갔다. 다시 같은 상황을 만들려고 하면 로봇은 이상하게도 아주 얌전하게 움직인다.
이럴 때 필요한 것이 로봇의 블랙박스다. 자동차 블랙박스가 사고 순간의 영상과 소리를 남기듯, ROS2에서는 로봇 내부에서 오간 메시지를 파일로 저장해 둘 수 있다. 이 도구가 바로 ros2 bag이다. ros2 bag은 ROS2 시스템에서 토픽, 서비스, 액션으로 오가는 데이터를 기록하고, 나중에 다시 재생할 수 있는 명령줄 도구다. 기록된 데이터는 하나의 데이터베이스 형태로 저장되며, 같은 데이터를 여러 번 재생하면서 테스트와 실험 결과를 재현할 수 있다.1
이 장에서는 이동 로봇에서 가장 자주 기록하는 /scan, /odom, /tf, /cmd_vel, /camera 계열 토픽을 중심으로 rosbag 사용법을 익힌다. 여기서 목표는 단순히 명령어 몇 개를 외우는 것이 아니다. 앞으로 SLAM과 Nav2를 다룰 때 "현장에서 한 번 경험한 상황을 실험실에서 여러 번 다시 분석하는 능력"을 갖추는 것이 핵심이다.

rosbag은 무엇을 저장하는가
ROS2 로봇은 수많은 노드가 동시에 움직이는 시스템이다. LiDAR 노드는 장애물 거리 데이터를 내보내고, 오도메트리 노드는 바퀴 회전량으로 추정한 위치를 내보낸다. 제어 노드는 /cmd_vel을 받아 바퀴 속도를 바꾸고, TF는 로봇 몸체와 센서 사이의 좌표 관계를 계속 알려 준다.
rosbag은 이 메시지 흐름을 시간 순서대로 저장한다. 즉, "어떤 토픽에 어떤 메시지가 언제 발행되었는가"를 기록한다. 그래서 나중에 bag을 재생하면, 실제 로봇이 다시 움직이지 않아도 그때와 비슷한 데이터 흐름을 ROS2 그래프 위에 되살릴 수 있다.
예를 들어 TurtleBot3가 복도를 주행하면서 다음 토픽을 발행했다고 하자.
/scan
/odom
/tf
/tf_static
/cmd_vel이 토픽들을 bag으로 기록해 두면 나중에 로봇 없이도 SLAM 노드를 실행해 볼 수 있다. LiDAR 스캔이 다시 흘러가고, 오도메트리가 다시 들어오며, TF도 재생된다. SLAM 알고리즘 입장에서는 마치 로봇이 다시 복도를 달리고 있는 것처럼 보인다. 이처럼 rosbag은 실제 하드웨어와 알고리즘 개발을 느슨하게 분리해 준다. 현장에서는 데이터를 얻고, 실험실에서는 그 데이터를 반복해서 분석한다.
기록할 토픽을 고르는 감각
처음 rosbag을 사용할 때 가장 쉬운 명령은 모든 토픽을 기록하는 것이다.
ros2 bag record -a-a 또는 --all은 현재 ROS2 시스템에서 발견되는 모든 토픽을 기록한다. rosbag2는 기록 중 새로 나타나는 토픽도 자동으로 발견할 수 있으며, 특정 토픽만 명시해서 기록할 수도 있다.2 모든 토픽 기록은 빠르게 상황을 보존해야 할 때 편리하다. 하지만 실제 로봇 개발에서는 습관적으로 모든 토픽을 기록하면 곧 문제가 생긴다. 카메라 이미지, 포인트클라우드, 디버그 영상이 함께 저장되면 몇 분 만에 수 GB가 쌓일 수 있다. 디스크가 가득 차면 기록이 깨질 뿐 아니라 로봇 PC 전체가 느려질 수도 있다.
그래서 좋은 rosbag 기록은 "많이 저장하는 것"이 아니라 "나중에 문제를 재현하는 데 필요한 것을 빠뜨리지 않는 것"에 가깝다. 이동 로봇에서는 보통 다음 토픽을 먼저 생각한다.
/scan: 2D LiDAR 데이터다. SLAM, 장애물 회피, Costmap 생성의 핵심 입력이다./odom: 바퀴 엔코더나 관성 센서 등을 바탕으로 추정한 로봇 이동 정보다./tf,/tf_static: 좌표계 사이의 관계다. 센서 데이터가 어느 좌표계 기준인지 해석하는 데 필요하다./cmd_vel: 로봇에 내려간 속도 명령이다. 사람이 조종했는지, Nav2가 명령했는지 추적할 수 있다./camera/image_raw,/camera/camera_info: 카메라 원본 이미지와 카메라 내부 파라미터다. Visual SLAM이나 인식 실험에 필요하다.
/tf_static은 정적인 좌표 변환을 담는다. 예를 들어 base_link에서 laser_frame까지의 고정된 위치 관계가 여기에 들어갈 수 있다. 이 토픽을 빠뜨리면 나중에 RViz에서 LiDAR가 어디에 붙어 있는지 알 수 없거나, SLAM 노드가 센서 데이터를 로봇 기준으로 변환하지 못할 수 있다. "지도는 있는데 로봇이 엉뚱한 곳에 있다"는 문제는 종종 TF 기록 누락에서 시작된다.
TurtleBot 주행 데이터 기록하기
이전 장에서 우리는 가상 센서를 붙이고 /scan, /odom, /tf 같은 토픽이 살아 있는지 확인했다. 이제 그 흐름을 파일로 남겨 보자. TurtleBot3 시뮬레이션이나 실제 로봇 bringup이 이미 실행되어 있다고 가정한다.
먼저 bag 파일을 모아 둘 디렉터리를 만든다.
mkdir -p ~/ros2_bags
cd ~/ros2_bagsrosbag은 기본적으로 명령을 실행한 현재 디렉터리에 기록 결과를 만든다. 그래서 아무 곳에서나 실행하면 나중에 bag 파일이 어디 있는지 헷갈리기 쉽다. 실험 날짜별, 로봇별, 프로젝트별로 디렉터리를 정해 두면 훨씬 편하다.
현재 어떤 토픽이 있는지 확인한다.
ros2 topic listTurtleBot 계열 시뮬레이션이라면 대략 다음과 비슷한 토픽을 볼 수 있다.
/cmd_vel
/odom
/scan
/tf
/tf_static
/joint_states
/robot_description
/clock
/parameter_events
/rosout여기서 최소한의 주행 분석용 bag을 기록해 보자.
ros2 bag record -o tb3_lidar_drive --topics /scan /odom /tf /tf_static /cmd_vel이 명령은 tb3_lidar_drive라는 이름의 bag 디렉터리를 만들고, 지정한 토픽만 기록한다. --topics 뒤에는 저장할 토픽 이름을 공백으로 나열한다. 기록이 시작되면 터미널에는 각 토픽을 구독했다는 메시지가 나온다. 이제 키보드 조종이나 Nav2 명령으로 로봇을 움직이면 된다.
기록을 멈추고 싶을 때는 Ctrl+C를 누른다.
[INFO] [rosbag2_recorder]: Recording...
[INFO] [rosbag2_recorder]: Subscribed to topic '/scan'
[INFO] [rosbag2_recorder]: Subscribed to topic '/odom'
[INFO] [rosbag2_recorder]: Subscribed to topic '/tf'
[INFO] [rosbag2_recorder]: Subscribed to topic '/tf_static'
[INFO] [rosbag2_recorder]: Subscribed to topic '/cmd_vel'기록이 끝나면 tb3_lidar_drive 디렉터리 안에 metadata.yaml과 실제 저장 파일이 생긴다. ROS2 배포판과 설정에 따라 파일 확장자는 .mcap 또는 .db3일 수 있다. 중요한 점은 bag 디렉터리 전체를 하나의 기록 단위로 다루어야 한다는 것이다. 파일만 하나 복사하고 metadata.yaml을 빠뜨리면 나중에 ros2 bag info나 ros2 bag play가 제대로 동작하지 않을 수 있다.
카메라까지 함께 기록하려면 토픽을 더 추가한다.
ros2 bag record -o tb3_camera_lidar_drive --topics \
/scan \
/odom \
/tf \
/tf_static \
/cmd_vel \
/camera/image_raw \
/camera/camera_info여기서 /camera/camera_info를 함께 기록하는 것이 중요하다. 이미지만 있으면 사람 눈에는 사진이 보이지만, 알고리즘은 그 카메라의 초점 거리, 왜곡 계수, 이미지 중심 같은 정보를 모른다. Visual SLAM이나 LiDAR-카메라 캘리브레이션을 할 때는 이미지와 camera info가 한 쌍처럼 움직인다.
기록 전에 토픽의 상태를 확인한다
bag을 기록하기 전에 30초만 점검하면 나중에 한 시간을 아낄 수 있다. 특히 센서 토픽은 이름만 있다고 충분하지 않다. 실제 메시지가 흐르고 있는지, 주기가 적절한지, frame_id가 올바른지 확인해야 한다.
LiDAR가 살아 있는지 보려면 다음 명령을 사용한다.
ros2 topic hz /scan메시지 내용도 한 번 확인한다.
ros2 topic echo /scan --once출력에서 header.frame_id를 본다.
header:
stamp:
sec: 123
nanosec: 456000000
frame_id: laser_frame이 laser_frame이 TF 트리 안에서 base_link와 연결되어 있어야 한다. 오도메트리도 마찬가지다.
ros2 topic echo /odom --once/odom 메시지에는 보통 header.frame_id와 child_frame_id가 있다. 흔히 header.frame_id는 odom, child_frame_id는 base_link 또는 base_footprint다. 이 이름들이 URDF, TF, Nav2 설정과 맞지 않으면 bag을 아무리 잘 기록해도 재생 시 알고리즘이 데이터를 해석하지 못한다.
카메라는 데이터 양이 크기 때문에 기록 전에 주기와 해상도를 확인하는 것이 좋다.
ros2 topic hz /camera/image_raw
ros2 topic echo /camera/camera_info --once만약 이미지가 초당 30장으로 발행되고 해상도도 높다면, 짧은 실험만 기록하거나 압축 이미지 토픽을 쓰는 전략을 세워야 한다. rosbag은 충실한 기록자다. 필요 없는 데이터까지 너무 성실하게 저장한다.
기록한 bag의 정체를 확인하기
기록이 끝났다면 바로 ros2 bag info를 실행한다.
ros2 bag info tb3_lidar_driveros2 bag info는 bag의 파일 크기, 저장 형식, 기록 시간, 시작과 종료 시각, 전체 메시지 수, 토픽별 메시지 개수와 타입 등을 보여 준다.3
출력은 배포판에 따라 조금 다르지만 대략 이런 형태다.
Files: tb3_lidar_drive_0.mcap
Bag size: 184.7 MiB
Storage id: mcap
Duration: 62.34s
Start: May 14 2026 15:10:21.12
End: May 14 2026 15:11:23.46
Messages: 5248
Topic information: Topic: /scan | Type: sensor_msgs/msg/LaserScan | Count: 620 | Serialization Format: cdr
Topic: /odom | Type: nav_msgs/msg/Odometry | Count: 3120 | Serialization Format: cdr
Topic: /tf | Type: tf2_msgs/msg/TFMessage | Count: 1430 | Serialization Format: cdr
Topic: /tf_static | Type: tf2_msgs/msg/TFMessage | Count: 1 | Serialization Format: cdr
Topic: /cmd_vel | Type: geometry_msgs/msg/Twist | Count: 77 | Serialization Format: cdr이 정보는 단순한 목록이 아니다. bag의 건강검진표다.
Duration이 62초이고 /scan의 Count가 620이라면 LiDAR는 대략 10Hz로 기록된 것이다. /odom이 3120개라면 약 50Hz다. /cmd_vel이 77개뿐인 것은 이상하지 않다. 속도 명령은 사람이 키를 누르거나 제어기가 명령을 갱신할 때만 발행될 수 있기 때문이다. 반대로 /scan이 0개라면 LiDAR 토픽 이름을 잘못 적었거나, 기록 당시 LiDAR 노드가 아직 실행되지 않았을 가능성이 크다.
/tf_static의 개수가 1개인 것도 자연스럽다. 정적 변환은 계속 반복해서 발행되는 데이터가 아니라, 고정된 관계를 한 번 또는 드물게 알려 주는 데이터이기 때문이다. 하지만 바로 이 한 개가 없어서 전체 분석이 막히는 경우가 많다.
bag 재생하기
이제 기록한 데이터를 다시 재생해 보자. 먼저 실제 로봇을 움직이는 노드와 충돌하지 않도록 주의한다. 특히 /cmd_vel을 재생하는 bag은 실제 로봇의 구동 노드가 살아 있다면 로봇을 움직일 수 있다. 실험실 책상 위에서 "데이터만 보려고 했는데 로봇이 갑자기 출발하는" 상황은 꽤 무섭다.
시뮬레이션이나 분석 환경에서 다음 명령을 실행한다.
ros2 bag play tb3_lidar_drivebag이 재생되면 기록 당시의 토픽들이 다시 발행된다. 다른 터미널에서 확인해 보자.
ros2 topic list
ros2 topic echo /cmd_vel
ros2 topic hz /scanRViz를 열고 LaserScan, Odometry, TF를 추가하면 기록 당시의 센서 흐름을 볼 수 있다. 로봇 모델까지 함께 보고 싶다면 robot_state_publisher와 URDF 설정도 실행되어 있어야 한다. bag은 메시지를 재생할 뿐, 로봇 모델을 자동으로 띄워 주지는 않는다.
재생 속도를 바꾸고 싶다면 --rate를 사용한다.
ros2 bag play tb3_lidar_drive --rate 0.5이 명령은 절반 속도로 재생한다. 빠르게 훑어보고 싶다면 2배속도 가능하다.
ros2 bag play tb3_lidar_drive --rate 2.0같은 데이터를 계속 반복하고 싶다면 --loop를 사용한다.
ros2 bag play tb3_lidar_drive --loop문제 장면을 천천히 살펴볼 때는 일시정지 기능이 유용하다. 최신 rosbag2 재생기는 키보드 입력으로 일시정지와 재개를 지원한다. 재생 중 터미널에 표시되는 안내를 보면 스페이스바로 멈추고 다시 시작할 수 있다.
use_sim_time과 함께 재생하기
SLAM이나 Nav2 같은 알고리즘은 시간에 민감하다. 센서 메시지의 시각, TF의 시각, 오도메트리의 시각이 맞아야 한다. 실시간으로 로봇이 움직일 때는 시스템 시간이 흐르지만, bag을 재생할 때는 기록된 시간 흐름을 기준으로 알고리즘을 돌리는 편이 안전하다.
ROS2에는 use_sim_time이라는 파라미터가 있다. 이름은 "시뮬레이션 시간 사용"이지만, 실제로는 /clock 토픽으로 들어오는 시간을 노드의 기준 시간으로 쓰겠다는 뜻이다. Gazebo 같은 시뮬레이터도 /clock을 발행하고, rosbag 재생도 기록된 시간 흐름을 /clock으로 내보내도록 설정할 수 있다.
SLAM 노드를 bag 데이터로 반복 실행하는 흐름은 보통 다음과 같다.
먼저 SLAM 노드를 use_sim_time:=true로 실행한다.
ros2 launch slam_toolbox online_async_launch.py use_sim_time:=true또는 TurtleBot3 SLAM launch를 사용한다면 다음과 같은 형태가 될 수 있다.
ros2 launch turtlebot3_slam turtlebot3_slam.launch.py use_sim_time:=true그다음 bag을 재생하면서 clock을 발행한다.
ros2 bag play tb3_lidar_drive --clock이렇게 하면 SLAM 노드는 현재 컴퓨터의 벽시계 시간이 아니라 bag에서 재생되는 시간 흐름을 기준으로 메시지를 처리한다. 만약 use_sim_time을 켰는데 /clock이 들어오지 않으면 노드의 시간이 0 근처에 멈춘 것처럼 보일 수 있다. 이 상태에서는 TF 조회가 실패하거나, 메시지 필터가 데이터를 계속 버릴 수 있다.
RViz도 bag 시간에 맞추고 싶다면 RViz의 use_sim_time 파라미터를 켜는 것이 좋다.
ros2 run rviz2 rviz2 --ros-args -p use_sim_time:=true정리하면 bag 기반 실험에서는 "알고리즘 노드는 use_sim_time:=true, bag 재생은 --clock"이라는 조합을 기억하면 된다. 이 조합은 다음 장부터 다룰 SLAM 실습에서 자주 등장한다.
같은 데이터로 SLAM을 반복 실행하기
rosbag의 진짜 힘은 반복성에서 나온다. 실제 로봇을 매번 같은 속도와 같은 경로로 조종하는 것은 어렵다. 사람이 키보드를 누르는 타이밍도 다르고, 바퀴가 미끄러지는 정도도 매번 다르다. 하지만 bag에 기록된 /scan, /odom, /tf 흐름은 매번 같다.
예를 들어 SLAM 파라미터를 바꾸며 지도 품질을 비교한다고 하자. 첫 번째 실험에서는 기본 설정으로 실행한다.
ros2 launch slam_toolbox online_async_launch.py use_sim_time:=true
ros2 bag play tb3_lidar_drive --clock결과 지도를 저장한다.
ros2 run nav2_map_server map_saver_cli -f ~/maps/map_default두 번째 실험에서는 SLAM 파라미터 파일을 바꾼다.
ros2 launch slam_toolbox online_async_launch.py \
use_sim_time:=true \
slam_params_file:=/path/to/slam_params_tuned.yaml그리고 같은 bag을 다시 재생한다.
ros2 bag play tb3_lidar_drive --clock이제 두 지도는 같은 센서 데이터에서 나온 결과다. 차이가 있다면 알고리즘 설정이나 코드 변경 때문이라고 훨씬 자신 있게 말할 수 있다. 이것이 데이터 기반 로봇 개발의 기본 자세다. 감으로 "이번에는 좀 잘 된 것 같다"고 말하는 대신, 같은 입력에서 결과가 어떻게 달라졌는지 비교한다.
문제 상황 직전으로 돌아가기
로봇 디버깅은 탐정 일과 비슷하다. 사건은 이미 벌어졌고, 우리는 흔적을 모아 원인을 좁혀 간다. rosbag은 그 흔적을 가장 많이 담고 있는 증거물이다.
상황을 하나 상상해 보자. TurtleBot이 복도 모퉁이를 돌다가 갑자기 지도 위 위치가 옆방으로 튀었다. SLAM 화면에서는 순간적으로 스캔 매칭이 깨진 것처럼 보였다. 이때 bag에 /scan, /odom, /tf, /tf_static, /cmd_vel이 기록되어 있다면 다음 순서로 확인할 수 있다.
먼저 bag 정보를 본다.
ros2 bag info tb3_corner_failure문제 발생 시각이 기록 시작 후 약 38초라고 메모해 두었다면, 재생을 시작한 뒤 RViz에서 38초 근처를 유심히 본다. 필요하면 느리게 재생한다.
ros2 bag play tb3_corner_failure --clock --rate 0.3새 터미널에서 LiDAR 주기를 확인한다.
ros2 topic hz /scan문제 순간에 /scan 주기가 급격히 떨어지거나 메시지가 멈춘다면 센서 드라이버, 네트워크, 시뮬레이션 부하를 의심할 수 있다. LiDAR 메시지는 정상인데 RViz에서 점들이 이상한 방향으로 튄다면 frame_id와 TF를 본다.
ros2 run tf2_ros tf2_echo odom base_link
ros2 run tf2_ros tf2_echo base_link laser_frameTF가 끊기거나 시간 차이가 너무 크면 SLAM 노드는 센서 데이터를 올바른 위치에 놓지 못한다. 특히 /tf는 계속 변하는 좌표 관계이고, /tf_static은 고정된 좌표 관계다. 둘 중 하나만 빠져도 전체 좌표계 트리가 끊길 수 있다.
/cmd_vel도 중요한 단서다.
ros2 topic echo /cmd_vel로봇이 갑자기 빠르게 회전했다면 사람이 키보드로 잘못 조종했는지, Nav2 컨트롤러가 과한 회전 명령을 보냈는지 확인해야 한다. /cmd_vel은 "로봇이 왜 그렇게 움직이려고 했는가"를 보여 주는 토픽이다. 반면 /odom은 "실제로 얼마나 움직였다고 추정했는가"를 보여 준다. 두 토픽을 함께 보면 명령과 결과 사이의 차이를 알 수 있다.
예를 들어 /cmd_vel의 각속도 angular.z는 0인데 /odom의 방향이 계속 변한다면 바퀴 미끄러짐, 오도메트리 계산 오류, TF 발행 오류를 의심할 수 있다. 반대로 /cmd_vel이 급격히 튀고 /odom도 그에 따라 튄다면 상위 제어 노드나 조종 입력을 추적해야 한다.
재생 중 실제 노드와 충돌하지 않게 하기
bag 재생은 ROS2 그래프 위에 메시지를 다시 발행하는 일이다. 그래서 실제로 같은 이름의 토픽을 발행하는 노드가 이미 실행 중이면 메시지가 섞일 수 있다. 특히 다음 상황을 조심해야 한다.
실제 로봇 bringup이 켜진 상태에서
/cmd_vel이 포함된 bag을 재생하는 경우Gazebo가
/clock,/odom,/tf를 내보내는 중에 bag도 같은 토픽을 재생하는 경우SLAM 노드가
/map이나map→odomTF를 발행하는데, bag에도 같은 성격의 데이터가 들어 있는 경우
분석만 할 때는 실제 구동 노드를 꺼 두는 것이 안전하다. 하드웨어가 연결된 로봇에서는 모터 전원을 빼거나, safety stop을 걸거나, /cmd_vel이 실제 base controller에 닿지 않도록 네임스페이스를 분리한다.
토픽 이름이 알고리즘 기대와 다를 때는 재생 시 remap을 사용할 수 있다.
ros2 bag play hallway_run --remap /lidar_scan:=/scan이 명령은 bag 안의 /lidar_scan을 재생하면서 현재 ROS2 그래프에서는 /scan으로 보이게 한다. 공개 데이터셋이나 다른 로봇에서 기록한 bag을 사용할 때 자주 필요한 기법이다.
대용량 데이터 기록 전략
LiDAR와 오도메트리만 기록할 때는 bag 크기가 그럭저럭 감당된다. 하지만 카메라 이미지와 3D LiDAR 포인트클라우드가 들어오는 순간 이야기가 달라진다. sensor_msgs/msg/Image는 압축되지 않은 원본 이미지일 수 있고, sensor_msgs/msg/PointCloud2는 한 프레임에 수만 개 이상의 점을 담을 수 있다. 초당 10프레임, 20프레임으로 쌓이면 디스크는 금방 뜨거워진다.
이럴 때는 기록 전에 전략을 세워야 한다.
첫째, 필요한 토픽만 고른다. -a는 편하지만, 대용량 센서가 많은 로봇에서는 위험하다. 예를 들어 카메라 기반 실험이 아니라면 /camera/image_raw를 빼고 /scan, /odom, /tf, /cmd_vel만 기록해도 충분할 수 있다.
둘째, 기록 시간을 짧게 나눈다. rosbag2는 기록 파일을 시간이나 크기 기준으로 나누는 옵션을 제공한다.4
ros2 bag record -o tb3_split_run -d 60 --topics /scan /odom /tf /tf_static /cmd_vel-d 60은 약 60초마다 파일을 나누어 저장한다. 파일 하나가 너무 커지는 것을 막고, 중간에 기록이 깨졌을 때 전체 데이터를 잃을 위험도 줄인다.
크기 기준으로 나눌 수도 있다.
ros2 bag record -o tb3_size_split -b 1073741824 --topics /scan /odom /tf /tf_static /cmd_vel여기서 1073741824는 1GiB에 해당하는 바이트 수다. 숫자가 조금 부담스럽지만, 단위가 바이트라는 점만 기억하면 된다.
셋째, 압축을 고려한다. rosbag2는 zstd 압축을 지원한다. 파일 단위 압축을 켜면 저장 공간을 줄일 수 있다.5
ros2 bag record -o tb3_compressed \
--compression-mode file \
--compression-format zstd \
--topics /scan /odom /tf /tf_static /cmd_vel /camera/image_raw /camera/camera_info압축은 디스크 공간을 아껴 주지만 CPU를 더 사용한다. 로봇 PC의 성능이 낮거나 센서 데이터가 매우 빠르게 들어온다면 압축 때문에 오히려 기록을 놓칠 수도 있다. 중요한 실험 전에는 짧게 시험 기록을 해 보고 ros2 bag info로 메시지 개수가 예상과 맞는지 확인하자.
넷째, 이미지 토픽은 원본과 압축본을 구분한다. 많은 카메라 드라이버는 /camera/image_raw와 함께 /camera/image_raw/compressed 같은 압축 이미지 토픽을 제공한다. 인식 알고리즘 학습용으로 원본 품질이 꼭 필요하다면 raw를 기록해야 하지만, 단순 상황 확인이나 원격 리뷰 목적이라면 compressed 토픽이 훨씬 가볍다.
다섯째, 실험 이름을 알아보기 쉽게 붙인다. rosbag2_2026_05_14-15_10_21 같은 기본 이름도 좋지만, 나중에 수십 개가 쌓이면 헷갈린다.
ros2 bag record -o 2026_05_14_tb3_lab_corner_fail_01 --topics /scan /odom /tf /tf_static /cmd_vel이름만 봐도 날짜, 로봇, 장소, 상황, 반복 번호를 알 수 있다. 좋은 파일 이름은 미래의 나에게 보내는 친절한 편지다.
bag을 믿기 전에 검증한다
기록이 끝났다고 해서 그 bag이 쓸 만하다는 뜻은 아니다. 실험 현장에서 가장 아쉬운 순간은 집에 돌아와 bag을 열었는데 핵심 토픽이 빠져 있는 경우다. 그래서 기록 직후에는 짧은 검증 루틴을 습관으로 만들자.
먼저 정보를 확인한다.
ros2 bag info 2026_05_14_tb3_lab_corner_fail_01그다음 실제로 재생해 본다.
ros2 bag play 2026_05_14_tb3_lab_corner_fail_01 --clock --rate 0.5다른 터미널에서 핵심 토픽이 나오는지 본다.
ros2 topic hz /scan
ros2 topic echo /odom --once
ros2 topic echo /tf_static --onceRViz에서 Fixed Frame을 odom 또는 base_link로 바꾸어 가며 LaserScan이 보이는지도 확인한다. 만약 RViz에 아무것도 보이지 않는다면 지난 장에서 익힌 순서대로 점검한다. 토픽이 발행되는가, 메시지 타입이 맞는가, frame_id가 무엇인가, TF가 연결되어 있는가, RViz의 Fixed Frame이 올바른가를 차례로 본다.
이 검증은 귀찮아 보여도 실제 프로젝트에서는 큰 차이를 만든다. 좋은 개발팀은 문제가 생긴 뒤에야 데이터를 찾지 않는다. 실험이 끝나는 즉시 "이 bag으로 내일도 같은 장면을 재현할 수 있는가"를 확인한다.
rosbag과 앞으로의 SLAM, Nav2
이 장에서 배운 rosbag은 다음 부로 넘어가기 위한 다리다. SLAM은 로봇이 움직이며 얻은 센서 데이터로 지도를 만든다. Nav2는 지도, 현재 위치, 장애물 정보를 바탕으로 목표 지점까지 이동한다. 두 시스템 모두 입력 데이터의 품질에 크게 영향을 받는다.
만약 SLAM 결과가 이상하다면 알고리즘만 탓하기 전에 bag을 열어 봐야 한다. LiDAR가 벽을 제대로 보고 있었는지, 오도메트리가 지나치게 드리프트했는지, TF가 끊겼는지 확인해야 한다. Nav2가 장애물을 못 피했다면 Costmap 설정만 보기 전에 /scan과 /cmd_vel을 함께 재생해 봐야 한다. 센서가 장애물을 보지 못한 것인지, 봤지만 Costmap에 반영되지 않은 것인지, 반영됐지만 controller가 회피 명령을 만들지 못한 것인지 구분해야 한다.
rosbag은 이 질문들에 답하는 출발점이다. 로봇이 한 번 경험한 세계를 파일 안에 붙잡아 두고, 우리는 그 세계를 다시 열어 천천히 관찰한다. 그리고 같은 데이터를 여러 알고리즘에 넣어 보며 더 나은 선택을 찾는다.
이제 우리는 시뮬레이션에서 로봇을 움직이고, 센서를 붙이고, 데이터를 기록하고 재생할 수 있게 되었다. 다음 장부터는 그 데이터를 가지고 로봇이 자기 위치를 추정하고 지도를 만들어 가는 세계, SLAM으로 들어간다.
참고
1ROS 2 공식 문서: Recording and playing back data
2rosbag2 GitHub README: Recording data
3ROS 2 Jazzy 문서: Recording and playing back data
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.