Simulation Code: Where To Put Safety? Control Barrier Function Placement in Networked Control Systems
This repository contains the Python code accompanying the paper
Where To Put Safety? Control Barrier Function Placement in Networked Control Systems by S. Beger, Y. Chen and S. Hirche.
submitted to IEEE Control System Letters 2026.
This repository simulates a 3 DoF planar robot conducting a pick-and-place task with obstacle avoidance. A model predictive controller creates a desired path at 20 Hz, which a local PD+ controller tracks at 200 Hz. We compare four safety-filter architectures:
Nominal: no safety filter is considered.LocalCBF: a myopic CBF is placed locally before the PD+ controller.MPC-CBF: the remote MPC includes the CBF constraints.Combined: remote MPC-CBF and local myopic CBF are used together.
Overview of the considered networked predictive control system. We analyse the robustness-performance tradeoff following from the different CBF placements in the control architecture.
Clone the repository and create a clean Python environment:
git clone https://github.com/TUM-ITR/WhereToPutSafety.git
cd WhereToPutSafety
python -m venv .venvActivate the environment.
On Windows:
.venv\Scripts\activateOn Linux/macOS:
source .venv/bin/activateInstall the required packages:
pip install -r requirements.txtRun the default example:
python main.pyThe default example runs the Combined architecture with bounded disturbances. Simulation outputs as well as generated figures or animations are written to timestamped folders in data/.
The main simulation routines are implemented in src/sim_module/sim_runner.py and are exposed through the command-line interface in main.py.
The general command structure is:
python main.py --mode <mode> [options]The available modes are:
| Mode | Description |
|---|---|
single |
Run one simulation for one selected architecture. |
compare |
Run one simulation for each architecture. |
monte-carlo |
Run Monte Carlo simulations for selected architectures. |
delay-sweep |
Run Monte Carlo simulations over several delay values. |
disturbance-sweep |
Run Monte Carlo simulations over several disturbance bounds. |
Generated simulation data, plots, and animations are saved in timestamped folders under data/.
The default single-run example uses the Combined architecture.
A different architecture can be selected with --architecture:
python main.py --mode single --architecture LocalCBFThe available architecture names are:
| Architecture | Description |
|---|---|
Nominal |
No safety filter is considered. |
LocalCBF |
A myopic CBF is placed locally before the PD+ controller. |
MPC-CBF |
The remote MPC includes the CBF constraints. |
Combined |
Remote MPC-CBF and local myopic CBF are used together. |
For single runs, plots and animation are enabled by default. They can be disabled with:
python main.py --mode single --architecture Combined --no-plot --no-animateThe comparison mode runs all four architectures:
python main.py --mode compareDisturbances can be disabled with the additional flag --no-disturbances.
Monte Carlo simulations can be run with:
python main.py --mode monte-carlo --trials 50 --architectures LocalCBF MPC-CBF CombinedBy default, individual plots and animations are disabled for Monte Carlo runs to reduce computation time. Summary plots can be enabled with --summary-plot.
A delay sweep can be run with:
python main.py --mode delay-sweep --trials 20 --delays 1 3 7 10The selected architectures can be specified using --architectures LocalCBF MPC-CBF Combined.
If no delay values are provided, the default delay sweep values from src/sim_module/params.py are used.
All delays here are known, compensated delays. To add uncompensated delays, please change params.tau_residual.
A disturbance sweep can be run with:
python main.py --mode disturbance-sweep --trials 20 --disturbances 0.005 0.01 0.02 0.03The selected architectures can be specified as --architectures LocalCBF MPC-CBF Combined.
If no disturbance bounds are provided, the default disturbance sweep values from src/sim_module/params.py are used.
The following flags control output generation:
| Flag | Effect |
|---|---|
--plot |
Generate plots for individual runs. |
--no-plot |
Disable plots for individual runs. |
--animate |
Generate animations for individual runs. |
--no-animate |
Disable animations for individual runs. |
--summary-plot |
Generate summary plots for comparison, Monte Carlo, and sweep modes. |
--no-summary-plot |
Disable summary plots. |
For example, to run a fast single simulation without animation:
python main.py --mode single --architecture Combined --no-animateWhereToPutSafety/
├── README.md
├── requirements.txt
├── main.py
├── assets/
│ ├── robot.gif
│ └── SystemOverview.svg
├── data/
│ └── .gitignore
└── src/
├── controller_module/
│ ├── local_cbf.py
│ ├── pd_plus.py
│ └── remote_mpc_cbf.py
├── plant_module/
│ └── robot_dynamics.py
├── predictor_module/
│ └── state_predictor.py
├── sim_module/
│ ├── data_recorder.py
│ ├── generate_disturbance.py
│ ├── obstacles.py
│ ├── params.py
│ └── sim_runner.py
└── helper/
├── analysis/
│ ├── post_processing.py
│ └── post_processing_MonteCarlo.py
└── plot_code/
├── plots_for_paper.py
└── plotting_3dof.py
The main modules are:
controller_module: remote MPC-CBF, local CBF, and local PD+ tracking control.plant_module: 3 DoF planar robot dynamics and kinematics.predictor_module: delay compensation through state prediction.sim_module: simulation loop, obstacle definitions, disturbance generation, and data recording.helper/analysis: post-processing and paper-plot routines.helper/plot_code: plotting, animation, and trajectory export utilities.
Generated simulation data is intentionally excluded from version control. The data/ folder is kept as output location, but their generated contents should not be committed.
The code was tested with Python 3.10. It uses the following main packages:
numpyscipypandasmatplotlibcasadiopenpyxlpillow
The optimal control problem is solved with Casadi (click for references).
Install all dependencies with:
pip install -r requirements.txtThe simulations can be computationally demanding because the remote MPC and the local CBF are solved repeatedly along the trajectory. For a quick test, reduce params.N_horizon or the number of Monte Carlo trials.
If you use this software in your research, please cite:
@article{WhereToPutSafety2026,
title={Where To Put Safety? Control Barrier Function Placement in Networked Control Systems},
author={Beger, Severin and Chen, Yuling and Hirche, Sandra},
journal={arXiv preprint arXiv:2603.29792},
year={2026}
}