[ROS2 Mastery 8편] 로봇 수학의 핵심, TF2(Transform) 시스템 개요 완벽 가이드
안녕하세요! 로봇 공학의 세계에서 자율주행과 시스템 제어를 깊이 있게 연구하고 계신 대학생 및 연구원 여러분. 쿼드(QUAD) 드론연구소의 자료를 바탕으로 진행되는 ‘ROS2 속성 마스터 과정’ 연재 블로그 8편에 오신 것을 진심으로 환영합니다.
지금까지 우리는 노드(Node), 토픽(Topic), 서비스(Service) 등 로봇 소프트웨어의 ‘신경망’ 역할을 하는 통신 메커니즘을 마스터했습니다. 오늘부터 시작할 2부의 주제는 로봇의 ‘공간적 뇌’ 역할을 하는 TF2 (Transform System, 좌표 변환 시스템)입니다.
로봇 공학에서 수학, 특히 3차원 공간에서의 삼각법과 행렬 연산은 피할 수 없는 거대한 장벽처럼 느껴지곤 합니다. 하지만 걱정하지 마세요! ROS2가 제공하는 강력한 TF2 시스템을 이해하고 나면, 복잡한 로봇 수학이 얼마나 우아하고 쉽게 해결되는지 깨닫게 되실 것입니다.

왜 TF2(좌표 변환) 시스템이 필요할까?
로봇 수학에서 ‘좌표 변환(Transform)’은 매우 큰 역할을 차지합니다. 좌표 변환이란 하나의 기준점(시점)에서 표현된 위치나 측정값을, 더 유용하게 쓰일 수 있는 다른 기준점의 좌표로 변환해 주는 수학적 도구입니다. 만약 이러한 변환 시스템을 사용하지 않고 모든 계산을 직접 삼각법과 행렬로 처리하려고 한다면, 특히 3차원 공간에서는 그 복잡도가 기하급수적으로 증가하여 엄청난 문제에 직면하게 됩니다.
연구원 여러분의 이해를 돕기 위해, 변환이 필수적인 두 가지 로봇 시스템 예시를 살펴보겠습니다.
- 다중 모바일 로봇 탐색: 두 대의 모바일 로봇이 미지의 공간을 탐색 중이라고 가정해 봅시다. 로봇 A가 관심 있는 목표물을 발견했을 때, 로봇 B는 어떻게 그 목표물의 정확한 위치를 알고 찾아갈 수 있을까요?
- 로봇팔(Manipulator) 제어: 로봇팔 끝에 장착된 카메라가 목표물을 발견했습니다. 이때 로봇의 손(그리퍼)을 목표물로 정확히 이동시키려면 어떤 각도와 방향으로 움직여야 할까요?
이러한 문제들을 해결하기 위한 첫걸음은 시스템의 각 구성 요소(로봇 몸체, 바닥, 카메라, 그리퍼 등)에 좌표계(Frame, 프레임)를 할당하는 것입니다. 그다음 프레임 간의 위치 및 회전 관계를 정의하는 변환(Transform)을 설정하면, 한 프레임에서 다른 프레임으로 데이터를 쉽게 전환할 수 있게 됩니다.
TF2 시스템의 핵심 원리와 트리(Tree) 구조
ROS2는 이 복잡한 변환 작업을 쉽게 처리할 수 있도록 TF2 (Transform 버전 2)라는 강력한 하위 시스템을 제공합니다.
1. 닫힌 루프(Closed-loop)가 없는 트리(Tree) 구조
TF2 시스템에서 모든 노드는 TF2 라이브러리를 사용하여 한 프레임에서 다른 프레임으로의 변환 정보를 ‘브로드캐스트(Broadcast)’할 수 있습니다. 이때 가장 중요한 규칙은 모든 변환 프레임이 ‘트리(Tree) 구조’를 형성해야 한다는 것입니다. 트리의 각 프레임은 오직 하나의 부모(Parent) 프레임에 종속되어 정의되지만, 자식(Child) 프레임은 여러 개를 가질 수 있습니다. 절대 꼬리를 무는 닫힌 루프(Closed loop)가 형성되어서는 안 됩니다.

