659.120 TF2와 시뮬레이션 시간의 연계 (TF2 and Simulation Time (ROS Time) Integration)

659.120 TF2와 시뮬레이션 시간의 연계 (TF2 and Simulation Time (ROS Time) Integration)

1. ROS2 시간 체계의 개요

ROS2는 두 가지 시간 소스(time source)를 지원한다. 시스템 시간(system time, wall time)은 운영체제의 실시간 시계(real-time clock)로부터 제공되며, 현실 세계의 시간 흐름을 반영한다. ROS 시간(ROS time)은 /clock 토픽을 통해 외부에서 공급되는 가상 시간이며, 시뮬레이터나 로그 재생 도구(예: ros2 bag play)가 이 토픽을 발행한다. ROS 시간은 시스템 시간과 독립적으로 흐를 수 있으며, 일시 정지, 가속, 감속, 역행 등의 비표준적 시간 흐름이 가능하다.

TF2 좌표 변환 시스템은 변환 데이터의 저장, 보간, 외삽 과정에서 타임스탬프에 전적으로 의존하므로, 시간 소스의 선택과 일관성은 TF2의 정확한 동작에 직접적인 영향을 미친다.

2. 시간 소스의 선택 메커니즘

2.1 use_sim_time 파라미터

ROS2에서 노드의 시간 소스는 use_sim_time 파라미터에 의해 결정된다. 이 파라미터가 true로 설정되면, 노드의 get_clock()->now() 호출은 /clock 토픽으로부터 수신된 최신 시뮬레이션 시간을 반환한다. false(기본값)이면 시스템 시간을 반환한다.

# 런치 파일에서 use_sim_time 설정
from launch_ros.actions import Node

node = Node(
    package='my_package',
    executable='my_node',
    parameters=[{'use_sim_time': True}],
)

2.2 TF2 구성 요소별 시간 소스 의존성

TF2의 주요 구성 요소가 시간 소스를 사용하는 방식은 다음과 같다.

구성 요소시간 사용 목적시간 소스 영향
TransformBroadcaster발행 변환의 타임스탬프 설정노드의 시계에서 now()를 호출하여 타임스탬프 생성
StaticTransformBroadcaster정적 변환의 타임스탬프 설정발행 시점의 시계값 사용 (이후 불변)
TransformListener수신 변환의 타임스탬프 해석수신된 메시지의 타임스탬프를 Buffer에 그대로 저장
tf2::Buffer보간, 외삽 시 시간 비교조회 요청의 시각과 저장된 변환의 시각 비교
lookupTransform()요청 시각의 변환 계산호출자가 전달하는 시각값에 의존

3. 시뮬레이션 환경에서의 TF2 동작

3.1 일관된 시간 소스 설정의 필요성

시뮬레이션 환경에서 모든 노드가 동일한 시간 소스를 사용하지 않으면 다음의 문제가 발생한다.

변환 발행자가 시스템 시간, 소비자가 시뮬레이션 시간을 사용하는 경우: 발행된 변환의 타임스탬프가 시스템 시간 기준이면, 시뮬레이션 시간 기준으로 lookupTransform()을 호출하는 소비자 노드의 요청 시각과 불일치가 발생한다. 시뮬레이션 시간이 시스템 시간보다 느리면 소비자의 요청 시각이 저장된 변환의 시각보다 과거에 위치하게 되어 ExtrapolationException이 발생한다. 반대로 시뮬레이션 시간이 시스템 시간보다 빠르면 미래 시각 외삽이 발생한다.

변환 발행자가 시뮬레이션 시간, 소비자가 시스템 시간을 사용하는 경우: 동일한 불일치가 반대 방향으로 발생한다.

따라서 시뮬레이션 환경에서는 TF2와 상호작용하는 모든 노드에 use_sim_time: true를 일관되게 적용하여야 한다.

3.2 전역 파라미터를 통한 일괄 설정

런치 파일에서 모든 노드에 use_sim_time을 개별적으로 설정하는 것은 누락 위험이 높으므로, 전역 파라미터 설정을 활용하는 것이 바람직하다.

