659.75 tf2_ros 패키지의 구성 요소

1. 개요

tf2_ros는 TF2 프레임워크와 ROS2 시스템을 연결하는 인터페이스 패키지이다. 핵심 변환 라이브러리인 tf2가 순수 C++ 라이브러리로서 ROS에 독립적인 변환 로직을 제공하는 반면, tf2_ros는 ROS2의 노드, 토픽, 서비스, 파라미터, 시간 관리 등과 통합되어 실제 로봇 시스템에서 좌표 변환을 수행하기 위한 모든 실무적 기능을 제공한다.

2. 패키지 아키텍처

2.1 계층 구조

tf2_ros (ROS2 인터페이스 계층)
  ↓ 의존
tf2 (핵심 변환 라이브러리)
  ↓ 의존
geometry_msgs, sensor_msgs (표준 메시지)

tf2_rostf2의 기능을 ROS2 통신 인프라 위에 랩핑(wrapping)하여, 분산 시스템에서의 좌표 변환 발행, 수신, 조회를 투명하게 처리한다.

3. 핵심 구성 요소

3.1 TransformBroadcaster

동적 좌표 변환을 /tf 토픽으로 발행하는 클래스이다.

#include <tf2_ros/transform_broadcaster.h>

auto tf_broadcaster = 
  std::make_shared<tf2_ros::TransformBroadcaster>(node);

geometry_msgs::msg::TransformStamped ts;
ts.header.stamp = node->now();
ts.header.frame_id = "odom";
ts.child_frame_id = "base_link";
ts.transform.translation.x = 1.0;
ts.transform.rotation.w = 1.0;

tf_broadcaster->sendTransform(ts);

TransformBroadcaster는 내부적으로 /tf 토픽에 대한 퍼블리셔(publisher)를 생성하며, tf2_msgs::msg::TFMessage를 발행한다. QoS 정책은 기본적으로 RELIABLE, KEEP_LAST(100)이다.

3.2 StaticTransformBroadcaster

정적 좌표 변환을 /tf_static 토픽으로 발행하는 클래스이다.

#include <tf2_ros/static_transform_broadcaster.h>

auto static_tf_broadcaster = 
  std::make_shared<tf2_ros::StaticTransformBroadcaster>(node);

geometry_msgs::msg::TransformStamped ts;
ts.header.stamp = node->now();
ts.header.frame_id = "base_link";
ts.child_frame_id = "laser_link";
ts.transform.translation.x = 0.1;
ts.transform.translation.z = 0.2;
ts.transform.rotation.w = 1.0;

static_tf_broadcaster->sendTransform(ts);

StaticTransformBroadcaster/tf_static 토픽에 TRANSIENT_LOCAL 지속성(durability) QoS를 사용하여, 새로운 구독자(subscriber)가 연결될 때 과거에 발행된 정적 변환을 자동으로 전달받을 수 있도록 한다.

3.3 Buffer

변환 데이터를 저장하고 조회하는 핵심 클래스이다.

#include <tf2_ros/buffer.h>

auto tf_buffer = std::make_shared<tf2_ros::Buffer>(node->get_clock());

Buffer는 다음의 핵심 메서드를 제공한다.

메서드역할
lookupTransform()두 프레임 간의 변환 조회
canTransform()변환 가용 여부 확인
transform()데이터 변환 (조회 + 적용)

Buffer는 내부적으로 tf2::BufferCore를 래핑하며, ROS2 시간 인터페이스(rclcpp::Clock)와의 통합을 추가한다. 캐시 기간(cache duration)은 기본 10초이며, 생성자의 두 번째 인자로 변경할 수 있다.

// 캐시 기간을 30초로 설정
auto tf_buffer = std::make_shared<tf2_ros::Buffer>(
  node->get_clock(), tf2::Duration(std::chrono::seconds(30)));

3.4 TransformListener

/tf/tf_static 토픽을 구독하여 수신된 변환을 Buffer에 자동으로 저장하는 클래스이다.

#include <tf2_ros/transform_listener.h>

auto tf_buffer = std::make_shared<tf2_ros::Buffer>(node->get_clock());
auto tf_listener = std::make_shared<tf2_ros::TransformListener>(
  *tf_buffer);

