Skip to content

Commit 25cf0cc

Browse files
committed
add safety_filter_cbf example
A new navigation example that teaches runtime safety as a separate layer. The agent is split into two pieces: - a naive nominal policy that ignores obstacles and points straight at the goal - a runtime safety filter that, at every step, checks the control-barrier-function condition dh/dt >= -alpha * h for each obstacle and projects the nominal velocity onto the closest safe half-space when it would be violated This is intentionally a different lesson from 02_reactive_obstacle_avoidance (the policy itself avoids obstacles) and 08_interactive_mpc (avoidance is folded into rollout cost). Here the policy stays naive on purpose; the filter is what keeps the robot safe. The info dict exposes u_nominal, u_safe, barrier_h_min, closest_approach, filter_active, filter_active_count, and stuck_count. A recoverable Failure(kind='safety_filter_stuck') fires when the projected velocity falls below the stuck threshold for a step. Smoke test asserts that the filter actually engages (filter_active_count >= 5), that u_nominal and u_safe differ on at least one step, and that the goal is reached with zero stuck steps under seed=0. Counts move to 32 examples / 31 GIFs / 80 tests / 12 navigation examples. The follow-up consultation with GPT Pro that produced this example, the 22 removal, and the 04/09 keep-both decision is recorded in docs/implementation_gap_audit.md.
1 parent ef0ffb6 commit 25cf0cc

10 files changed

Lines changed: 629 additions & 15 deletions

File tree

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ robotics loops rather than standalone algorithms.
1111

1212
## Current Status
1313

14-
- 31 runnable examples
14+
- 32 runnable examples
1515
- 20 learning-path roadmap examples
16-
- 30 README GIFs generated from runnable examples
17-
- 79 smoke and regression tests
16+
- 31 README GIFs generated from runnable examples
17+
- 80 smoke and regression tests
1818
- Core dependencies only: `numpy` and `matplotlib`
1919

