13.5.1.1. GPS_RTCM_DATA (메시지 ID 233) 패킷 C 구조체 해부
MAVLink 프로토콜은 드론 생태계 전체를 관통하는 통신 혈맥(Bloodline)과 같으며, 그 혈맥을 타고 지상의 베이스 스테이션(Base Station)에서 하늘의 드론으로 끊임없이 주입되는 산소가 바로 ’RTCM 보정 데이터’이다. 이 방대한 바이너리 스트림을 좁은 텔레메트리 대역폭으로 실어나르기 위해, MAVLink는 **GPS_RTCM_DATA (MAVLink Message ID #233)**라는 특수하고 독립적인 화물칸(Container) 메시지를 사양(Specification)으로 정의하였다.
본 절에서는 펌웨어와 QGroundControl(QGC) 양단에서 이 메시지가 물리적인 바이트 배열로 어떻게 캡슐화(Encapsulation)되고 직렬화(Serialization)되는지, mavlink_gps_rtcm_data_t C 구조체 내부의 필드들을 메모리 레벨에서 낱낱이 파헤친다.
1. mavlink_gps_rtcm_data_t C/C++ 구조체 선언 분석
자동 생성된(Auto-generated) MAVLink v1.0 및 v2.0 C 헤더 파일 폴더(예: common/mavlink_msg_gps_rtcm_data.h)를 살펴보면, 이 메시지 구조체는 극도로 최적화된 바이트 정렬(Byte Alignment)을 갖추고 있다.
// MAVLink C 라이브러리의 구조체 원형
typedef struct __mavlink_gps_rtcm_data_t {
uint8_t flags; // 1 byte: LSB (단편화 식별 비트)
uint8_t len; // 1 byte: 페이로드의 유효 바이트 길이 (최대 180)
uint8_t data[180]; // 180 bytes: RTCM 블록 데이터의 페이로드 바이트 버퍼
} mavlink_gps_rtcm_data_t;
C 구조체 구조체의 물리적 크기(sizeof(mavlink_gps_rtcm_data_t))는 정확히 **182\text{ bytes}**로 고정된다. 주목할 만한 점은, 이 메시지가 32비트 버스로 접근할 때 생길 수 있는 메모리 패딩(Padding) 오버헤드를 막기 위해 오직 8비트 자료형(uint8_t)만으로 납작하게 압착되어 있다는 것이다.
2. 주요 레지스터 필드 특성
구조체를 구성하는 각 필드는 아래와 같은 엄격한 프로토콜 명세서(Protocol Specification)에 따라 조작된다. 단 한 바이트라도 잘못 기입되면, 수신 측(PX4 MAVLink Receiver)에서 이 패킷을 엉뚱하게 버려버리거나(Drop) GPS 모듈에 잘못된 데이터를 박아넣을 수 있다.
2.1 len 필드: 유효 바이트 트리밍(Trimming)
len (Length) 변수는 배열 data[180] 중에서 실제로 RTCM 데이터가 차 있는 맨 마지막 인덱스(Index)의 길이( 1 \sim 180 )를 나타낸다.
전체 송신 메시지 퍼즐 덩어리(800\text{ bytes} 등)를 쪼개다 보면 맨 마지막에 전송되는 조각은 필연적으로 180바이트보다 적다. 가령, 마지막 남은 데이터가 45\text{ bytes}라면 len에는 45가 들어가며, 송신 측 MAVLink 파서(Parser)는 배열 뒤쪽의 135\text{ bytes}의 쓰레기값(Garbage Data)은 네트워크로 내보내지 않고 TRIM 하여 대역폭을 아낀다(MAVLink v2 빈 바이트 트리밍 기능의 지원을 받는 경우 더욱 효과적).
2.2 data[180] 배열: RTCM 바이너리 블록
여기에 담기는 것은 ASCII 문자열도, 사람이 읽을 수 있는 JSON 포맷도 아니다. 0x0D, 0xFF 와 같은 기계어 수준의 순수 Hex 데이터이다. 이 바이트가 변형되거나 뒤집혀서는 안 되기 때문에, 시스템 아키텍처는 이를 포인터 메모리 복사 방식인 memcpy() 명령어를 사용하여 다이렉트로 옮겨 심는다(Direct Memory Access, 하드웨어적 혹은 소프트웨어적인 복사).
2.3 flags 필드 구조 (단편화 ID 식별)
이 1바이트 짜리 플래그(flags)는 단순히 단편화(Fragmentation) 정보를 담는 것을 넘어, 수신기로 하여금 “이 수많은 180\text{ bytes} 조각들이 도대체 몇 번째 조각인가?“를 알려주는 조립 번호표(Sequence Tag) 역할을 한다.
플래그 내부의 8비트(Bit)는 다음과 같이 분할 사용된다:
- LSB (하위 0비트표식): 이 패킷이 하나의 거대한 RTCM 블록에 속하는 조각인지(Fragmented) 아닌지 가리킨다. 단편화된 상태를 유지하기 위해 LSB의 0비트 사용 (1 = 프래그먼트, 0 = 미사용)을 약속한다.
- 시퀀스 번호 식별 (1~2 비트): 이 패킷이 첫 조각인지(First Chunk), 두 번째 조각인지 식별한다. 각 배열 조각들은
Sequence ID = (flags & 0b00000110) >> 1수식 등에 의해 조각의 일련번호를 획득하여 0, 1, 2, 3 의 순서를 띠게 된다.
3. MAVLink MSG_ID 및 CRC_EXTRA 의 숨겨진 작동 원리
이 182바이트의 mavlink_gps_rtcm_data_t C 구조체가 직렬 포트(Serial Port)의 전기 신호로 날아가기 위해서는, MAVLink 프로토콜 스택이 그 앞뒤로 거대한 인프라스트럭처 프레임(Header + Payload + Checksum)을 씌워준다.
- 헤더 (Header): 송신자 System ID, Component ID (통상
SYSID 255,COMPID 0인 QGroundControl) 및 패킷 순번표(Sequence number) 부착. - 페이로드 (Payload):
len의 길이에 해당하는 데이터 블록 치환. - 체크섬 (Checksum, 2 \text{ bytes}): 이 데이터가 무선 전파 방해(RF Noise)를 받아
len이나flags가 손상되지 않았는지 검증하기 위한 ITU X.25 방식의 CRC16 무결성 검사 코드 부착.
여기서 가장 중요한 보안관(Sheriff) 역할을 하는 것이 컴파일 타임에 결정되는 각 메시지 고유의 매직 넘버(Magic Number), 즉 CRC_EXTRA 상수 이다.
GPS_RTCM_DATA (메시지 ID 233) 에는 C 소스코드 깊은 곳에 MAVLINK_MSG_ID_GPS_RTCM_DATA_CRC_EXTRA 35 혹은 유사 번호가 하드코딩되어 있다. 만약 QGC 측이 컴파일된 C 헤더의 len 위치와 PX4 측 펌웨어가 컴파일된 len 의 멤버 위치, 혹은 CRC_EXTRA 번호가 달라서 버전 간 불일치가 발생한다면 펌웨어는 ഈ 메시지를 버그로 인지하고 하드웨어적 수준에서 가차 없이 폐기(Discard) 처분한다.
결론적으로 GPS_RTCM_DATA의 C 구조체는 PX4-Autopilot 아키텍처 내에서 가장 단순하고 찌그러진(Flattened) 외형을 가졌지만, 무선 링크의 낭비를 제로화하고 RTK의 절대 정밀도 생명줄을 이어가기 위해 1\text{ byte}의 패딩(Padding)마저 허락하지 않는 극한의 메모리 밀집형(Memory-packed) 데이터 전송 규격의 정수라 평가할 수 있다.