659.121 TF2와 use_sim_time 파라미터 (TF2 and the use_sim_time Parameter)
1. use_sim_time 파라미터의 정의
use_sim_time은 ROS2 노드의 시계 소스(clock source)를 결정하는 부울형(boolean) 파라미터이다. 이 파라미터가 true로 설정되면, 노드의 내부 시계(rclcpp::Clock 또는 rclpy.clock.Clock)는 시스템 시간(wall clock) 대신 /clock 토픽으로부터 수신되는 시뮬레이션 시간(simulated time)을 사용한다. 모든 ROS2 노드는 이 파라미터를 내장 파라미터(built-in parameter)로 자동 선언하며, 기본값은 false이다.
이 파라미터는 TF2 프레임워크의 동작에 결정적인 영향을 미친다. TF2의 TransformBroadcaster, TransformListener, Buffer 등의 모든 구성 요소는 노드의 시계 객체를 참조하여 타임스탬프를 생성하거나 해석하므로, use_sim_time의 설정 상태가 변환 데이터의 시간적 일관성을 좌우한다.
2. 파라미터의 설정 방법
2.1 런치 파일에서의 설정
from launch_ros.actions import Node
robot_state_publisher = Node(
package='robot_state_publisher',
executable='robot_state_publisher',
parameters=[{
'robot_description': robot_description,
'use_sim_time': True,
}],
)
2.2 전역 설정을 통한 일괄 적용
동일 런치 파일 내의 모든 노드에 일괄적으로 use_sim_time을 적용하려면 SetParameter 액션을 사용한다.
from launch import LaunchDescription
from launch.actions import SetParameter
def generate_launch_description():
return LaunchDescription([
SetParameter(name='use_sim_time', value=True),
# 이후 모든 Node 액션에 자동 적용
])
2.3 명령행에서의 동적 변경
실행 중인 노드의 use_sim_time 파라미터를 동적으로 변경할 수 있다.
ros2 param set /my_node use_sim_time true
그러나 이 동적 변경은 이미 생성된 tf2::Buffer의 시계 소스에 즉시 반영되지 않을 수 있으므로, 가능한 한 노드 기동 시점에 설정하는 것이 권장된다.
2.4 YAML 파라미터 파일에서의 설정
/**:
ros__parameters:
use_sim_time: true
YAML 파일의 /** 와일드카드는 이 파일을 로드하는 모든 노드에 해당 파라미터를 적용한다.
3. TF2 구성 요소에 대한 영향
3.1 TransformBroadcaster
TransformBroadcaster가 변환을 발행할 때, 변환 메시지의 header.stamp 필드에 현재 시각을 기록한다. 개발자가 this->get_clock()->now()를 사용하여 타임스탬프를 생성하면, use_sim_time 설정에 따라 시스템 시간 또는 시뮬레이션 시간이 기록된다.
geometry_msgs::msg::TransformStamped t;
t.header.stamp = this->get_clock()->now(); // use_sim_time에 의존
t.header.frame_id = "odom";
t.child_frame_id = "base_link";
tf_broadcaster_->sendTransform(t);
use_sim_time: true인 환경에서 rclcpp::Clock(RCL_SYSTEM_TIME).now()를 사용하여 시스템 시간을 강제로 타임스탬프에 기록하면, 시뮬레이션 시간 기준의 다른 변환과 시간적 불일치가 발생하므로 이러한 혼용은 반드시 지양하여야 한다.
3.2 TransformListener와 Buffer
TransformListener는 /tf 및 /tf_static 토픽에서 수신한 변환 메시지를 Buffer에 저장한다. 저장 시 메시지에 포함된 타임스탬프를 그대로 사용하므로, use_sim_time 설정과 무관하게 발행자가 기록한 타임스탬프가 보존된다.
Buffer의 lookupTransform() 호출 시 요청 시각은 호출자가 명시적으로 전달하거나 tf2::TimePointZero를 사용한다. 호출자가 this->get_clock()->now()로 요청 시각을 생성하면, 이 시각은 use_sim_time 설정에 따라 결정된다. 발행자와 소비자의 시간 소스가 일치하지 않으면 보간 및 외삽 과정에서 오류가 발생한다.
3.3 robot_state_publisher
robot_state_publisher는 joint_states 토픽의 타임스탬프와 자체 시계를 사용하여 변환 타임스탬프를 결정한다. use_sim_time: true가 설정되면, joint_states의 타임스탬프(시뮬레이터에서 발행 시 시뮬레이션 시간 기준)와 robot_state_publisher의 내부 시계가 모두 시뮬레이션 시간을 사용하므로 일관성이 보장된다.
use_sim_time 설정이 robot_state_publisher에는 적용되고 joint_state_publisher에는 적용되지 않으면, 관절 상태의 타임스탬프와 변환의 타임스탬프 간에 불일치가 발생할 수 있다.
4. /clock 토픽의 구조와 발행 조건
4.1 메시지 형식
/clock 토픽은 rosgraph_msgs/msg/Clock 메시지 유형을 사용하며, 단일 필드 clock이 builtin_interfaces/msg/Time 형식의 시간 값을 포함한다.
rosgraph_msgs/msg/Clock
builtin_interfaces/msg/Time clock
int32 sec
uint32 nanosec
4.2 발행 소스
/clock 토픽을 발행하는 주요 소스는 다음과 같다.
| 소스 | 발행 조건 | 시간 특성 |
|---|---|---|
| Gazebo Classic | libgazebo_ros_init.so 플러그인 로드 시 | 물리 엔진 시간 단계에 동기화 |
| Ignition Gazebo | ros_gz_bridge 통해 연결 시 | 물리 엔진 시간 단계에 동기화 |
ros2 bag play --clock | --clock 옵션 지정 시 | 기록된 메시지의 타임스탬프 기준 |
| 사용자 정의 노드 | 명시적 발행 시 | 사용자 정의 |
/clock 토픽이 발행되지 않는 상태에서 use_sim_time: true가 설정되면, 노드의 시계가 초기값(0)에서 진행하지 않아 모든 시간 기반 연산이 정상적으로 동작하지 않는다. 이 경우 lookupTransform()에서 지속적으로 ExtrapolationException이 발생하거나, 타이머 콜백이 트리거되지 않는 현상이 나타난다.
5. 불일치 시나리오의 상세 분석
5.1 시나리오 1: 단일 노드 설정 누락
시스템 내 대부분의 노드가 use_sim_time: true로 설정되어 있으나, 특정 센서 처리 노드만 false인 경우를 고려한다. 이 노드가 센서 데이터의 타임스탬프(시뮬레이션 시간)를 사용하여 lookupTransform()을 호출하면, 요청 시각은 시뮬레이션 시간이지만 노드의 get_clock()->now()는 시스템 시간을 반환한다. 변환 발행자들이 시뮬레이션 시간 기준의 타임스탬프로 발행하고 있으므로, 센서 타임스탬프 기준의 조회 자체는 성공할 수 있다. 그러나 노드 내부에서 now()를 사용한 시간 계산(예: 지연 시간 측정, 타임아웃 검사)은 시간 기준의 불일치로 인해 비정상적인 결과를 산출한다.
5.2 시나리오 2: /clock 토픽 부재
시뮬레이터 없이 실제 로봇에서 use_sim_time: true가 잔존하는 경우, /clock 토픽이 발행되지 않으므로 노드의 시계가 진행하지 않는다. TF2의 관점에서 get_clock()->now()가 항상 시간 0을 반환하게 되어, 변환 조회 시 항상 외삽 범위를 초과하는 결과가 발생한다.
이러한 상황을 탐지하기 위해 노드 초기화 시 /clock 토픽의 발행 여부를 확인하는 방어적 검증 로직을 구현할 수 있다.
if (this->get_parameter("use_sim_time").as_bool()) {
auto clock_sub = this->create_subscription<rosgraph_msgs::msg::Clock>(
"/clock", 10,
[this](const%20rosgraph_msgs::msg::Clock::SharedPtr) {
clock_received_ = true;
});
// 5초 내에 /clock 수신 여부 확인
rclcpp::sleep_for(std::chrono::seconds(5));
if (!clock_received_) {
RCLCPP_FATAL(this->get_logger(),
"use_sim_time이 true이나 /clock 토픽이 수신되지 않음. "
"시뮬레이터 또는 rosbag 재생이 필요합니다.");
}
}
6. 디버깅 도구와 검증 명령
6.1 파라미터 설정 상태 일괄 확인
# 실행 중인 모든 노드의 use_sim_time 설정 확인
for node in $(ros2 node list); do
echo -n "$node: "
ros2 param get $node use_sim_time 2>/dev/null || echo "파라미터 없음"
done
6.2 시간 소스 일관성 검증
# /clock 토픽의 현재 시간 확인
ros2 topic echo /clock --once
# /tf 메시지의 타임스탬프와 /clock 비교
ros2 topic echo /tf --field transforms[0].header.stamp --once
두 시간 값이 유사한 범위에 있으면 시간 소스가 일관되게 설정된 것이며, 큰 차이(수십 초 이상)가 있으면 설정 불일치를 의심하여야 한다.
7. 모범 사례 요약
| 항목 | 권장 사항 |
|---|---|
| 시뮬레이션 환경 | 모든 노드에 use_sim_time: true 일관 적용 |
| 실제 로봇 환경 | 모든 노드에 use_sim_time: false (기본값) |
| 런치 파일 설정 | SetParameter를 이용한 전역 설정 사용 |
| /clock 부재 대비 | 노드 초기화 시 /clock 수신 확인 로직 구현 |
| 시간 기준 전환 | 노드 재시작을 통해 전환 (동적 변경 비권장) |
| 혼합 환경 | 절대 금지 (일관되지 않은 use_sim_time 설정) |
참고 문헌 및 출처
- ROS2 설계 문서, Clock and Time, https://design.ros2.org/articles/clock_and_time.html
- ROS2 geometry2 리포지터리,
tf2_ros패키지, https://github.com/ros2/geometry2 - Foote, T. (2013). “tf: The transform library.” IEEE International Conference on Technologies for Practical Robot Applications (TePRA), pp. 1–6.
- ROS2 공식 문서, Launching Nodes, https://docs.ros.org/en/humble/Tutorials/Intermediate/Launch/Launch-Main.html
버전: 1.0