### 0.0.1 원시 데이터 uORB 퍼블리싱(Publishing) 과정

### 0.0.1 원시 데이터 uORB 퍼블리싱(Publishing) 과정

GPS 드라이버 통신 파서 계층(Parser Layer)이 직렬(Serial) 바이트 단위의 전투를 끝내고 나면, 획득한 전리품(Raw Data)을 시스템 전체가 공유할 수 있도록 사내 게시판에 공지해야 한다. PX4-Autopilot 아키텍처에서 이 게시판 계층을 담당하는 것이 바로 uORB(Micro Object Request Broker) 미들웨어이다.

본 절에서는 벤더(Vendor)의 특정 프로토콜에 종속되었던 원시(Raw) GPS 패킷이, 어떻게 PX4의 범용 메시징 시스템인 sensor_gps 토픽으로 포장(Encapsulation)되어 다른 모듈들을 향해 쏘아 올려지는지(Publishing) 살펴본다.

0.1 uORB의 비동기적(Asynchronous) 출판-구독 철학

만약 PX4가 Ardupilot의 일부 레거시 버전들처럼 객체를 포인터로 직접 참조하는 강한 결합(Tight Coupling) 모델을 사용했다면, EKF2 추정기는 GPS 객체의 메모리 주소를 직접 들여다봐야 했을 것이다. 이는 다중 스레드 환경에서 메모리 접근 충돌(Race Condition)을 유발하거나 시스템의 상호 의존성을 극도로 높이는 원인이 된다.

  • PX4는 이 문제를 해결하기 위해 출판-구독(Publish-Subscribe) 패턴을 도입했다.
  • GPS 파서(UbxGps, NmeaGps 등)는 데이터를 파싱해 낸 직후 오직 orb_publish()라는 시스템 콜 한 번만 호출하고 본연의 임무(다음 바이트 대기)로 돌아간다. 누가 이 데이터를 가져가는지, 심지어 아무도 가져가지 않는지조차 전혀 신경 쓰지 않는다.
  • 이 고도로 분리된(Decoupled) 구조 덕분에, 모듈 개발자들은 GPS 드라이버를 단 한 줄도 건드리지 않은 채 자신만의 새로운 내비게이션 앱(App)을 만들고, 단순히 orb_subscribe(ORB_ID(sensor_gps)) 선언만으로 데이터를 끌어다 쓸 수 있다.

0.2 sensor_gps_s 인스턴스: 규격화된 화물 컨테이너

GPS 모듈 안에는 10개가 훌쩍 넘는 다양한 NAV 클래스의 패킷들이 돌아다닌다. 이 난잡한 정보들은 발행되기 직전, msg/sensor_gps.msg 파일 정의로부터 자동 생성된 C++ 구조체 **sensor_gps_s**라는 단일 규격의 컨테이너에 옮겨 담긴다.

  1. 데이터 조립(Assembly):
    하위 베이스 클래스인 GPSProvider는 파서 루틴 내부에서 이 구조체를 멤버 변수로 들고 있다. UBX 파서가 위도 파싱을 마치면 _gps_position->lat, 속도 파싱을 마치면 _gps_position->vel_m_s 등에 차곡차곡 데이터를 적재한다.
  2. 타임스탬프 각인(Timestamping):
    모든 데이터 조립이 끝나면, 앞 절에서 확인한 정밀 동기화 알고리즘에 의해 계산된 절대 영점 시각(timestamp)을 가장 마지막에 쾅 하고 찍어 넣는다.
  3. 상태 머신 초기화:
    이 ‘퍼블리시 준비 완료’ 행위가 끝나면, 파서의 상태 머신은 자신이 들고 있던 내부 카운터나 임시 변수를 깨끗이 지우고 다음 메시지의 SYNC 헤더를 맞이할 준비 상태로 완전히 초기화된다.

0.3 uORB 퍼블리싱 트리거(orb_publish)

구조체 변환이 완벽히 끝났음을 파악한 시스템 스레드는 마침내 데이터를 쏘아 올린다.

  • PX4 드라이버 래퍼(Wrapper) 계층 스레드(gps_thread_main 폴링 루프 등)는 helper->receive() 함수의 반환값이 양수(1)일 때 데이터가 유효함을 파악한다.
  • 반환값이 1로 떨어지는 즉시, 드라이버 코드는 퍼블리시 전용 래퍼 함수(예: orb_publish(ORB_ID(sensor_gps), _report_gps_pub, &report_gps))를 전격 호출한다.
  • 이 함수가 호출되는 1마이크로초(1 \mu s)도 안 되는 찰나에, uORB 링 버퍼(Ring Buffer)에는 새로운 구조체 패킷이 메모리 카피(memcpy)되어 들어간다. 동시에 이 토픽(sensor_gps)을 구독 중이던 EKF2나 로거(logger), MAVLink 스트리밍 데몬들의 파일 디스크립터(poll fd)에 SIGPOLL 인터럽트 깃발(Flag)이 번쩍 치솟으며 수십 개의 소비자 스레드들이 동시에 깨어나 데이터를 퍼가기 시작한다.

결국 원시 데이터의 퍼블리싱 과정은 무질서하게 날아오는 바이트들을 단단한 규격 박스(sensor_gps_s)에 구겨 넣은 뒤, PX4 생태계 한가운데 포진한 택배 물류 창고(uORB)에 벨트를 태워 보내는 정교한 일원화 공정이라 할 수 있다.