A component-based template system for creating synthetic ROS 2 systems through YAML configuration. This system provides a generic ROS 2 node that can be configured to simulate different behaviors and deployed using Docker Compose.
- Component-Based Architecture: Uses ROS 2 components for dynamic node loading
- YAML Configuration: Separate configuration files for system topology and individual nodes
- Docker Compose: Containerized deployment with simple command execution
- Flexible Node Behavior: Configurable timers, publishers, subscribers, and variables
- Namespace Support: Configurable ROS namespaces for multi-robot scenarios
- Docker and Docker Compose
- X11 forwarding for GUI applications (optional)
Edit the .env file to configure your system:
# System configuration
SYSTEM_CONFIG_FILE=system.yaml # Defines system topology
TEMPLATE_NAMESPACE=template_ns # ROS namespace
ROS_DOMAIN_ID=0 # ROS domain ID# Run the template system
docker compose --profile app upThat's it! The system will:
- Build the container if needed
- Load the system configuration from
system.yaml - Create multiple executors with nodes as defined in the configuration
- Run until you press Ctrl+C
The system includes support for ROS 2 tracing to monitor and analyze system behavior. The tracing functionality allows you to capture detailed execution traces of your template system.
To use the tracing functionality, you need to start services in a specific order:
First, start the tracing container in interactive mode:
# Start tracing service (requires interactive shell)
docker compose run tracingThis will start the tracing daemon and wait for you to press Enter to begin tracing.
Go back to the terminal running the tracing container and press Enter to start tracing. The system will now capture execution traces of all running ROS 2 nodes.
In a new terminal, start the Zenoh communication service:
# Start zenoh service
docker compose up zenohdNow start the actual services that run your template system:
# Start the template system
docker compose up template_system
# Or start other services like demo nodes
docker compose up talker listenerWhen you're done collecting traces, go back to the tracing terminal and press Enter again to stop tracing. The traces will be automatically saved to the traces/ directory.
Traces are saved in the traces/ directory with timestamps:
traces/session-YYYYMMDDHHMMSS/ust/uid/- Contains the actual trace data- Use analysis tools like
babeltrace2or ROS 2 tracing analysis tools to examine the traces
| Service | Purpose | Usage |
|---|---|---|
tracing |
Main tracing service | docker compose run tracing (interactive) |
analysis |
Analysis environment | docker compose run analysis |
test_tracing |
Test publisher for tracing | docker compose up test_tracing |
# Terminal 1: Start tracing (interactive)
docker compose run tracing
# Wait for prompt, then press Enter when ready to start tracing
# Terminal 1: Press Enter to begin tracing
# Terminal 2: Start zenoh
docker compose up zenohd
# Terminal 3: Start your system
docker compose up template_system
# ... let system run ...
# Terminal 1: Press Enter again to stop tracing
# Traces are now saved in traces/ directoryThe template system uses two types of configuration files:
Defines the overall system topology - which executors to create and which nodes run in each executor:
system:
name: "multi_node_template_system"
executors:
- name: "executor_1"
type: "single-threaded"
nodes: ["node1"]
- name: "executor_2"
type: "single-threaded"
nodes: ["node2"]
- name: "executor_3"
type: "single-threaded"
nodes: ["node3"]
nodes:
- name: "node1"
config_file: "node1_config.yaml"
- name: "node2"
config_file: "node2_config.yaml"
- name: "node3"
config_file: "node3_config.yaml"Each node has its own configuration file (e.g., node1_config.yaml) that defines its behavior:
name: "node1"
timers:
- period: 1.0
callback: "timer_callback_1"
subscriptions: []
publishers:
- topic: "/topic1"
variables:
- type: "std_msgs::Header"
name: "var1"
callbacks:
timer_callback_1:
execution_time: 0.1
publishers_to_publish: ["/topic1"]
variables_to_write: ["var1"]
variables_to_read: []Edit packages/src/template_system/config/system.yaml to:
- Change number of executors
- Assign different nodes to executors
- Add or remove nodes
Edit individual node config files in packages/src/template_system/config/ to:
- Change timer periods
- Add/remove publishers and subscribers
- Modify callback execution times
- Configure topic names
Edit .env file:
TEMPLATE_NAMESPACE=my_robots # Changes namespace from template_ns to my_robotsThe repository is structured as a ROS 2 workspace:
packages/src/template_system: The main ROS 2 package containing the generic node and launch files.config/: Contains YAML configuration files for the system and nodes.dockerfiles/: Dockerfile for building the application image.docker-compose.yml: Defines all the services for development, deployment, and tooling..vscode/: Contains VS Code specific settings like recommended extensions and tasks.traces/: Default output directory for ROS 2 tracing data.
The template_system package (located in packages/src/template_system/) provides:
- Generic Node Component: A configurable ROS 2 component that adapts its behavior based on YAML configuration
- Launch File: Dynamic launch file that reads system configuration and creates the appropriate executors and nodes
- Configuration Files: YAML files defining system topology and individual node behaviors
# List all topics
docker exec -it template_system ros2 topic list
# Monitor a specific topic
docker exec -it template_system ros2 topic echo /template_ns/topic1# Launch RQT graph tool
docker compose run rqt_graph# List running nodes
docker exec -it template_system ros2 node list
# Get node info
docker exec -it template_system ros2 node info /template_ns/node1# Enter development container
docker compose run development
# Inside container - build the package
colcon build --packages-select template_system --symlink-install
# Test the launch file
ros2 launch template_system multi_node_system.launch.pysystem.name: System identifierexecutors[]: List of executor definitionsname: Executor identifiertype: "single-threaded" or "multi-threaded"nodes[]: List of node names to run in this executor
nodes[]: List of node definitionsname: Node identifier (must match names used in executors)config_file: Path to individual node configuration file
name: Node nametimers[]: Timer definitionsperiod: Timer period in secondscallback: Callback name to execute
subscriptions[]: Subscription definitionstopic: Topic name to subscribe tobuffer_size: Queue size for messagescallback: Callback name to execute on message receipt
publishers[]: Publisher definitionstopic: Topic name to publish to
variables[]: Variable definitionstype: Variable type (currently supports "std_msgs::Header")name: Variable identifier
callbacks{}: Callback definitionsexecution_time: Simulated processing time in secondspublishers_to_publish[]: Topics to publish to during callbackvariables_to_write[]: Variables to update during callbackvariables_to_read[]: Variables to read during callback
| Variable | Description | Default |
|---|---|---|
SYSTEM_CONFIG_FILE |
System topology configuration file | system.yaml |
TEMPLATE_NAMESPACE |
ROS namespace for all nodes | template_ns |
ROS_DOMAIN_ID |
ROS 2 domain ID | 0 |
ROS_DISTRO |
ROS 2 distribution | humble |
RMW_IMPLEMENTATION |
ROS middleware | rmw_zenoh_cpp |
# Rebuild the container
docker compose build template_system
# Clean up containers
docker system prune# Check ROS_DOMAIN_ID conflicts
echo $ROS_DOMAIN_ID
# Use different domain ID
ROS_DOMAIN_ID=1 docker compose run template_system# Validate YAML configuration
python3 validate_configs.py
# Check configuration loading
docker exec -it template_system cat /home/ubuntu/workspace/packages/install/template_system/share/template_system/config/system.yaml- Fork the repository
- Create feature branch
- Make changes in development container
- Test with template system
- Submit pull request
Apache License 2.0