13.3.1.2. QGroundControl 백엔드(src/GPS/RTCMMavlink.cc 등)의 MAVLink 파싱 및 UI 업데이트 동기화 메커니즘
무인 항공기(UAS)의 지상 관제를 책임지는 QGroundControl(QGC)은 단순한 모니터링 대시보드가 아니다. 그 이면에는 방대한 센서 데이터를 라우팅하고, 프로토콜을 변환하며, 제한된 텔레메트리 대역폭을 통제하는 거대한 멀티 스레딩 기반 C++ 백엔드 엔진이 박동하고 있다. 특히 로컬 베이스 스테이션(Base Station)에서 생성된 무겁고 연속적인 RTCM 보정 데이터를 드론으로 쏘아 보내기 위한 MAVLink 변환 프로세스는 QGC 아키텍처의 백미라 할 수 있다.
본 절에서는 QGC 소스 코드의 핵심 컴포넌트인 RTCMMavlink.cc 클래스를 중심으로, RTCM 바이너리 스트림이 어떻게 파싱(Parsing)되어 MAVLink 패킷으로 재조립되는지, 그리고 이 백그라운드 연산 과정이 어떻게 프론트엔드(QML) UI 요소들과 상태 동기화를 이루는지 그 소프트웨어적 메커니즘을 낱낱이 해부한다.
1. RTCMMavlink 기반의 데이터 파싱 및 인캡슐레이션 루틴
베이스 스테이션 수신기(예: u-blox F9P)가 Fixed Mode 에 진입하면, USB 포트를 거쳐 초당 수천 바이트의 RTCM 3.3 메시지 무더기를 QGC로 쏟아낸다. 이 거대한 바이트 배열(Byte Array)을 텔레메트리 라디오 모뎀(57600\text{ bps} 급)에 그대로 밀어 넣으면 즉각적인 버퍼 오버플로우와 통신 단절이 발생한다.
QGC의 C++ 백엔드 클래스인 RTCMMavlink 는 이 병목 현상을 해결하기 위한 전위대 역할을 담당한다.
1.1 버퍼링 (Buffering) 과 프레이밍 (Framing)
우선 USB 시리얼 포트를 통해 들어오는 생(Raw) 바이트 스트림은 RTCMMavlink 의 수신 버퍼 큐(Queue)에 적재된다.
RTCM 메시지는 고정된 크기를 갖지 않는다. 따라서 파서(Parser)는 스트림의 첫 바이트에서 RTCM 프리앰블(Preamble, 0xD3 헥스값)을 찾아내고 길이(Length) 필드를 읽어 들여 정확히 하나의 완벽한 RTCM 프레임을 찢어내는 프레이밍 연산을 수행한다.
1.2 MAVLink 인캡슐레이션 (Encapsulation)
추출된 1개의 RTCM 프레임은 길이가 100\text{ bytes} 일 수도 있고, 여러 위성군의 데이터를 담아 무려 400\text{ bytes} 일 수도 있다. 반면 MAVLink v2.0 프로토콜에서 페이로드(Payload)는 전송 안정성을 고려하여 제한된 크기(일반적으로 180\text{ bytes} 내외)로 잘라 보내는 것이 관례이다.
- 청크 분할 (Chunking):
RTCMMavlink알고리즘은 단일 RTCM 패킷 사이즈가 180\text{ bytes} 를 초과하면 이를 여러 개의 작은 조각(Chunk)으로 토막 낸다. GPS_RTCM_DATA(ID: 233) 래핑: 쪼개진 각각의 조각들은MAVLINK_MSG_ID_GPS_RTCM_DATA구조체의data배열에 담긴다.- 플래그(Flag) 비트 마스킹: 조각이 분할되었음을 수신 측(PX4 기체)에 알리기 위해, 첫 번째 패킷부터 마지막 패킷까지 플래그(1바이트) 비트를 조작하여 ’시퀀스 순서’와 ‘패킷의 단편화 여부(Fragmented)’ 속성을 마스킹하여 동봉한다.
이렇게 포장된 수십 개의 MAVLink 패킷 덩어리들은 QGC의 메인 텔레메트리 송신 스레드(Vehicle Link) 큐로 넘겨져 공중을 향해 발사될 준비를 마친다.
2. 대역폭 통제 (Bandwidth Throttling) 엔진
QGC는 비행 제어를 위한 생명선(Lifeline)이다. 만약 RTK 보정 데이터를 쏘느라 조종사의 “Return to Launch(RTL)” 비상 명령 패킷이 큐에서 밀려난다면 이는 비행기 추락으로 이어진다.
이를 방지하기 위해 RTCMMavlink 및 관련 매니저 클래스는 Rate Limiter (속도 제한기) 타이머를 구동한다.
- 우선순위 역전 방지: 만약 현재 사용자 명령(Command Long) 패킷이 대기 중이거나 텔레메트리 송신 버퍼 밀집도(Congestion)가 70\% 를 넘어선다면, QGC 백엔드는 즉시 RTCM 데이터의 MAVLink 인캡슐레이션을 일시 중단(Pause) 하거나 일부 RTCM 패킷 번호(예: 불필요한 위성군 데이터)를 통째로 폐기(Drop) 해 버린다. (어차피 RTK 알고리즘 특성상 잠시 데이터가 유실되어도 기체 내의 EKF2 필터가 상당 시간 추론을 유지해 준다.)
3. 백엔드-프론트엔드 간의 상태 동기화 (UI Update)
C++ 백엔드(Back-end)의 무거운 연산 상태는 실시간으로 사용자 인터페이스(QML Front-end)에 피드백되어야 한다. 이 과정은 Qt 프레임워크의 심장인 QObject 기반 시그널-슬롯(Signal-Slot) 메커니즘을 타고 이루어진다.
3.1 위성 상태 (Survey-in) 프로퍼티 바인딩
베이스 스테이션 GPS 수신기를 관리하는 C++ 매니저 클래스(예: GPSManager)는 지속적으로 UBX-NAV-SVIN 패킷을 해석하여 _currentAccuracy (현재 오차 반경) 와 _surveyInValid (고정 모드 전환 여부 플래그) 멤버 변수를 업데이트한다.
// C++ 백엔드 시그널 발생부 예시
if (accuracy < targetAccuracy && duration > targetDuration) {
_surveyInValid = true;
emit surveyInValidChanged(_surveyInValid);
}
3.2 QML UI의 반응적 (Reactive) 렌더링
프론트엔드의 QML 코드(예: 상단 툴바의 GPS 상태 아이콘 요소)는 이 C++ 속성(Property)에 데이터 바인딩(Data Binding) 되어 있다.
surveyInValidChanged시그널이 발사되는 즉시, Qt의 메인 이벤트 루프(주 스레드)가 이를 캐치하여 QML 객체의 색상 프로퍼티를 즉시 재계산한다. 회색이던 베이스 스테이션 위성 아이콘이 흰색으로 점등하고, “RTK Survey-in completed” 라는 화면 중앙의 알럿(Alert) 메시지 팝업이 활성화되는 것이다.- 또한, 백엔드를 통과하여 통신 라디로를 타고 날아간 RTCM 데이터의 총 누적 송신량 (Total Bytes Sent) 수치 역시
emit시그널을 통해 실시간으로 QML 텍스트 필드 숫자로 굴러가며, 사용자에게 시스템의 활성 상태를 투명하게 체감시킨다.
종합하자면, GCS 내부에서 RTK 베이스 시스템을 통제한다는 것은 단순히 물리적으로 선을 꽂는 행위가 아니라, 초당 수천 바이트의 바이너리 쓰레기통에서 알짜배기 조각을 파싱(Parsing)해내고, 이를 MAVLink 규격으로 예쁘게 썰어 포장(Encapsulation)한 뒤, 제한된 무선 대역폭 내에서 텔레메트리 병목을 우회하여(Throttling) 드론에게 주사기처럼 투여하는 고도의 C++ 네트워크 프로그래밍의 총체이다.