21.7.4. 폴링(Polling)을 활용한 다중 토픽 동기화 융합
지금까지 우리는 비행 제어기(mc_rate_control)처럼 자이로 센서 하나만 바라보며 빛의 속도로 반응해야 하는 단일 토픽(Single Topic) 이벤트 기반 아키텍처를 살펴보았다.
하지만 세상 모든 모듈이 그렇게 단순하지만은 않다.
드론의 위치와 속도를 추정하는 핵심 필터인 EKF(Extended Kalman Filter, 확장 칼만 필터) 모듈을 상상해 보자. EKF는 다음과 같은 수많은 센서 데이터들을 한곳으로 모아 융합(Fusion)해야 비로소 의미 있는 결괏값을 계산해 낼 수 있다.
- IMU (자이로/가속도): 250Hz로 미친 듯이 들어옴
- 마그네토미터(지자기 센서): 50Hz로 간간이 들어옴
- 기압계(Baro): 20Hz로 느긋하게 들어옴
- GPS: 5Hz로 가끔 한 번씩 툭툭 던져짐
이 상황에서 만약 EKF가 앞서 배운 이벤트 기반 콜백(SubscriptionCallbackWorkItem)을 모든 센서 토픽에 덕지덕지 달아놓는다면 어떻게 될까?
GPS가 들어올 때 콜백으로 깨어나서 EKF를 돌리려다가 계산이 끝나기도 전에 IMU가 250Hz로 콜백을 때리면서 스레드가 미친 듯이 큐를 들락거리는 대혼란(Thrashing)이 발생할 것이다.
1. 다중 토픽 동기화의 딜레마
EKF 같은 데이터 융합(Sensor Fusion) 모듈이 원하는 것은 개별 센서의 즉각적인 알람이 아니다.
**“IMU, 지자기, 기압계, GPS 데이터가 각자의 주기로 날아올 텐데, 가장 핵심이 되는 기준 센서(예: IMU)의 데이터가 도착했을 때 깨어나서, 그동안 나머지 센서 우체통에 쌓여있던 값들을 한꺼번에 싹 쓸어 담아 계산하고 싶다”**는 것이다.
이러한 **동기화 대기(Synchronized Waiting)**를 구현하기 위해, PX4는 최신 이벤트 기반 콜백 패러다임을 잠시 내려놓고 Linux/Unix의 전통적인 다중 I/O 감시 기법인 poll() 시스템 콜 매커니즘을 꺼내 든다.
2. px4_poll 구조
px4_poll 함수는 원래 소켓 통신이나 파일 입출력에서 여러 개의 파일(File Descriptor 번호) 중 어느 하나라도 읽을거리가 생겼는지 멈춰서 기다리는(Blocking) 함수다. PX4는 uORB 토픽들을 마치 파일처럼 다루기 때문에, 이 poll 함수를 이용해 여러 토픽을 동시에 감시(Monitoring)할 수 있다.
이 방식의 철학은 다음과 같다:
- 관심 있는 토픽들을 배열로 묶는다: IMU, GPS, 기압계를 하나의 배열(Poll Array)에 등록한다.
- 동기화 대기 (Blocking Wait):
px4_poll함수를 호출하여 “이 배열에 등록된 토픽 중 단 하나라도 새 데이터가 도착할 때까지 내 스레드를 잠재워(Sleep) 줘!” 라고 커널에 명령한다. - 일괄 수거: 누군가(예: IMU) 데이터를 쏴서 스레드가 깨어나면, 배열 안의 모든 토픽 우체통을 순회하며 그동안 도착해 있던 최신 데이터들을 몽땅 복사(Copy)해 온다.
이 투박해 보이는 타임아웃과 폴링(Polling) 기법이 어떻게 수많은 센서들의 파편화된 타임스탬프를 하나로 정렬시키고, 잃어버린 데이터(Drop)의 구멍을 메워내는지, 그 강력하고 고전적인 구조체 배열(px4_pollfd_struct_t) 구축의 예술을 다음 장 21.7.4.1에서 파헤쳐보자.