from launch import LaunchDescription
from launch.actions import SetParameter

def generate_launch_description():
    return LaunchDescription([
        # 모든 하위 노드에 use_sim_time 일괄 적용
        SetParameter(name='use_sim_time', value=True),
        
        # 이후 선언된 모든 노드에 자동 적용
        Node(package='robot_state_publisher', ...),
        Node(package='nav2_bringup', ...),
        Node(package='my_controller', ...),
    ])

4. tf2::Buffer와 시뮬레이션 시간의 연동

4.1 Buffer의 시계 소스 설정

tf2_ros::Buffer는 생성 시 노드의 시계 객체(rclcpp::Clock)를 인자로 받는다. 이 시계 객체는 use_sim_time 파라미터에 따라 시스템 시계 또는 시뮬레이션 시계를 제공한다.

// 노드의 시계를 Buffer에 전달
auto tf_buffer = std::make_unique<tf2_ros::Buffer>(this->get_clock());

Buffer가 사용하는 시계 소스는 다음의 기능에 영향을 미친다.

  1. canTransform()의 타임아웃 대기: 시뮬레이션 시간 모드에서 canTransform()에 타임아웃을 지정하면, 타임아웃 측정이 시뮬레이션 시간 기준으로 수행된다. 시뮬레이터가 일시 정지되면 시뮬레이션 시간도 정지하므로, 타임아웃이 시스템 시간 기준으로는 예상보다 길어질 수 있다.
  2. lookupTransform()에서 TimePointZero의 해석: TimePointZero는 시간 소스와 무관하게 “가장 최근의 가용 변환“으로 해석된다.

4.2 시뮬레이션 시간 비활성화 시의 영향

use_sim_timefalse인 상태에서 시뮬레이터가 /clock 토픽을 발행하더라도, 노드의 시계는 이를 무시하고 시스템 시간을 사용한다. 그러나 시뮬레이터 내부의 센서 플러그인이 시뮬레이션 시간 기준의 타임스탬프를 메시지에 부여하면, 이 타임스탬프와 노드의 시스템 시간 간에 불일치가 발생하여 TF2의 보간 및 외삽 과정에서 오류가 발생한다.

5. 시뮬레이터별 시간 연동

5.1 Gazebo (Ignition Gazebo / Classic Gazebo)

Gazebo 시뮬레이터는 ros_gz_bridge 또는 gazebo_ros 플러그인을 통해 /clock 토픽을 ROS2에 발행한다. Gazebo의 시뮬레이션 시간은 물리 엔진의 시간 단계(time step)에 의해 결정되며, 실시간 팩터(real-time factor)에 따라 시스템 시간 대비 가속 또는 감속될 수 있다.

# Gazebo Classic에서 /clock 발행 확인
ros2 topic echo /clock

Gazebo 환경에서 TF2를 사용하는 모든 노드에 use_sim_time: true를 설정하면, robot_state_publisher, 내비게이션 스택, 센서 처리 노드 등이 Gazebo의 시뮬레이션 시간에 동기화된 변환 체계를 형성한다.

5.2 ros2 bag play에 의한 시간 재생

ros2 bag play는 기록된 토픽 메시지를 재생하면서 /clock 토픽을 함께 발행하는 기능을 제공한다.

ros2 bag play recorded_bag --clock

--clock 옵션은 기록된 메시지의 원래 타임스탬프에 기반하여 /clock을 발행한다. 재생 속도를 조절하면(--rate 옵션) /clock의 진행 속도도 비례하여 변경된다. 이 환경에서 TF2 노드가 use_sim_time: true로 설정되어 있으면, 재생되는 /tf 메시지의 타임스탬프와 노드의 시계가 동기화되어 정확한 변환 조회가 가능하다.

6. 시간 불일치 진단

6.1 시간 소스 불일치 감지

시간 소스 불일치로 인한 TF2 오류는 ExtrapolationException의 형태로 나타나는 경우가 많다. 오류 메시지에서 요청 시각과 가용 시각 간의 차이가 비정상적으로 큰(수초에서 수시간) 경우, 시간 소스 불일치를 의심하여야 한다.

