19.4.1.2. `orb_copy()`를 이용한 최신 데이터 스냅샷(Snapshot) 획득 구조

19.4.1.2. orb_copy()를 이용한 최신 데이터 스냅샷(Snapshot) 획득 구조

앞선 orb_subscribe() 시스템 콜의 고된 타격을 통해, 거대한 링 버퍼(Ring Buffer) 우체통에서 내 스레드로 다이렉트 직결되는 하나뿐인 전용 VFS 파이프라인 수신 마스터 키(sensor_sub_fd)를 손에 쥐었다면, 이제 자비 없는 무한 루프 감옥 안으로 용감하게 뛰어 들어갈 차례이다.
스레드의 무한 루프가 회전(Tick)할 때마다, 우리는 방금 꽂아 넣은 이 파일 디스크립터 빨대를 통해 링 버퍼의 가장 윗단(Top)에 고여있는 가장 따끈따끈한 최신 데이터 복사본 단 1개를 내 로컬 스레드 메모리 방 안으로 폭력적이고도 무지성으로 흡입 강탈해 오는 행위, 바로 orb_copy() C 코어 매크로 함수의 강제 집행을 감행한다.

1. orb_copy() 매크로 함수의 물리적 데이터 탈취 타격

orb_copy()는 커널의 젠틀한 동기화 인터럽트 신호를 조신하게 기다려주는 예의 바른 녀석이 아니다. 내 데몬 루프가 usleep에서 깨어난 바로 그 찰나의 순간에 즉결 처분하듯 VFS 링 버퍼 노드에 돌격하여, “지금 당장 버퍼 꼬리(Tail) 끄트머리에 묻어 있는 가장 마지막 스냅샷을 통째로 내놔라!“라고 메모리를 협박하는, 아주 무자비하고 일방적인 블록 카피(memcpy) 함수이다.

while (!thread_should_exit) {

    // 1. 방금 빨대로 빨아들일 파이프 건너편의 동종 신선한 데이터를 담기 위한 텅 빈 수신용 C++ 구조체 깡통을 타설한다.
    // [절대 철칙]: 이전 루프 사이클에서 사용한 내 스레드의 쓰레기값을 완벽히 씻어내기 위해 반드시 영 초기화(Zero-init, {}) 타격을 때린다.
    sensor_test_data_s sensor_data_raw{};

    // 2. [가장 폭력적이고 무지성적인 데이터 강탈] orb_copy() 시스템 콜 링커 타격
    // - 첫 번째 인자 ORB_ID(sensor_test_data): VFS를 파고드는 메타데이터 절대 DNS 앵커 심볼
    // - 두 번째 인자 sensor_sub_fd: 루프 진입 전 내가 읍소해 겨우 얻어낸 파이프라인 핸들 마스터 키
    // - 세 번째 인자 &sensor_data_raw: 미들웨어에서 훔쳐 온 생 데이터를 덮어씌워버릴(Overwrite) 내 로컬 메모리 주소 포인터
    int copy_ret = orb_copy(ORB_ID(sensor_test_data), sensor_sub_fd, &sensor_data_raw);

    // 3. 메모리 카피 실패(Fault)에 대한 최소한의 빙벽 방어 처리망
    if (copy_ret == PX4_OK) {
        // 복사 대성공: 이 통제선을 뚫은 시점부터 sensor_data_raw 안의 온도, 스칼라값 등은 
        // 방금 건너편 퍼블리셔가 쏜 그 위대한 최신 값으로 완전히 오버라이트(Overwrite) 복제되었다.
        PX4_INFO("Subscribed Latest Temp: %.2f", (double)sensor_data_raw.temperature);
    } else {
        // VFS 노드 포인터가 깨졌거나, 부팅 직후라 아직 단 한 명의 퍼블리셔 생존자도 데이터를 쏘지 않아 통신 버퍼가 완전히 텅 비어있는(Empty) 상태
        PX4_WARN("Ring buffer is currently deeply empty or corrupted. Skipping this physical loop.");
    }

    // 4. [매우 중요] 이기적인 내 스레드 혼자만 CPU를 지독하게 100% 독식하여 
    // 나를 제외한 다른 핵심 데몬들을 기아(Starvation) 상태로 죽이지 않도록, 반드시 자발적 수면(Sleep)에 돌입!
    // 이것이 바로 Simple Read 방식 데몬이 버티는 유일한 커널 생명선이다.
    px4_usleep(200000); // 200ms (5Hz) 주기로 타이머 대기
}

2. Simple Read 스냅샷의 치명적인 한계와 100% 맹점의 짙은 그늘

orb_copy() 기반의 1차원적인 단순 무지성 맹목적 읽기 아키텍처는, 그 코딩 접근성이 구글링 코드 복붙만으로도 우스울 정도로 너무나 쉽고 직관적이지만, PX4 코어 펌웨어 생태계 아키텍처 관점에서는 도저히 묵과할 수 없는 두 가지의 커다란 맹점(Blind Spot) 딜레마를 필연적으로 안고 있다.

  1. Over-reading (무의미한 중복 섭취의 CPU 낭비): 만약 저 반대편 퍼블리셔 모듈이 느려터져 데이터를 고작 초당 1번(1Hz) 쏘는데, 역으로 내 굶주린 구독자 루프가 초당 10번(10Hz)의 스케줄러로 돈다면 어떻게 될까? 내 데몬은 orb_copy()를 무식하게 10번 연속으로 때려대며, 값이 하나도 변하지 않은 “방금 먹고 소화 끝난 옛날 데이터“를 10번 중복해서 다시 씹어먹어대며 불필요한 필터 연산력(CPU Cost)을 허공에 미친 듯이 태워버리게 되는 대참사가 빚어진다.
  2. Under-reading (데이터 타임라인 공중 증발): 반대로 퍼블리셔는 센서 레지스터를 실시간으로 긁어대며 100Hz로 미친 듯이 쏘는데, 유독 내 게으른 수신 루프가 px4_usleep 세팅 오판으로 5Hz로 더럽게 느리게 돈다면? 나는 1초에 단 5개의 파편 스냅샷만 건져 올릴 뿐, 그 사이 빈 공간에 낀 95개의 살아 숨 쉬는 귀중한 동역학 데이터들의 맥박은 내가 빨아들이기도 전에 이미 퍼블리셔의 다음 데이터 인젝션에 의해 memcpy 덮어씌워지며(Overwritten), 이 세상에 흔적도 없이 심연으로 영구 폐기 폭파(Drop)증발해 버린다.

그렇기 때문에 이 원시적인 아키텍처 기법은, EKF 고속 자세 제어 매트릭스나 ESC/모터 고속 PWM 출력 루프처럼 데이터 맥박 프레임 하나하나의 유실이 모두 기체의 즉각적 자유 낙하 추락으로 연결되는 크리티컬 코어 비행 제어 모듈에는 “맹세컨대 시스템 역사상 절대로(Never) 구현 사용되어서는 안 되는” 쓰레기 1세대 임시방편(Workaround)일 뿐이다.