대상: ROS(특히 TF/tf2)를 사용하다가 RViz에서 프레임이 안 보이거나,
“TF not found”, “No transform from base_link to map” 같은 에러를 해결하고 싶은 개발자
환경: Ubuntu 20.04 / ROS Noetic / TF2 / RViz
1. 문제/주제 요약
ROS 프로젝트에서 TF가 꼬이면 RViz에서 다음과 같은 메시지가 자주 뜹니다 👇
[ WARN] [tf2_ros]: Lookup would require extrapolation into the past.
[ERROR] No transform from [laser] to [base_link]
[ WARN] No transform from [odom] to [map]
이 문제는 대부분 TF 프레임 이름, 방향, 브로드캐스트 누락, 시간 오차 때문입니다.
하지만 TF는 눈에 보이지 않기 때문에 디버깅이 어렵죠.
이 글에서는
- RViz의 TF 시각화 기능,
tf_echo명령어
를 이용해서 TF 트리를 분석하고 문제를 찾는 방법을 단계별로 설명합니다.
2. TF 문제의 전형적인 증상
| 증상 | 원인 |
|---|---|
| RViz에 로봇 모델이 안 보임 | base_link 관련 TF 누락 |
| 센서 프레임만 떠 있고 로봇 본체 없음 | static_transform 누락 |
| RViz 좌표계(map, odom 등) 바꿔도 움직이지 않음 | 잘못된 root frame 설정 |
| “No transform from odom → map” | localization or odometry 문제 |
| “Extrapolation into the future” | 시간 동기화 문제 (use_sim_time 등) |
3. 1단계: RViz에서 TF 시각화
✅ (1) TF Display 추가
- RViz 실행
rviz Displays→Add→By display type→ TF 선택- TF 화살표들이 3D 공간에 표시됨
각 프레임의 관계가 다음처럼 보입니다:
map
└── odom
└── base_link
├── laser
└── camera_link
🎯 이때
Fixed Frame설정이 핵심입니다.
RViz 왼쪽 상단의 Fixed Frame을 현재 root 프레임(map또는odom)으로 지정해야 TF가 제대로 표시됩니다.
✅ (2) Fixed Frame 바꿔보기
- 만약
Fixed Frame: map에서 아무것도 안 보이면,
→odom또는base_link로 변경해보세요. - root 프레임이 TF 트리 최상위와 맞지 않으면
RViz가 아무것도 표시하지 않습니다.
예를 들어
현재 TF 트리의 root가 odom이라면
RViz의 Fixed Frame은 odom이어야 합니다.
✅ (3) TF 화살표 색상 및 구조 확인
RViz에서 TF Display 활성화 시:
- 녹색/파란색 화살표 → 각 프레임의 X/Y/Z 축 방향
- 프레임이 끊겨 있거나 화살표가 안 이어지면
→ 중간 변환이 빠졌다는 뜻입니다.
예:map -> odom 변환이 없다면 RViz에서 odom 이하만 표시됨.
4. 2단계: tf_echo로 실시간 프레임 확인
TF는 결국 “한 프레임에서 다른 프레임까지의 변환”입니다.
이걸 숫자로 직접 확인할 수 있는 명령이 tf_echo입니다.
✅ 기본 사용법
rosrun tf tf_echo [source_frame] [target_frame]
예:
rosrun tf tf_echo map base_link
출력 예:
At time 172.624
- Translation: [3.14, -0.22, 0.0]
- Rotation: in Quaternion [0.0, 0.0, 0.707, 0.707]
👉 map 좌표계 기준으로 base_link가 어디에 있는지 보여줍니다.
✅ 주의: 프레임 순서 (source vs target)
rosrun tf tf_echo A B→ “A 기준에서 B의 위치”- 즉, A → B 변환을 조회
이 순서를 반대로 하면 결과가 완전히 달라집니다.
필요에 따라 tf2_ros 명령으로도 동일한 기능을 수행할 수 있습니다:
ros2 run tf2_ros tf2_echo map base_link
✅ “LookupException” 발생 시
[ERROR] Lookup would require extrapolation into the future.
이 메시지는 다음 원인을 의미합니다:
| 원인 | 해결 방법 |
|---|---|
| TF를 브로드캐스트하지 않음 | 해당 센서 노드나 static_transform 확인 |
| 프레임 이름 오타 | rosrun tf view_frames 로 전체 프레임 확인 |
| 시간 오차 (clock mismatch) | /use_sim_time 일관성 확인 |
| 메시지가 너무 오래됨 | tf_buffer.set_using_dedicated_thread(true) 적용 |
5. 3단계: TF 트리 전체 확인 (view_frames.py)
TF 트리 전체 구조를 이미지로 저장할 수 있습니다.
rosrun tf2_tools view_frames.py
결과:
Listening to /tf for 5.0 seconds
Wrote graph to tf_frames.pdf
생성된 tf_frames.pdf를 열면
현재 활성화된 모든 프레임 관계가 시각적으로 표시됩니다.
💡 이 파일은 TF 구조를 한눈에 파악할 때 최고의 디버깅 도구입니다.
예:laser_link가base_link에 연결 안 되어 있거나,maproot가 없는 경우 바로 확인 가능.
6. 4단계: static transform 존재 여부 확인
센서 프레임(laser_link, camera_link)이 보이지 않는다면
대부분 static transform broadcaster를 빼먹은 경우입니다.
확인:
rosrun tf view_frames
→ base_link -> laser_link 변환이 없으면 아래 명령으로 수동 확인:
rosrun tf static_transform_publisher 0 0 0 0 0 0 base_link laser_link 100
이후 다시 rosrun tf tf_echo base_link laser_link 실행해보면 변환이 생깁니다.
7. 5단계: TF 시간 동기화 확인
TF 오류 중 "extrapolation into the past/future"는 시간 문제가 대부분입니다.
| 상황 | 원인 | 해결 |
|---|---|---|
| 시뮬레이터 사용 중 | /use_sim_time 불일치 | 모든 노드에서 동일하게 설정 |
| TF 메시지 시간 너무 앞섬 | TF broadcaster 주기 조정 | |
| 센서 메시지 timestamp 오래됨 | 드라이버의 timestamp 확인 (rostopic echo header.stamp) |
시간 동기화를 확인하려면:
rostopic echo /clock
rostopic echo /tf_header
8. 6단계: RViz에서 root-frame 맞춰보기
RViz에서
Fixed Frame을map으로 했는데 TF 오류가 뜬다면,/map프레임이 실제로 존재하는지 확인해야 합니다.
rosparam list | grep frame
rosrun tf view_frames.py
없다면 Localization 노드(amcl, slam_toolbox)가map -> odom 변환을 안 보내고 있는 상황입니다.
→ 해결: Localization 노드 실행 확인 (/amcl_pose 토픽이 살아있는지)
9. 자주 하는 실수
| 실수 | 증상 | 해결 |
|---|---|---|
프레임 이름 불일치 (base_link vs base_footprint) | RViz에서 로봇 안 보임 | launch / URDF 프레임 이름 통일 |
| static transform 누락 | 센서만 떠 있음 | static_transform_publisher 추가 |
| Fixed Frame 잘못 설정 | TF Display 전부 사라짐 | RViz → Fixed Frame = root frame 지정 |
| use_sim_time 안 맞음 | “Extrapolation into the future” | 모든 노드에 동일 설정 |
| TF broadcast 지연 | 프레임 떨림, RViz 딜레이 | TF 주기 확인 (tf_echo로 timestamp 체크) |
10. 디버깅 절차 요약
1️⃣ TF 구조 시각화:
rosrun tf2_tools view_frames.py
2️⃣ 각 변환 존재 여부 확인:
rosrun tf tf_echo map base_link
3️⃣ RViz에서 Fixed Frame 바꿔보기:
- map / odom / base_link 순으로 변경하며 확인
4️⃣ 센서 프레임 연결 확인:
static_transform_publisher정상 동작 확인
5️⃣ 시간 동기화 확인:
/use_sim_time및/clock상태 확인
11. 정리
| 도구 | 명령 | 주요 목적 |
|---|---|---|
| RViz (TF Display) | 시각화 | 프레임 연결 상태, Fixed Frame 확인 |
| tf_echo | rosrun tf tf_echo A B | 특정 프레임 간 위치/회전 실시간 확인 |
| view_frames.py | rosrun tf2_tools view_frames.py | 전체 트리 시각화 (PDF) |
| static_transform_publisher | 수동 TF 추가 | 센서/기기 프레임 보정 |
| rqt_tf_tree | GUI 버전 | 실시간 트리 확인 |
👉 요약하자면:
- RViz에서는 Fixed Frame을 root로 맞추고 TF Display로 구조를 확인
tf_echo로 두 프레임 간 변환이 존재하고, 시간적으로 유효한지 확인- 안 나온다면
view_frames.py로 전체 트리를 시각화해 빠진 링크를 찾기