Skip to main content

Develop Your Own Packages

Once you're comfortable operating your drone, the next step is building your own ROS packages on top of the MRS UAV System. To get started, you need a development environment that matches the drone's onboard stack.

What You're Building

A ROS workspace is just a folder with a src/ directory containing one or more packages, each with its own package.xml and CMakeLists.txt. A build tool compiles every package in src/ at once; you then source install/setup.bash to make them available.

Setting Up Your Workspace

The drone's onboard computer might have a prepared ~/example_session/development session (similar to the Docker session used in Autonomous Flight), except its ros2_ws/ comes with the mrs_core_examples packages checked out and its tmux session pre-wired to launch them. That's the fastest way to see an example package fly before you write your own — see Starting From an Example Package below.

The template's docker/ folder builds a development container on top of the same MRS UAV System image used by the Apptainer and native installs, so you're developing against the exact stack your drone runs — just with ROS2 (Jazzy) tooling layered on top and a ros2_ws ready for your own packages. A few things the image and compose file set up for you:

  • A non-root user matching your host UID/GID, so files the container creates in ros2_ws/ are owned by you, not root.
  • Host networking, so ROS2's DDS discovery works between the container and any other machine on your network without extra configuration.
  • X11 forwarding, so GUI tools like Rviz, Gazebo, or QGroundControl display on your desktop as if they ran natively.
  • Bind-mounted ros2_ws/ and tmux/ folders (not baked into the image), so edits you make on the host with your own editor take effect immediately — no rebuild needed to pick up source changes.
  • UAV_NAME, UAV_TYPE, UAV_MASS, and ROS_DOMAIN_ID environment variables, wired through so your packages address the right robot by default.

Steps

  1. Install Docker.

  2. The workspace sources still need to be cloned on the host first, since they're bind-mounted rather than built into the image. Install vcstool and pull in the repositories listed in .repos:

    cd ~/git/<your-repo>
    vcs import < .repos

    Update them later with vcs pull -n.

  3. From the repository root, use the provided scripts — they set the correct user/group ID, GPU access, and X server access for you automatically:

    ./start.sh # build (if needed), start the container and launch the tmux sessions
    ./start.sh dev # build (if needed), start the container and attach an interactive shell instead
    ./build.sh # install rosdep dependencies and (re)build the workspace with colcon inside the container, then stop it
    ./kill.sh # stop the running container

    GPU support is auto-detected: an AMD GPU needs nothing extra, while an NVIDIA GPU is picked up automatically when nvidia-smi works on the host (this requires the NVIDIA Container Toolkit).

    If you'd rather drive docker compose directly instead of the wrapper scripts:

    docker compose -f docker/compose.yaml --project-directory . up -d --build
    # On an NVIDIA host, also layer in the GPU reservation:
    # docker compose -f docker/compose.yaml -f docker/compose.nvidia.yaml --project-directory . up -d --build
    docker exec -it meta-package bash

Starting From an Example Package

Rather than writing a package from scratch, base it on one of the mrs_core_examples packages — each one is a working, documented starting point for a specific kind of node:

  • example_waypoint_flier (C++) — a full MRS component that flies a list of waypoints loaded from a config file, exposed as services. The best starting point for a custom mission node, and the one already wired up in the onboard ~/example_session/development tmux session (see below).
  • example_waypoint_flier_native (C++) — the same idea, but built with vanilla ROS2 APIs instead of the MRS wrappers.
  • example_controller_plugin, example_tracker_plugin, example_estimator_plugin (C++) — plugins for the ControlManager, for when you need custom control, trajectory generation, or state estimation.
  • example_pluginlib (C++) — a minimal example of the ROS pluginlib mechanism the plugins above are built on.
  • example_sweeping_generator (Python) — a minimal Python node that generates a sweeping path.

Pull in an example and rename it as your own

  1. Add mrs_core_examples to your workspace's .repos file (or clone it directly into ros2_ws/src/mrs_core_examples):

    repositories:
    ros2_ws/src/mrs_core_examples:
    type: git
    url: https://github.com/ctu-mrs/mrs_core_examples.git
    version: main
    vcs import < .repos
  2. Repurpose the example you picked into your own package. The repo ships a repurpose_package.sh script that renames every occurrence of the old package name — in files, filenames, and CamelCase symbols — to your new one, and re-initializes it as a fresh git repo:

    cd ~/ros2_ws/src/mrs_core_examples
    ./repurpose_package.sh example_waypoint_flier my_first_package
    tip

    The script asks for confirmation before each change (and supports --dry-run to preview them first). Run it from inside mrs_core_examples so it can find the package directory by name; it only touches files under that package.

  3. Move the renamed package into your workspace and drop the scratch clone:

    mv cpp/example_waypoint_flier ~/ros2_ws/src/my_first_package
    rm -rf ~/ros2_ws/src/mrs_core_examples

    Remove the mrs_core_examples entry from .repos too, unless you plan to pull more examples from it later.

  4. Build it like any other package in your workspace (see Setting Up Your Workspace above), then launch it:

    colcon build --packages-select my_first_package --symlink-install
    source install/setup.bash
    ros2 launch my_first_package my_first_package.launch.py uav_name:=$UAV_NAME

Try the stock example on the drone first

Before forking example_waypoint_flier into your own package, it's worth flying the unmodified version once. The onboard ~/example_session/development session already has mrs_core_examples checked out in its ros2_ws/src/ and its tmux session has an example_waypoint_flier window with the launch command and service calls pre-typed:

cd ~/example_session/development
./start.sh

Switch to the example_waypoint_flier window, launch it, then call fly_to_first_waypoint and start_waypoints_following from the pre-typed commands. See Autonomous Flight for the takeoff/arming procedure, and Simulation to try it without touching real hardware first.

Next Steps

Once your workspace is built (either way), ./start.sh launches tmux sessions for the simulator and your UAVs. See the template repository's tmux/README.md for how those sessions are organized and how to add your own nodes to them. To try things out before touching real hardware, see Simulation.