ROS2 Development Base
ros2_metapackage_template is a ready-made base for ROS2 projects (CORE) — a workspace, a Docker environment with the MRS UAV System inside, and a tmux launch layer — which you copy with Use this template on GitHub and then fill with your own packages.
It is not a library and you never depend on it. It is a starting point: after the first commit the repository is yours, and every line in it is meant to be edited.
The idea
- One environment. We already run Docker on the real drones for other reasons, so why not make the same image base for development and simulation too? It carries the MRS UAV System, ROS2 and the usual development tools, so what runs on one machine runs the same way on every other. That traceability pays off when debugging, both inside the team and with a client.
- The same project runs in simulation and on the drone. One script, one set of configs; the difference is a single flag.
- Less duplication, less work to extend. The sessions are ERB templates, so one tmuxinator session covers both the simulator and the real robot. The templating has been there all along, we simply started using it — no wrapper shell scripts and no second copy of every session to keep in sync. Adding a node, an airframe or a new combination of flags is a single entry in a yaml or one small file, and it takes effect in simulation and in flight at once.
- Docker stays out of your way. You never attach to a container by hand. A few scripts in the repository root build it, start it and tear it down, and the workspace is bind-mounted, so you keep editing on your own machine with your own editor. Most of the time you do not notice there is a container at all.
- It is meant to stay only as a base. Projects differ a lot and have their own needs, so nothing here is meant to constrain them. But the more of us start from the same structure and keep it roughly intact, the easier it gets to move between each other's projects.
What's inside
The repository carries the configuration, the environment and the launch layer, and nothing else. The ROS code lives in its own repositories and is cloned in, and whatever a build produces stays on your machine.
| Path | Purpose |
|---|---|
.repos | The manifest of git repositories that make up the project, imported by vcstool. Nothing forces this choice — git submodules do the same job if you prefer them. |
ros2_ws/ | The colcon workspace. Only colcon_defaults.yaml and an empty src/ are tracked; build/, install/, log/ and the imported packages are local. |
docker/ | The image definition and its compose files, plus env.sh, which detects your user, GPU and display. |
start.sh, build.sh, kill.sh | The three commands you will actually type day to day. |
tmux/ | The launch layer: sessions, per-airframe configs, presets and ERB templates. |
logs/ | Bind-mounted runtime logs from real flights. |
A few details worth knowing:
- The image is built on
ctumrs/mrs_uav_systemand recreates your host user inside the container, so files created in the workspace belong to you, not to root. ros2_ws/andtmux/are bind-mounted into the container. You edit them on the host with your own editor and the container sees the change immediately.colcon_defaults.yamlturns on--symlink-installand a release-with-debug-info build withcompile_commands.json, which is what your editor's C++ tooling wants.- GPU access is automatic: an AMD card needs nothing, an NVIDIA card is picked up when the Docker
nvidiaruntime is registered on the host.
Getting it running
On the host you need Docker with your user in the docker group, an SSH key registered in your GitHub account, and vcstool. ROS itself lives in the image, so you do not install it.
- Create your repository from the metapackage template on GitHub, then clone it.
- Import the packages listed in the manifest:
vcs import < .reposfrom the repository root. Do this before the first build, because the image collects everypackage.xmland resolves the dependencies while it is being built. Later,vcs pull -nupdates all of them at once. - Build the image and the workspace with
./build.sh. - Start it:
./start.sh --sim=gz(./start.sh sim) for simulation, plain./start.shon a real drone.
You know it worked when the tmux session opens and the status window fills with the MRS status overlay. In simulation you can take off straight away from the arm_and_offboard window, where the arming and offboard calls are waiting in the shell history.
./start.sh dev drops you into an interactive shell instead of the sessions, and ./kill.sh tears everything down.
It works too — rosdep install --from-paths src --ignore-src -r -y and colcon build --symlink-install from the workspace root. The template's own README.md has the step-by-step version of both paths.
How launching works
Everything you start is described by two tmuxinator sessions: one for the simulator and one per UAV. ./start.sh renders them and attaches you to the result.
./start.sh [--uavs=uav1,uav2,...] [--sim=gz|mrs] [--gui] [preset] [tmuxinator args]
- Asking for a simulator is what decides the mode. With
--simyou get the simulator session plus one session per UAV, without it you get the UAV sessions alone, which is what you want on a real drone. sessions/simulator.yamlandsessions/robot.yamlare the two templates; a ROS node you want launched is one entry in theirwindows:list.config/common/world.yamlcarries the shared world origin and safety area, whileconfig/<platform>/custom.yamlcarries the per-airframe MRS UAV System settings, chosen by$UAV_TYPEon a real robot and bysimin simulation.- A preset is a text file of flags under
presets/that you invoke by name, so./start.sh two_drones_gz_guireplaces a line of arguments you would otherwise retype. - Inside the session, Ctrl+a then Shift+S switches between UAVs and Ctrl+a then k closes it.
Always start from the repository root. tmux/start.sh is the inside-the-container half of the machinery and is not meant to be run by hand.
For how the sessions themselves are put together, see Tmux Session Preparation in the robot setup section.
Making it yours
Right after you create the repository, replace the example content:
README.md— the project name, description, logo and docs link, and delete the template notice at the top..repos— swap the examplemrs_robot_diagnosticsentry for your project's own repositories.tmux/sessions/,config/,presets/— your nodes, your airframes, your shortcuts.docker/Dockerfile— the MRS system version and ROS distribution build args, plus any extraaptorpipdependencies.
Everything else — the compose, the GPU detection, the vcs or colcon wiring — is meant to stay untouched. If you find yourself rewriting it, that is a good sign the fix belongs back in the template.
Tips
Release a package as a .deb
The template carries no release tooling of its own. Use the MRS CI scripts, which wrap bloom-generate in the same environment the build farm uses, see Local Docker Package Build.
Troubleshooting
Warning: you are already inside a tmux session
./start.sh refuses to nest sessions. Run it from a plain terminal. If you only lost the view of a running session, reattach with tmux -L f4f attach.
The NVIDIA GPU is not used
Starting the project prints a warning when nvidia-smi works but Docker has no nvidia runtime registered. Install the NVIDIA Container Toolkit and run nvidia-ctk runtime configure --runtime=docker.