예를 들어, world 프레임을 기준으로 base와 camera 프레임이 정의되고, base 프레임을 기준으로 로봇의 바퀴인 l3 프레임이 정의되는 식입니다. 트리가 올바르게 연결되어 있기만 하면, 시스템 내의 어떤 노드든 TF2를 ‘청취(Listen)’하여 트리의 끝에서 끝까지 임의의 프레임 간 데이터를 자유롭게 변환할 수 있습니다.
2. 정적(Static) 변환 vs 동적(Dynamic) 변환
노드가 브로드캐스트하는 변환은 크게 두 가지로 나뉩니다.
- 정적 변환 (Static Transform): 방의 벽이나 로봇 베이스에 고정된 센서처럼 시간이 지나도 위치가 변하지 않는 변환입니다. 이는 한 번만 브로드캐스트되어도 새로운 변환이 들어오기 전까지 항상 올바른 것으로 간주되므로 통신 비용이 매우 저렴합니다.
- 동적 변환 (Dynamic Transform): 주행 중인 로봇의 위치나 움직이는 로봇팔의 관절처럼 시간이 지남에 따라 계속해서 변하는 변환입니다. 정보가 최신 상태인지 확인해야 하므로 지속적인 업데이트가 필요하며, 한동안 업데이트가 없으면 TF2 시스템은 오류(Error)를 발생시켜 오래된 데이터로 인한 사고를 방지합니다.
내부적으로 TF2는 /tf (동적) 및 /tf_static (정적)이라는 토픽을 사용하여 통신하지만, 사용자 입장에서는 직접 토픽을 다루지 않기 때문에 ‘Publish/Subscribe’ 대신 ‘Broadcast/Listen’이라는 용어를 사용합니다.
3. 싱글 프레임 브로드캐스팅 실습: 커맨드라인 도구 활용
파이썬 코드를 작성하기 전에, 터미널 명령어를 통해 정적 변환을 시스템에 띄우고(Broadcast) 눈으로 확인해 보겠습니다.
1. static_transform_publisher 실행
tf2_ros 패키지에서 제공하는 static_transform_publisher 도구를 사용하면 매우 쉽게 정적 변환을 쏠 수 있습니다. 이 도구는 서로 다른 두 노드가 각각 다른 기준 프레임을 사용할 때, 두 프레임을 연결해 주는 “접착제” 역할을 하는 데 매우 유용합니다.
터미널을 열고 다음 명령어를 입력해 보세요. 명령어의 인자는 [x] [y] [z] [yaw] [pitch] [roll] [parent_frame] [child_frame] 순서입니다. (참고로 ROS2에서 회전 각도는 라디안 단위입니다.)
# world 프레임을 부모로, x축으로 0, y축으로 0, z축으로 0, yaw 회전 0.785(약 45도)인 robot_1 프레임 생성
ros2 run tf2_ros static_transform_publisher 0 0 0 0.785 0 0 world robot_1
이어서 두 번째 터미널을 열고, 첫 번째 로봇의 오른쪽(x축 방향)에 1m 떨어져 있는 두 번째 로봇(robot_2) 프레임을 만들어 줍니다.
# robot_1 프레임을 부모로, x축 1m 위치에 robot_2 프레임 생성
ros2 run tf2_ros static_transform_publisher 1 0 0 0 0 0 robot_1 robot_2
2. RViz2를 이용한 3D 시각화
변환이 잘 적용되었는지 ROS2의 강력한 3D 시각화 도구인 RViz2를 통해 확인해 보겠습니다. 세 번째 터미널을 열고 아래 명령을 실행합니다.
rviz2

RViz가 실행되면 다음 순서로 설정합니다.
- 좌측 하단의 “Add” 버튼을 클릭하고 “TF”를 선택하여 추가합니다.
- 처음에는 아무것도 보이지 않을 것입니다. 좌측 패널의 “Global Options”에서 “Fixed Frame”을
map에서 우리가 방금 만든 최상위 부모 프레임인world로 변경합니다. - 상태가 정상으로 바뀌며 화면 중앙에 세 개의 프레임 축(world, robot_1, robot_2)과 이들을 연결하는 노란색 선이 나타납니다.
RViz는 부모 프레임에서 자식 프레임 방향이 아닌, 자식 프레임에서 부모 프레임 방향으로 향하는 화살표로 변환 트리를 시각화하여 보여줍니다. 첫 번째 터미널의 명령어를 취소(Ctrl+C)하고 각도 값(0.785)을 1.57(90도) 등으로 수정하여 재실행해 보세요. robot_1이 회전함에 따라 자식 프레임인 robot_2의 위치도 덩달아 연동되어 움직이는 것을 실시간으로 확인할 수 있습니다.
움직이는 로봇 브로드캐스팅: URDF와 TF2의 결합
지금까지는 정적인 위치만을 브로드캐스트했습니다. 그렇다면 관절이 움직이는 진짜 로봇의 변환은 어떻게 처리할까요?
로봇의 기구학적 형태, 크기, 색상, 그리고 관절(Joint)의 구조를 정의하는 XML 파일을 URDF (Universal Robot Description Format)라고 부릅니다. URDF 파일에서 로봇은 단단한 부품인 링크(Link)와 이들을 잇는 관절(Joint)로 이루어지며, 이는 부모-자식 트리 구조를 가집니다.
눈치채셨나요? URDF의 링크/관절(Link/Joint) 패턴은 TF2의 프레임/변환(Frame/Transform) 패턴과 구조가 완벽하게 동일합니다!
1. robot_state_publisher의 마법
이러한 유사성 덕분에, ROS2에는 URDF 파일을 읽어 들여 로봇의 모든 TF2 변환을 자동으로 계산하고 브로드캐스트해 주는 robot_state_publisher라는 마법 같은 노드가 존재합니다.
이 노드는 /robot_description 토픽으로 로봇의 전체 URDF 정보를 시스템에 배포합니다. 그리고 회전이나 이동이 가능한 동적 관절들의 현재 상태 값을 구하기 위해 /joint_states 토픽을 구독(Subscribe)합니다.

