19.5.1.3. 타임아웃(Timeout) 파라미터 튜닝 및 지연(Latency) 허용 범위 설정
px4_pollfd_struct_t 배열이라는 잔혹하고 정밀한 VFS 감시 명세서 트랩 코드까지 외곽에 완벽하게 타설했다면, 드디어 실체적인 C++ 무한 루프 블록 안쪽 심연으로 진입하여 이 명세서 배열을 커널 스케줄러의 아가리에 던져 넣고 스레드의 강제 수면과 번개 같은 기상을 통제하는 위대한 px4_poll() 시스템 콜을 타격할 시간이다.
이때 이 px4_poll 매크로 함수의 마지막 인자 파라미터로 들어가는 가장 치명적이고 무미건조한 텍스트 숫자가 하나 있는데, 이것이 바로 타임아웃(Timeout) 물리적 밀리초(ms) 파라미터이다.
초보자들은 이 매크로 파라미터를 단순히 스레드가 ’얼마를 잠잘 것인가’로 무식하게 오해한다. 절대 아니다. 스레드를 깨우는 권한은 앞선 단원에서 배운 POLLIN 물리 인터럽트에 있다. 이 타임아웃 변수의 파괴적인 설계 철학은 바로 **“만약 저 건너편 퍼블리셔가 불의의 충격으로 죽어버리거나 I2C 단선이 나버려 수신 버퍼 쪽에 데이터가 영원히 물리적으로 오지 않는다면, 내 스레드는 시스템에서 언제까지 무한 대기(Block)하다가 포기(Give-up)하고 스스로 락을 비상 해제한 채 깨어날 것인가?”**를 개발자가 커널에게 선언 맹세하는 시스템 생명선(Lifeline)이자 사형 선고 시간(Deadline)이다.
1. px4_poll()의 타격 아키텍처와 분기별 Timeout 파싱
// 1. 루프 외곽 위에서 타설한 명세서 (크기 1짜리 배열 컨테이너)
px4_pollfd_struct_t fds[1];
fds[0].fd = sensor_sub_fd;
fds[0].events = POLLIN;
while (!thread_should_exit) {
// 2. [PX4 스케줄링의 알파와 오메가] px4_poll() 강제 블로킹 타격
// - 첫 번째 인자 fds: 내가 감시를 청부하고 싶은 타겟 대상 목록 객체 배열 주소
// - 두 번째 인자 1: 내가 넘긴 fds 배열 메모리 크기 (지금은 1개 채널만 집중 감시)
// - 세 번째 인자 1000: Timeout 파라미터 (단위: 밀리초 ms).
// "데이터가 안 와도 내 스레드는 수면 큐에서 '최대 1초'까지만 물리적으로 기다리겠다"는 생존의 절대 선언
int poll_ret = px4_poll(fds, 1, 1000);
// 3. px4_poll() 시스템 콜의 세 가지 치명적이고 운명적인 분기 반환값 파싱
if (poll_ret == 0) {
// [Timeout 데드라인 붕괴] 1000ms라는 긴 시간 동안 버퍼단에 단 한 번의 POLLIN 이벤트도 전송되지 않았음.
// 이것은 단순 데이터 지연이 아니라 퍼블리셔 데몬이 멈췄거나 하드웨어 케이블이 단선되었음을 확증하는, 가장 치명적인 에러 케이스이다.
PX4_ERR("Timeout Error! No sensor payload received for 1 entire second. Failsafe algorithm triggered.");
continue; // 무거운 연산을 전면 포기하고 루프를 리셋하여 비상 Failsafe 모드로 넘긴다.
} else if (poll_ret < 0) {
// [Fatal Kernel Error] 타임아웃이 아니라, 시스템 내부의 VFS poll 큐 자체가 찢어졌거나 심각한 메모리 오류 발생
PX4_ERR("px4_poll system core returned a fatal OS error: %d", poll_ret);
continue;
}
// 4. [인터럽트 초광속 기상 대성공 구간]
// poll_ret > 0 값 반환: 1000ms의 Timeout이 끝나기 그 이전에, 누군가 VFS 버퍼 꼬리단에
// 데이터를 내려써 발생시킨 POLLIN 하드웨어 인터럽트로 스레드가 영광스럽게 기상 강제 멱살 잡힌 경우!
if (fds[0].revents & POLLIN) { // 내가 세팅한 배열의 결과 이벤트(revents) 레지스터가 POLLIN을 확정 지었다면
// [중복 오버헤드 0%의 진정한 최신 물리적 데이터 획득 구간]
// 새로운 데이터가 버퍼망에 존재한다는 사실을 커널이 이미 물리적으로 100% 보장(Guarantee)하므로,
// 19.4단원의 그 구질구질한 orb_check 따위의 방벽은 다 무시해버리고 무지성으로 통쾌하게 orb_copy만 때려 단번에 구조체를 훔쳐 온다.
sensor_test_data_s sensor_data_raw{};
orb_copy(ORB_ID(sensor_test_data), sensor_sub_fd, &sensor_data_raw);
PX4_INFO("Interrupt explicitly fired! Subscribed New Perfect Temp: %.2f", (double)sensor_data_raw.temperature);
// ... 이하 무거운 비즈니스 모터 믹싱, 제어, EKF 칼만 매트릭스 알고리즘 등을 이곳에서 처리한다 ...
}
}
2. 시스템 추락선과 Timeout 지연(Latency) 허용의 끔찍한 딜레마 역학
위 기초 예제 뼈대 모델에서 초보자답게 타임아웃을 낭만적인 1000(1초) 물리량으로 잡은 것은 시스템 안전그물(Safety Net)을 아주 느슨하고 게으르게 펼친 덜 치명적인(Non-critical) 데몬 케이스이다.
하지만 만약 당신이 설계하고 통제하는 이 모듈이 400Hz로 미친 듯이 실시간 동작해야만 하는 고속 ESC 모터 믹서(Mixer) 이너 루프(Inner-loop) 데몬이라면 어떨까?
원래 그 파이프의 자이로 센서 송출 빈도가 정규 스펙 마진상 무조건 400Hz(2.5ms 주기)씩 쏟아져야 하는 데이터인데, 감시자인 당신이 멍청하게 타임아웃 파라미터를 똑같이 1000ms로 잡아둔다면? 자이로 센서 I2C 보드가 불의의 충격으로 죽었을 때, 모터 믹서 스레드는 그 죽음도 모른 채 1초 동안 어리바리하게 멍때리며 VFS에서 하염없이 블로킹(Blocking)되어 기다리게 된다. 결국 그 영원의 1초 동안 수천만 원짜리 산업용 드론은 공중에서 어떠한 PWM 출력 제어도 스케줄링받지 못한 채 허공에 모터를 끄고 자유낙하 추락해 완전히 박살 나버릴 것이다.
이런 초고속 크리티컬 생존 데몬의 경우 타임아웃 파라미터 숫자를 반대로 역으로 매우 타이트하게, 예를 들어 10(10ms) 단위로 아주 거칠고 잔인하게 조여버려야 한다. 퍼블리셔가 단 10ms만 데이터를 늦게 써서 지연(Latency)시켜도 커널이 즉각 “센서 타임아웃 기절!” 알람을 올려버리게 만들고, 메인 제어 보드가 예비(Redundant) 멀티플렉싱 센서로 강제 스위칭을 단행하거나, 전체 비행 모드를 비상 Failsafe(추락 방지 귀환) 모드로 긴급 피벗 변환하도록 칩셋의 생존 지연(Latency) 오차 허용 범위를 물리적으로 극단적으로 제한해야만 하는 것이다.
수만 줄의 펌웨어 시스템 상에서 이 px4_poll 타임아웃 숫자 하나하나의 파라미터 에지 튜닝을 예술적으로 맞물리는 통제야말로, 기체 전체의 목숨을 쥐고 물리적으로 흔드는 시스템 통합 미들웨어 아키텍처 스케줄링의 진정한 묘미이자 전부이다.