[자율주행] 3D 기하 기초 — 좌표계·회전·yaw, 그리고 쿼터니언
자율주행/기초
· 2026-07-23
시리즈를 여기까지 읽었다면 '좌표계로 옮긴다', '자세(yaw)를 회귀한다', '에고 포즈로 정합한다' 같은 말을 수십 번 봤을 것이다. 씬 데이터도, 캘리브레이션도, 3D 객체 검출도 결국 이 문장의 변주였다. 이번 글은 그 바닥의 기하를 짚는다. 여기가 흔들리면 위의 모든 것이 흔들린다.
점 하나는 '어느 기준에서' 없이 무의미하다
(3, 0, 0)이라는 점이 있다. 이게 어디인가? 모른다. 라이다 기준으로 3m 앞일 수도, 차 뒷축 기준일 수도, 지도 원점 기준일 수도 있다. 3D에서 좌표는 항상 '어떤 좌표계(frame)에서 본 값인가'를 달고 다닌다. 자율주행에서 최소한 세 개의 좌표계가 겹친다.
- 센서 좌표계 — 그 라이다/카메라 자신이 원점.
- 에고(차량) 좌표계 — 보통 뒷축 중심. 보통 x=전방, y=좌측, z=상방(오른손 좌표계)이지만 데이터셋마다 축 규약이 다르다 — 이게 첫 번째 함정이다.
- 월드/맵 좌표계 — 지도 위 절대 위치.
같은 물체라도 센서 좌표에선 이 값, 에고 좌표에선 저 값이다. 둘은 변환으로만 이어진다.
위치 3 + 자세 3 = 6-DOF
강체(차·박스)의 상태는 두 부분이다.
- 위치(translation) —
(x, y, z), 3자유도. - 자세(orientation/rotation) — 어느 쪽을 향하는가, 3자유도.
합쳐 6-DOF pose. 위치는 쉽다. 어려운 건 늘 회전이다. 회전을 숫자로 적는 방법이 여러 개이고, 각각 함정이 다르기 때문이다.
회전을 적는 세 가지 방법
① 오일러각 — yaw/pitch/roll
가장 직관적이다. 세 축을 중심으로 각각 얼마나 돌았나.
- yaw — 위에서 봤을 때의 회전(heading). 차가 '어느 방향을 보는가'.
- pitch — 앞뒤로 숙임.
- roll — 좌우로 기울어짐.
지상 차량은 대부분 평면을 달리므로 yaw가 지배적이다. 3D 박스의 방향을 보통 yaw 하나로 표현하는 이유가 이것이다. 다만 오일러각엔 치명적 약점 — 짐벌 락(gimbal lock) 이 있다. 특정 자세에서 두 축이 겹쳐 한 자유도를 잃고, 각도를 보간하면 튄다. 그래서 계산의 중간 표현으로는 위험하다.
② 회전행렬 — 3×3
회전을 3×3 행렬 R로 적는다. 합성(연쇄 회전)이 곱셈으로 깔끔하고 짐벌 락이 없다. 대신 3자유도를 9개 숫자로 적으니 낭비가 있고, 수치 오차가 쌓이면 '진짜 회전'이 아니게 되어(직교성 붕괴) 정규화가 필요하다.
③ 쿼터니언 — 4개 숫자
자율주행 데이터가 자세를 저장할 때 가장 많이 쓰는 형식이다. (w, x, y, z) 네 숫자로 회전을 적는다.
- 짐벌 락이 없다.
- 부드럽게 보간된다(slerp) — 두 자세 사이를 자연스럽게 잇는다. 에고 포즈를 프레임 사이에서 보간하거나, 스윕을 모션 디스큐할 때 필수.
- 작고 안정적이다(4개 숫자, 정규화 쉬움).
그래서 nuScenes 같은 데이터셋의 ego_pose·calibrated_sensor는 회전을 쿼터니언으로 준다. 직관은 오일러(yaw)로 이해하되, 저장·계산은 쿼터니언/행렬로 — 이 분업이 실무의 기본기다.
동차 변환 — 좌표계를 잇는 4×4
회전 R과 이동 t를 하나로 묶으면 4×4 동차 변환 T가 된다.
[ R t ]
T = [ 0 1 ]
이게 강력한 이유는 연쇄(chaining) 다. 라이다 점을 지도 위에 얹으려면 변환을 곱해서 이어붙이면 된다.
p_world = T_ego→world · T_lidar→ego · p_lidar
T_lidar→ego는 외부 캘리브레이션, T_ego→world는 에고 포즈. 즉 이 시리즈에서 "좌표계로 모으고 지도에 얹는다"고 했던 모든 문장이 실은 이 행렬 곱 하나였다. 역변환(T⁻¹)으로 반대 방향도 간다.
각도 오차는 거리에 비례해 커진다
기하에서 실무자가 몸으로 기억하는 사실 하나. 각도 오차는 멀수록 위치 오차로 증폭된다. 회전이 1° 틀어지면, 50m 앞 물체는 약 50 × sin(1°) ≈ 0.87m 밀린다. 캘리브레이션의 extrinsic 각도가 먼 물체 검출을 흔드는 이유, 그리고 방향(yaw) 추정이 거리 추정만큼 중요한 이유가 여기서 나온다.
데이터 엔지니어의 시선
기하는 모델러의 수학 같지만, 데이터 파이프라인에 그대로 얹힌다.
- 프레임 규약을 통일·명시하라. x가 전방인지 y가 전방인지, yaw의 0도가 어디인지는 데이터셋마다 다르다. 로그마다 규약을 메타데이터로 박아두지 않으면, 나중에 좌표가 90도 돌아간 채로 학습된다.
- 자세는 쿼터니언으로 저장하되 검증은 오일러로. 저장은 4-벡터, 디버깅·시각화는 yaw로 눈에 보이게.
- 변환은 조합 가능한 최소 단위로 저장하라. 매 프레임의
T_ego→world(쿼터니언+이동)만 있으면, 어떤 좌표계로든 즉석에서 옮길 수 있다.
정리
- 3D의 모든 값은 좌표계(frame) 를 달고 다니며, 좌표계는 변환으로만 이어진다.
- 강체 상태 = 위치 3 + 자세 3 = 6-DOF. 어려운 건 늘 회전이다.
- 회전 표현은 오일러(yaw/pitch/roll, 직관적이나 짐벌 락)·회전행렬(합성 깔끔)·쿼터니언(짐벌 락 없음·보간·소형)이며, 자율주행 데이터는 자세를 쿼터니언으로 저장한다.
- 동차 변환(4×4)의 연쇄가 이 시리즈 내내 말한 "좌표계로 모아 지도에 얹기"의 실체다.
- 각도 오차는 거리에 비례해 커지므로 방향(yaw)은 거리만큼 중요하다.
바닥을 깔았으니, 이제 이 좌표·자세가 실제로 어떤 파일에 어떻게 담겨 흘러가는지 — 로그 데이터와 포맷: rosbag에서 MCAP, 그리고 컬럼형까지로 간다.