Development Workflow

This page describes how to organize your code, build and test it, debug it in the two ROS domains, and contribute changes to the CPM Lab.

Where to Put Your Code

Your own planner or tool belongs in your own workspace on top of the CPM Lab installation. You do not need to change or rebuild the CPM Lab:

mkdir -p ~/planner_ws/src
# create or clone your packages in ~/planner_ws/src

cd ~/planner_ws
source /opt/ros/jazzy/setup.bash        # Debian installation
# or: source <path-to-ros2-workspace>/install/setup.bash   # source build
colcon build --symlink-install
source install/setup.bash

The order of the source commands matters: your workspace is an overlay on top of the CPM Lab, so its packages are found first. Source the overlay in every terminal in which you start the lab or your planner. The control flow only lists planners that are installed in the environment it was started in.

Changes to the CPM Lab itself, e.g. a bug fix in the vehicle controller, require a source build, see Building from Source. The workspace also builds and runs in Docker, from the terminal or in the VS Code dev container, see Developing in Docker.

Working with the CPM Lab Repository

The workspace repository ros2-workspace-lab contains the meta package cpm_lab and includes all other packages as git submodules in src/:

Submodule

Packages

src/bridge

Bridge and control flow

src/common-interfaces

Message and service definitions

src/evaluation

Experiment recorder and cpm_eval

src/high-level-controller

Motion planners, including the example planner

src/indoor-positioning-system

IPS and cpm_calibrate

src/maps

Map server, maps and Lanelet2 extensions

src/mid-level-controller

Vehicle controller and simulation

src/visualization

Control Center and RViz plugins

Common commands:

# Clone with all submodules
git clone --recursive git@git.rwth-aachen.de:CPM/Project/Lab/ros2/workspaces/ros2-workspace-lab.git

# Update the workspace and check out the submodule commits it references
git pull
git submodule update --init --recursive

# Show the commit of every submodule
git submodule status

A submodule is a separate repository. A change usually touches one or more submodules and the workspace, and every repository gets a branch of the same name from dev:

# 1. In the workspace: a feature branch from dev
git switch dev && git pull && git submodule update --init --recursive
git switch -c feature/my-change

# 2. In every submodule you change: the same branch from its dev
cd src/mid-level-controller
git switch dev && git pull
git switch -c feature/my-change
# edit, build, test, commit and push inside the submodule
git push -u origin feature/my-change

# 3. In the workspace: record the new submodule commit on the feature branch
cd ../..
git add src/mid-level-controller
git commit -m "Update mid-level-controller"
git push -u origin feature/my-change

After git submodule update the submodules are in detached HEAD state. Switch to a branch before you commit.

Submodule pointers are updated together with the feature branch of the workspace. Merge the merge requests in this order:

  1. Merge the merge request of every submodule into its dev.

  2. In the workspace feature branch, point each changed submodule to the merged commit on its dev (git -C src/<submodule> switch dev && git -C src/<submodule> pull, then git add src/<submodule> and commit).

  3. Merge the workspace feature branch into the workspace dev. Its pipeline builds and tests exactly the submodule commits recorded in it.

The workspace dev therefore always references submodule commits that are on the dev branch of their repository, never commits of feature branches. Do not update submodule pointers directly on dev. The release later points the submodules to the released commits on main, see Releasing the CPM Lab.

Building

make build                                         # whole workspace
colcon build --packages-select <package>           # one package
colcon build --packages-up-to <package>            # one package and its dependencies
make simulation                                    # without the IPS, for computers without pylon

Testing

Most packages contain unit tests and the standard ROS2 linters (flake8, pep257, cpplint, uncrustify). Run them before you push, the same way the CI does:

make test PACKAGES="<package> ..."                 # build if needed, colcon test, print the results
make test                                          # all packages, like the CI job run_gtest

Keep the logic of your code separate from the ROS interface, so it can be tested without running ROS. The example planner shows this with path_utils.py, see Your First Motion Planner.

See Testing and CI for the CI jobs of every repository and how to reproduce them in the dev container.

Debugging

Mind the domain. A terminal only sees the nodes of its own ROS_DOMAIN_ID. Log messages of your planner are only visible in domain 1, the vehicles in domain 21, see Understanding the Domain IDs.

export ROS_DOMAIN_ID=1

# Is my planner running and connected?
ros2 node list
ros2 topic info /planner/command --verbose

# Are the states arriving and how often?
ros2 topic hz /planner/vehicle_states

# What does my planner send?
ros2 topic echo /planner/command --once

# Graph of nodes and topics
rqt_graph

# Log output of all nodes
ros2 run rqt_console rqt_console

Useful techniques:

  • Start your planner as external planner in its own terminal while developing, so you see its output and can restart it without restarting the lab, see Your First Motion Planner.

  • Record your experiments and evaluate them with cpm_eval, or replay them with ros2 bag play, see Evaluation Metrics and Own Analyses.

  • If Start never becomes available after deploying, follow the Deploy Checks.

  • QoS mismatches are a common reason for missing messages. ros2 topic info <topic> --verbose shows the QoS of all publishers and subscribers.

Contributing

Changes to the CPM Lab are welcome. Please:

  1. Follow the Style Guide.

  2. Add or update tests for your change.

  3. Add an entry to the Forthcoming section of the CHANGELOG.rst of every package you changed, see Releasing the CPM Lab.

  4. Push a branch and open a merge request into dev in the repository of the submodule and in the workspace, see above. main only receives releases.

  5. Do not change messages or services without need, see Changing Messages and Services.

  6. Update the documentation in the same change, see Maintaining the Documentation.

All contributions are licensed under the MIT license.