TransformListener는 생성 시 자동으로 /tf/tf_static 토픽의 구독을 시작하며, 수신된 TFMessage를 파싱하여 Buffer에 등록한다. 내부적으로 별도의 콜백 그룹(callback group)과 전용 스레드를 사용하여, 메인 콜백의 실행과 독립적으로 변환 데이터를 수신한다.

3.5 MessageFilter

특정 토픽의 메시지와 TF2 변환의 시간적 동기화를 수행하는 클래스이다.

#include <tf2_ros/message_filter.h>
#include <message_filters/subscriber.h>

message_filters::Subscriber<geometry_msgs::msg::PointStamped>
  point_sub(node, "point_topic", rmw_qos_profile_sensor_data);

tf2_ros::MessageFilter<geometry_msgs::msg::PointStamped>
  tf_filter(point_sub, *tf_buffer, "base_link", 100,
            node->get_node_logging_interface(),
            node->get_node_clock_interface());

tf_filter.registerCallback(
  std::bind(&MyNode::filtered_callback, this, 
            std::placeholders::_1));

MessageFilter는 입력 메시지의 header.stamp에 해당하는 TF2 변환이 가용해질 때까지 메시지를 큐에 보관하고, 변환이 가용해지면 등록된 콜백을 호출한다. 이를 통해 센서 데이터와 좌표 변환의 시간적 동기화를 보장한다.

4. 부가 구성 요소

4.1 static_transform_publisher 노드

명령행 또는 런치 파일에서 정적 변환을 발행하는 독립 실행형 노드이다.

ros2 run tf2_ros static_transform_publisher \
  --x 0.1 --y 0.0 --z 0.2 \
  --roll 0.0 --pitch 0.0 --yaw 0.0 \
  --frame-id base_link \
  --child-frame-id laser_link

런치 파일에서의 사용:

from launch_ros.actions import Node

Node(
    package='tf2_ros',
    executable='static_transform_publisher',
    arguments=['--x', '0.1', '--z', '0.2',
               '--frame-id', 'base_link',
               '--child-frame-id', 'laser_link'],
)

4.2 tf2_echo

두 프레임 간의 변환을 실시간으로 출력하는 명령행 도구이다.

ros2 run tf2_ros tf2_echo base_link laser_link

4.3 tf2_monitor

변환 발행 상태(주파수, 지연 시간 등)를 모니터링하는 명령행 도구이다.

ros2 run tf2_ros tf2_monitor

4.4 view_frames

현재 변환 트리의 전체 구조를 PDF 파일로 시각화하는 도구이다.

ros2 run tf2_tools view_frames

5. Buffer와 TransformListener의 전형적 초기화 패턴

5.1 권장 초기화 패턴

class MyNode : public rclcpp::Node
{
public:
  MyNode() : Node("my_node")
  {
    // 1. Buffer 생성 (노드의 Clock 전달)
    tf_buffer_ = std::make_unique<tf2_ros::Buffer>(this->get_clock());
    
    // 2. TransformListener 생성 (Buffer에 연결)
    tf_listener_ = std::make_shared<tf2_ros::TransformListener>(
      *tf_buffer_);
    
    // 3. 이후 tf_buffer_를 통해 변환 조회
  }

private:
  std::unique_ptr<tf2_ros::Buffer> tf_buffer_;
  std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
};

5.2 소유권 관리

BufferTransformListener보다 오래 존재해야 한다. TransformListenerBuffer의 참조를 보유하므로, Buffer가 먼저 소멸되면 미정의 동작(undefined behavior)이 발생한다. 클래스 멤버 변수의 선언 순서로 소멸 순서를 관리하거나, shared_ptr을 사용하여 수명을 보장한다.

6. Python에서의 tf2_ros

Python에서도 동일한 구성 요소가 제공된다.

from tf2_ros import Buffer, TransformListener
from tf2_ros import TransformBroadcaster, StaticTransformBroadcaster
from tf2_ros import TransformException

# Buffer + TransformListener
tf_buffer = Buffer()
tf_listener = TransformListener(tf_buffer, node)

# 변환 조회
transform = tf_buffer.lookup_transform(
    'base_link', 'sensor_link', rclpy.time.Time())

# 변환 발행
tf_broadcaster = TransformBroadcaster(node)
tf_broadcaster.sendTransform(transform_stamped)

7. 참고 문헌


버전: 2026-03-26