### 0.0.1 mavlink_messages.cpp의 스트림 클래스에서 uORB sensor_gps 데이터를 GPS_RAW_INT 패킷으로 변환하는 직렬화(Serialization) 과정
uORB 구조체를 MAVLink 데이터 스트림으로 포맷팅하는 실제 기계적 변환 과정은 src/modules/mavlink/mavlink_messages.cpp 파일 내에 정의된 개별 스트림 클래스들에 의해 주도된다. GPS의 경우, MavlinkStreamGPSRawInt 라는 전담 클래스가 이 직렬화(Serialization)의 최전선에 서 있다.
본 절에서는 단일 GPS 데이터를 MAVLink #24번 GPS_RAW_INT 패킷으로 매핑(Mapping)하고 조립해 내는 소스 코드 레벨의 알고리즘을 분석한다.
0.1 전용 스트림 클래스: MavlinkStreamGPSRawInt
PX4의 mavlink_messages.cpp를 열어보면, 각 MAVLink 메시지 스트림은 MavlinkStream이라는 순수 가상 클래스(Pure Virtual Class)를 상속받아 구현되어 있음을 알 수 있다.
MavlinkStreamGPSRawInt클래스는 부팅 시 MAVLink 모듈 초기화 과정에서 인스턴스화되며, 내부적으로sensor_gpsuORB 토픽을 구독(Subscription)하는 핸들(_gps_sub)을 보유한다.- 가장 핵심이 되는 메서드는 가상 함수인
send()이다. MAVLink 송신 루프가 “GPS 데이터를 보낼 차례“라고 스케줄러를 통해 신호를 주면 이send()함수가 트리거(Trigger)된다. - 이 함수가 호출되면 가장 먼저
_gps_sub.update(&gps)를 실행하여 uORB 버퍼에 쌓여있던 최신sensor_gps_s구조체 데이터를 로컬 변수(gps)로 복사해 온다.
0.2 필드 대 필드 매핑(Field-to-Field Mapping)
가져온 sensor_gps_s 구조체의 데이터는 MAVLink C 헤더(mavlink_msg_gps_raw_int.h)에 정의된 mavlink_gps_raw_int_t 구조체로 옮겨 담겨야 한다. 이 과정은 다음과 같은 정교한 스케일링(Scaling) 및 단위(Unit) 변환을 수반한다.
- Timestamp: uORB의 마이크로초(\mu\text{s}) 단위
timestamp는 MAVLink의 규격에 맞춰 부팅 후 경과 시간(Time since system boot)으로 변환되어time_usec필드에 채워진다. - Fix Type: 3D Fix, DGPS, RTK 상태를 나타내는
gps.fix_type(0~6의 값)은 직관적으로 MAVLink의fix_type필드에 1:1로 매핑된다. - 위도/경도/고도: 이미 10^7 로 스케일링 된
lat,lon값은 그대로 복사되며, 미터(m) 단위의 고도는 밀리미터(mm) 단위인alt필드와 매핑된다. 고도 타원체 기준 값(Ellipsoid)인지 해수면 기준 값(MSL)인지에 유의하여 변환된다. - 신뢰성 지표 (
epv,eph): uORB에서 미터(m) 단위 실수(float)로 존재했던 수평/수직 분산 오차는 MAVLinkGPS_RAW_INT규격에 따라 센티미터(cm) 단위의 정수(uint16_t)로 스케일 변환된 후eph,epv필드에 각각 캐스팅(Casting)되어 들어간다. 만약 값이UINT16_MAX를 초과하면 최댓값으로 클램핑(Clamping) 처리한다. - 속도 (Velocity): NED 좌표계의 북, 동, 하 속도 벡터(
vel_n_m_s등)는 스칼라 형태의 절대 지면 속도(cm/s 단위)와 진행 방위각(Course Over Ground, 0 \sim 359.99^{\circ} 의 센티 디그리 단위)인vel,cog필드로 삼각함수(아크탄젠트와 피타고라스 정리) 연산을 거쳐 변환된다. - 위성 개수:
satellites_used필드는 255(0xFF)를 넘지 않도록 안전하게satellites_visible필드로 매핑된다.
0.3 메시지 엔코딩 및 버퍼 송출 (mavlink_msg_gps_raw_int_send_struct)
모든 필드 매핑이 완수되어 mavlink_gps_raw_int_t 구조체가 빽빽하게 채워지면, 코드는 송신을 위한 마지막 엑셀을 밟는다.
- PX4는 MAVLink C 라이브러리가 제공하는 자동 생성 인라인 함수인
mavlink_msg_gps_raw_int_send_struct()를 호출한다. - 이 함수는 채워진 구조체 포인터를 받아, 구조체의 빈 공간(Padding)을 밀어버리고 MAVLink v1.0 혹은 v2.0 규격에 맞는 직렬화(Serialization)를 수행한다. 즉, 리틀 엔디안 방식의 바이트 배열(Byte Array)로 납작하게 누르는 것이다.
- 그다음 데이터 덩어리 앞뒤로
0xFD(MAVLink v2 마커), 시퀀스 ID, 시스템 ID, 컴포넌트 ID가 직조된 헤더(Header) 10바이트와, 메시지 무결성 검증을 위한 2바이트 CRC 체크섬(Checksum) 꼬리표를 강제로 이어 붙인다. - 마지막으로 조립이 완료된 이 패킷은 UART 포트나 UDP 소켓 버퍼(Tx Buffer)로 밀어 넣어지며, 하드웨어 인터럽트를 타고 QGroundControl을 향한 전파의 바다로 다이빙한다.
이 일련의 mavlink_messages.cpp 직렬화 알고리즘 덕분에, 드론 컨트롤러 내부의 추상화된 이기종 데이터들은 전 세계 어디서나 통용되는 표준 통신 규격으로 변환되어 GCS 화면의 계기판을 부드럽게 움직일 수 있게 된다.