28.1.3.2.2. Ardupilot의 전역 변수(Global Variable) 및 싱글톤(Singleton) 객체 참조 방식
현대 컴퓨터 공학의 모듈화 철학의 정수인 미들웨어(uORB)를 계층 간의 완충 공간으로 삼아 컴포넌트 독립성을 눈부시게 극대화한 시스템이 PX4라면, Ardupilot은 철저히 운영체제적 레이어 추상화를 사치품으로 배제하고 C/C++ 컴파일 언어 본연의 날카로운 메모리 포인터 직접 접근(Direct Memory Access) 방식을 극한까지 밀어붙여 통신 레이턴시(Latency)를 사실상 0으로 삭제해 버린다.
이러한 Ardupilot의 극단적인 엔지니어링 실용주의 아키텍처를 든든하게 뒷받침하는 핵심 코딩 패턴 철학이 바로 전역 변수(Global Variable)와 싱글톤(Singleton) 객체의 전방위적 난립 및 공유다.
1. 전역 시스템 객체(Global Singleton) 메인프레임의 융단폭격
Ardupilot 펌웨어 코어(ArduCopter, ArduPlane 등 메인 디렉터리) 소스 코드를 해부해 보면, C++ 객체 지향 프로그래밍 문법 교과서에서 보통 치명적인 안티패턴(Anti-pattern)으로 고강도로 경계하는 거대 전역 변수들이 시스템을 떠받치는 중심 기둥으로 온 사방에 당당하게 박혀 있는 압도적 광경을 볼 수 있다.
- 주요 시스템 싱글톤 객체 포인터: 관성 센서(자이로/가속도계) 로우 데이터를 다루는
AP_InertialSensor ins;, 나침반 벡터를 관리하는Compass compass;, 기압계 데이터를 파싱하는AP_Baro barometer;, 그리고 가장 우두머리 격인 기체 칼만 필터 상태 추정기(EKF) 엔진AP_AHRS ahrs;클래스 객체들이, 메인 스레드가 구동되는 펌웨어 전역 네임스페이스(Global Namespace) 허공에 거대한 싱글톤 메모리 구조체 형태로 떠 있다. - 직접 참조 결합(Direct Pointer Reference): 산하의 구체적인 하위 비행 모드 클래스(
ModeLoiter,ModeRTL,ModePosHold등)들은 이 무겁고 외부적인 글로벌 신(God) 객체들의 메모리 주소를 포인터로 덥석덥석 가져와, 자신의 비행 로직 파이프라인 내부에서 아무런 스스럼이나 인터페이스 추상화 없이 완전히 한 몸처럼 뒤섞어버린다.
2. 다이렉트 메서드 콜(Direct Method Call)의 폭력적 런타임 이점
자율 비행 모드 데몬이 다음 궤적 조종 목표 가속도를 계산하기 위해, 현재 바람을 맞고 기체가 기울어진 롤/피치(Roll/Pitch) 오일러 각도를 시급하게 알고 싶다고 가정하자. Ardupilot은 PX4처럼 uORB 토픽 링 버퍼 박스에 이벤트 패킷 데이터가 스케줄러에 의해 점잖게 복사되어 오기를 얌전히 기다리는 느긋함 따위는 던져버렸다.
- 즉각적인 다이렉트 하드코딩 콜: Ardupilot의 파생 비행 모드 실행 함수는 계산 루프를 돌다 당장 포지션 추정치가 필요하면 곧바로
ahrs.roll퍼블릭 멤버 변수 주소를 직접 끄집어내어 하드웨어 램 리드로 읽어버리거나,ahrs.get_position()전역 시스템 구동 메서드를 동일한 단일 프로세스 램 메모리 공간(Heap/BSS) 안에서 즉시 동기식으로 하드코딩 호출(Synchronous Direct Call) 하여 값을 무자비하게 쏙 빼내어 간다. - 통신 버퍼링의 절대적 제로(Zero Penalty): 컴파일러 단에서 메모리 직행 버스를 타기 때문에 uORB와 같은 메시지 구조체 컴포넌트 직렬화/역직렬화(Serialization) CPU 연산 비용이나, 파이프라인 버퍼 복사(Memory Copy) 큐잉으로 인한 마이크로초(us) 단위의 스케줄러 전환 딜레이조차 아예 0(Zero Cycle)으로 말끔히 소거된다.
이 무식하지만 위대한 하드웨어 밀착성 덕분에 Ardupilot은 동일한 저가형 ARM CPU 클럭 하에서 PX4 대비 조종 스틱 체감 반응 속도와 실제 모터 출력 지연 간의 딜레이 타임 벤치마크 지수상에서, 사람이 체감하기 힘든 수 마이크로초 단위라도 기어이 철저하게 미세 비교 우위를 점해내는 극강의 1차원적 실용주의 퍼포먼스를 뽐낸다.
3. 강결합(Tight Coupling) 생태계의 잔혹한 덫과 확장성 패널티 청구서
그러나 이렇게 글로벌 전역 변수 혈관을 온 동네 백 수십 개의 파일들이 거미줄 세포처럼 끈적하게 직접 꽂아다 하나로 동기 전파하여 사용하는 초강결합(Ultra-Tight Coupling) 모놀리식 아키텍처는, C++ 시스템 베이스 규모가 커질수록 개발자들에게 막대하고 잔혹한 기술 부채(Technical Debt)의 청구서를 가차 없이 들이민다.
- 단일 메모리 크래시의 치명적 전체 전파(Crash Propagation): 느슨하게 결합된 네트워크의 PX4에서는 하나의 타스크 스레드가 터져도 시스템 복원이 가능했다. 그러나 Ardupilot에서는 특정 비행 모드 구석의 수학 로직 분기에서 주니어 개발자의 실수로 널 포인터 역참조(Null Pointer Dereference)나 배열 오버플로우 메모리 침범 누수가 단 한 픽셀이라도 발생하는 순간, 램 공간에 위치한 글로벌
Copter통합 객체의 인접 메모리 주소가 파괴 침범되며 운영체제 전체 시스템이 세그멘테이션 폴트(Segmentation Fault) 패닉 하드 록(Hard lock)에 빠진다. 메인 루프 전체가 동시에 0.001초 만에 멈춰 굳어버려 그 즉시 기체가 공중에서 프로펠러가 멎은 채 돌덩이처럼 수직 추락한다. - 지옥불의 족쇄, 풀 리컴파일(Full Recompile): 하단 센서 코어의 심장인
ahrs나 전역ins클래스 헤더 파일에 메서드 함수 원형 파라미터를 하나라도 C++ 문법으로 수정하거나 새로 추가하면, 이를 직접#include하여 피를 빨아먹듯 포인터 참조하고 있는 상단의 수십 개의 하위 비행 모드 코드와 전체 C++ 링커 의존성(Dependency) 트리가 와장창 다 깨져버리며 펌웨어 소스 시스템 80% 이상을 컴파일러가 강제로 풀 리컴파일(Full Recompile) 해야 하는 기나긴 시간 단위의 빌드 고통을 매번 수반한다. 독립된 모듈 하나만 뽑아내어 스마트하게 컴파일하는 것은 사실상 불가능의 영역이다. - 독립 유닛 테스트(Unit Test)의 철저한 좌절: 거대 전역 변수에 메인 로직들이 거미줄처럼 물려 있다 보니, 외부 연구원 팀이 코어를 건드리지 않고 비행 모드 알고리즘 하나만을 예쁘게 격리 떼어내어 그루터기 가짜 단위 데이터(Mocking Injection)를 우아하게 주입해 순수 소프트웨어 유닛 테스트 시뮬레이션 환경(SITL Sandbox)을 구축하기가 아키텍처적으로 무척이나 까다롭고 고통스럽다는 모던 소프트웨어 엔지니어링의 한계를 여실히 드러낸다.