13.5.3.1. `ubx.cpp` 내 `decodeMessage()` 메서드 분석: `UBX-RXM-RTCM` 메시지 파싱을 통한 보정 신호 수신 무결성(CRC) 및 처리 상태 검증 로직

13.5.3.1. ubx.cppdecodeMessage() 메서드 분석: UBX-RXM-RTCM 메시지 파싱을 통한 보정 신호 수신 무결성(CRC) 및 처리 상태 검증 로직

드론과 지상 관제소 간의 텔레메트리 대역폭을 뚫고 무사히 GPS 칩셋(예: u-blox F9P)까지 도달한 RTCM 데이터 조각들은, 수신기 내부에서 성공적으로 적용되었는지 아니면 노이즈(Noise)에 의해 버려졌는지 외부(PX4 펌웨어)에 보고되어야 한다. 이를 위해 u-blox 하드웨어는 보정 데이터를 수신할 때마다 내부 상태를 요약하여 UBX-RXM-RTCM 이라는 피드백(Feedback) 프레임을 PX4 측으로 조용히 반환(Echoing)한다.

본 절에서는 PX4 GPS 드라이버의 UBX 파서 엔진인 src/drivers/gps/devices/src/ubx.cpp 내의 decodeMessage() 메서드 중에서, UBX-RXM-RTCM 메시지를 낚아채어 RTCM 주입의 무결성(CRC 상태)과 처리 성공 여부를 디코딩(Decoding)하는 핵심 알고리즘을 소스 코드 수준에서 해부한다.

1. UBX-RXM-RTCM 프레임의 존재 이유: 장님 코끼리 만지기 방지

PX4의 gps_inject_data 토픽을 통해 RTCM 바이트 배열을 무작정 write() 시스템 콜로 칩셋에 들이붓는 행위(Fire-and-Forget)는, 칩셋이 데이터를 제대로 소화했는지 체했는지 알 수 없는 이른바 ’장님 코끼리 만지기(Blind Injection)’와 같다.

UBX-RXM-RTCM 메시지는 이 맹점을 보완하는 유일한 창구다. 이 프레임이 수신되었다는 것 자체가 “u-blox 모듈이 방금 넘겨받은 RTCM 프레임을 파싱하려고 시도했다“는 인터럽트(Interrupt) 신호이며, 프레임 내부에는 ‘어떤 메시지(예: 1077, 1087)를 받았는지’, ’글로벌 CRC 검증을 패스했는지(Passed) 실패했는지(Failed)’가 플래그(Flag) 형태로 담겨 있다.

2. decodeMessage() 메서드의 분기 체계 스위칭(Switching)

앞선 parseChar() 메서드에서 동기화 바이트(0xB5 0x62)와 헤더, 그리고 페이로드 체크섬 2바이트까지 완벽하게 일치하면 payloadRxDone() 핸들러가 트리거되며, 여기서 decodeMessage() 가 호출된다.
메시지 클래스(Class)와 아이디(ID) 조합으로 구성된 장대한 switch - case 문을 통해 UBX-RXM-RTCM 의 전용 구역으로 진입한다.

// src/drivers/gps/devices/src/ubx.cpp (수신기 에코 분석 릴레이)
int Ubx::decodeMessage() {
    // _rx_msg 플래그를 통해 어떤 종류의 UBX 메시지인지 판단 (예: RXM 클래스)
    switch (_rx_msg) {
        
        // (중략 ... NAV-PVT, ACK-ACK 등 다른 메시지 분기)
        
        // RXM-RTCM 메시지가 도달한 경우
        case UBX_MSG_RXM_RTCM: {
            
            // 1. C 구조체 포인터 캐스팅을 통해 페이로드 메모리 접근
            ubx_payload_rx_rxm_rtcm_t *rtcm_stat = &_buf.payload_rxm_rtcm;

            // 2. flags 변수의 최하위 0번 비트(CRC 상태) 추출
            bool crc_failed = ((rtcm_stat->flags & 1) == 0); 

            // 3. 통계 누적기(Accumulator) 업데이트
            if (crc_failed) {
                _gps_position->rtcm_injection_rate = 0; // 혹은 에러 카운트로 치환
                _rtcm_crc_failures++; // MAVLink 텔레메트리로 전송될 에러 수치
            } else {
                _rtcm_injections_successful++;
            }
            break;
        }
    }
}

3. flags 레지스터의 비트 단위 마스킹(Bit Masking): CRC 무결성 검증

가혹한 무선 환경에서는 데이터 손실(Drop)이 일상이다. QGroundControl에서 보내는 RTCM이 MAVLink 단계를 통과했다 하더라도, FC 보드 내부의 구리선(UART 와이어) 노이즈나 슬립 링(Slip Ring) 접촉 불량으로 바이트가 깨진다면 수신기는 곧바로 폐기 처분한다.

ubx_payload_rx_rxm_rtcm_t 구조체의 flags 필드는 이 실패 여부를 직관적인 LSB 마스킹으로 판별할 수 있도록 설계되었다.

  • flags & 1 연산 결과가 1: 수신기에 도착한 배열의 자체 CRC가 일치하여 완벽히 수용(Accepted)되었음을 의미한다.
  • flags & 1 연산 결과가 0: 메시지 형식이 깨졌거나(CRC Failed) 무결성이 거부(Rejected)되었음을 의미한다.

PX4 개발진은 단순히 ഈ 플래그를 읽어 버리기만 하지 않고, _rtcm_crc_failures 와 같은 멤버 변수를 증가시킴으로써 누적된 실패율(Failure Rate) 통계를 작성한다. 이 카운터 지표는 상위 uORB 토픽(vehicle_gps_position_s)의 오류 스탯 필드에 담겨 다시 지상 관제소(QGC)로 향하게 된다.

3.1 디버깅 힌트: QGC의 MAVLink 인스펙터 분석

실제 현장에서 조종사가 QGC의 MAVLink Inspector 창을 열었을 때 HEARTBEAT 와 함께 넘어오는 텔레메트리 정보 중, GPS 주입 상태의 ’실패 카운트(Error count)’가 초당 수십 개씩 맹렬히 상승한다면 원인은 둘 중 하나이다.

  1. 드론 측의 보드레이트 설정(SER_TEL1_BAUD) 병목으로 인해 MAVLink 프레임 전송에서 병목 조각이 손실되어 잘린 패킷이 u-blox 핀에 꽂혔다.
  2. 베이스 스테이션(Base)에서 u-blox 칩셋이 지원하지 않는 메시지 타입(예: 구형 F9P 모듈에 최신 BeiDou B2b 메시지 강제 주입)을 보내어 칩셋 자체 파서가 지원 불가를 이유로 뱉어내고(Dropped) 있다.

결론적으로 ubx.cpp 내의 UBX-RXM-RTCM 메시지 파싱 블록은 텔레메트리의 무선 구간(Airborne)에서 발생한 통신 손실과 시스템적 노이즈를, 드론의 뇌(Autopilot)가 능동적으로 모니터링하고 피드백 루프(Feedback Loop)를 도출할 수 있게 해주는 가장 강력한 가시성(Visibility) 프로브(Probe)이자 텔레메트리 건강 검진기라 할 수 있다.