Side Project/ROS2 & LLM Autonomous Robot

ROS 2 디버깅

ns4A 2026. 2. 11. 19:03

 

 

# Logger

Logger는 “노드가 어떤 판단을 했는지”를 텍스트로 남깁니다. GUI가 강력하긴 하지만, 원인 추적의 시작점은 로그가 더 빠른 경우가 많습니다.

로그 레벨은 보통 아래처럼 쓰입니다.

  • DEBUG: 개발 단계의 상세 상태(자주 찍힘)
  • INFO: 정상 흐름에서 주요 이벤트
  • WARN: 이상 징후(치명적이진 않음)
  • ERROR: 실패/예외 상황
  • FATAL: 계속 진행하기 어려운 실패

 

 

패키지 생성

간단한 Python 노드를 만들어 로깅 동작을 바로 확인할 때
무엇을 확인해야 하는지: rclpy 의존성이 포함되었는지

 
ros2 pkg create --build-type ament_python logger_test --dependencies rclpy
  • --build-type ament_python: Python 패키지 형태로 생성
  • --dependencies rclpy: rclpy를 종속성에 포함

노드 코드 작성 (log_demo.py)

언제 쓰는지: 각 레벨 로그가 실제로 출력되는지, 레벨 변경이 필터링에 반영되는지 확인할 때
무엇을 확인해야 하는지: 타이머 콜백이 주기적으로 돌고, 레벨별 메시지가 콘솔에 출력되는지

 
import rclpy
from rclpy.node import Node

class LogDemo(Node):
    def __init__(self):
        # call super() in the constructor in order to initialize the Node object
        # the parameter we pass is the node name
        super().__init__('logger_example')
        # Logger level configuration
        rclpy.logging.set_logger_level('logger_example', rclpy.logging.LoggingSeverity.DEBUG)
        # create a timer sending two parameters:
        # - the duration between 2 callbacks (0.2 seeconds)
        # - the timer function (timer_callback)
        self.create_timer(0.2, self.timer_callback)

    def timer_callback(self):
        # print a ROS2 log debugging
        self.get_logger().debug("print a ROS2 log debugging")
        # print a ROS2 log info
        self.get_logger().info("print a ROS2 log info")
        # print a ROS2 log warning
        self.get_logger().warn("print a ROS2 log warning")
        # print a ROS2 log error
        self.get_logger().error("print a ROS2 log error")
        # print a ROS2 log fatal
        self.get_logger().fatal("print a ROS2 log fatal")

def main(args=None):
    # initialize the ROS communication
    rclpy.init(args=args)
    # declare the node constructor
    log_demo = LogDemo()
    # pause the program execution, waits for a request to kill the node (ctrl+c)
    rclpy.spin(log_demo)
    # shutdown the ROS communication
    rclpy.shutdown()

if __name__ == '__main__':
    main()
  • super().__init__('logger_example')
    → 이 노드의 이름이 logger_example가 됩니다.
  • set_logger_level('logger_example', LoggingSeverity.DEBUG)
    → 특정 로거 이름에 대해 최소 출력 레벨을 DEBUG로 맞춥니다.
  • create_timer(0.2, ...)
    → 0.2초마다 콜백이 돌아서, 로그가 계속 찍힙니다.

엔트리포인트 추가 (setup.py)

언제 쓰는지: ros2 run으로 Python 노드를 실행 가능하게 만들 때
무엇을 확인해야 하는지: 모듈 경로(logger_test.log_demo:main)가 실제 파일/함수와 일치하는지

entry_points={
    'console_scripts': [
        'log_demo = logger_test.log_demo:main',
    ],
},

 


빌드 및 환경 적용

언제 쓰는지: 새 패키지/노드를 워크스페이스에 반영할 때
무엇을 확인해야 하는지: 빌드 성공 여부, source가 반영됐는지

cd ~/ros2_ws
colcon build --symlink-install --packages-select logger_test
source install/local_setup.zsh # 환경에 따라 local_setup.bash
  • --symlink-install: Python/리소스 수정 시 반영이 편해집니다.
  • --packages-select logger_test: 해당 패키지만 빠르게 빌드합니다.

실행 및 레벨 변경 실험

언제 쓰는지: 로그가 레벨에 따라 필터링되는지 확인할 때
무엇을 확인해야 하는지: 레벨을 WARN으로 올리면 DEBUG/INFO 메시지가 사라지는지

 
ros2 run logger_test log_demo

그리고 코드에서 아래 부분을 바꿔서 확인합니다.

 
rclpy.logging.set_logger_level('logger_name', rclpy.logging.LoggingSeverity.<LOG_LEVEL>)

 

 

 

# RViz2

RViz2는 3D 시각화로 토픽/TF 기반 데이터를 직관적으로 보여줍니다. 특히 아래 범주가 자주 쓰입니다.

  • 기본 표시: RobotModel, TF, Grid
  • 센서 데이터: LaserScan, PointCloud2, Image
  • 네비게이션: Map, Path, Odometry

 

# RQt

 

RQt는 Qt 기반 GUI 프레임워크이면서, 여러 디버깅 도구가 플러그인으로 묶여 있습니다. 한 창에서 노드 그래프, 토픽 모니터링, 플롯 등을 조합해 쓰는 형태입니다. (필요하면 플러그인 자체를 개발하는 것도 가능합니다.)

