9.83 ROS2의 TF2 프레임워크와 좌표 변환

9.83 ROS2의 TF2 프레임워크와 좌표 변환

1. TF2 프레임워크의 개요

TF2는 ROS2(Robot Operating System 2)의 좌표 변환 라이브러리이며, ROS의 1세대 TF의 후속이다. TF2는 로봇 시스템의 다중 좌표계와 그들 사이의 시간 의존적 변환을 관리하는 표준 도구로, ROS 기반 로봇 응용의 거의 모든 노드가 TF2를 직접 또는 간접적으로 사용한다.

2. TF2의 주요 특징

2.1 분산 아키텍처

TF2는 ROS2의 메시지 전달 시스템 위에 구축되어, 여러 노드가 변환 정보를 분산적으로 발행하고 구독할 수 있다. 한 노드가 모든 변환을 관리하지 않고, 각 노드가 자신이 알고 있는 변환을 발행한다.

2.2 시간 의존적 관리

각 변환은 시각 정보와 함께 저장된다. 특정 시각의 변환을 요청하면 그 시각에 가장 가까운 변환이 반환되며, 필요시 보간이 수행된다.

2.3 자동 변환 합성

임의의 두 좌표계 사이의 변환을 요청하면, TF2가 자동으로 트리 경로를 따라 변환을 합성한다.

2.4 정적과 동적 변환의 구분

정적 변환(시간에 변하지 않는)과 동적 변환(시간에 따라 변하는)을 구분하여 관리한다. 정적 변환은 한 번만 발행하면 영구적으로 유효하다.

2.5 다중 언어 지원

C++, Python 등 ROS2의 표준 클라이언트 라이브러리에서 모두 사용 가능하다.

3. TF2의 주요 구성 요소

3.1 tf2 라이브러리 (코어)

좌표 변환의 핵심 자료 구조와 알고리즘을 제공한다. 트리 관리, 변환 합성, 시간 보간 등이 포함된다.

3.2 tf2_ros 라이브러리

ROS2와의 통합을 제공한다. 변환 발행자(broadcaster)와 청취자(listener) 클래스가 포함된다.

3.3 tf2_msgs

TF2가 사용하는 ROS2 메시지 정의이다. 변환 정보의 표준화된 형식을 정의한다.

3.4 tf2_geometry_msgs

geometry_msgs(점, 벡터, 자세 등)와 TF2 사이의 변환 함수를 제공한다.

3.5 tf2_eigen

Eigen 라이브러리의 행렬과 TF2 사이의 변환을 제공한다.

4. 변환의 발행

ROS2 노드는 두 가지 방식으로 변환을 발행한다.

4.1 TransformBroadcaster (동적 변환)

시간에 따라 변하는 변환을 발행한다. 매니퓰레이터의 관절 운동, 차량의 운동 등에 사용된다.

# Python 예시
from tf2_ros import TransformBroadcaster
from geometry_msgs.msg import TransformStamped

broadcaster = TransformBroadcaster(node)
t = TransformStamped()
t.header.stamp = node.get_clock().now().to_msg()
t.header.frame_id = 'parent_frame'
t.child_frame_id = 'child_frame'
# 변환 값 설정
broadcaster.sendTransform(t)

4.2 StaticTransformBroadcaster (정적 변환)

시간에 변하지 않는 변환을 발행한다. 카메라가 매니퓰레이터에 단단히 부착된 경우 등에 사용된다. 한 번 발행하면 시스템 종료까지 유효하다.

# Python 예시
from tf2_ros.static_transform_broadcaster import StaticTransformBroadcaster

static_broadcaster = StaticTransformBroadcaster(node)
t = TransformStamped()
# 변환 값 설정
static_broadcaster.sendTransform(t)

5. 변환의 사용

변환을 사용하는 노드는 TransformListener를 통해 TF2에 접근한다.

5.1 Buffer와 Listener

# Python 예시
from tf2_ros import Buffer, TransformListener

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

# 변환 조회
try:
    transform = tf_buffer.lookup_transform(
        target_frame='target_frame',
        source_frame='source_frame',
        time=rclpy.time.Time()  # 가장 최신 변환
    )
except (LookupException, ConnectivityException, ExtrapolationException):
    pass

5.2 시각 지정

특정 시각의 변환을 요청할 수 있다.

transform = tf_buffer.lookup_transform(
    'target_frame', 'source_frame',
    desired_time
)

요청된 시각이 트리에 저장된 변환의 시각과 다르면 TF2가 자동으로 보간한다.

6. 변환의 합성과 순회

TF2는 임의의 두 좌표계 사이의 변환을 자동으로 합성한다. 사용자는 시작과 끝 좌표계만 지정하면 된다.

6.1 트리 순회

TF2는 트리에서 두 좌표계 사이의 경로를 찾고, 경로를 따라 변환을 곱한다. 일부 변환은 부모-자식 방향이 반대일 수 있으므로 역행렬이 적용된다.

6.2 효율성

내부적으로 트리 순회는 효율적인 자료 구조(해시 맵, 인덱스 등)로 구현되어 있다. 일반적인 트리 깊이에서 변환 조회는 마이크로초 단위로 완료된다.

7. 시간 동기화와 보간

7.1 변환의 시간 이력

TF2는 각 변환에 대해 일정 시간 이력(통상 10초)을 저장한다. 이력 기간 동안의 변환은 모두 사용 가능하다.

7.2 보간 알고리즘

