[MAVSDK C++ Part 4] Building Your Own App: Project Setup and Drone Connection

Hello! This is Aiden from the Marketing Team. In our previous episode (Part 3), we built a SITL virtual environment for safe autonomous flight testing and ran basic MAVSDK examples to see our drone take off in virtual space.

However, as a researcher or developer, simply running pre-made examples isn’t enough, right? In this Part 4, we will guide you from a blank folder to setting up your own C++ project (Build) and establishing a communication link (Connection) with the drone system. Even if you are a college student unfamiliar with C++ build systems, you can master this by following along step-by-step!


Understanding the MAVSDK C++ Build System

To turn C++ source code into an executable program, you must go through a process called Compilation and Linking. While the MAVSDK core library is written in the modern C++17 standard, it provides C++11 interfaces (such as std::function) for external apps, meaning your application must be built in a C++11 environment or higher.

MAVSDK uses CMake, a cross-platform open-source toolchain, as its build system. We strongly recommend using CMake for your apps as well. With CMake, you can configure your app with the same build settings regardless of whether you are on Linux, macOS, or Windows.


Writing CMakeLists.txt

The first step in building your app is to create a build definition file named CMakeLists.txt in your project’s root directory. This file contains the project name, source files to be used, and information about the libraries (MAVSDK) to link.

Here is a basic template for CMakeLists.txt:

CMake
# 1. Set minimum CMake version
cmake_minimum_required(VERSION 3.10)

# 2. Set project name and language
project(MyDroneApp LANGUAGES CXX)

# 3. Enable C++17 standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 4. Find MAVSDK library package
find_package(MAVSDK REQUIRED)

# 5. Create executable (compile main.cpp to create my_drone_app)
add_executable(my_drone_app main.cpp)

# 6. Link MAVSDK libraries to the created executable
target_link_libraries(my_drone_app
    MAVSDK::mavsdk
    MAVSDK::mavsdk_action
    MAVSDK::mavsdk_telemetry
)

💡 Practical Tip for Researchers: Setting Library Paths

  • System-wide Installation: If you installed MAVSDK to /usr/local using sudo make install in Part 3, the find_package(MAVSDK REQUIRED) command will find it automatically.
  • Local Installation: If you built it in a specific folder (e.g., ~/mavsdk_local) to avoid conflicts with system libraries, you must specify -DCMAKE_PREFIX_PATH when building your app so CMake can locate it.
    • Build command example: cmake -DCMAKE_PREFIX_PATH=~/mavsdk_local -Bbuild -S.


Fundamentals of Drone Connection (add_any_connection)

Now that your build environment is ready, it’s time to write the code to connect to the drone. MAVSDK can connect to one or more vehicles (drones) via a local WiFi network or a Serial port.

When specifying a communication port and starting monitoring, use the add_any_connection() method, which returns a ConnectionResult indicating success or failure. The connection URL format varies depending on the network environment.

Connection URL Formats:

  • UDP: udpin://[ip][:port], udpout://[ip][:port]
  • TCP: tcpin://[ip][:port], tcpout://[ip][:port]
  • Serial: serial://[path][:baudrate]

1) Connecting to an Actual Aircraft via Serial Port

Used when connecting to a Pixhawk flight controller via USB, FTDI, or Telemetry radio.

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

2) SITL Connection via UDP (Server Mode)

When communicating with virtual environments or network-based drones, UDP server mode (udpin) is primarily used. Specifying 0.0.0.0 allows listening on all network interfaces.

  • Connecting to SITL Standard Offboard Port 14540: mavsdk.add_any_connection("udpin://0.0.0.0:14540");
    • Note: Port 14540 is standardized for external APIs in SITL, while Ground Control Stations like QGroundControl use port 14550.


System Discovery Notifications and Essential C++ Syntax

Once the port is open, you need to wait for the drone to be “discovered” by detecting Heartbeat messages.

Registering System Detection Callback (subscribe_on_new_system)

MAVSDK provides subscribe_on_new_system(), which notifies you when a new drone is discovered. Using C++ Lambda functions makes this code very intuitive.

C++
mavsdk.subscribe_on_new_system([]() {
    std::cout << "A new drone system has been discovered!\n";
});

The lambda function [](){ ... } is an “anonymous on-the-fly function,” a powerful C++11 feature that allows you to write callback logic directly where it’s needed without defining a separate function elsewhere.

Accessing the Drone (System) Object

Once a drone is discovered, you can get a list of currently connected systems (in Vector format) using the systems() method.

C++
mavsdk.subscribe_on_new_system([]() {
    std::cout << "A new drone system has been discovered!\n";
});

💡 C++ Tip! Using the auto Keyword
The auto keyword allows the compiler to automatically deduce the variable’s data type.
MAVSDK often has long and complex return types (like std::vector<std::shared_ptr<System>>);
using auto makes your code much cleaner and more accurate, significantly increasing research efficiency.


Full Code Integration and Build Execution

Let’s combine everything we’ve learned into one complete main.cpp source file.

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

using namespace mavsdk;

int main() {
    // 1. Create Core Engine Object
    Mavsdk mavsdk{Mavsdk::Configuration{ComponentType::GroundStation}};

    // 2. Set up UDP Port 14540 (SITL) Connection
    std::cout << "Attempting to connect to SITL environment...\n";
    auto connection_result = mavsdk.add_any_connection("udpin://0.0.0.0:14540");

    if (connection_result != ConnectionResult::Success) {
        std::cerr << "Connection failed: " << connection_result << '\n';
        return 1;
    }

    // 3. Register notification for new system detection (using Lambda)
    std::atomic<bool> discovered{false};
    mavsdk.subscribe_on_new_system([&discovered]() {
        std::cout << "🎉 A new system (drone) has been discovered!\n";
        discovered = true;
    });

    // 4. Wait until the drone is discovered
    std::cout << "Waiting for drone heartbeat messages...\n";
    while (!discovered) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    // 5. Access and verify the System object
    auto system = mavsdk.systems().front();
    std::cout << "Connected System ID: " << static_cast<int>(system->get_system_id()) << '\n';

    return 0;
}

Now, open your terminal and enter the following commands to build and run the app we wrote:

Bash
# 1. Create build directory and configure CMake environment
cmake -Bbuild -S.

# 2. Proceed with compilation (use 4 cores for faster building)
cmake --build build -j4

# 3. Run the application (ensure SITL simulator is running)
./build/my_drone_app

If you see the message “A new drone system has been discovered!” in your terminal, your first C++ drone control app has successfully established a communication channel with the drone!


In this Part 4, we learned how to write CMakeLists.txt for a professional MAVSDK project, how to use add_any_connection() for various environments (UDP, Serial), and even sophisticated discovery logic using lambdas and auto.

Now that the communication pipeline is complete, it’s time to extract detailed data through it. In the next [Part 5: Querying System Info and Using Telemetry], we will dive deep into real-time monitoring of GPS location, battery levels, and flight modes using asynchronous methods.


YouTube Tutorial

재생


Author: Aiden, QUAD Drone Lab Marketing Team

Date: March 14 , 2026

Similar Posts

답글 남기기

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