28.7.4.2. QGroundControl 백엔드 소스(`PX4FirmwarePlugin.cc`)의 `flightModes()` 딕셔너리 수정을 통한 UI 모드 이름 노출 구현

28.7.4.2. QGroundControl 백엔드 소스(PX4FirmwarePlugin.cc)의 flightModes() 딕셔너리 수정을 통한 UI 모드 이름 노출 구현

PX4 펌웨어 내부에서 FlightTaskCustom이 동작할 수 있는 모든 물리적, 논리적 배선이 통신단(mavlink_receiver)까지 완료결되었다. 하지만 조종사가 노트북 화면(QGroundControl)을 열어 비행 모드 드롭다운 메뉴를 클릭했을 때 “Custom Mode“라는 글자가 보이지 않는다면, 결국 징크스(Jinx) 명령어(MAV_CMD_DO_SET_MODE + param2=25)를 CLI 콘솔로 직접 치는 수고로움을 감수해야 한다.

따라서 커스텀 모드 개발의 대미(Finale)는 지상 관제소(GCS) UI에 사용자 친화적인 버튼을 달아주는 작업으로 장식된다. 본 절에서는 QGC의 C++ 백엔드 소스인 PX4FirmwarePlugin.cc를 수정하여 펌웨어의 모드 매핑 숫자를 직관적인 UI 텍스트로 치환하는 딕셔너리(Dictionary) 등록 절차를 다룬다.


1. QGroundControl(QGC) 내 펌웨어 플러그인 아키텍처

QGroundControl은 이름 그대로 ‘범용’ 관제 시스템이다. PX4뿐만 아니라 ArduPilot(ArduCopter, ArduPlane 등) 기체와 통신할 때도 사용된다.
따라서 기체가 MAVLink로 HEARTBEAT를 쏘면, QGC는 autopilot 필드를 검사하여 이 기체가 PX4 모델인지 ArduPilot 모델인지 판별한 후, 각각 전담하는 Firmware Plugin(펌웨어 플러그인) 으로 통신 권한을 넘긴다.

PX4의 모드 이름과 딕셔너리를 담당하는 백엔드 파일은 QGC 소스 트리 내 src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc 에 깊숙이 자리 잡고 있다.


2. flightModeInfoList() 딕셔너리 수술

PX4FirmwarePlugin.cc 파일을 열고 파라미터나 비행 모드를 설정하는 구역을 찾아보면, PX4FirmwarePlugin::flightModeInfoList() (또는 QGC 버전에 따라 _flightModeInfoList) 라는 팩토리 함수가 존재한다.

이 함수는 QList<FlightModeInfo_t> 라는 구조체 배열을 반환하는데, 이 배열 안에 등록된 데이터들이 QML(Qt 프론트엔드 언어) 화면으로 넘어가 우리가 흔히 보는 UI 버튼을 생성하게 된다.

2.1 커스텀 모드 튜플(Tuple) 구조 분석

기존 코드의 FlightModeInfo_t 딕셔너리 튜플 구조는 대략 다음과 같이 생겼다.
{ MAVLink_Custom_Mode_Number, MAVLink_Custom_Sub_Mode_Number, "UI_Display_Name", Can_Be_Set_By_User, Is_Advanced_Mode }

이 배열의 끝자락(보통 Return 직전)에 우리가 펌웨어에서 선점했던 고유 번호(예: 25)와 UI 텍스트를 바인딩하는 한 줄을 추가한다.

QList<FlightModeInfo_t> PX4FirmwarePlugin::flightModeInfoList()
{
    // ... 초기화 여부 검사 로직 (_flightModeInfoList.isEmpty())

        // 기존 QGC 소스 코드 내 하드코딩된 모드 리스트
        _flightModeInfoList << FlightModeInfo_t{ PX4_CUSTOM_MAIN_MODE_MANUAL,   0, tr("Manual"),    true,  false };
        _flightModeInfoList << FlightModeInfo_t{ PX4_CUSTOM_MAIN_MODE_STABILIZED,0, tr("Stabilized"),true,  false };
        _flightModeInfoList << FlightModeInfo_t{ PX4_CUSTOM_MAIN_MODE_ACRO,      0, tr("Acro"),      true,  false };
        _flightModeInfoList << FlightModeInfo_t{ PX4_CUSTOM_MAIN_MODE_POSCTL,    0, tr("Position"),  true,  false };
        _flightModeInfoList << FlightModeInfo_t{ PX4_CUSTOM_MAIN_MODE_OFFBOARD,  0, tr("Offboard"),  true,  false };
        // ... (나머지 생략) ...

        // [NEW] 우리가 개발한 커스텀 모드의 MAVLink 파라미터 매핑 등록
        // 25번: 이전 단계 mavlink_receiver.cpp 에서 파싱하도록 약속한 param2 (custom_mode) 번호
        // 0번: sub_mode 번호 (사용하지 않으므로 0)
        // tr("Wall Follow"): 프론트엔드 화면에 출력될 다국어 지원 텍스트
        // true: 조종사가 UI에서 클릭하여 강제 변경(Set)할 수 있도록 허가
        _flightModeInfoList << FlightModeInfo_t{ 25, 0, tr("Wall Follow"), true, false };
    
    // ...
    return _flightModeInfoList;
}

2.2 부가 가치(Value-add): 색상 및 아이콘 지정

버전에 따라 이 FlightModeInfo_t 딕셔너리 옆에 모드의 위험성(Acro 모드는 빨간색 등)이나 유형을 지정하는 프로퍼티가 더 존재할 수 있다. 우리의 “Wall Follow” 모드가 자율 비행(Auto) 인지 수동 개입형(Manual) 인지에 따라 적절한 기존 모드의 프로퍼티를 흉내 내어 등록해 주면 UI 상의 이질감을 줄일 수 있다.


3. 데스크톱 통합 빌드(Qt Creator) 및 최종 검증

수정이 완료되었다면, Qt 환경에서 QGroundControl을 데스크톱 실행 파일(.AppImage, .exe)로 새롭게 컴파일(Compile)한다.

  1. 결과물 확인: 새롭게 빌드된 사용자 정의 QGC를 실행하고, 앞서 1~3단계에 걸쳐 펌웨어를 올린 기체(또는 SITL 시뮬레이터)를 연결한다.
  2. UI 노출: 좌측 상단의 비행 모드 드롭다운 메뉴를 클릭한다. 우리가 방금 px4FirmwarePlugin.cc 에 박아넣은 “Wall Follow” 라는 버튼이 영롱하게 빛나고 있을 것이다.
  3. End-to-End 심리스 테스트:
  • 조종사가 “Wall Follow” 버튼을 클릭한다.
  • QGC는 백엔드의 딕셔너리를 역순환하여 param2=25 가 세팅된 MAV_CMD_DO_SET_MODE 커맨드를 쏜다.
  • PX4 기체의 mavlink_receiver.cpp가 25번을 파싱하여 내부 상태망을 NAVIGATION_STATE_CUSTOM_FOO 로 바꾼다.
  • commander.cpp의 삼중 안전망이 센서를 검사하여 승인을 떨어뜨린다.
  • FlightModeManager.cppswitchTask(Custom) 를 쳐서 뇌(Brain)를 램에 올린다.
  • 초당 250번씩 우리가 짠 FlightTaskCustom::update() 가 미친 듯이 연산을 뱉어내며 드론의 모터 피치를 제어하기 시작한다.

이 완벽한 연쇄 작용(Chain Reaction) 구조를 이해하는 것이야말로 PX4-Autopilot의 아키텍처 세계관을 마스터(Master) 하는 핵심 열쇠이다.