PX4 MAVSDK – C++ Programming [4편] C++ 앱 빌드 및 통신 연결

안녕하세요! 마케팅팀 에이든(Aiden)입니다. 지난 3편에서는 안전한 자율 비행 테스트를 위한 SITL 가상 환경을 구축하고, MAVSDK에서 제공하는 기본 예제를 실행해 보며 드론이 가상 공간에서 이륙하는 모습을 확인했습니다.

하지만 연구자나 개발자라면 남이 만들어둔 예제를 실행하는 것에 만족할 수 없겠죠? 이번 4편에서는 빈 폴더에서부터 시작해 나만의 C++ 프로젝트를 설정(Build)하고, 드론 시스템과 통신을 연결(Connection)하는 방법을 처음부터 끝까지 친절하게 안내해 드리겠습니다. C++ 빌드 시스템이 낯선 대학생분들도 천천히 따라오시면 충분히 마스터할 수 있습니다!


MAVSDK C++ 빌드 시스템의 이해

C++로 작성된 소스 코드를 실행 가능한 프로그램으로 만들려면 컴파일(Compile)과 링킹(Linking)이라는 빌드 과정을 거쳐야 합니다. MAVSDK 코어 라이브러리는 최신 C++17 표준으로 작성되어 있지만, 외부 앱에서 사용할 수 있도록 std::function과 같은 C++11 인터페이스를 제공하므로 여러분의 애플리케이션은 C++11 이상의 환경에서 빌드되어야 합니다.

MAVSDK는 크로스 플랫폼 오픈소스 툴체인인 CMake를 빌드 시스템으로 사용하며, 우리 앱도 CMake를 사용하여 빌드하는 것을 강력히 권장합니다. CMake를 사용하면 Linux, macOS, Windows 환경에 구애받지 않고 동일한 빌드 설정으로 앱을 구성할 수 있습니다.


CMakeLists.txt 작성하기

앱을 구축하기 위한 첫걸음은 프로젝트의 루트 디렉터리에 CMakeLists.txt라는 빌드 정의 파일을 작성하는 것입니다. 이 파일에는 프로젝트 이름, 사용할 소스 파일, 그리고 링크할 라이브러리(MAVSDK) 정보가 들어갑니다.

가장 기본적인 CMakeLists.txt의 템플릿은 다음과 같습니다.

CMake
# 1. CMake 최소 요구 버전 설정
cmake_minimum_required(VERSION 3.10)

# 2. 프로젝트 이름 및 언어 설정
project(MyDroneApp LANGUAGES CXX)

# 3. C++17 표준 사용 설정
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 4. MAVSDK 라이브러리 패키지 찾기
find_package(MAVSDK REQUIRED)

# 5. 실행 파일 생성 (main.cpp를 컴파일하여 my_drone_app 생성)
add_executable(my_drone_app main.cpp)

# 6. 생성된 실행 파일에 MAVSDK 라이브러리 링크하기
target_link_libraries(my_drone_app
    MAVSDK::mavsdk
    MAVSDK::mavsdk_action
    MAVSDK::mavsdk_telemetry
)

💡 연구원들을 위한 실전 팁: 라이브러리 설치 경로 설정

  • 시스템 전체 설치 시: 이전 3편에서 sudo make install을 통해 MAVSDK를 /usr/local에 설치했다면, 위의 find_package(MAVSDK REQUIRED) 명령어만으로 시스템이 알아서 라이브러리를 찾습니다.
  • 로컬 설치 시: 만약 기존 시스템 라이브러리와 충돌을 피하고자 특정 폴더(예: ~/mavsdk_local)에 빌드했다면, 앱을 빌드할 때 -DCMAKE_PREFIX_PATH를 지정하여 CMake가 해당 경로를 찾게 해주어야 합니다.
    • 빌드 명령어 예시: cmake -DCMAKE_PREFIX_PATH=~/mavsdk_local -Bbuild -S.


드론과의 통신 연결 기초 (add_any_connection)

빌드 환경이 준비되었으니, 이제 드론과 연결하는 코드를 작성해 볼 차례입니다. MAVSDK는 로컬 WiFi 네트워크나 직렬(Serial) 포트를 통해 하나 이상의 차량(드론)에 연결할 수 있습니다.

통신 포트를 지정하고 모니터링을 시작할 때는 add_any_connection() 메서드를 사용하며, 이 메서드는 연결 성공 여부를 나타내는 ConnectionResult를 반환합니다. 연결 URL 형식은 네트워크 환경에 따라 다양하게 설정할 수 있습니다.

연결 URL 형식 포맷

  • UDP: udpin://[ip][:port], udpout://[ip][:port]
  • TCP: tcpin://[ip][:port], tcpout://[ip][:port]
  • Serial (시리얼): serial://[path][:baudrate]

1) 시리얼(Serial) 포트를 통한 실제 기체 연결

실제 드론 내부의 픽스호크(Pixhawk) 비행 제어기와 USB, FTDI 또는 텔레메트리 라디오로 연결할 때 사용합니다.

  • Linux 예시: mavsdk.add_any_connection("serial:///dev/ttyUSB0:57600");
  • Windows 예시: mavsdk.add_any_connection("serial://COM3:57600");

2) UDP를 통한 시뮬레이션(SITL) 연결 (Server Mode)

