Cbfkit
Toolbox for Robotics Control
Install / Use
/learn @bardhh/CbfkitREADME
CBFKit: A Control Barrier Function Toolbox for Robotics Applications
CBFKit is a Python/ROS2 toolbox designed to facilitate safe planning and control for robotics applications, particularly in uncertain environments. The toolbox utilizes Control Barrier Functions (CBFs) to provide formal safety guarantees while offering flexibility and ease of use. We additionally provide efficient JAX implementation of Model Predictive Path Integral (MPPI) control with support for reach-avoid specifications.
Table of Contents
- Key Features
- Supported Models
- Applications
- Installation
- Start with Tutorials
- ROS2
- Examples
- Citing CBFKit
- License
Key Features
- Generalized Framework: Supports the design of CBFs for various robotic systems operating in both deterministic and stochastic settings.
- ROS Integration: Seamlessly connects with ROS2, enabling multi-robot applications, environment and map encoding, and integration with motion planning algorithms.
- Diverse CBF Options: Provides a variety of CBF formulations and algorithms to address different control scenarios.
- Model-based and Model-free Control: Accommodates both model-based control strategies using system dynamics and model-free control approaches. Model-free algorithms to be added soon.
- Safety Guarantee: CBFs provide mathematically rigorous guarantees of safety by ensuring the system remains within a defined safe operating region.
- Flexibility: Allows users to specify custom safety constraints and barrier functions to tailor the control behavior to specific needs.
- Multi-layer Architecture: Allows seamless integration of planners, nominal controllers, and safety filter controllers.
- Efficiency: Leverages JAX for efficient automatic differentiation and jaxopt for fast quadratic program (QP) solving, enabling real-time control applications. Includes optional JIT compilation (
use_jit=True) for high-performance simulation loops. - Code Generation: Simplifies model creation with automatic code generation for dynamics, controllers, and certificate functions.
- Usability: Includes tutorials and examples for a smooth learning curve and rapid prototyping.
- Functional Programming: Built on functional programming principles, emphasizing data immutability and programmatic determinism.
Supported Models
CBFKit accommodates a range of control-affine system models:
- Deterministic Continuous-time ODEs: $\dot{x} = f(x) + g(x)u$
- ODEs with Bounded Disturbances: $\dot{x} = f(x) + g(x)u + Mw$
- Stochastic Differential Equations (SDEs): $dx = (f(x) + g(x)u)dt + \sigma(x)dw$
Applications
CBFKit can be applied to diverse robotics applications, including:
- Autonomous Navigation: Ensure collision avoidance with static and dynamic obstacles.
- Human-Robot Interaction: Guarantee safety during collaborative tasks and physical interaction.
- Manipulation: Control robot arms while avoiding obstacles and joint limits.
- Multi-Robot Coordination: Coordinate the movement of multiple robots while maintaining safe distances and avoiding collisions.
Installation
Prerequisites
- Python 3.10 – 3.12 (3.13+ is not yet supported)
Local Installation (pip)
-
Clone the repository:
git clone https://github.com/bardhh/cbfkit.git cd cbfkit -
Install the package:
pip install . -
(Optional) Install extras depending on your use case:
# Code generation support (needed by most tutorials) pip install ".[codegen]" # Visualization (matplotlib) pip install ".[vis]" # CasADi support pip install ".[casadi]" # Everything needed for development (linting, testing, notebooks, etc.) pip install ".[dev]" # Or combine several extras at once pip install ".[codegen,vis,dev]" -
(Optional) For an editable/development install so that local changes are reflected immediately:
pip install -e ".[dev]"
Note: On Apple Silicon (aarch64/arm64),
kvxoptis installed in place ofcvxopt. This is handled automatically.
Docker
CBFKit is also deployable via Docker. After setting up Docker (refer to the official Docker documentation for detailed instructions), proceed with one of the following methods:
VS Code Dev Container
- Open the project in VS Code.
- When prompted, reopen the folder in container and choose the CBFKit CPU Dev Container definition located at
.devcontainer/cbfkit-container. - The container uses the standard
Dockerfilethrough Docker Compose so macOS hosts always build the CPU image, while Linux users can optionally select the GPU profile (see below).
Docker Compose (command line)
The dev containers are backed by .devcontainer/docker-compose.yml, so you can use the same configuration outside of VS Code:
- Build the CPU image (works on macOS via x86 emulation):
docker compose -f .devcontainer/docker-compose.yml build cbfkit - Start an interactive development shell:
docker compose -f .devcontainer/docker-compose.yml run --rm cbfkit bash - When you are done, clean up the container:
docker compose -f .devcontainer/docker-compose.yml down
GPU Development (Linux hosts only)
The Compose file exposes a cbfkit_gpu service behind a gpu profile. Linux users with NVIDIA GPUs can enable it with:
docker compose -f .devcontainer/docker-compose.yml --profile gpu build cbfkit_gpu
docker compose -f .devcontainer/docker-compose.yml --profile gpu run --rm cbfkit_gpu bash
macOS builds always target the CPU image because GPU passthrough is not supported.
Start with Tutorials
Explore the tutorials directory to help you get started with CBFKit.
Note: Many tutorials utilize the code generation feature of CBFKit. Please ensure you have installed the necessary dependencies by running pip install "cbfkit[codegen]" before running them.
For a quick start without additional dependencies, try tutorials/unicycle_reach_avoid.py:
python tutorials/unicycle_reach_avoid.py
Open the Python notebook in the tutorials directory to get started. The script code_generation_tutorial.ipynb automatically generates the controller, plant, and certificate function for a Van der Pol oscillator. It also generates ROS2 nodes for the plant, controller, sensor, and estimator. These serve as a starting point for developing your own CBF-based controller.
Generated files/folders:
van_der_pol_oscillator
┣ certificate_functions
┃ ┣ barrier_functions
┃ ┃ ┣ __init__.py
┃ ┃ ┣ barrier_1.py
┃ ┃ ┗ barrier_2.py
┃ ┣ lyapunov_functions
┃ ┃ ┣ __init__.py
┃ ┃ ┗ lyapunov_1.py
┃ ┗ __init__.py
┣ controllers
┃ ┣ __init__.py
┃ ┣ controller_1.py
┃ ┗ zero_controller.py
┣ ros2
┃ ┣ __init__.py
┃ ┣ config.py
┃ ┣ controller.py
┃ ┣ estimator.py
┃ ┣ plant_model.py
┃ ┗ sensor.py
┣ __init__.py
┣ constants.py
┣ plant.py
┗ run_ros2_nodes.sh
We recommend going through the tutorials in the following order to get familiar with the architecture of our library.
code_generation_tutorial.ipynb(requirescbfkit[codegen])multi_robot_coordination.ipynb(requirescbfkit[codegen])mppi_cbf_reach_avoid.py(requirescbfkit[codegen])mppi_stl_reach_avoid.py(requirescbfkit[codegen])
Simulation Architecture
- Every simulation must define a planner, nominal controller, and a controller where the output of planner is passed to nominal controller and the output of nominal controller is then passed to the controller. The nominal controller is expected to designed to generate control input that steers towards a state waypoint. The controller is designed to be a filter after nominal controller.
- The planner can return a state or control input trajectory. If the planner returns a control input trajectory, the nominal controller is skipped and the controller is directly employed. If the planner returns a state trajectory, then the nominal controller is called first to convert the desired state into corresponding control input command which is then passed to the controller.
The flowchart below summarizes the architecture
Each function (dynamics, cost, constraint, controller) must follow a specific structure.
- dynamics:
- Input arguments: x (state)
- Return arguments: f, g (dynamics matrix for affine dynamics x_dot = f(x) + g(x)u)
- nominal controller:
- Input arguments: t (time), x (state), key (random key), reference (optional reference state)
- Return arguments: u (control), data (dictionary with the key "u_nom" mapping to designed u )
- Note: You can use
cbfkit.controllers.setup_nominal_controllerto adapt simpler functions likef(t, x)to this signature.
- cost function:
- Input arguments: state (array), action (array)
- Return arguments: cost (float)
- planner:
- Input arguments: t (time), x (state), key (for random number generation), data (dictionary containing necessary information)
- Return arguments: u (first control input in planned sequence (can be None if planner retutrns state trajectory instead of control trajectory)), data (dictionary containing extra information like found control or state trajectory)
- controller:
- Input arguments: t (time), x (state), u_nom (nominal control input), key (for random number generation), data (dictionary containing necessary information)
- Return arguments: u (control input), data (dictionary containing extra information)
The data (python dictionary) in planners and controllers is designed to cater to needs of different types of comntrollers and planners.
