神经安全过滤器

对应作业任务(2)传感器感知与任务(3)导航控制。

输入 360° 激光距离栅格与当前速度,输出修正后的速度指令。几何 CBF 层计算 候选动作的 0.6 s 路径间距,神经网络用行为克隆学习该层;标称控制器不含避障。


1. 模块定位

课程内的无人机项目都是"一个控制器/策略直接输出指令",没有独立的指令级 安全层:

已有模块 区别
uav_ppo_nav 端到端 RL,策略本身承担避障,无独立安全约束
uav_depth_gate_racing_e2e 端到端策略,碰撞率随训练波动
octree_uav_3d_pathfinding 几何规划,默认位姿已知,不处理底层指令

2. 架构

/lidar/points ──→ 3×36 距离栅格 ─┐
/uav/odom ─────→ 机头系速度 ──────┼─→ 116 维观测 ──┬─→ 几何 CBF(教师)
/uav/goal ─────→ 目标方向 ────────┘                 └─→ 神经安全层(部署)
/uav/cmd_vel_nominal ──→ 标称指令 ──────────────────────→ 修正指令

两个实现共用同一套观测与动作语义:

几何 CBF 神经安全层
间距来源 场景真值 SDF 网络前向
决策 候选集 + 0.6 s rollout 一次回归
延迟 19 ms 0.14 ms
用途 教师 / 上界 部署

3. 环境与数据

SafetyEnv:safety_field 场景,20 个盒/柱障碍,高度 1.2–2.8 m,范围 ±9 m。 障碍高度下限保证三层激光(−15°/0°/+15°)都能打到;底座自带的 obstacle_field 有 0.6 m 的低柱,在雷达锥之间是盲区。

动作是机头系速度,经一阶低通(tau=0.12 s)与航向跟随(2.5 rad/s) 变成参考轨迹,再由几何控制器跟踪。

项 值
控制频率 20 Hz
雷达 36 方位 × 3 俯仰,8 m
机体半径 0.16 m
标称速度 2.5 m/s
训练场景 seed 0–15
测试场景 seed 100–111

评价器数据(safety_dataset.npz):10 个场景、每场景 12 集,随机动作 + 标称扰动,11126 帧。标签 h 是沿当前速度的 0.6 s rollout 间距,q 是 给定动作后的 rollout 间距。

行为克隆数据(safety_imitation.npz):几何层闭环飞行 16 个场景 × 4 集, 10057 帧,左右镜像后 20114 条。


4. 几何 CBF 层

对候选速度 ,按环境动力学外推 0.6 s:

航向按速度方向以 2.5 rad/s 跟随,每一步取到障碍表面与地面的最小距离, 是整段路径的最小值。约束

可行候选里取离标称指令最近的一个,代价里加 0.2 的目标方向项;无可行候选时 输出零指令。候选集为速度缩放 × 方位角偏转(0/±30°/±60°/±90°)× 高度偏置, 共 89 个。

rollout 必须与环境的低通和航向跟随一致。早期用直线扫掠代替,安全层会把 转弯后的路径当成安全,碰撞率反而上升到 38%;换成同动力学 rollout 后 降到 8%。


5. 神经安全层

输入 116 维观测 + 3 维标称指令,输出 3 维修正指令:

Linear(119,128) → ReLU → Linear(128,128) → ReLU → Linear(128,3)

32259 个参数,纯 numpy 前向,CPU 单帧 0.14 ms。

训练用行为克隆,按 episode 切验证集(12%),MSE,Adam(lr=2e-3, weight decay=1e-4),120 轮,保留验证最优。

训练集 MSE 0.009,验证 0.15:16 个场景的覆盖仍然有限,换场景类型需要重采。


6. 闭环评测

12 个未见场景(seed 100–111),每个场景一集,起点/终点对穿障碍场,初始 扫掠间距 >1.0 m。碰撞判据是机体中心到障碍表面 <0.16 m;到达判据是离目标 <0.8 m;推进率 。


7. 实测结果

过滤器 碰撞率 到达率 推进率 最小间距 延迟
无过滤 42% 58% 74% 0.63 m 0.01 ms
刹车 17% 50% 72% 0.62 m 0.01 ms
几何 CBF 8% 75% 83% 0.84 m 19.0 ms
神经安全层 8% 75% 79% 0.77 m 0.14 ms

神经层与教师层的碰撞率、到达率相同,推进率低 4 个百分点,延迟低 136 倍。

单集时序(无过滤在 5.6 s 撞上障碍,神经层减速绕过):

测距噪声 0.08 m + 15% 丢点:

条件 碰撞率 到达率 推进率 最小间距
无噪声 8% 75% 79% 0.77 m
噪声 + 丢点 17% 75% 81% 0.53 m


8. 源码解析

uav_neural_safety_filter/core/
├── geometry.py   盒/柱/球 SDF、批量点间距、rollout 间距
├── ranges.py     3×36 距离栅格、方向距离、激光下界
├── env.py        SafetyEnv、safety_field、episode 生成
├── dataset.py    评价器数据、行为克隆数据、镜像增广
├── network.py    SafetyNet(h/q)与 PolicyNet(指令)
├── training.py   两类训练、按 episode 切验证集
├── filter.py     候选集、几何层、神经层、评价器层
└── experiment.py 闭环评测与汇总

8.1 geometry.py:rollout 间距

rollout_clearance_many 按环境的低通与航向跟随逐点外推,每步调用 clearance_points(向量化 SDF)。这是教师层与数据标签的共同来源。 用直线扫掠代替时,转弯后的路径被高估,闭环碰撞 38%。

8.2 ranges.py:零指令的方向约束

direction_range 对水平速度小于 0.2 m/s 的指令返回 (1,1),不施加方向 约束。早期对所有指令都取全局最近回波,刹停候选被误判为不安全,安全层 转而加速,碰撞率 75%。

8.3 env.py:场景与起点

safety_field 的障碍高度下限 1.2 m,保证三层雷达都能打到。起点/终点 生成时检查初始扫掠间距 >1.0 m,避免"一出生就注定碰撞"的评测样本。

8.4 filter.py:候选集与退路

候选集覆盖速度缩放、方位偏转与高度偏置,共 89 个。可行集为空时输出零 指令,而不是"离标称最近"——后者在近距状态会把无人机继续推向障碍。

8.5 评价器路线(对照)

SafetyNet 同时预测当前间距 h 与候选动作间距 q,在候选集上求 q >= 0.8 m。训练集 MAE 0.09 m,但闭环碰撞 25–75%:短视界约束对 0.1 m 级预测误差非常敏感。这条路线保留在代码里,作为"为什么不直接用 学习式评价器"的对照。


9. 复现步骤

# 仿真侧(Python ≥3.10)
python main.py --collect           --out data/safety_dataset.npz
python main.py --train             --data data/safety_dataset.npz --out data/safety_net.npz
python main.py --collect-imitation --out data/safety_imitation.npz
python main.py --train-policy      --data data/safety_imitation.npz \
                                   --out data/safety_policy.npz --epochs 120

# 任意机器(只需 numpy)
python main.py --selftest
python main.py --evaluate --model data/safety_policy.npz \
               --episodes 12 --max-time 20 --eval-seed 100 --out results.json
python main.py --figures  --model data/safety_policy.npz --results results.json \
               --outdir ../docs/img/air/uav_neural_safety_filter

ROS2 在线运行见包内 README.md。


10. 依赖