가상 환경이나 네트워크 기반 드론과 통신할 때는 UDP 서버 모드(udpin)를 주로 사용합니다. 0.0.0.0을 지정하면 모든 네트워크 인터페이스에서 수신을 대기합니다.

  • SITL 표준 오프보드 포트 14540 연결: mavsdk.add_any_connection("udpin://0.0.0.0:14540");
    • SITL에서 14540 포트는 외부 API용으로 표준화되어 있으며, QGroundControl 같은 지상국 소프트웨어는 14550 포트를 사용합니다.


시스템 감지 알림 및 C++ 필수 문법 적용

포트를 열어두었다면, 드론이 보내는 하트비트(Heartbeat) 메시지를 감지하여 드론이 “발견(Discovery)”될 때까지 기다려야 합니다.

시스템 감지 콜백 등록 (subscribe_on_new_system)

MAVSDK는 새 드론이 발견되었을 때 알려주는 콜백 등록 함수 subscribe_on_new_system()을 제공합니다. 이때 C++의 람다(Lambda) 함수를 사용하면 매우 직관적으로 코드를 작성할 수 있습니다.

C++
mavsdk.subscribe_on_new_system([]() {
    std::cout << "새로운 드론 시스템이 발견되었습니다!\n";
});

람다 함수 [](){ ... }는 “이름 없는 즉석 함수”로, 콜백 함수를 외부에 따로 정의할 필요 없이 코드가 필요한 그 자리에 바로 작성할 수 있게 해주는 C++11의 강력한 기능입니다.

드론(System) 객체 가져오기

드론이 발견되면 systems() 메서드를 통해 현재 연결된 시스템들의 리스트(Vector 형태)를 가져올 수 있습니다.

C++
// 감지된 첫 번째 시스템 가져오기
auto system = mavsdk.systems().front();

if (system->has_autopilot()) {
    std::cout << "오토파일럿이 탑재된 드론에 성공적으로 연결되었습니다.\n";
}

💡 C++ Tip! auto 키워드의 활용 위 코드에서 쓰인 auto 키워드는 컴파일러가 변수의 자료형을 알아서 추론하게 해줍니다. MAVSDK에는 길고 복잡한 반환 타입(std::vector<std::shared_ptr<System>> 등)이 많은데, auto를 사용하면 코드를 훨씬 간결하고 정확하게 작성할 수 있어 연구 효율이 크게 올라갑니다.


전체 코드 통합 및 앱 빌드 실행

지금까지 배운 내용을 하나의 완전한 main.cpp 소스 코드로 합쳐보겠습니다.

C++
#include <iostream>
#include <thread>
#include <chrono>
#include <mavsdk/mavsdk.h>

using namespace mavsdk;

int main() {
    // 1. 코어 엔진 객체 생성
    Mavsdk mavsdk{Mavsdk::Configuration{ComponentType::GroundStation}};

    // 2. UDP 포트 14540(SITL) 연결 설정
    std::cout << "SITL 환경에 연결을 시도합니다...\n";
    auto connection_result = mavsdk.add_any_connection("udpin://0.0.0.0:14540");

    if (connection_result != ConnectionResult::Success) {
        std::cerr << "연결 실패: " << connection_result << '\n';
        return 1;
    }

    // 3. 새로운 시스템 감지 시 알림 등록 (람다 함수 사용)
    std::atomic<bool> discovered{false};
    mavsdk.subscribe_on_new_system([&discovered]() {
        std::cout << "🎉 새로운 시스템(드론)이 발견되었습니다!\n";
        discovered = true;
    });

    // 4. 드론이 발견될 때까지 대기
    std::cout << "드론의 하트비트 메시지를 기다리는 중...\n";
    while (!discovered) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 5. System 객체 접근 및 확인
    auto system = mavsdk.systems().front();
    std::cout << "접속된 시스템 ID: " << static_cast<int>(system->get_system_id()) << '\n';

    return 0;
}

이제 터미널을 열고 다음 명령어를 입력하여 우리가 작성한 앱을 빌드하고 실행해 봅시다.

Bash
# 1. build 디렉터리 생성 및 CMake 환경 구성
cmake -Bbuild -S.

# 2. 컴파일 진행 (빠른 빌드를 위해 4코어 사용)
cmake --build build -j4

# 3. SITL 시뮬레이터가 켜져있는 상태에서 실행 앱 구동
./build/my_drone_app

위 명령어를 통해 터미널에 “새로운 드론 시스템이 발견되었습니다!”라는 메시지가 출력되었다면, 여러분의 첫 C++ 드론 제어 앱이 성공적으로 드론과 통신 채널을 확보한 것입니다!


이번 4편에서는 본격적인 MAVSDK 프로젝트를 세팅하기 위한 CMakeLists.txt 작성법과, 다양한 통신 환경(UDP, Serial)에 대응하는 add_any_connection() 활용법, 그리고 람다와 auto를 활용한 세련된 시스템 발견(Discovery) 로직까지 모두 학습했습니다.

통신 파이프라인이 완성되었으니, 이제 이 파이프라인을 통해 드론의 세부 데이터를 빨아들일 차례입니다. 다음 [5편: 시스템 정보 쿼리 및 원격 측정(Telemetry) 활용]에서는 드론의 현재 GPS 위치, 배터리 잔량, 비행 모드 등을 비동기 방식으로 실시간 모니터링하는 방법을 깊이 있게 파헤쳐 보겠습니다.


YouTube 강좌

재생


작성자: 에이든(Aiden), 쿼드(QUAD) 드론연구소 마케팅팀

기고일: 2026.03.14

Similar Posts

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다