18.8.2.1. `uxrce_dds_client` 앱 내에서의 uORB 이벤트 루프 및 DDS 퍼블리셔/서브스크라이버 양방향 매핑 테이블

18.8.2.1. uxrce_dds_client 앱 내에서의 uORB 이벤트 루프 및 DDS 퍼블리셔/서브스크라이버 양방향 매핑 테이블

PX4-Autopilot과 ROS 2 분산 운영체제 간의 초연결(Hyper-connectivity) 시대를 개막한 Micro XRCE-DDS 클라이언트(Client) 모듈은 단순한 네트워크 소켓(Socket) 드라이버 래퍼(Wrapper)가 아니라, 그 자체로 고속 펌웨어 스케줄링 전략이 집약된 하나의 독립된 생태계(Sub-system App)이다. 이 핵심 백그라운드 프로세스는 uORB 미들웨어의 가파른 토픽 흐름과 외부 단말망 DDS 에이전트의 I/O 이벤트 사이에서 영리한 교통순경이자 능동적 번역기 역할을 전담한다. 본 절에서는 uxrce_dds_client 앱의 런타임 C++ 루프 구조와, 그 내부적으로 관리되는 퍼블리셔(Publisher)/서브스크라이버(Subscriber) 간의 양방향 매핑 테이블(Mapping Table) 런타임 아키텍처를 심층 분석한다.

1. 메인 이벤트 루프: 다중 프로토콜 폴링(Polling) 통합 아키텍처

uxrce_dds_client 노드의 메인 제어 실행 루틴은 크게 두 가지의 근본적으로 이질적인 데이터 소스를 단 하나의 단일 C++ 스레드(Thread)에서 동시에 비동기 감시(Asynchronous Polling)해야 하는 극단의 논리 설계적 난제를 안고 있다. 하나는 내부 커널 VFS 레벨에서 수시로 깨어나는 PX4 uORB 하드웨어 토픽 업데이트 이벤트이고, 다른 하나는 직렬 포트(UART)나 이더넷 물리망 등에서 불규칙적으로 밀려 들어오는 글로벌 Micro-XRCE-DDS 외부 패킷 수신 이벤트이다.

// uxrce_dds_client 메인 이벤트 루프의 아키텍처 개념적 구조
void UxrceDdsClient::run() {
    while (!should_exit()) {
        // [1] 외부망 DDS 에이전트로부터의 다운스트림(수신) 통신 확인 (Non-blocking)
        // (RX 큐에 들어온 ROS 2 외부 비전 명령 등이 있는지 확인하고 즉시 로컬 uORB로 퍼블리시)
        uxr_run_session_until_timeout(&_session, 10 /* timeout ms */); 

        // [2] 펌웨어 내부망 uORB 토픽 업데이트 검사 (업스트림 송신 준비)
        // (컴파일 타임에 생성된 내부 _publishers 큐 루프 순회)
        for (auto& pub : _publishers) {
            if (pub.update()) {
                // uORB 신규 비행 데이터 물리 도달: DDS 프로토콜 망으로의 송신 큐(TX) 스트림 예약
                uxr_prepare_output_stream(&_session, ...);
            }
        }
        
        // [3] RTOS 스케줄러 컨텍스트 양보 (Yield)
        px4_usleep(1000); // 1,000Hz 베이스라인 틱(Tick) 유지 및 CPU 과점 방어
    }
}

이 견고한 비동기 이벤트 루프는 C 라이브러리의 uxr_run_session_until_timeout API를 주축으로 호출하여, 외부 ROS 2 노드로부터 라우팅 수신된 명령(예: 외부 AI가 내리는 웨이포인트 이동 비행 명령, 모터 시동 해제 제어 신호 등)이 있는지 먼저 I/O 폴링(Polling)하고 즉시 내부 처리한다. 그리고 곧바로 등록된 PX4 기체 내부 uORB 센서 토픽 목록(_publishers 배열 큐)을 순회 조사하면서 새로운 IMU나 GPS 상태 갱신 이벤트를 체크해 낸다. 이 거시적 양방향 폴링 과정 구역은 극도로 자원 효율화되어 구현되어 있어 EKF2 등 타 비행 메인 믹서(Mixer) 루프의 지연(Latency)에 일절 간섭을 발생시키지 않는다.

