21.7.1.2.1. `instance` 매개변수를 조정하여 3중 리던던시(Triple Redundancy) IMU 중 특정 인덱스의 데이터만 필터링하는 방법

21.7.1.2.1. instance 매개변수를 조정하여 3중 리던던시(Triple Redundancy) IMU 중 특정 인덱스의 데이터만 필터링하는 방법

앞서 배운 SubscriptionMultiArray가 모든 센서 데이터를 한 줄기로 쓸어 담는 커다란 투망(Cast net)이라면, 단일 Subscription 객체 생성자에 instance 번호를 넘겨주는 방식은 내가 원하는 단 하나의 물고기만 정확히 꿰뚫는 작살(Harpoon)과 같다.

만약 여러분이 드론에 달린 3개의 짐벌 카메라 중에서, 오직 ’2번 카메라’의 각도 데이터만 뽑아서 독립적으로 구동되는 커스텀 객체 인식 모듈을 만들고 싶다면 어떻게 해야 할까?

1. instance 매개변수 하드코딩

가장 단순하고 무식한 방법은 구조체 선언 부에 토픽 이름(ORB_ID)과 함께 내가 원하는 고정된 인스턴스 번호(예: 1번 인스턴스는 두 번째 센서를 의미)를 박아 넣는 것이다.

#include <uORB/Subscription.hpp>

class CustomVisionApp {
private:
    // "나는 묻지도 따지지도 않고 무조건 두 번째(인덱스 1) 짐벌 각도만 구독하겠다!"
    uORB::Subscription _gimbal_sub{ORB_ID(gimbal_device_attitude_status), 1}; 
};

이렇게 instance 매개변수로 1을 넘겨주면, 제아무리 0번이나 2번 짐벌이 초당 100번씩 데이터를 뱉어내도 _gimbal_sub.updated() 함수는 무심하게 false를 반환하며 그 소음(Noise)들을 철저히 무시(Filtering)해 버린다.
오직 내가 찍어둔 ‘1번’ 호수에서 출판된 데이터가 도착했을 때만 비로소 true를 띠링 하고 울려주는 완벽한 개인 비서가 되는 것이다.

2. 파라미터(Parameter) 연동을 통한 동적 인스턴스 스위칭

하지만 하드코딩은 유지보수의 적이다. 만약 조종사가 비행장에 나가서 갑자기 커스텀 모듈을 “1번 짐벌“에서 “0번 짐벌“로 바꾸고 싶다면 어떻게 할 것인가? 노트북을 열고 C++ 코드를 고친 뒤 펌웨어를 다시 빌드해서 픽스호크에 플래싱(Flashing)할 수는 없는 노릇이다.

그래서 우수한 PX4 시스템 프로그래머들은 앞 장(21.5.2)에서 피땀 흘려 배운 ModuleParams 시스템과 이 instance 필터링 래퍼를 예술적으로 결합해 낸다.

class DynamicVisionApp : public ModuleParams {
public:
    DynamicVisionApp() : ModuleParams(nullptr) {
        // 1. 객체가 생성될 때, QGroundControl에서 조종사가 설정한 
        //    파라미터(TARGET_GIMBAL_ID) 값을 읽어온다.
        int target_instance = _param_target_gimbal_id.get();
        
        // 2. 읽어온 그 번호로 C++ 구독자 래퍼의 추적 대상(instance)을 동적으로 변경한다!
        _gimbal_sub.ChangeInstance(target_instance);
    }
    
private:
    // 생성 시점에는 기본값(0)으로 일단 만들어 둔다.
    uORB::Subscription _gimbal_sub{ORB_ID(gimbal_device_attitude_status)}; 

    // QGroundControl에서 조종사가 숫자를 바꿀 수 있는 마법의 변수
    DEFINE_PARAMETERS(
        (ParamInt<px4::params::TARGET_GIMBAL_ID>) _param_target_gimbal_id
    )
};

이제 조종사는 QGroundControl (QGC) 프로그램의 Parameter 메뉴에 들어가서 TARGET_GIMBAL_ID 값을 단축키 누르듯 딸깍딸깍 바꾸기만 하면 된다. 재부팅 따위는 필요 없다.
픽스호크 내부에서 DynamicVisionApp 모듈의 uORB 신경망은 그 즉시 0번 타겟에서 1번 타겟으로 마치 스나이퍼처럼 목표물(Instance)을 동적으로 스위칭하게 된다.

이처럼 내가 필요한 데이터만 쏙쏙 안전하게 뽑아오는 방법을 모두 마스터했다.
하지만 여전히 uORB의 “데이터 복사“까지만 온전치, “이벤트 기반 스케줄링(Event-driven Scheduling)“의 진면목은 아직 보지 못했다. 데이터가 도착하는 바로 그 폭발적인 순간, 어떻게 커널을 깨워 내 모듈을 버스에 강제로 태울 수 있는지 대망의 콜백(Callback) 트리거 메커니즘을 21.7.2장에서 속 시원하게 파헤쳐 보자.