2020
See `docs/status.md` for the implementation snapshot and `docs/plan.md` for
@@ -134,6 +134,10 @@ These GIFs are generated from the runnable examples, not separate animations.
134134
| --- | --- |
135135
| ![A grid robot scouts an observation point to reveal an unknown gate state, then runs A* with full information to either the short route or the long detour.](docs/assets/gifs/information_gain_navigation.gif) | ![A grid robot shares the grid with two goal-seeking other agents, predicts each agent's next step, and A* around the predicted cells to reach its own goal.](docs/assets/gifs/multi_agent_avoidance.gif) |
136136

137+
| Safety filter (CBF) |
138+
| --- |
139+
| ![A point robot's naive go-to-goal nominal velocity is projected at each step onto a control-barrier-function half-space for each obstacle, sliding around them without the policy itself ever knowing they exist.](docs/assets/gifs/safety_filter_cbf.gif) |
140+
137141
### Embodied AI
138142

139143
| Goal command pick | Door search POMDP |
378 KB
Loading

docs/implementation_gap_audit.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ continuous-control Gymnasium adapter, and the curiosity exploration example.
66

77
## Current Stable Surface
88

9-
- 31 runnable examples
10-
- 20 numbered learning-path examples plus 11 extras
11-
- 30 generated README GIFs with nonblank checks
12-
- 79 smoke, adapter, and regression tests
9+
- 32 runnable examples
10+
- 20 numbered learning-path examples plus 12 extras
11+
- 31 generated README GIFs with nonblank checks
12+
- 80 smoke, adapter, and regression tests
1313
- CI green on Python 3.10, 3.11, and 3.12
1414
- Gymnasium-style adapters for `GridWorld2D`, `DynamicObstacleGridWorld`,
1515
`BlockedPathWorld`, `MovingObstacleWorld`, and `Tabletop2D`

docs/plan.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ first-run experience small, fast, and failure-aware.
88

99
The repository currently has:
1010

11-
- 31 runnable examples
11+
- 32 runnable examples
1212
- 20 numbered learning-path examples
13-
- 11 extra examples outside the original learning-path roadmap
14-
- 30 generated README GIFs
15-
- 79 smoke and regression tests
13+
- 12 extra examples outside the original learning-path roadmap
14+
- 31 generated README GIFs
15+
- 80 smoke and regression tests
1616
- GitHub Actions CI for Python 3.10, 3.11, and 3.12
1717
- core dependencies limited to `numpy` and `matplotlib`
1818
- optional Gymnasium-style adapters for `GridWorld2D`,
@@ -104,6 +104,15 @@ Recent completed work:
104104
`21_object_permanence_toy.py` without adding a clearly different lesson.
105105
The remaining cognitive-robotics example for memory under loss of
106106
observation is `21_object_permanence_toy.py`.
107+
- `examples/navigation/29_safety_filter_cbf.py` was added. A naive
108+
go-to-goal nominal policy is paired with a separate runtime safety
109+
filter that, at every step, projects the nominal velocity onto the
110+
closest CBF-style safe half-space for each obstacle. The example
111+
exposes `u_nominal`, `u_safe`, `barrier_h_min`, `closest_approach`,
112+
`filter_active_count`, and `stuck_count` in `info`, and surfaces a
113+
recoverable `safety_filter_stuck` Failure when the projection clips
114+
the velocity below the stuck threshold. GIF and smoke test cover the
115+
loop.
107116
- `examples/world_models/23_model_error_recovery.py` was added. The agent
108117
starts with an identity dynamics model, detects a regime shift when
109118
prediction error spikes, runs a short system-identification probe phase,

docs/status.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ see what exists, what is verified, and what should come next.
55

66
## Snapshot
77

8-
- Runnable examples: 31
8+
- Runnable examples: 32
99
- Learning-path roadmap examples: 20
10-
- README GIFs: 30
11-
- Smoke and regression tests: 79
10+
- README GIFs: 31
11+
- Smoke and regression tests: 80
1212
- Core dependencies: `numpy`, `matplotlib`
1313
- Contributor extra: `pip install -e ".[dev]"`
1414
- CI: Python 3.10, 3.11, 3.12
@@ -29,7 +29,7 @@ goal-command example. The numbered 20-example roadmap is tracked in
2929
| Area | Examples | Main concepts |
3030
| --- | ---: | --- |
3131
| Runtime | 2 | smallest observe-act-observe loop, trace replay |
32-
| Navigation | 11 | reactive avoidance, dynamic obstacles, replanning, exploration, belief, active SLAM, MPC, recovery, localization recovery, information-gain detour, multi-agent avoidance |
32+
| Navigation | 12 | reactive avoidance, dynamic obstacles, replanning, exploration, belief, active SLAM, MPC, recovery, localization recovery, information-gain detour, multi-agent avoidance, CBF safety filter |
3333
| Manipulation | 10 | retry, reactive grasping, IK servo, moving target reaching, search, push recovery, suction sorting, belief grasp selection, active viewpoint grasp, clear path before pick |
3434
| Embodied AI | 6 | controlled goals, memory, POMDP search, tiny VLA loop, object permanence, curiosity exploration |
3535
| World models | 2 | action-conditioned dynamics, prediction error, model update, replanning, regime-shift detection, system identification |

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Run any example headless with its `--no-render` flag when available.
2727
| `navigation/10_localization_uncertainty_recovery.py` | `python examples/navigation/10_localization_uncertainty_recovery.py` | ambiguous pose -> information action -> resume goal |
2828
| `navigation/24_information_gain_navigation.py` | `python examples/navigation/24_information_gain_navigation.py` | scout observation -> reveal gate -> A* with full info |
2929
| `navigation/27_multi_agent_avoidance.py` | `python examples/navigation/27_multi_agent_avoidance.py` | observe agents -> predict next -> A* around predictions |
30+
| `navigation/29_safety_filter_cbf.py` | `python examples/navigation/29_safety_filter_cbf.py` | nominal u -> CBF projection -> safe u |
3031

3132
## Manipulation
3233

0 commit comments

Comments
 (0)