NN 输入含障碍物坐标 · 动态场景 · 方案B坐标拼接 · 最多5个障碍物
本演示采用 障碍物感知神经网络:NN 输入不仅包含起点位姿(4D),还包含障碍物坐标(25D = 5个障碍物 × 5参数),共 29 维。网络能根据不同障碍物布局生成不同的泊车轨迹,而非仅适应固定场景。
v3 版本的核心改进是将障碍物信息直接编码到 NN 输入中(方案B 坐标拼接),使网络能根据不同障碍物布局生成不同轨迹。求解管线在 v2 的 NN 热启动基础上增加了碰撞拒绝机制——如果精修结果仍有碰撞,自动回退到完整同伦延拓;如果同伦也无法消解碰撞,则拒绝求解而非返回危险路径。
与 v2 的关键区别:v2 的 IPOPT 精修失败时直接返回不可行解(不触发兜底);v3 增加了碰撞检查 → 同伦兜底 → 碰撞拒绝的完整安全链。这是因为 v3 面对随机障碍物布局,NN 泛化不到的场景更多,必须有可靠的回退机制。
采用方案B(坐标拼接):每个障碍物用 5 个参数 (cx, cy, w, h, θ) 描述,最多 5 个障碍物,不足补零。所有输入在送入网络前做 z-score 归一化(减均值除标准差),这在 v2 中未实现。
| 分量 | 维度 | 含义 |
|---|---|---|
| 起点位姿 | 4 | x, y, θ₁, θ₂ — 卡车起始位置和朝向 |
| 障碍物 1-5 | 25 | 每个 5 参数:中心点(cx,cy)、宽高(w,h)、旋转角(θ) |
| 填充 | 0 | 不足 5 个障碍物时补零 |
| 总计 | 29 | 固定长度,无需变长网络结构 |
与 v2 完全相同的 ResNet MLP 架构,仅输入维度从 4D 改为 29D:
| 层 | 类型 | 输入→输出 | 参数量 |
|---|---|---|---|
| ① 输入映射 | Linear + GELU | 29 → 256 | 7,680 |
| ② ResBlock × 5 | 残差块(fc+LN+残差) | 256 → 256 | 659,200 |
| ③ 输出映射 | Linear + tanh缩放 | 256 → 160 | 41,120 |
| 总计 | ≈ 708,000 (0.71M) | ||
残差块结构(与 v2 相同):h = GELU(fc₁(x)); h = LayerNorm(h); h = fc₂(h); out = GELU(x + h)。输入直接跳过两层加到输出(残差连接),保证梯度可以无损传回。
归一化差异:v3 在训练和推理时都使用 z-score 归一化(norm_stats_v3.json 存储了 start 和 obstacles 各自的均值/标准差)。v2 虽然训练时也计算了归一化统计量,但推理代码从未读取使用——这是 v3 相对 v2 的一个隐性改进。
从 NN 预测出发,通过 3 个阶段逐步施加碰撞约束。每个阶段的解作为下一阶段的初始猜测:
| 阶段 | 终端权重 tw | 碰撞权重 cw | 预算 | 碰撞处理 | 目标 |
|---|---|---|---|---|---|
| Stage 0 | 10⁴ | 0 | 1s | 无碰撞项 | NLP 更小更快,先把终端姿态拉到位 |
| Stage 1 | 10⁴ | 5,000 | 1.5s | 软惩罚 (hinge²) | soft penalty 把车身逐渐推离障碍物 |
| Stage 2 | 10⁶ | 10⁶ | 2s | 硬约束 (g ≥ 0) | cw ≥ 10⁶ 触发硬碰撞约束,得到零碰撞解 |
NLP 建模:决策变量 X(4×81) + U(2×80) = 484 维。运动学约束使用 RK4 积分(dt=0.5s, N=80, 总时窗 40s)。目标函数与 v1/v2 一致:J = 0.1·Σv² + 0.1·Σδ² + 0.5·Σ(Δδ)² + 0.5·Σ(Δv)² + tw·终端偏差。碰撞约束对每步 12 个车身采样点检查 AABB 有符号距离(含 0.5m 安全裕度)。
自适应通道约束:y_front_max 根据起点距离三档切换——远点 (dist>14) 为 8.0、高近点 (y>0.5) 为 7.5、低点为 99.0(不限制),限制牵引车前端 y 坐标防止摆入上方墙。
这是 v3 独有的安全机制。3 阶段精修完成后,求解器会评估最终轨迹的碰撞次数:
同伦兜底使用与训练数据生成相同的完整 solve_homotopy_v3(4-6 阶段,按起点类型自适应),从 gen_guess_adaptive 4 段前向仿真出发求解。这是最慢但最可靠的路径——当 NN 热启动 + 3 阶段精修都无法消解碰撞时(通常是因为障碍物布局极端),回退到暴力求解。
| 项目 | 数值 | 说明 |
|---|---|---|
| 训练数据 | 6,113 条 | 6 组随机种子生成(seed 100-600),每条约 1000-2000 条 |
| 每条样本 | start(4D) + obstacles(25D) + X(4×81) + U(2×80) | 起点 + 障碍物编码 + 轨迹 + 控制序列 |
| 训练/验证比 | 90% / 10% | ≈5500 训练 / ≈600 验证 |
| 损失函数 | L_ctrl + 0.5·L_traj + 1.0·L_coll | 与 v2 相同的三重约束(详见 v2 页面 §6) |
| 优化器 | AdamW (lr=1e-3, wd=1e-4) | CosineAnnealing 余弦退火 |
| Batch / Epochs | 32 / 500 | 梯度裁剪 max_norm=1.0 |
| 最佳模型 | epoch 100, val_loss=0.418 | 保存验证集 loss 最低的 checkpoint |
损失函数三项(与 v2 完全一致):
① L_control(权重 1.0):MSE(预测控制序列, 真实控制序列)
② L_trajectory(权重 0.5):将预测控制序列通过可微 RK4 积分成轨迹,与真实轨迹做 MSE——端到端学习
③ L_collision(权重 1.0):12 个车身采样点对当前样本的障碍物做 hinge² 惩罚——每条样本的障碍物不同,碰撞损失是 sample-specific 的
v3 的训练数据由 generate_data_v3.py 离线生成。每条样本的生成流程:随机障碍物布局 → 随机起点 → 完整同伦求解 → 质量筛选 → 保存。
结构化障碍物布局(random_obstacles())——不是纯随机撒点,而是模拟真实停车场结构:
| 障碍物 | 生成方式 | 位置范围 | 尺寸范围 |
|---|---|---|---|
| ① 左侧邻车(必选) | 随机 | cx∈[−7,−4], cy∈[−12,−10] | w∈[4,6], h∈[7,9] |
| ② 右侧邻车(必选) | 随机 | cx∈[3,6], cy∈[−12,−10] | w∈[4,6], h∈[7,9] |
| ③ 对侧墙(n≥3 时) | 随机 | cx∈[−5,5], cy∈[8,9.5] | w∈[20,35], h∈[1.5,2.5] |
| ④ 额外车辆(0-2 个) | 安全区域随机 | 左远/右远/左下/右下 | w∈[2,4], h∈[2,4] |
起点采样:x∈[−20, 2], y∈[−2, 3], θ₁∈±20°, θ₂∈±15°,最多重试 200 次找到无碰撞起点。
求解器:使用完整 solve_homotopy_v3(CasADi/IPOPT),按起点距离自适应 4-6 阶段(远点 6 阶段 timeout=40s,高近点 4 阶段 timeout=25s,低点 4 阶段 timeout=20s)。
质量门:collisions==0 且 θ₁误差<0.5° 且 θ₂误差<0.5° 且 U_sol≠None 才保存。6113 条数据全部满足此标准。
| 特性 | v2(固定场景) | v3(障碍物感知) |
|---|---|---|
| NN 输入 | 4D (起点) | 29D (起点 + 障碍物) |
| 输入归一化 | 未使用(死代码) | z-score 归一化 ✓ |
| 障碍物 | 硬编码 3 个 (WALL+CAR_L+CAR_R) | 动态输入,最多 5 个,用户可编辑 |
| IPOPT 精修 | 2 阶段 mini-homotopy | 3 阶段 mini-homotopy |
| 碰撞处理 | 精修失败返回不可行解 | 同伦兜底 + 碰撞拒绝 ✗ |
| 训练数据 | 756 条,固定场景 | 6,113 条,6组随机种子,随机障碍物 |
| 最佳 val_loss | 0.328 (epoch 225) | 0.418 (epoch 100) |
| 网络参数 | 0.70M (4→256→160) | 0.71M (29→256→160) |
| 求解器端口 | :5781 | :5782 |
| API 路径 | /api2/solve | /api3/solve |