28.2.1.2. 모듈 초기화(init()) 및 런타임 시작(start()) 루틴의 메모리 할당 검증
PX4 시스템의 커널에 메인 전원(5V)이 인가되고 리눅스와 유사한 부팅 시퀀스(rc.board 스크립트 등)가 순차적으로 실행될 때, Flight Mode Manager (이하 FMM)는 단순한 일반 백그라운드 로깅 데몬 따위와는 궤를 달리하며 기체와 조종사의 생존 물리 법칙을 최전선에서 책임지는 코어 마이크로서비스 모듈이다. 따라서 FMM은 시스템의 런타임 궤도에 오르기 전에 매우 엄격하고 보수적인 자기 검증 기반 초기화(init()) 및 시작(start()) 부트 절차를 거친다.
특히 픽스호크 마이크로컨트롤러(MCU)와 같은 임베디드 극한의 협소한 램(RAM) 용량 환경에서는, 메모리 파편화(Fragmentation)로 인한 ’동적 메모리 할당 실패(Out-of-memory)’가 곧 10초 뒤의 즉각적인 비행기 추락 및 인명 피해로 이어질 수 있으므로, FMM 데몬은 심장 박동기가 켜지기 직전에 메모리 및 널 포인터(Null Pointer) 무결성 검증에 아키텍처적으로 각별한 공을 들인다.
1. 전역 인스턴스화 래퍼(Wrapper) 팩토리와 init() 메모리 검증
부팅 셸 텍스트 텍스트(RCS) 스크립트 파서 엔진이 텍스트 라인에서 flight_mode_manager start 셸(NuttShell) 커맨드를 읽고 트리거하면, C++ FMM 베이스 모듈 클래스는 가장 먼저 정적(Static) 네임스페이스 스코프 내에서 스스로의 팩토리 빌더인 instantiate() 생성 함수를 호출하여 자신의 몸집을 부풀리기 시작한다.
- 메모리 힙(Heap) 할당 실패 방어기제의 발동:
FMM 최상위 뼈대 객체를 시스템 메모리 힙 공간에 올리기 위해 C++new키워드 연산자를 호출하는 찰나의 순간, PX4 특유의 동적 할당 래퍼(Wrapper) 매크로 구조체는 아주 냉정하고 깐깐하게 OS 레벨의 청크(Chunk) 할당 성공 여부를 검사한다.
만약 서드파티 제조사의 알 수 없는 이기종 데몬들이 부팅 과정에서 램 공간을 과다하게 무질서하게 선점해버려 FMM 거대 객체가 온전히 들어갈 연속된 빈 힙(Heap) 주소 블록 메모리가 부족하다면, PX4에 오버라이딩된new메모리 생성자는 C++ 표준 규약처럼 어설프게 런타임 예외(Exception OOM) 플래그를 미친 듯이 냅다 던져버리는 대신, 얌전하고 조용하게 절대 반지인nullptr(Null Pointer)만을 안전하게 반환(No-throw Guarantee)한다. - 하드 록업(Hard Lock-up) 연쇄 추락의 사전 차단:
init()초기화 루틴은 이렇게 반환된 베이스 포인터 인스턴스 주소값이 널(Null) 인지 아닌지 if 문으로 철저하게 검사하며, 단 한 바이트라도 실패 메모리 누수가 발생 시PX4_ERR("alloc failed")라는 섬뜩한 에러 텍스트 로그 한 줄을 붉은색 NSH 터미널 콘솔에 서늘하게 토해내고 데몬 구동 트리 자체를 그 즉시 포기하고 자폭한다.
이 보수적인 안전주의 철학 덕분에 PX4 펌웨어는, 존재하지도 않는 엉뚱한 쓰레기 메모리 주소를 포인터 끈으로 부여잡고 400Hz 메인 루프를 아슬아슬하게 돌다가, 어느 순간 공중에서 전체 OS 커널이 세그멘테이션 폴트(Segmentation Fault) 패닉에 빠져 프리징(Freezing)되는 끔찍한 인공지능 살인 사태를 부팅 단계 그라운드 상태에서 원천 차단해 낸다.
2. uORB 파이프라인 통신 혈관 포팅 및 무결성 록인(Lock-in)
FMM 메인 뼈대 구조체 객체가 다행히 무사히 램에 널 포인터 없이 안착(init() 성공)하고 나면, 본격적인 워크 큐(Work Queue) 스케줄러의 타임 대기열에 자신의 존재감을 알리기 앞서 가장 필수적인 통신 혈관 연결 작업들을 마친다.
- 구독자(Subscriber) 노드 객체의 명시적 사전 가동:
FMM 데몬 C++ 구조체 내부에 선언된vehicle_status,vehicle_local_position,manual_control_setpoint등 수십 개에 달하는 읽기 전용 uORB 구독자(Subscriber) 클래스 객체 포인터들을 커널단에 생성하고, 내부 토픽 핸들(Handle) 연결 상태를 초기화한다. - 발행자(Publisher) 파이프 연동의 선제적 컴파일 타겟팅:
FMM이 나중에 하늘을 날면서 밤낮없이 3차원 궤적들을 수식 산출하여 뱉어낼 출구 파이프인trajectory_setpoint.msg토픽의 커스텀 퍼블리셔(Publisher) 메모리 주소 빈 공간을 사전에 uORB 미들웨어와 결찰하여 연결해 둔다. 이 작업 세트가start()루틴 진입 전에 완벽하게 이루어지지 않으면, 런타임 메인 루프에서 값이 오갈 때 널 포인터 역참조 런타임 오류가 발생할 수 있으므로 편집증적으로 철저하게 셋업 검증을 거친다.
3. start() 펑션 콜: OS 스케줄러(NuttX WorkQueue)와의 첫 키스
모든 힙 메모리 공간 무결성과 uORB 혈관파이프라인이 기체 설계도대로 티끌 하나 없이 완벽히 에러 0 상태로 장착된 것이 확인된 가장 마지막 찰나의 순간에야, FMM 컴포넌트 데몬은 start() 실행 함수 내부에서 ScheduleNow() API 명령어를 우렁차게 대차게 호출한다.
비로소 FMM 워크 아이템(Work Item Task) 종이 번호표가, 잠잠하던 비행 OS 커널의 nav_and_controllers 상주 특수 대기열(Queue Board) 테이블 공간에 잉크 마크와 함께 당당하게 접수되는 역사적 순간이다.
이 단 한 줄의 C++ 인터페이스 코드(ScheduleNow())가 마이크로초 단위안에 커널에서 실행됨과 동시에, 그전까지 징그러운 C++ 수학 수식 객체 덩어리에 불과하며 비활성화된 채 잠들어 있던 FMM 바이트 뭉치는, 비로소 아키텍처 스케줄러의 살아 숨 쉬는 워크 타임 인터럽트 펄스를 받으며 펄떡이는 ‘리얼타임 태스크 데몬(Real-time Task Daemon)’ 피조물로 기적적으로 부활하여, 400Hz의 영원히 죽지 않는 무한 궤적 생성 달리기 루프의 첫 발(First Tick)을 하늘을 향해 강렬하게 내딛게 된다.