요청된 시각이 저장된 변환들 사이에 있으면, TF2가 보간한다.

  • 위치: 선형 보간
  • 회전: SLERP (구면 선형 보간)

이는 매끄러운 변환 결과를 보장한다.

7.3 외삽 (Extrapolation)

요청된 시각이 이력 범위를 벗어나면 외삽이 시도되거나 예외가 발생한다. 일반적으로는 외삽을 피하는 것이 좋다.

8. ROS2 TF2와 ROS1 TF의 차이

ROS2의 TF2는 ROS1의 TF에서 다음과 같이 개선되었다.

8.1 이름 변경

tf 패키지가 tf2로 변경되었다. 새 API가 더 일관되고 효율적이다.

8.2 분산 노드 지원

ROS2의 DDS(Data Distribution Service) 기반 통신을 활용하여 더 효율적인 분산 처리가 가능하다.

8.3 정적 변환 별도 처리

정적 변환을 위한 별도의 클래스(StaticTransformBroadcaster)가 제공되어, 메모리와 네트워크 사용이 최적화된다.

8.4 C++14/17 활용

ROS2의 C++ 표준에 맞춰 더 현대적인 API와 구현을 제공한다.

8.5 ament 빌드 시스템

ROS2의 ament 빌드 시스템에 통합되어 더 효율적인 컴파일과 패키징을 지원한다.

9. TF2의 디버깅 도구

9.1 tf2_echo

특정 두 좌표계 사이의 변환을 명령줄에서 확인할 수 있다.

ros2 run tf2_ros tf2_echo source_frame target_frame

9.2 view_frames

현재 트리 구조를 PDF로 출력한다. 시스템의 좌표계 관계를 한눈에 파악할 수 있다.

ros2 run tf2_tools view_frames

9.3 RViz2

ROS2의 시각화 도구 RViz2는 TF2 트리를 직접 시각화할 수 있다. 좌표계가 3D 공간에 표시되어 디버깅에 매우 유용하다.

10. TF2와 다른 ROS2 컴포넌트의 통합

10.1 URDF와 robot_state_publisher

robot_state_publisher 노드는 URDF 파일과 관절 상태를 입력으로 받아 TF2에 각 링크의 변환을 자동으로 발행한다. 매니퓰레이터를 다룰 때 가장 흔히 사용되는 패턴이다.

10.2 MoveIt2와 통합

MoveIt2(매니퓰레이터 운동 계획 라이브러리)는 TF2를 통해 매니퓰레이터의 현재 자세를 파악하고, 계획 결과를 TF2에 발행한다.

10.3 Nav2와 통합

Nav2(이동 로봇 내비게이션 스택)는 TF2를 통해 로봇의 자세, 센서의 위치, 목표 위치 등을 관리한다.

10.4 gazebo_ros와 시뮬레이션

Gazebo 시뮬레이터는 시뮬레이션 내의 모든 객체의 자세를 TF2에 발행하여 다른 ROS2 노드가 사용할 수 있게 한다.

11. TF2 사용의 모범 사례

11.1 명확한 좌표계 명명

좌표계 이름은 일관성과 명확성을 유지해야 한다. URDF의 링크 이름과 일치시키는 것이 좋다.

11.2 정적/동적 구분

시간에 변하지 않는 변환은 반드시 StaticTransformBroadcaster를 사용한다. 효율성과 정확성이 향상된다.

11.3 적절한 이력 기간

이력 기간은 응용에 맞게 설정한다. 너무 짧으면 외삽 오류가 발생하고, 너무 길면 메모리를 낭비한다.

11.4 변환 발행 빈도

변환의 발행 빈도가 충분해야 한다. 매니퓰레이터의 경우 50-100Hz, 자율 주행의 경우 100-1000Hz가 일반적이다.

11.5 예외 처리

lookup_transform 호출은 다양한 예외(LookupException, ConnectivityException, ExtrapolationException)를 발생시킬 수 있다. 항상 예외 처리를 구현해야 한다.

11.6 시간 표시

각 변환의 정확한 시각이 메시지에 포함되어야 한다. 노드의 시각이 일치하지 않으면 변환이 부정확해진다.

12. 성능 고려 사항

12.1 메모리 사용

많은 좌표계와 긴 이력은 메모리를 사용한다. 트리의 크기와 이력 기간을 모니터링한다.

12.2 통신 부하

분산 시스템에서 변환 메시지는 ROS2 네트워크 위로 전송된다. 매우 빈번한 변환 발행은 네트워크 부하를 만든다.

12.3 조회 비용

lookup_transform은 일반적으로 빠르지만, 매우 빈번한 호출은 누적 비용이 된다. 결과를 캐싱할 수 있다.

13. 참고 문헌

  • Foote, T. (2013). “tf: The Transform Library.” 2013 IEEE Conference on Technologies for Practical Robot Applications (TePRA), 1–6.
  • Macenski, S., Foote, T., Gerkey, B., Lalancette, C., & Woodall, W. (2022). “Robot Operating System 2: Design, Architecture, and Uses in the Wild.” Science Robotics, 7(66), eabm6074.
  • Quigley, M., Gerkey, B., & Smart, W. D. (2015). Programming Robots with ROS. O’Reilly Media.
  • Joseph, L. (2018). Robot Operating System (ROS) for Absolute Beginners. Apress.
  • ROS2 Documentation. https://docs.ros.org/en/

version: 1.0