From ac49594e95b437f869a0ce0752bf8b4416841e1a Mon Sep 17 00:00:00 2001 From: Bardh Hoxha Date: Tue, 7 Jul 2026 13:47:01 -0400 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20v0.3.0=20=E2=80=94=20slim=20install?= =?UTF-8?q?,=20safe-RL=20Colab,=20GitHub=20Pages,=20and=20green=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Package CBFKit for distribution and first-time users: - Slim the core: move casadi/cvxopt/plotly/black from mandatory deps to extras (casadi, cvxopt, plotly, codegen); add all/solvers/vis umbrellas; dev pulls cbfkit[all]. `import cbfkit` now loads zero heavy deps, guarded by a new core-import CI job. - Bump VERSION to 0.3.0; enrich metadata (keywords, classifiers, URLs); absolutize README showcase image URLs so they render off-repo. - Add a Gymnasium safe-RL Colab quickstart (installs from GitHub). - README badges; GitHub Pages workflow to host the blog. - run_black degrades gracefully when black is absent so codegen works on a slim install; add a friendly ImportError for the CasADi controller path. Fix pre-existing CI failures (ruff was red on main, blocking all tests): - Remove unused locals (unicycle_sweep, monte_carlo_gpu, plot_mppi_ffmpeg). - Import Time in ros/_experiment.py (F821 undefined name). - Manim 2D backend raises NotImplementedError before requiring manim; guard the manim_3d_multi_robot import so the module loads without manim installed. Verified: 469 passed, ruff clean, python -m build + twine check pass. --- .github/workflows/ci.yml | 28 + .github/workflows/pages.yml | 41 + .gitignore | 3 + README.md | 86 +- blog/blog-carousel.js | 442 ++++ blog/index.html | 1813 +++++++++++++++++ .../gymnasium/safe_single_integrator.ipynb | 176 ++ pyproject.toml | 68 +- src/cbfkit/VERSION | 2 +- src/cbfkit/benchmarks/unicycle_sweep.py | 1 - .../create_new_system/generate_model.py | 22 +- src/cbfkit/controllers/adaptive_cvar_cbf.py | 5 + src/cbfkit/ros/_experiment.py | 1 + src/cbfkit/simulation/monte_carlo_gpu.py | 1 - src/cbfkit/utils/animators/animator.py | 24 +- .../visualizations/manim_3d_multi_robot.py | 7 +- .../utils/visualizations/plot_mppi_ffmpeg.py | 5 +- 17 files changed, 2644 insertions(+), 81 deletions(-) create mode 100644 .github/workflows/pages.yml create mode 100644 blog/blog-carousel.js create mode 100644 blog/index.html create mode 100644 examples/gymnasium/safe_single_integrator.ipynb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb33fcdd..f9dc6678 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,3 +68,31 @@ jobs: CBFKIT_TEST_MODE: "1" run: | pytest -m "slow" tests + + core-import: + name: Slim-core import (no extras) + runs-on: ubuntu-latest + env: + JAX_PLATFORM_NAME: cpu + steps: + - uses: actions/checkout@v6 + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.11" + - name: Install core only (no extras) + run: pip install . + - name: Assert the default import surface stays lean + run: | + python - <<'PY' + import sys + import cbfkit + from cbfkit.controllers.cbf_clf import vanilla_cbf_clf_qp_controller + from cbfkit.optimization.quadratic_program import get_solver + get_solver("fast") + get_solver("jaxopt") + heavy = {"casadi", "cvxopt", "kvxopt", "plotly"} + leaked = sorted(m for m in sys.modules if m.split(".")[0] in heavy) + assert not leaked, f"Heavy optional deps leaked into the default import: {leaked}" + print("OK: default import surface is lean (no casadi/cvxopt/plotly).") + PY diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 00000000..01b3f3e7 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,41 @@ +name: Deploy blog to GitHub Pages + +# Serves blog/ (the "CBFKit Reborn" landing page) at the project's Pages URL. +# One-time setup: repo Settings -> Pages -> Build and deployment -> Source: "GitHub Actions". +# All media in blog/index.html is referenced by absolute raw.githubusercontent URLs, +# so the deployed folder stays free of large binaries. + +on: + push: + branches: [main] + paths: + - "blog/**" + - ".github/workflows/pages.yml" + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Configure Pages + uses: actions/configure-pages@v5 + - name: Upload blog as Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: blog + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 6f6cbd97..51082cac 100644 --- a/.gitignore +++ b/.gitignore @@ -228,3 +228,6 @@ jax_cache/ # Generated results results/ + +# Local-only launch notes (not published to the repo) +docs/launch/ diff --git a/README.md b/README.md index 607de288..3e3c229a 100755 --- a/README.md +++ b/README.md @@ -1,14 +1,20 @@ # CBFKit: A Control Barrier Function Toolbox for Robotics Applications +[![Python 3.10–3.12](https://img.shields.io/badge/python-3.10--3.12-blue.svg)](https://github.com/bardhh/cbfkit) +[![CI](https://github.com/bardhh/cbfkit/actions/workflows/ci.yml/badge.svg)](https://github.com/bardhh/cbfkit/actions/workflows/ci.yml) +[![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://github.com/bardhh/cbfkit/blob/main/LICENSE) +[![arXiv](https://img.shields.io/badge/arXiv-2404.07158-b31b1b.svg)](https://arxiv.org/abs/2404.07158) +[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/bardhh/cbfkit/blob/main/examples/gymnasium/safe_single_integrator.ipynb) + CBFKit is a Python/ROS2 toolbox for safe planning and control using Control Barrier Functions (CBFs). Built on JAX for automatic differentiation and JIT compilation, it provides formal safety guarantees for robotic systems operating in deterministic, disturbed, and stochastic environments. It also includes an efficient JAX implementation of Model Predictive Path Integral (MPPI) control with reach-avoid specifications.

- MPPI navigation among pedestrians - CBF safety with head-on encounter + MPPI navigation among pedestrians + CBF safety with head-on encounter

- MPPI trajectory sampling - EKF state estimation + MPPI trajectory sampling + EKF state estimation

MPPI among pedestrians  |  CBF head-on safety
@@ -19,11 +25,19 @@ Supported dynamics: $\dot{x} = f(x) + g(x)u$, $\dot{x} = f(x) + g(x)u + Mw$, $dx ## Quick Start -Requires **Python 3.10--3.12**. +Requires **Python 3.10--3.12**. Install directly from GitHub: + +```bash +pip install "cbfkit @ git+https://github.com/bardhh/cbfkit.git" +``` + +Need optional features? Add extras, e.g. `pip install "cbfkit[gymnasium] @ git+https://github.com/bardhh/cbfkit.git"` (also available: `neural`, `casadi`, `cvxopt`, `plotly`, `manim`, or `all`). + +Or clone for development (editable install with all dev tools + extras): ```bash git clone https://github.com/bardhh/cbfkit.git && cd cbfkit -pip install -e . +pip install -e ".[dev]" python examples/unicycle/reach_goal/unicycle_reach_avoid_cbf.py ``` @@ -87,7 +101,7 @@ print(f"Final position: ({results.states[-1, 0]:.2f}, {results.states[-1, 1]:.2f Drop-in CBF safety filter for any continuous Gymnasium environment. Wraps the env so every action from your RL policy gets safety-projected by a CBF-QP before reaching the simulator — works with PPO, SAC, or any off-the-shelf algorithm, no policy retraining required. -

Safe RL: naive vs CBF-filtered policy

+

Safe RL: naive vs CBF-filtered policy

```bash python examples/gymnasium/safe_single_integrator.py @@ -97,7 +111,7 @@ python examples/gymnasium/safe_single_integrator.py Skip the math: learn the barrier function from samples. A small neural network learns h(x) from labeled safe/unsafe states, then plugs straight into CBFKit's CBF-QP controller. Useful when obstacles are hard to describe analytically — point clouds, learned occupancy maps, scanned environments. -

Neural CBF: agent avoiding a learned obstacle

+

Neural CBF: agent avoiding a learned obstacle

```bash python examples/neural_cbf/neural_cbf_obstacle_avoidance.py @@ -115,7 +129,7 @@ Measured on random PD QPs (50 reps after warmup) on the sizes typical of CBF-CLF | 4×10 | **785×** | 73× | | 8×20 | **696×** | 64× | -

QP solver wall-time comparison

+

QP solver wall-time comparison

```bash python benchmarks/qp_solver_comparison.py @@ -125,7 +139,7 @@ python benchmarks/qp_solver_comparison.py Cinematic 3D simulation rendering with Manim. Multi-robot reach-avoid in 3D, rendered via CBFKit's Manim backend. Shows the visualization stack scales from quick matplotlib plots to publication-quality 3D animations. -

Manim 3D render of multi-robot reach-avoid

+

Manim 3D render of multi-robot reach-avoid

```bash python tutorials/multi_robot_3d_reachavoid.py @@ -136,64 +150,64 @@ python tutorials/multi_robot_3d_reachavoid.py
- Ellipsoidal-obstacle CBF
- Ellipsoidal-obstacle CBF 🔗
Unicycle reach-goal with linear class-K
+ Ellipsoidal-obstacle CBF
+ Ellipsoidal-obstacle CBF 🔗
Unicycle reach-goal with linear class-K
- Stochastic CBF
- Stochastic CBF (SDE) 🔗
Safety under Brownian disturbance
+ Stochastic CBF
+ Stochastic CBF (SDE) 🔗
Safety under Brownian disturbance
- Robust CBF
- Robust CBF 🔗
Worst-case bounded disturbance
+ Robust CBF
+ Robust CBF 🔗
Worst-case bounded disturbance
- MPPI rollouts
- MPPI rollout sampling 🔗
Sampling-based planning
+ MPPI rollouts
+ MPPI rollout sampling 🔗
Sampling-based planning
- MPPI reach-avoid
- MPPI reach-avoid 🔗
Sampling-based planning with goal + obstacle cost
+ MPPI reach-avoid
+ MPPI reach-avoid 🔗
Sampling-based planning with goal + obstacle cost
- Multi-robot 2D coordination
- Multi-robot 2D 🔗
Coordination via shared CBFs
+ Multi-robot 2D coordination
+ Multi-robot 2D 🔗
Coordination via shared CBFs
- Fixed-wing aerial 3D
- Fixed-wing aerial 3D 🔗
UAV reach-drop-point in 3D
+ Fixed-wing aerial 3D
+ Fixed-wing aerial 3D 🔗
UAV reach-drop-point in 3D
- Pedestrian head-on
- Pedestrian head-on 🔗
Dynamic-agent avoidance
+ Pedestrian head-on
+ Pedestrian head-on 🔗
Dynamic-agent avoidance
- EKF state estimation
- EKF state estimation 🔗
Unicycle reach-goal under measurement noise
+ EKF state estimation
+ EKF state estimation 🔗
Unicycle reach-goal under measurement noise
- Van der Pol CLF
- Van der Pol (CLF) 🔗
Nonlinear regulation to the origin
+ Van der Pol CLF
+ Van der Pol (CLF) 🔗
Nonlinear regulation to the origin
- Model Predictive Control
- Model Predictive Control 🔗
Receding-horizon LTI tracking
+ Model Predictive Control
+ Model Predictive Control 🔗
Receding-horizon LTI tracking
- Quadrotor 6-DOF geometric tracking
- Quadrotor 6-DOF 🔗
Geometric SE(3) tracking + altitude CBF
+ Quadrotor 6-DOF geometric tracking
+ Quadrotor 6-DOF 🔗
Geometric SE(3) tracking + altitude CBF
- Monte Carlo safety verification
- Monte Carlo safety verification 🔗
200 stochastic CBF rollouts (jax.vmap), live empirical risk
+ Monte Carlo safety verification
+ Monte Carlo safety verification 🔗
200 stochastic CBF rollouts (jax.vmap), live empirical risk
diff --git a/blog/blog-carousel.js b/blog/blog-carousel.js new file mode 100644 index 00000000..d3901152 --- /dev/null +++ b/blog/blog-carousel.js @@ -0,0 +1,442 @@ +/** + * — Lightweight scroll-snap carousel Web Component. + * + * No Shadow DOM — uses scoped `bc-` class prefixes so page CSS still + * applies to slide content (benchmark charts, videos, images, etc.). + * + * The component fully owns video play/pause — do NOT put `autoplay` + * on