2. YAML 도메인 기반의 양방향 매핑 테이블(Mapping Table) 정적 컴파일

현대 PX4 호스트 펌웨어에는 현재 식별 가능한 것으로만 200개가 넘는 매우 방대한 uORB 메타 시스템 토픽이 존재하지만, 이 모든 마이크로 데이터를 ROS 2 네트워크 망으로 생각 없이 모두 쏘아 올린다면 하드웨어의 유선 시리얼 대역폭(통상 921600bps 텔레메트리 보레이트 구역)은 불과 수 초 만에 즉시 포화(Saturation) 상태로 먹통이 될 것이다.

따라서 uxrce_dds_client 모듈은 자신이 거대한 ROS 2 생태계와 선택적으로 통신할 구체적인 대상 목록 쌍을 사전에 규정한 **하드 매핑 테이블(Mapping Table)**을 지니고 있다. 이 매핑은 빌드 전 개발자가 펌웨어 소스 트리 내의 .yaml 파일(예: dds_topics.yaml 설정 파일) 테이블 구조를 텍스트 편집함으로써 통제 선언된다.

  • 업스트림 송신(Publish) 테이블 매핑: 기체(PX4) 내부의 특정 상태 uORB 센서 토픽(예를 들어 sensor_gps)의 FD 노드를 구독 바인딩하여, 이를 가로채어 외부 ROS 2 망에 특유의 계층형 DDS 토픽 이름 규칙 구조(fmu/sensor_gps/out)로 네임스페이스를 역변환하여 퍼블리싱(Publishing)하도록 스레드를 연결한다.
  • 다운스트림 수신(Subscribe) 테이블 매핑: 반대로 외부 ROS 2 지능 제어망의 특정 인터페이스 명령 토픽(fmu/vehicle_command/in 등) 노드 포인트를 클라이언트가 영구 구독(Listen)하여, 외부 인터럽트 수신된 직렬 데이터를 언패킹(Unpacking) 및 역직렬화(Deserialize)한 뒤 픽스호크 칩 내부 깊숙한 메인 C++ uORB 링 버퍼에 동일한 호스트 원본 이름(vehicle_command)으로 정식 발행(Publish)하도록 시스템 백 채널을 바인딩한다.

파이썬 기반 CMake 빌드 스크립트 툴체인은 이 YAML 파일의 유저 선언 레이어들을 모아다가, 하드 코딩된 정적 C++ 배열 구조체 소스 코드(예: dds_topics.h/cpp 결합체)로 빌드 타임에 완벽히 변환(Transpile AOT Compile) 해 낸다.
이는 런타임 루프 환경에 동적으로 트리 구조 딕셔너리 매핑 테이블을 룩업(Lookup)하는 무겁고 변동성 높은 문자열 비교 해시(Hash) 연산을 아키텍처적으로 원천 배제하는 묘수이다. 런타임에는 오직 C 배열 인메모리 인덱스(Index) 오프셋 점프 매핑만을 사용하여, RAM 메모리 파편화 방지와 CPU 클럭 사이클 비용 파괴 측면에서 궁극의 리얼타임 제로 오버헤드(Zero Overhead) 라우팅을 우아하게 관철하게 만든다.

결론적으로 uxrce_dds_client 데몬의 통합된 폴링 이벤트 루프와 강력한 정적 컴파일 AOT(Ahead-of-Time) 매핑 테이블 조합은, ROS 2라는 외부 바깥세상의 거대한 AI 지능 파이프라인 엔진과 PX4라는 작은 내부 하드 실시간 반사 신경 사이의 벽을 가장 구조적으로 안전하고 기민 명쾌하게 접합하는 C++ 임베디드 오프보드(Off-board) 네트워크 코딩 디자인의 눈부신 걸작이라 칭송할 수 있다.