13.5.3.2. UBX-NAV-PVT (Position, Velocity, Time) 메시지 파싱: flags 레지스터의 carrSoln 필드(비트 6-7) 마스킹을 통한 Fix(2)/Float(1)/None(0) 상태 추출 및 uORB vehicle_gps_position 발행
RTCM 보정 데이터가 GPS 칩셋(u-blox)의 UART 핀을 타고 들어갔더라도, 그 데이터가 실제 내비게이션 필터(Kalman Filter)에 화학적으로 융합(Fusion)되어 센티미터(\text{cm}) 단위의 초정밀 삼각 측량을 이끌어냈는지 증명할 방법은 칩셋이 스스로 뱉어내는 측위 보고서(Position Report)뿐이다.
PX4 펌웨어의 Ubx 클래스 수신기 드라이버(src/drivers/gps/devices/src/ubx.cpp)는 이 최종 성과표를 열람하기 위해 모든 역량을 UBX-NAV-PVT (Position, Velocity, Time) 메시지 파싱에 집중한다. 본 절에서는 UBX-NAV-PVT 메시지의 1바이트 크기 flags 레지스터에서, 캐리어 위상 해석 상태(Carrier-phase range solution)를 판가름하는 핵심 비트 마스킹(Bit Masking, 6-7번 비트) 로직을 분석하고, 이 결과가 PX4 내부의 uORB 토픽(vehicle_gps_position)으로 번역(Translation)되는 브리지(Bridge) 아키텍처를 C++ 코드로 정밀 해부한다.
1. UBX-NAV-PVT: 무거운 측위 데이터의 최전방 통로
UBX-NAV-PVT 는 GPS 수신기가 위성들의 원시 반송파(Carrier Phase)와 의사 거리(Pseudorange) 데이터를 모아 EKF 엔진 위젯을 굴린 뒤 도출해낸 위도, 경도, 고도, 속도 단위(\text{mm/s}), 시간, 오차 타원 분산 수치를 총망라한 단 하나의 메가 프레임(약 92바이트) 이다.
NMEA 통신 규격이 여러 문장(GGA, RMC, VTG 등)으로 파편화되어 흩뿌려지는 것과 달리, UBX 프로토콜은 이 한 덩어리에 모든 정보를 응축(Packed)하여 1초에 기본 5번(5\text{Hz})씩 드론의 UART에 집어넣는다.
1.1 flags 레지스터: RTK의 상태를 결정짓는 1\text{ Byte}의 권력
PX4 스케줄러가 이 92바이트 프레임 전체를 파싱하여 복사(Copy)를 뜰 때 가장 주목하는 C 구조체 멤버는 단순한 1바이트 변수인 flags 이다.
수만 줄 짜리 EKF2 소스 코드의 진입 조건(RTK Fix로 전환할지 여부)은 오로지 이 1바이트 안에 있는 두 개의 특정 비트(Bit)가 쥐고 있다.
bit 0:gnssFixOK(1 = 유효한 3D Fix 완성, 0 = 위성 부족)bit 1:diffSoln(1 = DGPS 수신 상태, 보정 정보가 일부라도 수신됨)bit 6-7:carrSoln(캐리어 위상 기반 항법 해석 솔루션 상태)
2. carrSoln 필드(비트 6-7) 마스킹(Masking)과 RTK 등급 추출
드론 엔지니어링의 성배(Holy Grail)라 할 수 있는 RTK Fixed (센티미터 정확도)와 RTK Float (미터/데시미터 정확도) 상태는 오직 carrSoln (Carrier Solution) 영역의 비트로만 구별된다.
PX4의 C++ 파서는 이 두 비트만 깔끔하게 도려내기 위해 논리곱(AND) 비트 마스킹 연산과 우측 시프트(Shift)를 수행한다.
// src/drivers/gps/devices/src/ubx.cpp
// UBX-NAV-PVT 메시지 디코드 및 uORB 속성 치환 유사 코드
int Ubx::decodeMessage() {
switch (_rx_msg) {
case UBX_MSG_NAV_PVT: {
ubx_payload_rx_nav_pvt_t *pvt = &_buf.payload_nav_pvt;
// 1. 위도(lat), 경도(lon) 등 기본 멤버 변수 읽기
_gps_position->lat = pvt->lat;
_gps_position->lon = pvt->lon;
// 2. flags (1 byte) 에서 carrSoln 영역 비트 마스킹
// 0b11000000(0xC0) 로 윗부분 2비트만 살리고 나머지 버린 후(AND),
// 우측으로 6칸 이동시켜 0, 1, 2 정수값 도출
uint8_t carr_soln = (pvt->flags & 0b11000000) >> 6;
// 3. 추출된 레퍼런스 값에 따른 Fix 타입 분기
if (carr_soln == 2) {
// Integer Ambiguity Resolution 완료 = 정수 모호성 완전 해결
_gps_position->fix_type = 6; // uORB 규격 상 RTK FIXED 의미 (수 cm 오차)
} else if (carr_soln == 1) {
// Floating point ambiguity = 정수 모호성 미해결 상태, 추정 중
_gps_position->fix_type = 5; // uORB 규격 상 RTK FLOAT 의미 (0.1~1m 오차)
} else {
// carr_soln == 0 인 경우: 캐리어 위상 정보 아예 사용 안 됨 (No Carrier Phase)
if (pvt->flags & 1) { // 단순 3D Fix 확인
_gps_position->fix_type = 3; // 일반 3D Fix
} else {
_gps_position->fix_type = 0; // No Fix 상태
}
}
break;
}
}
}
이 고전적인 비트 연산((flags & 192) >> 6)으로 도출된 결과값(0, 1, 2)은 단순한 정수형 열거식(Enum)에 불과하지만, 이 값의 화학적 변화(예: 1 \rightarrow 2)가 일어나는 순간은 지상의 베이스 스테이션 안테나와 드론에 탑재된 이동 수신기 안테나가 우주공간을 날아오는 1.5\text{GHz} 대역의 GPS 반송파 파장(약 19\text{cm}) 주기 개수(정수 모호성, Integer Ambiguity)의 오차 방정식을 수렴시킨 아주 경이로운 순간이다.
3. uORB vehicle_gps_position 테이크오버(Takeover) 발행
carrSoln 파서 엔진에서 도출된 마스킹 결과(fix_type 은 5 또는 6)를 비롯한 위도, 경도 변수들은 내부 캐시 버퍼(_gps_position) 메모리에 고스란히 저장된다. 하지만 센서 인터페이스 계층에서 이 작업만 이룰 뿐 메인 비행 제어기 코어(Estimator)에게 스스로 변화를 알리지 않는다.
최후의 전달자는 바로 **uORB 퍼블리싱(Publishing)**이다.
데이터 추출이 무사히 끝난 Ubx 스레드는 vehicle_gps_position 이라는 최상위 토픽(Topic)으로 이 거대한 상태 보고서를 발행(Publish)한다.
// GPS 통합 드라이버(gps.cpp) 상단 래퍼의 유사 로직
if (_report_gps_pos && updated) {
// 타임스탬프 기록
_gps_position->timestamp = hrt_absolute_time();
// 1. uORB에 최종 퍼블리싱 (Publish)
// EKF2, Commander, MAVLink 스트리머 등 비행 제어기 전역 버스로 피드 전파
orb_publish(ORB_ID(vehicle_gps_position), _report_gps_pos_pub, _gps_position);
}
이 발행 행위를 통해:
- Estimator(EKF2): 토픽 센서가 “앗!
fix_type이 6(Fixed)으로 갱신되었군” 이라고 판단하고 GPS 혁신 가중치(Innovation Weight)를 대폭 끌어올려 기압계나 나침반의 오차를 맹렬히 교정하기 시작한다. - MAVLink Streamer:
fix_type정보를 MAVLinkGPS_RAW_INT패킷에 싸서 하향 통신(Downlink) 텔레메트리로 지상으로 쏘아 보낸다. 조종사는 QGroundControl 상단 상태표시줄에 “RTK GPS (Fixed)” 라는 녹색 마커 애니메이션을 눈으로 확인할 수 있게 된다.
결론적으로 u-blox 모듈의 UBX 프로토콜은 기상천외한 우주선 궤도역학을 92\text{ bytes}와 특정 비트(192) 하나로 욱여넣은 아키텍처의 결정체이다. 그리고 PX4의 decodeMessage() C++ 코드는 이 원시적인 비트를 우아한 uORB 토픽(메시징 혈관)으로 번역하는 완벽한 아키텍처 브리지(Bridge)의 모범 사례라 평가할 수 있다.