27.2.2.1. 메인 클래스 구조 및 PX4 모듈 베이스(ModuleBase) 상속 분석

27.2.2.1. 메인 클래스 구조 및 PX4 모듈 베이스(ModuleBase) 상속 분석

PX4 펌웨어 운영체제(NuttX 등) 위에서 수십 개의 시스템 백그라운드 프로세스가 충돌 없이 유기적으로 돌아갈 수 있는 이유는, 이들이 질서 정연한 객체 지향적 모듈 프레임워크 위에서 구동되기 때문이다.

ECL을 감싸고 있는 ekf2 모듈 역시 이 프레임워크의 핵심인 ModuleBase를 상속(Inheritance)받아 구현된다. 본 절에서는 EKF2 메인 클래스가 어떠한 C++ 문법적 기교를 통해 시스템 콘솔 명령어와 스레드 라이프사이클(Lifecycle)을 획득하는지 심층 분석한다.


1. CRTP 패턴을 활용한 ModuleBase 상속

src/modules/ekf2/EKF2.hpp 헤더 파일을 열어보면 EKF2 클래스는 다음과 같이 ModuleBase 템플릿을 스스로의 타입으로 상속받는 독특한 형태를 취하고 있다.

class EKF2 : public ModuleBase<EKF2>, public ModuleParams, public px4::WorkItem
{
    // ...
};

1.1 CRTP (Curiously Recurring Template Pattern) 기반

자기 자신의 클래스 이름(EKF2)을 부모 템플릿의 인자로 넘기는 이러한 C++ 기법을 CRTP(기이하게 반복되는 템플릿 패턴) 라고 부른다.

통상적인 객체 지향 프로그래밍에서 가상 함수(Virtual Function) 기반의 다형성(Polymorphism)을 사용하면, 실행 시간(Run-time)에 vtable 표를 참조해야 하므로 함수 호출 오버헤드가 발생한다. 하드 리얼타임 성능이 절실한 PX4 시스템에서는 이 미세한 오버헤드조차 아끼기 위해 CRTP를 적극 도입했다.

ModuleBase<EKF2>는 컴파일 타임(Compile-time)에 EKF2 클래스의 존재를 완벽히 인지하여 템플릿 인스턴스를 찍어낸다. 이를 통해 가상 함수 호출의 지연 없이도, 부모 클래스인 ModuleBase가 자식 모듈인 EKF2의 상태를 직접 제어하고 싱글톤(Singleton) 인스턴스를 관리할 수 있는 무결점의 정적 다형성(Static Polymorphism)을 획득하게 된다.


2. 콘솔 인터페이스(CLI)와 라이프사이클 관리 명세

ModuleBase를 상속받은 순간, EKF2 클래스는 NuttShell(NSH)이나 QGroundControl의 MAVLink 콘솔 창에서 사람이 타이핑하는 문자열 명령어들을 해석할 수 있는 강력한 파싱(Parsing) 능력을 물려받는다.

이를 위해 EKF2 클래스는 ModuleBase가 요구하는 필수 인터페이스 정적(Static) 함수들을 반드시 오버라이드(Override, 엄밀히는 템플릿 하이딩)하여 구현해야 한다.

2.1 task_spawn(int argc, char *argv[])

명령줄에서 ekf2 start 명령이 입력되었을 때 PX4 커널 로더에 의해 최초로 불리는 함수다. 이 함수 내에서 EKF2 객체가 힙(Heap) 메모리에 최초로 동적 할당(new EKF2())되며, 내부의 작업 스케줄링 큐(Work Queue)에 자신을 비동기 스레드로 등록(Schedule)시키는 일련의 부팅(Booting) 절차가 진행된다.

2.2 custom_command(int argc, char *argv[])

기본적인 start, stop, status 외에 EKF2만의 고유한 명령어를 처리하는 라우터(Router) 함수다. 사용자가 ekf2 replay 모드를 켜거나, 운영 중 ekf2 reset 명령을 날려 강제로 자이로 바이어스나 위치를 지면(Home)으로 초기화시킬 때의 분기가 이 함수 내에서 처리된다.

2.3 print_usage(const char *reason)

모듈을 실행할 때 잘못된 인자(Argument)를 넣거나 ekf2 help를 쳤을 때 나타나는 도움말 문자열을 방출한다.


3. 요약: 단일 진입점(Entry Point)의 강제화

과거 C 언어 기반의 구형 펌웨어들(예: 초기 MultiWii 등)은 전역 main() 함수 덩어리 안에 수십 가지 센서 퓨전 루프와 제어 루프가 while(1) 하나로 묶여 엉망진창으로 돌아가는 스파게티 형태(Spaghetti Architecture)를 띠었다.

반면 현대의 PX4는 ModuleBase라는 엄격한 C++ 기반 클래스 템플릿을 도입함으로써, ekf2 모듈뿐만 아니라 commander, mc_pos_control, sensors 등 수십 개의 복잡한 애플리케이션 데몬들을 ‘단일화된 문법’‘격리된 인스턴스’ 로 통제할 수 있게 되었다.

이 덕분에 시스템 프로세스 관리자는 EKF2 내부에 24상태 칼만 필터가 돌아가는지 100상태 딥러닝 모델이 돌아가는지 그 복잡도를 알 필요 없이, 단순히 ModuleBase의 공통 규격을 통해 메모리를 깨우고(task_spawn) 재울(stop) 수 있는 강력한 캡슐화(Encapsulation) 를 이뤄냈다.

다음 절에서는 이처럼 생명력을 부여받은 EKF2 모듈이 어떻게 CPU 타이밍을 섬세하게 쪼개 쓰며 센서 입력을 훔쳐가는지(Polling), WorkItem 스케줄링 로직의 비밀을 분석한다.