30.3 `Mission` 모드: 유한 상태 머신 및 자동 비행 실행 로직 (`mission.cpp`)

30.3 Mission 모드: 유한 상태 머신 및 자동 비행 실행 로직 (mission.cpp)

자율 비행의 핵심 구동축을 담당하는 Mission 모드는 사전 정의된 비행 경로(Waypoint)와 임무(Mission)를 차례대로 수행하는 시스템 상태이다. PX4-Autopilot의 아키텍처 내에서 임무의 진행은 단일 루프의 절차적 스크립트가 아니라, 유한 상태 머신(Finite State Machine, FSM) 기반의 이벤트 구동(Event-driven) 방식으로 제어된다. 이 장에서는 PX4(버전 1.14 기준)의 navigator 모듈 내 핵심 소스 코드인 mission.cpp를 중심으로 자동 비행 실행 로직의 구조와 동작 원리를 심층적으로 분석한다.

1. 자동 비행 실행의 구조적 개요 (Architecture Overview)

PX4-Autopilot의 내비게이터(Navigator) 모듈은 다수의 자동 비행 모드(Mission, RTL, Loiter, Takeoff, Land 등)를 관리하는 중앙 관제탑 역할을 수행한다. 그 가운데 Mission 클래스는 사용자가 지상 관제 시스템(GCS, 예: QGroundControl v4.3)을 통해 업로드한 MAVLink 임무(Mission Item)를 uORB 메시지 형태로 변환받아 기체가 수행해야 할 물리적인 목표 위치(Position Setpoint)로 가공하는 역할을 전담한다.

  • 데이터 계층적 추상화: GCS \rightarrow MAVLink \rightarrow uORB(Dataman) \rightarrow navigator \rightarrow position_controller
  • Ardupilot과의 비교: Ardupilot은 다소 방대한 크기의 mode_auto.cpp 파일 내부에서 고정익과 멀티로터의 동작을 절차적으로 다루는 경향이 강한 반면, PX4는 MissionBlock이라는 추상 계층(Abstract Layer)을 상속받은 Mission 클래스가 상태(State) 전환 기법을 사용하여 임무 항목을 관리하고 목표점(Setpoint)만 하위 제어기(Controller)로 하달하는 철저한 수직적 분리 아키텍처를 취한다.

2. 유한 상태 머신(FSM) 아키텍처 분석

mission.cpp의 본질은 들어오는 이벤트와 현재 기체의 진행 상태에 따라 다음 처리 절차를 결정짓는 유한 상태 머신에 있다. 임무 모드가 실행되면 시스템은 상태 상수(Enum)를 하나씩 전이시키며 비행을 관장한다.

2.1 ) 주요 상태(Mission State) 정의

코드 레벨에서 정의된 주요 상태는 다음과 같이 구성된다:

  • MISSION_STATE_NONE: 임무가 없거나 아직 활성화되지 않은 초기 대기 상태.
  • MISSION_STATE_IDLE: 임무 데이터는 존재하지만 아직 엔진이 시동(Arming)되지 않았거나 비행 전 대기 중인 상태.
  • MISSION_STATE_ACTIVE: 임무 항목(Waypoint)들을 순차적으로 실행하고 있는 주행 상태.
  • MISSION_STATE_COMPLETED: 임무 인덱스 상 마지막 항목까지 완수하고 종료된 상태.

2.2 ) 상태 전이(State Transition) 메커니즘 도해

다음은 mission.cpp 내부 on_activation(), on_active(), on_inactivation() 오버라이드 함수들을 통해 구현된 FSM의 동작 흐름을 시각화한 상태 다이어그램이다.

stateDiagram-v2
    [*] --> NONE : System Boot
    
    NONE --> IDLE : Mission Loaded via uORB
    IDLE --> NONE : Mission Cleared
    
    IDLE --> ACTIVE : Flight Mode Switched to 'Mission' & Armed
    
    state ACTIVE {
        [*] --> READ_NEXT_ITEM
        READ_NEXT_ITEM --> GENERATE_SETPOINT : Valid Item
        GENERATE_SETPOINT --> WAIT_FOR_ACCEPTANCE : Setpoint Reached?
        WAIT_FOR_ACCEPTANCE --> EXECUTE_DELAY : Delay > 0 ?
        EXECUTE_DELAY --> READ_NEXT_ITEM : Auto-continue
    }
    
    ACTIVE --> COMPLETED : Final Item Reached
    COMPLETED --> IDLE : Restart Command Received
    ACTIVE --> IDLE : Flight Mode Switched to 'Manual'
    
    IDLE --> [*]

3. 소스 코드 클래스 구조: mission.cpp

