ROS2 Systemd Manager
ROS2 Systemd Manager is a YAML-driven tool to manage ROS 2 launch tasks as systemd services. Describe your workspaces and services once in ros2_services.yaml, then install, start, enable, update, and uninstall them through a single declarative config — with a generated Makefile for everyday systemctl shortcuts and an optional helper to write the ROS DDS environment (ROS_DOMAIN_ID / RMW_IMPLEMENTATION / ROS_LOCALHOST_ONLY) into your shell profiles.
What It Does
- Bootstrap local files with
ros2-systemd-manager init - Install units with
install - Install + start + enable with
apply - Remove units with
uninstall - Run synchronized update flow with stale-unit cleanup via
update - Regenerate Makefile only with
makefile - Upgrade the tool to the latest version via
upgrade - Write the ROS DDS environment into all shell rc/profile files with
set
Installation
Note: This tool is designed for Linux systems with systemd. Ensure you have Python 3.9+ and pip installed. It is recommended to use sudo for installation to allow systemd unit management.
sudo pip install ros2-systemd-manager
Verify the install:
ros2-systemd-manager -v
CLI
ros2-systemd-manager [-v] [-c CONFIG] [-w WORKSPACE_KEY] [-f] [-d [N]] [-r [NAME]] [-l [0|1]] [action]
Global options:
| Option | Description |
|---|---|
-v, --version |
Show the program's version number and exit. |
-c, --config PATH |
Path to the YAML config file (default: ./ros2_services.yaml, then the packaged default). |
-w, --workspace-key KEY |
Operate on a single workspace key (default: all workspaces defined in the config). |
-f, --force |
Force overwrite when running init. |
-d, --domain-id [N] |
ROS_DOMAIN_ID for set (default 0). Bare -d applies the default after confirmation. |
-r, --rmw [NAME] |
RMW for set: cyclonedds | fastrtps (default cyclonedds). Bare -r applies the default after confirmation. |
-l, --localhost-only [0|1] |
ROS_LOCALHOST_ONLY for set (default 1). Bare -l applies the default after confirmation. |
Supported actions:
initinstallapplyuninstallupdatemakefilesetupgrade
Action reference
init— Create a defaultros2_services.yamltemplate and Makefile in the current directory. Auto-fillsuser/groupwith the current user,homewith the current home directory, and sets the workspace key/path to the current directory. Also auto-detects an existingROS_DOMAIN_IDfrom your shell rc/profile files and injects it asros_domain_id. Use--forceto overwrite an existing config, or--config PATHto write elsewhere.install— Write the unit files to the systemd unit directory and rundaemon-reload, without starting or enabling them. Requires root.apply— Install units, then start and enable them on boot (services withenable: falseare started but not enabled). Requires root.update— Synchronize systemd with the YAML: stop previously tracked units, remove stale units (tracked but no longer present in the config), then install/start/enable the current units and refresh the Makefile. Requires root.uninstall— Stop, disable, and remove the configured unit files, then rundaemon-reloadandreset-failed. Requires root.makefile— Regenerate the local Makefile helper only; no systemd changes are made.set— Write selected ROS DDS env vars into shell rc/profile files (only the keys you pass). See ROS DDS Environment below. Requires root.upgrade— Self-upgrade this CLI tool viapip install --upgrade. Adds--userautomatically when not in a virtual environment and not running as root.
ROS DDS Environment (set)
The set action writes (or updates) ROS DDS variables into all relevant shell rc/profile files. The three variables it can manage are:
ROS_DOMAIN_IDRMW_IMPLEMENTATION(resolved from-r:cyclonedds→rmw_cyclonedds_cpp,fastrtps→rmw_fastrtps_cpp; fullrmw_*_cppnames pass through unchanged)ROS_LOCALHOST_ONLY
What gets written
Only the keys you actually request are touched — variables you do not pass are left unchanged.
| Invocation | Behavior |
|---|---|
set (no flags) |
Prompts for confirmation, then writes all three defaults (ROS_DOMAIN_ID=0, RMW_IMPLEMENTATION=rmw_cyclonedds_cpp, ROS_LOCALHOST_ONLY=1). Declining aborts with no changes. |
set -d 42 -r fastrtps |
Writes only the keys you passed (ROS_DOMAIN_ID=42, RMW_IMPLEMENTATION=rmw_fastrtps_cpp); ROS_LOCALHOST_ONLY is untouched. No confirmation. |
set -d (bare flag) |
Prompts for confirmation, then writes only that key's default (ROS_DOMAIN_ID=0). Other keys untouched. |
set -d 42 -r |
ROS_DOMAIN_ID=42 (explicit, no prompt) + prompt to confirm RMW_IMPLEMENTATION default. |
In short:
- No flags at all → confirm before applying all three defaults.
- Any flag present → only those keys are written.
- Bare flag (no value) → confirm before applying that key's default.
- Explicit value → applied directly, no confirmation.
sudo ros2-systemd-manager set # confirm, then write all defaults
sudo ros2-systemd-manager set -d 42 # write only ROS_DOMAIN_ID=42
sudo ros2-systemd-manager set -d 42 -r fastrtps # write domain 42 + Fast DDS only
sudo ros2-systemd-manager set -d 7 -l 0 # domain 7, allow multicast/remote
sudo ros2-systemd-manager set -d # confirm, then write ROS_DOMAIN_ID=0
Files touched
Files considered include the per-user .bashrc, .bash_profile, .zshrc, and .profile (for the invoking user under sudo, the effective user, and /root), plus /etc/profile and /etc/environment. Existing assignments are updated in place; missing variables are appended under a single managed block. When run under sudo, it targets SUDO_USER's home so the real user's rc files are updated (not just /root).
Note:
setdoes not change the per-serviceROS_DOMAIN_IDset via theros_domain_idworkspace option — that one is injected directly into each unit'sEnvironment=. Usesetfor the interactive shell environment used when you runros2 ...manually.
Init Output
Run in your desired config directory (e.g., ROS 2 workspace root) to generate the default YAML config and Makefile targets:
ros2-systemd-manager init
Generated files:
./ros2_services.yaml(default configuration)./ros2-systemd-manager.mk(generated makefile targets fragment)./Makefile(entrypoint that includes the.mkfile)
Note: The tool places generated makefile targets into
ros2-systemd-manager.mkto keep your rootMakefileclean. The rootMakefilewill automatically include the.mkfragment.
YAML Keys
Required top-level sections:
systemdruntimeworkspaces
Optional top-level sections:
actions(e.g.default_action; default action isapply)makefile
systemd
Controls unit placement and install behavior.
| Key | Default | Description |
|---|---|---|
unit_dir |
/etc/systemd/system |
Directory where unit files are written. |
wanted_by |
multi-user.target |
[Install] WantedBy= target (auto-start on boot). |
runtime
Defaults shared by all services unless overridden per service.
| Key | Default | Description |
|---|---|---|
user |
user |
User the service runs as (ignored for use_root: true services). |
group |
user |
Group the service runs as. |
home |
/home/user |
Used for Environment=HOME=. |
shell |
/bin/bash |
Shell used for ExecStart (-lc). |
restart |
on-failure |
systemd Restart= policy. |
restart_sec |
3 |
systemd RestartSec= (seconds). |
workspaces
A mapping of workspace keys (selectable via --workspace-key). Each workspace supports:
| Key | Required | Description |
|---|---|---|
path |
yes | Absolute path to the ROS 2 workspace (used as WorkingDirectory). |
setup_script |
no | Relative/absolute script sourced before launch (e.g. install/setup.bash). |
setup_scripts |
no | List of scripts sourced in order (alternative to setup_script for multi-source). |
ros_domain_id |
no | Integer injected as Environment=ROS_DOMAIN_ID= for this workspace's services. |
services |
no | List of service entries (see below). |
Service entries (workspaces.<key>.services[])
| Key | Required | Default | Description |
|---|---|---|---|
unit_name |
yes | — | systemd unit file name (e.g. ros2-foo.service). |
launch_command |
yes | — | Command run after sourcing setup scripts (e.g. ros2 launch ...). |
description |
no | unit_name |
[Unit] Description=. |
depends_on |
no | [] |
List of unit names; emits Requires= and After=. Must exist in the same workspace. |
service_options |
no | [] |
List of raw [Service] lines (e.g. CapabilityBoundingSet=, CPUAffinity=). |
use_root |
no | false |
When true, force this service to run as root/root with HOME=/root. |
enable |
no | true |
When false, the service is started but not enabled on boot. |
makefile
| Key | Default | Description |
|---|---|---|
output_path |
ros2-systemd-manager.mk |
Output path for the generated Makefile fragment (relative to the config file). |
command |
ros2-systemd-manager |
CLI command the Makefile invokes. |
Generated unit structure
For each service, a unit file is generated roughly like:
[Unit]
Description=<description>
Requires=<depends_on ...> # only when depends_on is set
After=network-online.target <depends_on ...>
Wants=network-online.target
[Service]
Type=simple
User=<user|root>
Group=<group|root>
WorkingDirectory=<workspace path>
Environment=HOME=<home>
Environment=ROS_DOMAIN_ID=<id> # only when ros_domain_id is set
ExecStart=<shell> -lc 'source "<setup>" && ... && exec <launch_command>'
<service_options ...> # only when service_options is set
Restart=<restart>
RestartSec=<restart_sec>
[Install]
WantedBy=<wanted_by>
Example YAML Configuration
Below is a sample ros2_services.yaml demonstrating common fields and layout.
systemd:
unit_dir: /etc/systemd/system
wanted_by: multi-user.target
runtime:
user: user
group: user
home: /home/user
shell: /bin/bash
restart: on-failure
restart_sec: 3
workspaces:
default_ws: # Workspace key, selectable via --workspace-key
path: /home/user/default_ws
setup_script: install/setup.bash
# ros_domain_id: 0 # Optional: set ROS_DOMAIN_ID to isolate DDS traffic per workspace
services:
- unit_name: ros2-foxglove-bridge.service
description: ROS2 Foxglove Bridge
use_root: false # Optional: default false. When true, force this service to run as root.
enable: true # Optional: default true. Set false to start without auto-start on boot.
launch_command: ros2 launch foxglove_bridge foxglove_bridge_launch.xml
- unit_name: ros2-soem-bringup.service
description: ROS2 Simple Open EtherCAT Master Bringup (https://github.com/AIMEtherCAT/EcatV2_Master)
use_root: false
service_options: # Example of granting specific capabilities to a service without running as root
- CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN
- AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN
launch_command: ros2 launch soem_bringup bringup.launch.py
- unit_name: ros2-infantry-chassis.service
description: ROS2 Infantry Chassis Controller
depends_on:
- ros2-soem-bringup.service
launch_command: ros2 launch infantry_controller infantry_chassis.launch.py
- unit_name: ros2-sp-vision-autoaim.service
description: TongjiSuperPower/sp_vision_25 Auto Aim (via self defined sp_vision_launch)
enable: false # Example: start on demand, do not auto-start on boot
service_options:
- CPUAffinity=1 2 3 # Example of setting CPU affinity for a service
launch_command: ros2 launch sp_vision_launch sp_vision.launch.py config:=sentry.yaml
# Multi-source example with domain isolation:
# another_ws:
# path: /home/user/another_ws
# ros_domain_id: 42
# setup_scripts:
# - /opt/ros/humble/setup.bash
# - install/setup.bash
# services:
# - unit_name: ros2-another.service
# description: Another workspace service
# launch_command: ros2 run pkg node
This example shows how to define:
systemdsettings for unit placement and installation behaviorruntimedefaults shared by all services- one or more
workspaces, each with its ownserviceslist depends_onrelationships between services- optional
service_optionsfor extra systemd directives - optional
enable: falseto start a service without enabling it on boot - optional
ros_domain_idto isolate DDS traffic per workspace - optional
setup_scripts(list) to source multiple scripts before launching
Generated Makefile
Note: The generated Makefile targets are designed to be intuitive and cover common systemd management tasks. You can customize the generated targets by modifying the
workspacessection in your YAML config.
Primary targets:
make upgrade # self-upgrade ros2-systemd-manager via pip
make install # install unit files only
make apply # install + start + enable
make start # systemctl start all configured units
make stop # systemctl stop all configured units
make restart # systemctl restart all configured units
make status # systemctl status all configured units
make status-long # systemctl status with 100 log lines
make enable # systemctl enable all configured units
make disable # systemctl disable all configured units
make logs # follow logs for all configured units
make logs-recent # show last 200 log lines for all configured units
make <op>-<service> # op in start/stop/restart/status/enable/disable/logs
make <op>-<service>-<sfx> # e.g., logs-<svc>-recent, status-<svc>-long (100 lines)
make uninstall # uninstall all configured units
make update # stop old + uninstall + install/start/enable + refresh mk
make makefile # refresh generated mk only (no systemd changes)
Config behavior:
- No hardcoded absolute config path.
- Default auto-discovery strictly looks for
./ros2_services.yamlin the current running directory. - Override manually via
CONFIGenvironment variable or--configparameter:
# Using Makefile with custom config
make apply CONFIG=./my_services.yaml
# or
ros2-systemd-manager apply --config ./my_services.yaml
- Operate on a single workspace via
--workspace-key:
sudo ros2-systemd-manager apply --workspace-key default_ws
File Tracking & Safety
- Automatic Backups: Whenever files in
/etc/systemd/system/are modified (viaupdate,install, oruninstall), a copy of the exact deployed file along with its MD5 hash (and a globaltotal.md5hash) is stored in~/.config/ros2-systemd-manager/previous-update/. - Modification Detection: During
updateoruninstalloperations, the manager usesfilecmpanddiffto check if you have manually modified the systemd service file. If modifications are detected, it presents a diff in the terminal and asks if you want to archive your manual changes to~/.config/ros2-systemd-manager/archive/before proceeding with the overwrite/deletion. Choices: archive + proceed (Y), proceed without archiving (u), or cancel (c). - Stale-unit Cleanup:
updatecompares the previously tracked units against the current config and removes any unit that is no longer defined.
Safety
- Use trusted launch commands only.
- Validate workspace paths and setup scripts before
applyorupdate. - Prefer
installfirst for new services.
Contributing
Licensed under the Apache License 2.0. See LICENSE for details.
Contributions are welcome! Please open issues or submit pull requests for bug fixes, improvements, or new features.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ros2_systemd_manager-0.2.0.tar.gz.
File metadata
- Download URL: ros2_systemd_manager-0.2.0.tar.gz
- Upload date:
- Size: 32.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
37e44257e884a4efcaec33cc1dfb05c5f2e7c674bd312ef4e824380f35d1572d
|
|
| MD5 |
0a458f275f2ca35cd935dc37bc233937
|
|
| BLAKE2b-256 |
652f377d4265f9e07f0a9679ae73c78a571b4801b11a89eff49e42879b02475c
|
Provenance
The following attestation bundles were made for ros2_systemd_manager-0.2.0.tar.gz:
Publisher:
release-pypi.yml on hnrobert/ros2-systemd-manager
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ros2_systemd_manager-0.2.0.tar.gz -
Subject digest:
37e44257e884a4efcaec33cc1dfb05c5f2e7c674bd312ef4e824380f35d1572d - Sigstore transparency entry: 2012856493
- Sigstore integration time:
-
Permalink:
hnrobert/ros2-systemd-manager@4875b2c4654d97916e2278acee27b074324a89f4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/hnrobert
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@4875b2c4654d97916e2278acee27b074324a89f4 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ros2_systemd_manager-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ros2_systemd_manager-0.2.0-py3-none-any.whl
- Upload date:
- Size: 32.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
949a214c604c9ec70bebf2636331f5ca821fcf560c0ea23bc4934da74aeb3ddf
|
|
| MD5 |
3db41d4181380bd263a6d171ab165882
|
|
| BLAKE2b-256 |
6734fff596dcecfb7be5a4b6438dc6475fc14340d3d5acd11ee834403e92594f
|
Provenance
The following attestation bundles were made for ros2_systemd_manager-0.2.0-py3-none-any.whl:
Publisher:
release-pypi.yml on hnrobert/ros2-systemd-manager
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ros2_systemd_manager-0.2.0-py3-none-any.whl -
Subject digest:
949a214c604c9ec70bebf2636331f5ca821fcf560c0ea23bc4934da74aeb3ddf - Sigstore transparency entry: 2012856544
- Sigstore integration time:
-
Permalink:
hnrobert/ros2-systemd-manager@4875b2c4654d97916e2278acee27b074324a89f4 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/hnrobert
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@4875b2c4654d97916e2278acee27b074324a89f4 -
Trigger Event:
workflow_dispatch
-
Statement type: