제6장
WIA-COMM-003의 Phase 3은 V2X 메시지를 실제 차량 동작으로 연결하는 협조 프로토콜을 정의합니다. 대상은 두 가지입니다. 하나는 근거리에서 여러 차량의 기동을 조율하는 충돌 회피 프로토콜 스택(11절)이고, 다른 하나는 선두 차량과 후속 차량을 하나의 협조 단위로 운행하게 하는 플래투닝 프로토콜(12절)입니다. 두 프로토콜 모두 수신한 상태 정보로 위험을 판단하고, 그 결과를 경고 수준과 권고 동작으로 돌려주는 구조를 따릅니다.
충돌 회피 프로토콜은 FCW, IMA, 사각지대·차선 변경 경고(BSW/LCW), EEBL 네 가지 응용으로 구성됩니다. 각 응용은 위험을 판단하는 기준량이 서로 다릅니다.
| 응용 | 판단 기준 | 명세의 주요 기준값 | 출력 동작 |
|---|---|---|---|
| FCW (전방 충돌 경고) | 충돌까지 남은 시간(TTC) | 경고 2.5초, 위험 1.5초, 최소 거리 5.0 m | ALERT_DRIVER / EMERGENCY_BRAKE |
| IMA (교차로 이동 보조) | 충돌 예상 지점 도달 시각 차이 | 반경 50 m, 경고 시간 3.0초 | SLOW_DOWN / MONITOR |
| BSW / LCW | 자차 좌표계 기준 사각지대 구역 점유 | 좌우 구역, 종방향 ±2.0 m | 구역별 경고, 차선 변경 안전 여부 |
| EEBL (긴급 제동등) | 종방향 감속도 | -4.0 m/s², 전파 거리 300 m | DENM 방송 / PREPARE_TO_BRAKE, REDUCE_SPEED |
명세의 알고리즘은 Python 의사코드로 제시됩니다. 이 장의 코드 인용은 모두 그 의사코드를 줄여서 가져온 것이며, 임계값은 명세가 보여 주는 기본값이라는 점에 유의해야 합니다.
FCW는 자차 앞에 있는 대상 차량만 평가합니다. 상대 위치를 계산해 대상이 전방에 있는지 먼저 확인하고, 상대 속도를 자차 속도에서 대상 속도를 뺀 값으로 구합니다. 이 값이 0 이하이면 대상이 멀어지거나 같은 속도로 움직이는 것이므로 경고를 내지 않고 None을 반환합니다. 상대 속도가 양수일 때만 TTC를 거리 ÷ 상대 속도로 계산합니다.
if ttc < self.critical_threshold: # 1.5 s
return {'level': 'CRITICAL', 'action': 'EMERGENCY_BRAKE', ...}
elif ttc < self.warning_threshold: # 2.5 s
return {'level': 'WARNING', 'action': 'ALERT_DRIVER', ...}
# 필요 감속도: a = v² / (2d)
def calculate_required_decel(self, distance, rel_velocity):
return (rel_velocity ** 2) / (2 * distance)
두 수준 모두 결과에 ttc, distance, deceleration이 함께 담깁니다. 따라서 수신 측은 경고 문구뿐 아니라 충돌을 피하는 데 필요한 감속도까지 알 수 있습니다. 필요 감속도는 등가속 운동식 v² = v₀² + 2ad에서 도출한 것입니다.
IMA는 교차로 접근 상황을 다룹니다. 자차가 교차로(반경 50 m 기준)에 접근 중인지 확인하고, 마찬가지로 접근 중인 다른 차량마다 교차로 통과 경로를 예측합니다. 두 경로가 만나는 충돌 지점이 있으면 각 차량의 도착 시각을 계산합니다. 도착 시각 차이(time_delta)가 3.0초 미만이면 위협으로 기록합니다.
FCW가 같은 차선의 한 대상에 대한 거리와 속도만 보는 데 비해, IMA는 경로 교차와 도착 시각의 겹침을 판단합니다. 우선권(priority)은 교차로 지도(intersection_map)에 근거해 정해지므로, 지도 정보가 없으면 IMA는 의미 있는 판단을 내릴 수 없습니다.
BSW는 다른 차량의 위치를 자차 좌표계로 변환한 뒤, 좌우 사각지대 구역에 들어왔는지 판정합니다. 명세는 구역을 자차 중심 기준의 횡방향 오프셋과 종방향 범위로 정의합니다.
| 구역 | lateral_offset (m) | longitudinal_range (m) |
|---|---|---|
| left | (-0.5, -3.0) | (-2.0, 2.0) |
| right | (0.5, 3.0) | (-2.0, 2.0) |
구역 안에 차량이 있으면 해당 방향의 경고에 vehicle_id, distance, relative_velocity, position이 기록됩니다. 차선 변경 평가(evaluate_lane_change)는 이 결과를 두 단계로 활용합니다. 먼저 변경하려는 방향의 사각지대에 차량이 있으면 safe: False와 사유 'Vehicle in blind spot'을 반환합니다. 사각지대가 비어 있으면 목표 차선에 접근하는 차량이 있는지 다시 확인하고, 그 결과를 'Target lane clear' 또는 'Vehicle approaching'이라는 사유와 함께 돌려줍니다.
EEBL은 앞의 세 응용과 달리 이벤트를 방송하는 쪽과 수신하는 쪽으로 나뉩니다. 차량의 종방향 가속도가 하드 브레이크 임계값 -4.0 m/s²보다 작으면 긴급 제동으로 판정하고, 아래 필드를 가진 DENM을 만듭니다.
denm = {
'messageType': 'DENM',
'eventType': 'emergencyBrake',
'severity': 'danger',
'position': ..., 'heading': ..., 'speed': ...,
'deceleration': ego_vehicle.acceleration.longitudinal,
'relevanceDistance': 300, # meters
'validityDuration': 5 # seconds
}
relevanceDistance는 메시지가 의미를 갖는 공간 범위이고, validityDuration은 시간 범위입니다. 이 두 필드로 오래되거나 멀리 떨어진 사건이 경고로 이어지는 일을 막습니다.
수신 차량은 먼저 이 사건이 자신과 관련 있는지, 곧 같은 방향이면서 사건 차량의 뒤쪽인지를 판정합니다. 관련이 있으면 사건 위치까지의 거리와 자차 속도로 경고 수준을 정합니다. 거리가 100 m 미만이고 속도가 50 km/h를 넘으면 CRITICAL(PREPARE_TO_BRAKE)입니다. 거리가 200 m 미만이면 WARNING(REDUCE_SPEED)입니다. 앞 차량이 시야에서 가려져 있어도 뒤따르는 차량이 제동 사실을 미리 알 수 있다는 점이 EEBL의 가치입니다.
플래투닝은 선두(Leader)와 후속(Member)의 역할 분담에서 출발합니다. 선두는 편대 속도를 정하고, 주행 경로를 결정하며, 편대 상태를 방송하고, 멤버의 합류와 이탈을 관리합니다. 멤버는 선두의 속도와 방향을 따르고, 안전한 차간 거리를 유지하며, 선두에 상태를 보고합니다. 멤버는 이탈을 요청할 수도 있습니다.
편대를 시작하는 initiate_platoon은 platoon_id(UUID), 선두 ID, 빈 멤버 목록, 대열 형태(line 또는 column), 목표 속도, 간격, 최대 멤버 수, 상태 FORMING을 담은 편대 레코드를 만듭니다. 명세의 기본값은 최대 멤버 10대, 차간 간격은 최소 5 m, 최대 15 m, 목표 10 m입니다.
합류 요청(request_join)은 세 가지 자격을 순서대로 검사하며, 어느 하나라도 실패하면 REJECTED와 사유를 돌려줍니다.
모두 통과하면 APPROVED와 함께 합류 위치(현재 멤버 수 + 1), 목표 간격, 목표 속도, 형성 지점(formation_point)이 전달됩니다. 이탈(leave_platoon)할 때는 선두에게 MEMBER_LEAVING 이벤트를 알리고, 뒤따르던 멤버들에게 ADJUST_POSITION으로 새 위치를 통보합니다. 이후 멤버 목록에서 제거하고 LEFT 상태와 RESUME_MANUAL_CONTROL 동작을 반환하여 수동 운전으로 복귀시킵니다.
편대 유지의 기본은 간격 제어입니다. PlatoonSpacingControl은 실제 간격과 목표 간격의 오차에 비례항(kp 0.5)과 미분항(kd 0.2)을 적용하는 PD 제어입니다. 출력은 가속도 명령으로 바뀌며 -3.0~2.0 m/s² 범위로 제한됩니다. 오차의 절댓값이 1.0 미만이면 상태는 GOOD이고, 그 이상이면 ADJUSTING입니다.
CACC(Cooperative Adaptive Cruise Control)는 여기에 V2V로 받은 선두의 가속도를 더하는 방식입니다. 명세의 핵심은 다음과 같습니다.
desired_spacing = ego_vehicle.speed * self.time_gap + self.min_spacing # time_gap = 0.6 s
acceleration = (
0.4 * spacing_error + # 간격 오차
0.3 * speed_error + # 속도 오차
0.8 * leader_accel # 선두 가속도 feedforward
)
acceleration = np.clip(acceleration, self.max_decel, self.max_accel) # -4.0 ~ 2.0 m/s²
target_speed = ego_vehicle.speed + acceleration * 0.1 # 100 ms 갱신
time_gap은 0.6초로, 명세는 일반 ACC의 1.5~2.0초보다 훨씬 짧다고 설명합니다. 센서로 앞차의 움직임을 확인한 뒤 반응하지 않고, 통신으로 선두의 가속도를 미리 받아 반영하기 때문에 짧은 간격이 가능합니다.
편대 차선 변경(PlatoonLaneChange)은 합의 후 순차 실행하는 절차입니다.
편대 분할(split_platoon)은 지정한 위치에서 편대를 둘로 나눕니다. 편대 A는 기존 platoon_id와 선두, 분할 위치 앞의 멤버로 구성됩니다. 편대 B는 분할 위치의 멤버가 새 선두가 되고 새 UUID를 받아 나머지 멤버를 이끕니다. 새 선두에게는 INCREASE_SPACING 명령으로 목표 간격 50 m가 전달되고, 양쪽 편대에는 PLATOON_SPLIT 이벤트가 방송됩니다.
이 장의 내용을 정리하면 다음과 같습니다.
이 장의 임계값과 이득은 명세가 제시하는 기본값이며, 실제 적용에서는 이를 차량과 도로 조건에 맞게 검증해야 합니다. 다음 장에서는 이 프로토콜 동작이 실제 시스템에 배치되고 운영되는 과정을 이어서 살펴봅니다.