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)한다.
- 결과물 확인: 새롭게 빌드된 사용자 정의 QGC를 실행하고, 앞서 1~3단계에 걸쳐 펌웨어를 올린 기체(또는 SITL 시뮬레이터)를 연결한다.
- UI 노출: 좌측 상단의 비행 모드 드롭다운 메뉴를 클릭한다. 우리가 방금
px4FirmwarePlugin.cc에 박아넣은 “Wall Follow” 라는 버튼이 영롱하게 빛나고 있을 것이다. - 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.cpp가switchTask(Custom)를 쳐서 뇌(Brain)를 램에 올린다.- 초당 250번씩 우리가 짠
FlightTaskCustom::update()가 미친 듯이 연산을 뱉어내며 드론의 모터 피치를 제어하기 시작한다.
이 완벽한 연쇄 작용(Chain Reaction) 구조를 이해하는 것이야말로 PX4-Autopilot의 아키텍처 세계관을 마스터(Master) 하는 핵심 열쇠이다.