21.1.1.2.2. 하드 리얼타임(Hard Real-time) 요구사항을 가지는 인루프(In-loop) 제어 모듈의 제약 사항

21.1.1.2.2. 하드 리얼타임(Hard Real-time) 요구사항을 가지는 인루프(In-loop) 제어 모듈의 제약 사항

앞서 살펴본 데몬(Daemon) 컨텍스트가 여유로운 폴링(Polling)과 수면을 즐기는 우아한 세계였다면, ‘인루프 제어 모듈(In-loop Control Module)’ 컨텍스트는 단 0.001초의 틈바구니 속에서 생존과 추락을 결정지어야 하는 전쟁터이다. 인루프란 센서 데이터를 받아들여 기체의 물리적 거동 수식(예: PID)을 연산하고, 즉시 모터의 PWM 신호로 뿜어내는 ’핵심 제어기 경로(Controller Path)’에 여러분의 사용자 정의 코드가 직접 엮여 들어가는 것을 의미한다.

여러분이 기존의 연속적인 이송(Translation) 제어에서 벗어나 딥러닝 기반의 강화학습 에이전트(RL Agent)나 비선형 적응 제어기(Nonlinear Adaptive Controller)를 C++ 모듈로 포팅(Porting) 하려고 한다면, 여러분의 코드는 필연적으로 이 가혹한 하드 리얼타임(Hard Real-time) 인루프의 제약을 뚫고 나가야만 한다.

1. 하드 리얼타임(Hard Real-time)의 무자비한 철칙

소프트 리얼타임(Soft Real-time) 환경인 동영상 재생기나 웹 서버는 프레임이 10ms 밀리거나 렉이 걸려도 사용자가 짜증을 낼 뿐 치명적인 사고로 이어지진 않는다. 그러나 드론의 제어 모듈에 내려지는 하드 리얼타임의 율법은 **“반드시 약속된 시간(Deadline) 안에 연산 결과를 도출하라. 마감 기한을 넘긴 정답은 오답(추락)과 같다.”**는 것이다.

인루프 모듈은 이 절대시간 마감 기한을 맞추기 위해 일반 사용자 앱과는 완전히 다른 실행 구조와 금기 사항을 감내해야 한다.

1.1 절대 금지 조항: 블로킹 메커니즘 (No Blocking Wait)

인루프 계층의 사용자 모듈에서 절대 해서는 안 될 가장 멍청하고 위험한 짓은 스레드의 흐름을 고의로 막는 것이다.

  • sleep()이나 usleep()의 금지: 연산 중간에 1ms라도 스레드를 재워버리면, 그 1ms 동안 기체가 기울어지는 것을 보상할 모터 명령이 끊긴다.
  • 복잡한 I/O 호출 금지: printf를 통한 시리얼 포트 출력이나, FILE* 포인터를 연동한 SD 카드 로깅은 하드웨어 버스 스케줄에 종속되므로 락(Lock)이 걸릴 확률이 매우 높다. 인루프 안에서 로그를 찍고 싶다면, 절대 직접 쓰지 말고 uORB 로깅 토픽이나 PX4_INFO 매크로(내부 비동기 큐잉 처리됨)만 사용해야 한다.
  • 스핀락(Spinlock) 및 무거운 뮤텍스(Mutex) 주의: uORB 메시지를 읽을 때 락(Lock)을 잡게 되면, 데드락(Deadlock)에 빠질 확률이 기하급수적으로 올라간다. PX4의 uORB::Subscription 래퍼들이 내부적으로 락-프리(Lock-free)나 최소한의 권한 위임만 사용하는 이유가 여기에 있다.

1.2 콜백 기반의 협력형 스케줄링 (Cooperative Callback)

데몬이 while(true) 형태의 무한 루프를 도는 반면, 인루프 제어 모듈은 Work Queue 스케줄러라는 거대한 톱니바퀴의 하나의 날로 강제로 편입된다 (21.1.2 단원 참조).

  • 실행 권한 얹혀가기: 여러분의 모듈은 스스로 깨어나지 못한다. EKF2 같은 선행 모듈이 자이로스코프 데이터를 모두 갱신한 순간, OS 레벨 인터럽트나 스케줄러가 여러분의 모듈의 Run() 콜백 함수를 강제로 호출(Trigger)해 준다.
  • 빠른 반환 (Yielding): Run() 함수가 호출되어 진입했다면, 허락된 시간(예: 250us) 내에 벡터 내적이나 행렬 곱 같은 수식을 모두 마치고 모터 토픽을 퍼블리싱한 뒤, 반드시 함수의 끝(return;)에 도달하여 제어 지휘봉을 스케줄러에게 신속히 반납해야 한다.

결국 인루프 제어 모듈의 본질은, 자신이 원할 때 일어나는 것이 아니라 **“센서가 새로고침되는 타이밍(Frequency)에 강제로 호출받고, 가장 빨리 방 빼주는 순종적인 수학 연산기”**여야 한다는 뜻이다.

초보 연구원들이 매트랩(MATLAB)에서 자동 생성된(Autocast) 무겁고 비효율적인 수십만 줄의 C코드를 PX4 제어 루프 컨텍스트에 그대로 붙여 넣었다가 기체가 이륙조차 못 하고 스텝 오버(Step-over) 버그로 재부팅되는 이유가 이 하드 리얼타임 철칙을 무시했기 때문이다. 다음 단원에서는 이 무자비한 콜백 구조를 지탱하는 스케줄링 패러다임의 혁명, 즉 Task에서 Work Queue로 변모한 아키텍처적 진화를 현미경으로 들여다볼 것이다.