21.7.2. 인터럽트 핸들러 레벨의 콜백 기반 스케줄링 트리거

21.7.2. 인터럽트 핸들러 레벨의 콜백 기반 스케줄링 트리거

지금까지 우리는 내 모듈의 Run() 함수 안에서 “혹시 나한테 새로 온 uORB 데이터 없나?” 하고 기웃거리는 ‘구독(Subscription)’ 방식만을 살펴보았다.
이를 흔히 폴링(Polling) 방식이라고 부른다. 정주기(예: 100Hz)로 알람을 맞춰놓고 깨어나서 우체통을 확인하는 구조다.

하지만 레이싱 드론처럼 빛의 속도로 반응해야 하는 초고속 제어기에서는 이 폴링 방식의 치명적인 한계가 드러난다.

1. 폴링 방식의 지연 시간(Latency)의 한계

자이로 센서 드라이버가 I2C 통신을 통해 아주 신선한 각속도 데이터를 읽어와서 sensor_gyro 토픽에 출판(Publish) 했다고 치자.
그런데 불행하게도 내 자세 제어 모듈(mc_rate_control)은 불과 1ms 전에 깨어나서 빈 우체통을 확인하고 타임머 알람을 10ms 뒤로 맞춘 채 잠에 빠져든 상태다.

새로운 데이터는 이미 메모리에(uORB 게시판에) 올라와 있지만, 내 제어 모듈은 다음 알람이 울릴 때까지 남은 9ms 동안 세상 모르게 잠들어 있게 된다.
이 9ms의 데이터 지연(Data Age)은 초고속 제어기 입장에서는 치명적인 위상 지연(Phase Lag)을 유발하여 드론을 벌벌 떨게(Oscillation) 만든다.

초고속 비행을 위해서는 내 알람 시계(타이머)에 의존할 것이 아니라, **“우체부가 데이터를 넣는 즉시 나를 강제로 발로 차서 깨워달라”**는 이벤트 기반(Event-driven) 푸시(Push) 구조가 절실하게 필요했다.

2. 콜백(Callback): 하드웨어와 소프트웨어의 직결통로

PX4 코어팀은 이 딜레마를 해결하기 위해 운영체제의 심장부, 즉 uORB 토픽이 발행되는 인터럽트 핸들러(Interrupt Handler) 레벨에 직접 핀을 꽂을 수 있는 콜백(Callback) 메커니즘을 설계했다.

콜백 메커니즘의 철학은 다음과 같다:

  1. 센서 드라이버가 하드웨어 인터럽트(ISR)를 받아 데이터를 uORB에 orb_publish() 하는 순간, 커널 내부에서 uORB 매니저가 깨어난다.
  2. uORB 매니저는 이 토픽에 알람줄(Callback)을 묶어둔 구독자가 있는지 확인한다.
  3. 알람줄이 있다면, 그 즉시 구독자 모듈의 멱살을 잡고 ScheduleNow() 함수를 강제로 호출하여 Work Queue의 최상단에 쑤셔 넣는다!

이 덕분에 10ms 정주기 타이머 같은 엉성한 시계는 완전히 박살 나고, 센서 칩의 하드웨어 클럭(Hardware Clock)에서 발생한 전기 신호가 단 1ms의 지체도 없이 내 제어 루프의 C++ 코드로 직행하는 ’제로 레이턴시(Zero-latency)’의 기적이 완성된다.

그렇다면 구체적으로 내 C++ 클래스를 커널의 콜백 시스템에 어떻게 바인딩(Binding)시킬 수 있을까?
PX4가 제공하는 궁극의 템플릿 마법, SubscriptionCallbackWorkItem 클래스의 사용법을 다음 21.7.2.1 단원에서 상세히 조립해 보자.