第4章 DWA算法深度剖析
DWA,全称 Dynamic Window Approach,中文叫“动态窗口法”。
说白了,它就是个“贪心”的局部规划器——每一小步都选当前最划算的速度组合。
我最早接触 DWA 是在一个差速底盘的项目上,当时机器人总在走廊里左右乱晃,后来才发现是评价函数权重没配好。嗯,这一章咱们就把 DWA 的底裤扒干净。
4.1 动态窗口——速度采样空间
DWA 的第一步,就是找出所有“可能的速度组合”。
注意,不是所有速度都能用。受限于电机加减速、最大速度、安全刹车距离,真正可用的 (v, ω) 其实被限制在一个“动态窗口”里。
动态窗口的约束条件:
- 自身最大/最小速度:v ∈ [v_min, v_max],ω ∈ [ω_min, ω_max]
- 电机加速度限制:当前速度加减速极限 (v₀ ± a_v·Δt)
- 安全制动:能在碰到障碍物之前刹停 (最大减速度)
我个人习惯把这三个约束画成三个圆(在速度空间里),它们的交集就是真正的“动态窗口”。
曾经有个项目,机器人一转弯就抖动,我查了半天发现是加速度限制设得太宽,窗口里包含了太多急转弯速度组合。嗯,调小加速度上限,抖动立刻消失。
4.2 轨迹预测——前向模拟
对窗口里的每一组 (v, ω),DWA 都会“脑补”未来一段轨迹。
默认预测 3~4 秒,步长 0.1~0.2 秒。说白了,就是拿运动模型往前推演,看看机器人会走到哪里。
# 伪代码示意:轨迹预测
def predict_trajectory(v, omega, dt, steps):
x, y, theta = 0, 0, 0
traj = []
for _ in range(steps):
x += v * cos(theta) * dt
y += v * sin(theta) * dt
theta += omega * dt
traj.append((x, y))
return traj
这里有个坑:如果你用的机器人是阿克曼底盘,千万别直接用差速模型。我见过有人把 car-like 机器人当差速算轨迹,结果规划出来的路径根本转不过弯。
4.3 评价函数——三要素加权
每条预测轨迹都会被打分。DWA 的标准评价函数包含三个子项:
| 子项 | 含义 | 我的经验 |
|---|---|---|
| heading | 朝向误差:轨迹终点与目标点的角度差 | 权重太大容易“直愣愣”冲向目标,忽略障碍物 |
| velocity | 速度大小:鼓励快速移动 | 我一般给 0.1~0.3,太快容易刹不住 |
| clearance | 离最近障碍物的距离 | 这个权重低了会撞墙,高了会绕远路 |
调参小技巧: 我通常先固定 heading 权重为 1.0,然后调 clearance 让机器人刚好能通过窄门。velocity 权重最后加,用来微调速度。曾经在仓库项目中,clearance 权重从 0.2 提到 0.5,机器人就不再蹭货架了。
4.4 避坑指南 & 个人经验
DWA 看起来简单,但实际调参时容易踩坑。我列几个常见的:
- 窗口太小导致无解:如果动态窗口里所有轨迹都会碰撞,DWA 会直接卡住。解决办法是增大刹车距离或降低最大速度。
- 评价函数归一化:三个子项的量纲不同,必须归一化到 [0,1]。我习惯用当前窗口内的最大值做分母。
- 预测步数太多:预测 5 秒以上计算量暴增,而且远距离轨迹不准确。我一般设 3 秒,步长 0.15 秒。
⚠️ 曾经踩过的雷: 有一次我把
max_vel_x 设得很大,但加速度很小,导致动态窗口里全是低速组合,机器人慢得像蜗牛。后来把加速度和最大速度匹配起来,问题解决。记住:动态窗口的“动态”二字,就是强调它每帧都在变。
4.5 评价函数权重速查表
下面是我自己整理的一个初始参考范围,适合差速底盘室内导航:
| 参数 | 典型范围 | 说明 |
|---|---|---|
| heading_weight | 0.8 ~ 1.5 | 指向目标的重要性 |
| velocity_weight | 0.1 ~ 0.4 | 速度激励 |
| clearance_weight | 0.2 ~ 0.8 | 避障敏感度 |
你想想看,如果机器人总在空旷区域急刹车,大概率是 clearance 权重太高了。反过来,如果它贴着墙走,那就是 heading 权重过大。
最后说一句:DWA 的代码实现其实只有几百行,但调参能调一整天。