PX4 펌웨어 소스(src/modules/navigator/mission.cpp)에서 Mission 클래스는 자동 비행 로직을 다음과 같은 주요 멤버 함수들을 통해 구현하고 있다.

  • on_activation(): 임무 모드가 처음 트리거되었을 때 1회 호출된다. 이전 임무 진행 상황(Mission Progress)을 복원하거나 처음부터 재개하기 위해 인덱스를 초기화하고, 안전 장치(Dataman 등)와 결속되어 있는 임무 데이터를 메모리에 로드한다.
  • on_active(): 시스템 루프타임(보통 50Hz) 단위로 반복 호출되는 메인 제어 루프 로직이다. 이 함수 내부에서 상태 검사(_mission_state)를 갱신하며, 현재 이동해야 할 위치 목표점(position_setpoint_triplet_s)을 생성하여 uORB에 발행(publish())한다.
  • advance_mission(): 지정된 하나의 임무 개체를 완전히 완수(Acceptance) 하였을 때, 다음 인덱스로 이동(Index Increment)하기 위한 핵심 로직이다. Jump 또는 Do-command (이하 액트) 등의 특수 MAVLink 명령어도 이곳에서 처리된다.
  • set_mission_item(): dataman(SD 카드 내부 비휘발성 저장 포맷)으로부터 읽어들인 mission_item_s 구조체의 데이터를 분석하여 현재 임무의 타입을 식별(Takeoff, Waypoint, Land 등)한다.

3.1 on_active() 제어 주기 내 주요 연산 흐름

void Mission::on_active()
{
    // 1. 임무 상태 검증 및 예외 확인
    if (_mission_state != MISSION_STATE_ACTIVE) {
        return;
    }

    // 2. 현재 도달하려는 웨이포인트 범위 허용치(Acceptance Radius) 검사
    if (is_mission_item_reached()) {
        // 3. 딜레이(지연시간) 조건 검사
        if (_mission_item.time_inside > 0 && !delay_completed()) {
            return; // 딜레이 대기 수행
        }
        
        // 4. 다음 임무 스텝으로 이동
        advance_mission();
    }
    
    // 5. 지속적인 셋포인트 업데이트 (예: 이동 중 고도/경로 동적 수정)
    update_mission_setpoint();
}

4. 센서 이중화 및 GCS 관제 연동의 관점

자동 비행 중에는 통신(Data Link Loss) 단절이나 GPS 음영 지역(GPS Loss) 진입에 따른 예외 처리가 수반되어야 한다. Mission 모드 로직은 본질적으로 현재 기체의 상태 추정기(EKF2)로부터 제공되는 글로벌 좌표(vehicle_global_position_s) 데이터를 전적으로 신뢰하여 작동한다.
따라서 위치 추정기의 오차 공분산(Covariance)이 임계치(Threshold)를 초과하게 되면, 커맨더(Commander) 데몬에 의해 Mission 모드는 즉각적으로 중단되고, QGroundControl에는 에러 메시지가 경고되며 기체는 Hold (Loiter) 상태나 Land 로 강제 전환(Failsafe)된다.

  • ROS2 Offboard 연동: 종종 개발 과정에서 ROS2의 Offboard 모드와 Mission 모드를 혼동하는 경우가 발생한다. Mission 모드는 사전 적재된 GCS 발급 정적(Static) 웨이포인트 집합을 navigator 프로세스에서 순차적으로 소모하는 방식이다. 반면에 Offboard 모드는 ROS2(혹은 MAVSDK)에서 50Hz 이상의 고속으로 동적인 타겟점(Setpoints)을 기체 외부에서 주입하는 방식이므로, mission.cpp 로직은 완전히 바이패스(Bypass)된다. 경로 계획(Path Planning) 등의 동적 장애물 회피를 적용하기 위해선 Mission 모드 대신 Offboard 모드를 채택하는 것이 일반적이다.

5. Ardupilot 대비 성능 검증 및 구조적 차별점

PX4의 mission.cpp는 객체 지향적 상속(Object-oriented Inheritance) 원칙을 고수하여 작성되어 있다.
Ardupilot 메인 루프 구조가 update_mission() 함수의 거대한 switch-case 블록으로 구성되어 있는 데 비해, PX4는 MissionBlock이라는 기본 뼈대 클래스에서 재사용 가능한 기초 연산 기하학(구면 기하 공리, 활공각 계산 등)을 처리하기 때문에 유지보수가 용이하며, 개발자가 특수 커스텀 드론 목적의 비행 모드를 생성하고자 할 때 기존 클래스를 쉽게 오버라이드하여 확장(Extensibility)할 수 있는 장점을 지닌다. 이는 논문 “An Open-Source Architecture for Autonomous Micro Aerial Vehicles” (Meier et al.) 가 지향하는 모듈형 아키텍처의 철학을 엄격하게 따른 결과이다.

6. 챕터 요약 및 고도화 가이드

mission.cpp 모듈은 방대한 크기의 SD 카드 데이터를 실시간 메모리로 스트리밍(Dataman caching) 하면서도 O(1) 수준의 계산 복잡성을 보장하도록 설계되어 있다. 이러한 시스템의 구조적 특성을 깊이 이해하면, 복잡한 비행 시나리오에서도 무인 항공기가 교착 상태(Deadlock)에 빠지거나 임무를 누락하지 않도록 보장하는 항공용 RTOS 기반 펌웨어의 정밀한 타이밍 제어 기술을 마스터할 수 있다. 다음 단계의 자동 비행 분석에서는 개별 기동 명령어 모드(Hold, RTL)의 기하학적 제어 로직을 다룰 예정이다.