자료 기준으로 “자주 쓰는 플러그인 묶음”은 아래처럼 정리할 수 있습니다.

  • Configuration: Dynamic Reconfigure
  • Introspection: Node Graph
  • Services: Service Caller
  • Topics: Message Publisher, Topic Monitor
  • Visualization: Image View, Plot, TF Tree

 

# rosbag2

 

rosbag2는 토픽 데이터를 기록하고(play) 다시 재생할 수 있습니다. 디버깅에서 제일 큰 장점은 같은 입력을 여러 번 반복할 수 있다는 점입니다.

  • 기록(record) / 재생(play)
  • 선택적 기록(토픽 지정)
  • 녹화 중 파일 분할(크기/시간)
  • 파일 내용 요약(info)

또한 ROS ↔ ROS 2 간 bag 파일은 기본 호환이 되지 않아 변환이 필요할 수 있습니다.

 

레코딩(Recording data)

(1) 모든 토픽 기록

언제 쓰는지: “전체 흐름”을 통째로 남겨 재현 가능성을 최대로 올릴 때
무엇을 확인해야 하는지: 저장 중 새 토픽이 자동으로 추가되는지, 디스크 사용량

 
ros2 bag record -a
  • -a: 현재 사용 가능한 모든 토픽 기록
  • 녹화 중 새 토픽이 나타나면 자동 추가
  • 자동 발견 기능을 끄려면 --no-discovery

(2) 특정 토픽만 선택 기록

언제 쓰는지: 필요한 토픽만 골라 용량/분석 복잡도를 줄이고 싶을 때
무엇을 확인해야 하는지: 지정 토픽이 녹화 시작 시점에 없어도 나중에 등장하면 잡히는지(자동 발견)

 
ros2 bag record <topic 1> <topic 2> … <topic N>
  • 지정한 토픽 중 하나가 나타나면 자동 인식(시작 시점에 없어도 됨)
  • 이 자동 기능도 --no-discovery로 끌 수 있음
  • 출력 폴더 이름은 -o, --output으로 지정 가능
    (미지정 시 현재 타임스탬프 이름의 새 폴더 생성)

Simulation time (/clock) 기록 옵션

ROS 2에서 Simulation time은 “실시간” 대신 /clock 토픽 기반 시간을 쓰는 의미입니다. 녹화 시간축을 시뮬레이션 기준으로 맞춰야 할 때 아래 옵션을 씁니다.

  • --use-sim-time: record 노드에서 sim time 사용

녹화 중 파일 분할(Splitting files during recording)

rosbag2는 파일이 너무 커지는 걸 막기 위해 크기/시간 기준으로 분할할 수 있습니다.

(1) 크기 기준 분할

언제 쓰는지: 단일 파일이 과도하게 커지는 걸 방지하고 싶을 때
무엇을 확인해야 하는지: 분할 임계치가 바이트 단위이며, 지정값이 조건을 만족하는지

 
ros2 bag record -a -b 100000
  • -b: bag 파일이 지정 크기(바이트)보다 커지면 분할
  • 기본값 0: 분할 없이 단일 파일
  • 자료 기준: 배치 크기 단위는 바이트이며 86016보다 커야 함

(2) 시간 기준 분할

언제 쓰는지: 장시간 녹화에서 일정 시간 단위로 파일을 끊고 싶을 때
무엇을 확인해야 하는지: 분할 주기가 초 단위인지

 
ros2 bag record -a -d 9000
  • -d: 지정 시간(초) 후 bag 파일 분할
  • 기본값 0: 분할 없음

재생(Replaying data)

언제 쓰는지: 저장된 bag로 동일 입력을 반복 재생하며 디버깅할 때
무엇을 확인해야 하는지: 재생 속도/시작 오프셋/루프 여부가 의도대로인지

 
ros2 bag play <bag>

<bag>로 가능한 형태(자료 기준):

  • metadata.yaml과 하나 이상의 bag 파일이 들어있는 디렉터리 이름
  • *.mcap 또는 *.db3 같은 단일 저장 파일

재생 없이 정보 확인(Analyzing bag file)

언제 쓰는지: “뭐가 들어있는지”만 빠르게 확인하고 싶을 때
무엇을 확인해야 하는지: 토픽/타입/메시지 수/기간 등 핵심 요약

 
ros2 bag info <bag_file>

6-6. 저장 포맷(Storage format)

언제 쓰는지: 저장 포맷을 바꿔 I/O 성능이나 외부 도구 호환성을 맞출 때
무엇을 확인해야 하는지: 기본은 sqlite3이고, mcap은 외부 시각화 도구와 궁합이 좋을 수 있음

 
ros2 bag record -a -s mcap  # MCAP 포맷 사용
  • sqlite3(기본): 안정적이고 범용적
  • mcap: 더 빠른 읽기/쓰기 성능, Foxglove Studio 등에서 직접 시각화 가능

 

ROS 2 Doctor

ros2 doctor는 ROS 2 환경의 여러 측면(네트워크, 플랫폼, QoS, RMW, ROS 2 정보, 토픽 등)을 점검해 “바닥이 정상인지”를 확인하는 데 쓰입니다. 로그/토픽만 보다가 막힐 때, 의외로 여기서 실마리가 나오는 경우가 있습니다.