### 0.0.1 NMEA 0183 ASCII 프로토콜 구조와 병목(Bottleneck) 분석
NMEA(National Marine Electronics Association) 0183 표준은 1980년대 해양 선박 내비게이션 기기 간의 통신을 위해 고안된 유서 깊은 프로토콜이다. 직관적이고 사람이 직접 텍스트 에디터나 하이퍼터미널(HyperTerminal)로 읽어 낼 수 있는 형태의 평문(Human-readable ASCII) 구조를 지녔기에, 수십 년이 지난 현재까지도 가장 호환성이 뛰어난 범용 위성 항법 메시징 표준으로 널리 통용되고 있다.
비록 PX4 생태계가 U-Blox UBX와 같은 고효율 바이너리 프로토콜을 주력으로 밀고 있지만, 여전히 NMEA 0183은 서드파티 GPS 모듈이 가장 먼저 내뱉는 ‘생존 신고’ 텍스트이므로 PX4의 드라이버 아키텍처는 이를 기본적으로 파싱할 수 있는 능력을 철저히 내장하고 있다.
그러나 이 역사적인 표준 규격은 고속 비행 제어기(FC)의 실시간 연산 관점에서는 최악의 오버헤드를 유발하는 구조적 병목(Bottleneck)을 지니고 있다.
0.1 ASCII 기반 프로토콜의 비효율적 데이터 구조
NMEA 0183의 모든 데이터 문장(Sentence)은 항상 $ 기호로 시작하여 \r\n (CR LF)으로 끝나는 가변 길이의 쉼표(Comma, ,) 분리형 문자열이다.
$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47
위의 대표적인 3차원 측위 문장인 $GPGGA 문장을 살펴보자. 사람의 눈에는 “12시 35분 19초에 북위 48도…” 하고 의미가 뚜렷하게 보이지만, PX4 프로세서(MCU)의 파싱 엔진 입장에서는 극악의 비효율성을 강제하는 구조이다.
- 가변 길이 파싱의 오버헤드: 데이터의 바이트 수가 고정된 C 구조체(struct) 형태라면 포인터 캐스팅(Pointer Casting) 한 번으로 즉시 메모리 접근이 가능하다. 하지만 NMEA는 좌표의 자릿수가 바뀔 때마다 문자열 길이가 변하므로, 드라이버 코드는 매 글자마다 쉼표(
,)가 나왔는지 확인하는 조건문(if(c == ',')) 루프를 수없이 반복하며 토크나이징(Tokenizing)을 수행해야 한다. - 낭비되는 대역폭(Bandwidth): 위도의 방위를 알리는 글자
N은 단지 북/남 1비트(Bit) 정보면 충분하지만, ASCII 문자 ’N’을 전송하기 위해 무려 8비트(1바이트)를 소모하며 쉼표(,)라는 구분자까지 도합 2바이트를 강제 낭비한다.
0.2 형변환(Type Casting) 비용: ASCII to Integer/Float
NMEA 프로토콜의 가장 뼈아픈 연산 병목은 직렬 포트를 통해 수신된 아스키코드 배열(예: '4', '8', '0', '7', '.', '0', '3', '8')을 C++ 커널이 계산 가능한 실제 32비트/64비트 실수형이나 정수형 변수로 변환하는 함수 호출 비용이다.
atoi(),atof()계열 함수의 무거움: PX4 펌웨어는 고정밀 위도/경도를 유지하기 위해double급의 정밀도를 다루어야 한다. 텍스트 버퍼를 찌르며 루프를 돌고 곱하기 10을 반복하며 텍스트를 숫자로 치환하는strtod류의 변환 엔진은 한 문장을 변환할 때마다 수백 사이클(Cycle)의 CPU 명령어를 태워버린다.- 고정 소수점 최적화(Fixed-Point Hack): 오버헤드를 억제하기 위해 PX4의 내부
src/drivers/gps/nmea.cpp구현체를 뜯어보면 표준 C 라이브러리를 쓰지 않는다. 소수점 이하 자리수를 10의 7승(10^7) 스케일로 단순 곱(Shift)하여 문자 단위로 직접 32비트 정수(int32)에 욱여넣는 하드코딩된 ‘고속 정수화 파싱(Fast Integer Parsing)’ 트릭이 동원된다.
0.3 무결성 검증의 취약 구조: XOR 체크섬
노이즈가 가득한 무인기 배선 환경에서 직렬 통신(UART) 데이터는 언제든지 전압 리플에 의해 비트 플립(Bit Flip)이 발생하여 데이터 무결성이 깨어질 수 있다.
- NMEA 문장의 맨 끝에는
*47과 같이 별표 구획 뒤에 두 자리의 16진수 **체크섬(Checksum)**이 부착된다. 이 값은 문장의$직후부터*직전까지 모든 글자의 ASCII 코드 값을 단순하게 XOR(^) 연산하여 누적한 8비트 해시(Hash)에 불과하다. - 약한 충돌 저항성(Collision Resistance) 병목: CRC32나 Fletcher 알고리즘과 같이 자리바꿈 오류(Transposition Error)나 연속된 다중 비트 에러(Burst Error)를 정교하게 잡아내는 강력한 검증 메커니즘과 비교할 때, NMEA의 단순 XOR 체크섬은 두 개의 비트 오류가 교묘하게 동시에 일어날 경우 체크섬 값이 서로 상쇄되어 원래 결과와 일치해버리는 결함이 잦다. 이는 불량한 좌표값이 그대로 EKF2 추정기로 빨려 들어가는 필터 붕괴의 위험 요인이 된다.
결론적으로 NMEA 0183 ASCII 프로토콜은 1Hz 수준의 고전적인 시스템에는 훌륭하게 작동하지만, 멀티로터의 고도 제어를 위해 초당 10번~20번씩(10~20Hz) 수백 글자의 텍스트를 쪼개고 변환해야 하는 현대 PX4-Autopilot의 스케줄러 환경에서는 명백히 CPU 타임과 대역폭을 갉아먹는 설계 구조적 원죄(Original Sin)를 안고 있다.