19.8.3.1. 타임스탬프(Timestamp) 누락으로 인한 로거(Logger) 기록 실패 원인 분석
수많은 초급 uORB 데몬 개발자들이 자신들의 첫 번째 비행 테스트(Flight Test)를 마치고 랩으로 돌아와 노트북에 SD 카드를 꽂는 순간 겪는 가장 흔하고 절망적인 미스터리가 있다.
분명 비행 내내 QGroundControl 화면에는 내 모듈 시스템이 잘 작동한다고 떴고, NSH 터미널에서 listener를 쳤을 때도 구조체 숫자들이 미친 듯이 잘 올라갔는데, 막상 SD 카드에서 뽑아낸 .ulg 블랙박스 기록 파일을 PlotJuggler나 FlightPlot으로 열어보면 내가 만든 커스텀 센서 데이터만 통째로 하얗게 지워져 있는(Blank) 텅 빈 그래프를 마주하게 되는 현상이다.
이 유령 같은 현상의 절대적인 원인은 99% 확률로, 당신이 C++ 퍼블리셔(Publisher) 코드를 짤 때 가장 첫 줄에 적어 넣어야 했을 단 한 줄의 캐스팅 연산을 까먹었기 때문이다.
1. 로거(Logger) 데몬의 가혹한 생존 심사
PX4 시스템의 백그라운드에는 logger라는 이름의 거대하고 탐욕스러운 데몬이 항상 돌고 있다. 이 녀석의 유일한 목적은 VFS에 떠돌아다니는 수백 개의 토픽들을 입을 벌리고 모조리 빨아들여 SD 카드 메모리로 영구 플러시(Flush)하는 것이다.
하지만 이 로거 데몬은 미친 듯이 빠른 속도로 흘러들어오는 구조체들을 SD 카드에 버일러플레이트 없이 박아 넣기 위해 아주 가혹한 조건 하나를 내건다.
“모든 uORB 구조체의 첫 번째 8바이트 메모리 공간(uint64_t)은 무조건 이 시스템의 최신 절대 생존 시간(Timestamp)이어야만 한다. 만약 이 첫 구멍에 0이 찍혀 있거나 비정상적인 쓰레기 값이 들어있으면, 나는 이 데이터를 영구히 무시(Ignore)하고 SD 카드에 절대 적지 않는다!”
2. 침묵의 살인마: timestamp 할당 누락
당신이 퍼블리셔 Run() 루프 안에서 구조체를 렌더링 할 때, 아래쪽의 온도(temperature) 데이터나 자이로 값 필드만 미친 듯이 채워 넣고 정작 구조체 첫 줄의 timestamp 멤버 변수에 값을 밀어 넣는 행위를 망각해 보자.
// [최악의 퍼블리셔 안티 패턴]
sensor_test_data_s my_data{}; // 구조체 0으로 초기화됨 (timestamp = 0)
// 개발자는 오직 자신의 비즈니스 페이로드 데이터에만 정신이 팔려있다.
my_data.temperature = 25.4f;
my_data.error_count = 0;
// 타임스탬프 할당을 까먹은 채 그대로 발사해 버린다!
orb_publish(ORB_ID(sensor_test_data), _test_pub, &my_data);
이 코드가 빌드되어 드론에 얹혀 날아가는 동안, uORB 커널은 이 데이터가 0살(timestamp = 0)짜리 쓰레기 구조체이건 말건 파이프라인으로 무식하게 배달해 준다. 따라서 터미널에서 listener를 쳐보면 데이터 자체는 아주 예쁘게 보인다(하지만 timestamp 줄을 자세히 보면 시뻘건 에러로 Never published 혹은 NaN이 찍혀있을 것이다).
문제는 SD 카드의 파수꾼인 Logger 데몬이 이 0짜리 타임스탬프를 마주하는 순간, “아! 퍼블리셔가 아직 데이터를 준비하지 않았거나 데드락 상태구나!“라고 논리적 오판을 내리고 이 데이터 패킷 통째를 블랙박스 파일 기록 큐에서 조용히 삭제(Drop) 처리해 버리는 데 있다.
3. 영구적인 해결책: 구조체 최상단 타임스탬프 주입
이 절망적인 사후 맹점(Blind Spot)을 타개하기 위해, 당신이 퍼블리셔 루프를 짤 때는 무조건 함수 스코프의 첫 줄에서 hrt_absolute_time() (High Resolution Timer) API를 타격하여 구조체의 머리통에 생명의 숨결을 불어넣는 습관을 뼈에 새겨야 한다.
// [가장 안전한 무결성 퍼블리셔 패턴]
sensor_test_data_s my_data{};
// 1. [생명줄 타설] 데이터의 심장 박동 시간을 무조건 첫 번째로 각인한다!
my_data.timestamp = hrt_absolute_time();
// 2. 비즈니스 페이로드 삽입
my_data.temperature = 25.4f;
// 3. 우주로 발사 (이제 Logger 데몬이 이 데이터를 완벽히 인식하고 파싱한다)
orb_publish(ORB_ID(sensor_test_data), _test_pub, &my_data);
PX4 생태계에서 **timestamp는 단순한 숫자가 아니라, 그 코드가 살아있다는 것을 시스템 전체에 입증하는 유일한 맥박(Heartbeat)**이다. 이 맥박이 끊기면 당신의 코드는 VFS라는 투명한 우주 속에서 그 흔적조차 남기지 못하고 영원히 미아가 된다는 사실을 실무 현장에서 수천 번 명심해야만 한다.