18.1.1.1 강결합(Tight-coupling) 아키텍처의 한계와 모듈화의 필요성
초창기 취미용 드론 수준에서 시작된 오픈소스 비행 제어 프로젝트들은 하드웨어 리소스(메모리 및 CPU 클럭)의 극심한 제약으로 인해 직관적이고 단순한 형태의 소프트웨어 아키텍처를 가질 수밖에 없었다. 당시의 전형적인 구조가 바로 모듈 간에 데이터와 제어 흐름이 강력하게 묶여 있는 강결합(Tight-coupling) 아키텍처이다.
1. 강결합 아키텍처의 특징과 치명적 단점
강결합 시스템에서는 하나의 메인 루프(Main Loop) 안에서 센서 읽기, 필터 연산, PID 제어, 모터 출력 등의 모든 과정이 순차적인 함수 호출(Function Call)로 얽혀 있다. 각 모듈은 다른 모듈의 내부 데이터 구조체를 직접 참조(Pointer Dereferencing)하거나 전역 변수(Global Variable)를 통해 상태를 공유한다.
이러한 모놀리식(Monolithic) 접근 방식은 다음과 같은 치명적인 한계점들을 노출한다.
- 연쇄적인 오류 전파(Cascading Failures):
특정 센서 드라이버(예: I2C 라인의 노이즈로 인한 나침반 드라이버의 블로킹 현상)에서 병목(Bottleneck)이나 무한 루프가 발생할 경우, 동일한 스레드 컨텍스트 내에서 순차적으로 실행되는 메인 자세 제어기(Attitude Controller)마저 연산 기회를 잃게 된다. 이는 하늘을 날고 있는 기체의 즉각적인 추락(Crash)으로 직결된다. - 타이밍 제어의 복잡성:
자이로스코프 데이터는 1000Hz 주기로 읽어야 하고, GPS 데이터는 10Hz 주기로 들어온다. 이들을 하나의 동기화된 루프에서 강하게 결합하여 처리하려면 복잡한 스케줄링 카운터와 조건문들이 난무하게 되며, 이는 하드 실시간(Hard Real-time) 성능을 저해한다. - 코드의 확장성 및 유연성 부재:
새로운 충돌 회피 알고리즘이나 컴퓨터 비전 모듈을 추가하려 할 때, 기존 핵심 코드 베이스의 여러 부분을 헤집고 의존성을 주입해야 한다. 개발자는 다른 모듈에 미치는 사이드 이펙트(Side Effect)를 두려워하게 되며, 단위 테스트(Unit Test)를 작성하기 위해 수많은 목업(Mock-up) 모듈을 만들어야 하는 유지보수의 지옥에 빠진다.
2. 모듈화(Modularization)와 마이크로서비스 패러다임
초창기 버전 이후 ArduPilot과 PX4는 각자의 방식으로 발전해 왔다. ArduPilot은 C++ 객체 지향 프로그래밍과 스케줄러를 고도화하여 단일 공간 내에서의 모듈화를 이룩하는 방향(여전히 상대적으로 강한 결합도를 유지)을 택한 반면, PX4-Autopilot은 NuttX RTOS 상에서 완전히 독립적인 태스크(Task) 프로세스들의 집합으로 동작하는 마이크로서비스(Microservices) 아키텍처와 유사한 극단적 모듈화를 택했다.
PX4의 철학에서 모듈화의 필요성은 다음과 같이 정의된다.
- 독립적 실패 영역(Fault Isolation):
GPS 드라이버 데몬이 중단(Segfault 등)되더라도, 커맨더(Commander)와 제어기 데몬은 즉각적으로 멈추지 않는다. 이들은 단지 새로운 위치 데이터를 받지 못했다는 이벤트만을 감지하고, 안전하게 센서 페일세이프(Failsafe) 절차를 가동해 비상 착륙 등으로 기체를 보전할 수 있다. - 투명한 데이터 레이어 확보:
하드웨어 추상화 계층(HAL)을 넘어서 데이터 흐름 자체가 추상화된다. 시뮬레이션(SITL/HITL) 환경을 구축할 때 실제 하드웨어 센서 코드를 수정할 필요 없이, 시뮬레이터 프로그램이 가상의 센서 데이터를 PX4 데이터 버스에 찔러 넣어주는 것만으로 완벽한 인더루프 트윈(In-the-loop Twin)이 완성된다.
결국, 무인항공기 소프트웨어가 단순한 PID 루프를 넘어서 자율 주행, 딥러닝 비전 퓨전, 군집 비행 등을 처리하는 ’날아다니는 고성능 컴퓨터’로 진화함에 따라, 과거의 강결합 아키텍처를 버리고 확고한 기능 단위의 모듈화를 이룩하는 것은 필연적인 발전 과정이었다. 그리고 이 모듈화를 현실로 만들어준 근간이 바로 uORB 메시징 브로커이다.