# 각 노드의 use_sim_time 설정 확인
ros2 param get /robot_state_publisher use_sim_time
ros2 param get /controller_node use_sim_time

# /clock 토픽 발행 여부 및 값 확인
ros2 topic echo /clock --once

6.2 시스템 시간과 시뮬레이션 시간의 비교

RCLCPP_INFO(this->get_logger(),
    "시스템 시간: %.3f, 노드 시계: %.3f",
    rclcpp::Clock(RCL_SYSTEM_TIME).now().seconds(),
    this->get_clock()->now().seconds());

두 시간 값이 크게 다르면 해당 노드가 시뮬레이션 시간을 사용하고 있는 것이며, 동일하면 시스템 시간을 사용하고 있는 것이다.

7. 시간 도약과 역행에 대한 대응

7.1 시뮬레이터 재시작에 의한 시간 역행

시뮬레이터가 재시작되면 시뮬레이션 시간이 0으로 초기화되어 시간 역행(time jump backward)이 발생한다. tf2::Buffer에는 이전 실행의 미래 시점 변환이 캐시되어 있으므로, 새로운 시뮬레이션 시간(과거 시점)에 대한 조회가 ExtrapolationException을 유발할 수 있다.

이 상황에 대응하려면 시뮬레이터 재시작 시 tf2::Buffer를 초기화(clear)하여야 한다. ROS2는 시계 도약 콜백(clock jump callback)을 제공하므로, 이를 활용하여 시간 역행을 감지하고 Buffer를 자동으로 초기화할 수 있다.

#include <rclcpp/rclcpp.hpp>

// 시계 도약 콜백 등록
rcl_jump_threshold_t threshold;
threshold.on_clock_change = true;    // 시계 유형 변경 감지
threshold.min_backward.nanoseconds = -1;  // 모든 역행 감지
threshold.min_forward.nanoseconds = 0;    // 순행은 감지 안 함

auto jump_handler = this->get_clock()->create_jump_callback(
    nullptr,  // 사전 콜백
    [this](const%20rcl_time_jump_t&%20jump) {
        if (jump.delta.nanoseconds < 0) {
            RCLCPP_WARN(this->get_logger(),
                "시간 역행 감지. TF Buffer 초기화.");
            tf_buffer_->clear();
        }
    },
    threshold);

7.2 시뮬레이션 일시 정지

시뮬레이터가 일시 정지되면 /clock 토픽의 발행이 중단되고, 시뮬레이션 시간이 동결된다. 이 상태에서는 새로운 변환도 발행되지 않으므로, tf2::Buffer의 최신 변환 타임스탬프가 갱신되지 않는다. 시뮬레이터가 재개된 후 첫 번째 변환 조회에서 시간 간극으로 인한 외삽 예외가 발생할 수 있으나, 이는 새로운 변환이 수신되면 자연적으로 해소된다.

8. 시간 연동 구성의 체계적 검증

시뮬레이션 환경에서 TF2의 시간 연동이 올바르게 구성되었는지 검증하기 위한 점검 항목은 다음과 같다.

점검 항목검증 방법기대 결과
/clock 토픽 발행 여부ros2 topic hz /clock일정 주파수로 발행
모든 노드의 use_sim_timeros2 param list | grep use_sim_time모든 TF 관련 노드가 true
변환 타임스탬프 일관성ros2 topic echo /tf --field transforms[0].header.stamp/clock과 일관된 시각
변환 조회 성공 여부ros2 run tf2_ros tf2_echo map base_link예외 없이 변환 출력
센서 타임스탬프 일관성센서 메시지의 header.stamp 확인시뮬레이션 시간 기준

참고 문헌 및 출처

  • ROS2 geometry2 리포지터리, tf2_ros 패키지, https://github.com/ros2/geometry2
  • ROS2 공식 문서, Clock and Time, https://design.ros2.org/articles/clock_and_time.html
  • Foote, T. (2013). “tf: The transform library.” IEEE International Conference on Technologies for Practical Robot Applications (TePRA), pp. 1–6.
  • Open Robotics. Gazebo-ROS Integration, https://gazebosim.org/docs

버전: 1.0