Frenet 좌표계: 곡선 트랙을 곧게 펴서 다루기
레이스에서 상대 차의 위치와 움직임을 다루려면 좌표계가 필요합니다. 그런데 트랙은 직선이 아니라 구불구불한 곡선이라, 흔히 쓰는 직교좌표 $(x, y)$ 로는 “앞/뒤”, “좌/우” 같은 직관적인 질문에 답하기가 의외로 번거롭습니다. 이 글에서는 곡선 트랙을 곧게 편 것처럼 다루는 Frenet 좌표계 $(s, d)$ 와, 직교좌표와의 변환을 정리합니다.
1. Frenet 좌표계란 무엇인가?
1.1 직교좌표 $(x, y)$ 의 불편함
보통 위치는 지도 위 $(x, y)$ 로 표현합니다. 그런데 트랙은 직선이 아니라 구불구불한 곡선입니다. 곡선 트랙에서 “상대 차가 나보다 앞에 있나 뒤에 있나?”, “트랙 중앙에서 얼마나 왼쪽/오른쪽으로 벗어났나?” 를 $(x, y)$ 로 따지려면 매 순간 곡선의 방향을 함께 고려해야 해서 매우 번거롭습니다.
1.2 Frenet 좌표 $(s, d)$ 의 아이디어
Frenet 좌표계는 트랙의 기준선(centerline / racing line)을 새로운 “펴진 축”으로 삼습니다. 구불구불한 트랙을 가위로 잘라 쭉 편다고 상상하면 됩니다.
- $s$ (longitudinal, 종방향) — 기준선을 따라 출발선에서부터 진행한 거리입니다. “트랙을 따라 얼마나 갔나.”
- $d$ (lateral, 횡방향) — 기준선에서 좌우로 벗어난 수직 거리입니다. “중앙선에서 얼마나 옆으로 치우쳤나.” (보통 왼쪽 $+$, 오른쪽 $-$)
1.3 왜 racing에서 Frenet이 좋은가
레이싱에서 던지는 거의 모든 질문 — “상대보다 앞서 있나 뒤처져 있나?”, “코너에서 안쪽/바깥쪽 어디로 붙을까?”, “추월할 공간이 있나?” — 은 결국 트랙을 따라(종방향) 얼마나 갔고, 트랙에서 옆으로(횡방향) 얼마나 벗어났는가의 문제입니다. Frenet 좌표 $(s, d)$ 는 이 두 축을 그대로 좌표로 삼기 때문에, 곡선 트랙에서도 이런 판단이 아주 단순한 산수가 됩니다.
트랙을 따라 달리는 차의 움직임은 Frenet에서 “$s$ 는 등속으로 증가, $d$ 는 거의 일정” 이라는 단순한 패턴이 됩니다. 반면 $(x, y)$ 에서는 같은 움직임도 트랙이 휘어질 때마다 $v_x,\ v_y$ 가 계속 요동쳐서 다루기 어렵습니다. 그래서 racing line 계획, 상대 차의 움직임 예측, 추월 판단까지 — 레이싱 스택의 여러 모듈이 Frenet 위에서 훨씬 간단해집니다.
아래 데모에서 똑같은 등속 운동을 두 좌표계로 나눠 보세요. 왼쪽 Cartesian은 속도를 $v_x \cdot v_y$ 로 분해해 트랙이 휠 때마다 값이 계속 바뀌지만, 오른쪽 Frenet은 $v_s \cdot v_d$ 로 분해해 $v_s$ 는 일정하고 $v_d = 0$ 으로 유지됩니다.
2. Frenet ↔ Cartesian 변환
두 좌표계는 서로 변환할 수 있습니다. 기준선 위 각 점에서의 위치 $(x_r, y_r)$ 와 방향각 $\theta_r$ (접선 방향) 만 알면 됩니다.
2.1 Frenet → Cartesian: $(s, d) \rightarrow (x, y)$
Frenet 좌표 값을 알고 있을 때 실제 지도상의 $(x, y)$ 를 찾는 과정입니다.
- 기준점 찾기 — 주어진 $s$ 값으로 기준선 상의 점 $P_{ref} = (x_r, y_r)$ 를 찾습니다.
- 방향 벡터 계산 — $P_{ref}$ 에서의 접선 벡터 $\vec{t}$ 와 법선 벡터 $\vec{n}$ 을 구합니다. 경로의 방향각을 $\theta_r$ 이라 하면, 법선은 접선을 $90^\circ$ 회전한 방향 $(-\sin\theta_r,\ \cos\theta_r)$ 입니다.
- 횡방향 이동 — 기준점에서 법선 방향으로 $d$ 만큼 이동해 최종 좌표를 얻습니다.
2.2 Cartesian → Frenet: $(x, y) \rightarrow (s, d)$
현재 차량의 글로벌 좌표 $(x, y)$ 가 기준선 상 어디($s$)에 있고 얼마나 벗어나 있는지($d$)를 찾는 과정입니다. 기준선으로의 투영(projection) 이라고도 합니다.
- 최단 거리 점 찾기 — 기준선 상의 점들 중 현재 위치 $(x, y)$ 와 가장 가까운 점 $P_c = (x_c, y_c)$ 를 찾습니다. (이산화된 경로 점을 탐색하거나 최적화로 구합니다.)
- $s$ 계산 — 기준선의 시작점부터 $P_c$ 까지의 곡선 길이를 누적(적분)해 $s$ 를 구합니다.
- $d$ 계산 — $(x, y)$ 와 $P_c$ 사이의 유클리드 거리가 $d$ 의 크기입니다. 부호(좌/우)는 접선 벡터와 $(x - x_c,\ y - y_c)$ 의 외적(cross product) 으로 차량이 경로의 어느 쪽에 있는지 판단해 정합니다.
3. 사용 시 고려할 점
실제로 Frenet 변환을 쓸 때는 다음 두 가지를 특히 조심해야 합니다.
- 닫힌 트랙의 overlap — 트랙 길이가 $20\,\text{m}$ 라면 $s = 0$ 과 $s = 20$ 은 같은 지점을 뜻합니다. $s$ 를 다룰 때는 트랙 전체 길이 $L$ 로 modulo 처리($s \bmod L$)해야 시작점 근처에서 앞/뒤 비교가 어긋나지 않습니다.
- $s$ 의 점프 — Cartesian ↔ Frenet 변환 과정에서, 특히 트랙의 이음새나 급커브 구간에서 최단 거리 점이 갑자기 바뀌면 $s$ 값이 튈 수 있습니다. 연속성이 필요한 곳에서는 직전 $s$ 근방에서만 투영을 탐색하는 식으로 완화합니다.
아래 데모에서 점(차량)을 직접 드래그해 보세요. 얇은 벽을 사이에 두고 반대편으로 넘어가는 순간, 전역 최단 거리(naive global nearest) 로 찾은 기준선 위 대응점이 반대 차선으로 튀면서(빨간 선) $s$ 가 불연속적으로 점프하는 것을 볼 수 있습니다.
마무리
이 글에서는 곡선 트랙을 곧게 편 축으로 삼는 Frenet 좌표계 $(s, d)$ 의 개념과, 직교좌표와의 양방향 변환을 정리했습니다.
- $s$ 는 기준선을 따라 진행한 거리, $d$ 는 기준선에서 좌우로 벗어난 거리입니다.
- Frenet → Cartesian 은 기준점에서 법선 방향으로 $d$ 만큼 이동, Cartesian → Frenet 은 최단 거리 점으로의 투영으로 계산합니다.
- 곡선 트랙 위의 움직임이 Frenet에서는 아주 단순해지므로, racing line 계획부터 상대 차 예측·추월 판단까지 레이싱 스택 전반이 간단해집니다.
이렇게 정의한 Frenet 좌표 위에 perception 결과(예: 2D LiDAR Detection & Clustering)를 올리면, 곡선 트랙에서도 상대 차를 단순한 모델로 다룰 수 있습니다.