연구 단계나 시뮬레이션 환경에서는 실제 모터의 센서(인코더) 값이 없기 때문에, joint_state_publisher_gui 패키지를 실행하여 가상의 슬라이더 GUI 창을 띄웁니다. 우리가 이 슬라이더를 마우스로 드래그하면 가짜 센서 데이터가 /joint_states로 발행되고, 이를 받은 robot_state_publisher가 실시간으로 로봇의 동적 TF 변환을 다시 계산하여 RViz 화면의 로봇 팔을 움직이게 만드는 원리입니다.
연구원을 위한 디버깅 팁: tf2_tools 활용법
여러 대의 로봇을 구동하거나 복잡한 시스템을 개발하다 보면, TF 변환 프레임이 어디선가 끊기거나 충돌하여 시스템이 멈추는 에러가 반드시 발생합니다. 이때 문제의 원인을 파악하기 위해 ROS2가 제공하는 tf2_tools 패키지를 활용하는 방법을 알아두셔야 합니다.
터미널을 열고 다음 명령어를 실행해 보세요 (프레임들이 실행 중인 상태여야 합니다).
ros2 run tf2_tools view_frames
이 파이썬 스크립트는 약 5초 동안 현재 ROS2 네트워크를 돌아다니는 모든 /tf 및 /tf_static 토픽을 수신하여 분석합니다. 그리고 명령어를 실행한 현재 디렉토리에 frames.pdf 라는 시각화된 트리 구조 파일을 생성해 줍니다.

생성된 PDF 파일을 열어보면, 현재 어떤 노드가 어떤 프레임을 브로드캐스트하고 있는지, 최신 데이터 통신 주기(Hz)는 얼마나 빠른지, 부모와 자식 간의 연결이 올바르게 형성되어 있는지 한눈에 파악할 수 있는 강력한 디버깅 다이어그램을 얻을 수 있습니다. (트리의 숫자들은 Unix Epoch Time을 나타내며, Gazebo 시뮬레이터 실행 시에는 시뮬레이터가 켜진 이후의 초 단위 시간이 표시됩니다.)
마무리하며
이번 8편에서는 로봇 수학의 복잡성을 우아하게 해결해 주는 ROS2의 TF2(Transform) 시스템의 기본 개념과 트리 구조, 정적/동적 변환의 차이점을 깊이 있게 학습했습니다. 또한, 커맨드라인 도구와 URDF 모델링 시스템(robot_state_publisher)을 통해 변환이 어떻게 시스템 상에 배포되고 시각화되는지도 실습을 통해 확인해 보았습니다.
지금은 명령어를 통해 프레임을 브로드캐스트했지만, 본격적인 자율주행이나 로봇팔 제어 알고리즘을 개발하기 위해서는 코드 내부에서 직접 변환 데이터를 다룰 수 있어야 합니다.
다음 [ROS2 Mastery 9편]에서는 우리가 배운 이 개념들을 파이썬 코드에 직접 적용하여, Python 노드에서 정적 및 동적 TF 프레임을 생성하여 브로드캐스트하고 수신(Listen)하는 “TF2 프로그래밍 실습”을 본격적으로 진행해 보도록 하겠습니다.
로봇 공학의 가장 큰 산인 ‘좌표 변환’을 정복하기 위한 여러분의 열정을 쿼드 드론연구소가 끝까지 응원합니다! 다음 편에서 뵙겠습니다.
YouTube Tutorial

작성자: 에이든(Aiden), 쿼드(QUAD) 드론연구소 마케팅팀
기고일: 2026.05.31
