4、STOMP与CHOMP:梯度优化算法、参数调优、对比分析
说到避障规划,很多朋友一上来就盯着OMPL猛调。其实我个人觉得,STOMP和CHOMP才是真正能体现“调参艺术”的算法。它们不像RRT那样靠随机采样碰运气,而是用优化思想,让轨迹自己“长”成一条光滑无碰撞的路径。
今天咱们就聊聊这两个家伙。我会把我在项目里踩过的坑、总结的经验,一股脑倒出来。
4.1 梯度优化算法的核心思想
先问个问题:为什么需要梯度优化?
你想想看,RRT*虽然能找出一条路径,但那条路径往往歪歪扭扭,关节速度突变,机器人跑起来像喝醉了酒。而梯度优化算法,说白了就是给轨迹一个“初始猜测”,然后不断修正它,让它在“光滑”和“避障”之间找到平衡。
CHOMP用的是梯度下降。它计算轨迹的“代价函数”对每个路径点的梯度,然后沿着梯度下降方向更新轨迹。代价函数里包含两项:光滑代价(让轨迹平滑)和碰撞代价(让轨迹远离障碍物)。
STOMP呢?它用的是随机优化。它不依赖梯度,而是通过采样噪声来探索轨迹空间。每次迭代,它生成一批带噪声的轨迹,然后根据代价函数的好坏,加权平均得到新的轨迹。
核心区别一句话:CHOMP是“跟着梯度走”,STOMP是“撒网捞鱼再择优”。
我在一个六轴机器人焊接项目里试过这两种算法。当时工件表面反光严重,视觉识别偶尔会丢帧。CHOMP在梯度计算时容易陷入局部最优,而STOMP因为采样范围大,反而能跳出坑。嗯,这里要注意:没有的好坏,只有适不适合你的场景。
4.2 STOMP参数调优
STOMP的参数,说实话,比CHOMP多。但调好了,效果是真香。
4.2.1 核心参数一览
| 参数名 | 作用 | 我的推荐值 |
|---|---|---|
num_iterations |
迭代次数 | 40~80 |
num_rollouts |
每次迭代的采样轨迹数 | 10~30 |
noise_stddev |
噪声标准差 | 0.1~0.5 |
smooth_cost_weight |
光滑代价权重 | 0.1~1.0 |
collision_cost_weight |
碰撞代价权重 | 1.0~10.0 |
4.2.2 调参实战经验
先调噪声标准差。 我习惯从0.3开始。如果轨迹抖动厉害,就减小到0.1。如果轨迹一直无法避开障碍物,就增大到0.5。记住:噪声太小,探索不足;噪声太大,轨迹会散架。
再调采样数。 num_rollouts 设成20是个不错的起点。如果规划时间太长,可以降到10。如果碰撞检测总失败,就升到30。我曾经在一个狭窄通道场景里,把采样数提到50才找到可行路径——代价是规划时间多了3倍。
最后调权重。 我个人建议先固定 smooth_cost_weight 为0.5,然后调 collision_cost_weight。如果轨迹离障碍物太近,就加大碰撞权重。如果轨迹太“僵硬”,就减小光滑权重。
小技巧: 在MoveIt的STOMP配置文件中,可以开启 print_trajectory_info 来查看每次迭代的代价变化。如果代价曲线下降很快然后停滞,说明参数还行。如果曲线震荡,说明噪声太大了。
4.3 CHOMP参数调优
CHOMP的参数相对少,但每个参数都很“敏感”。
4.3.1 核心参数一览
| 参数名 | 作用 | 我的推荐值 |
|---|---|---|
learning_rate |
学习率 | 0.1~0.5 |
max_iterations |
最大迭代次数 | 50~100 |
smooth_cost_weight |
光滑代价权重 | 0.01~0.1 |
collision_cost_weight |
碰撞代价权重 | 1.0~5.0 |
collision_clearance |
碰撞安全距离 | 0.1~0.3米 |
4.3.2 调参实战经验
学习率是CHOMP的灵魂。 设大了,轨迹会发散;设小了,收敛太慢。我一般从0.2开始。如果轨迹在迭代过程中出现“弹跳”,就减半。如果收敛太慢,就加倍。但别超过0.5,否则容易炸。
碰撞安全距离 这个参数很有意思。它决定了机器人离障碍物多远就开始“感到威胁”。设成0.2米比较稳妥。如果场景里障碍物很多,可以降到0.1米,让机器人“贴边”走。但小心——太小的安全距离会导致轨迹紧贴障碍物,一旦有误差就会撞上。
我曾经在调试一个码垛机器人时,把 collision_clearance 设成了0.05米。结果仿真里看着完美,实际运行时因为吸盘有0.02米的误差,直接撞上了货架。嗯,从那以后我再也不敢把安全距离设得太小。
注意: CHOMP对初始轨迹很敏感。如果初始轨迹穿过障碍物,CHOMP很可能无法把它“拉”出来。建议先用RRT*生成一条无碰撞的初始轨迹,再用CHOMP做平滑优化。
4.4 对比分析
说了这么多,咱们来做个对比。我直接画了张图,帮你理清思路。
从图上能看出来,STOMP和CHOMP是互补的。我个人的经验是:
- 场景简单、要求实时性:用CHOMP。比如焊接、喷涂这类轨迹相对固定的任务。
- 场景复杂、障碍物多:用STOMP。比如仓库拣选、狭小空间作业。
- 最稳妥的方案:先用RRT*快速找一条无碰撞路径,然后用CHOMP做平滑优化。这样既保证了无碰撞,又得到了光滑轨迹。
我的建议: 别纠结于“哪个更好”。在MoveIt里,你可以同时配置STOMP和CHOMP,根据场景动态切换。我在一个柔性制造项目里就是这么干的——白天用CHOMP追求效率,晚上用STOMP处理复杂工件。
4.5 代码实战:在MoveIt中配置STOMP和CHOMP
光说不练假把式。咱们看看怎么在MoveIt里配这两个算法。
4.5.1 STOMP配置示例
# stomp_planning.yaml
stomp:
planner_configs:
- stomp_default
stomp_default:
num_iterations: 60
num_rollouts: 20
noise_stddev: 0.3
smooth_cost_weight: 0.5
collision_cost_weight: 5.0
max_rollouts: 100
exponentiated_cost: true
print_trajectory_info: true
4.5.2 CHOMP配置示例
# chomp_planning.yaml
chomp:
planner_configs:
- chomp_default
chomp_default:
learning_rate: 0.2
max_iterations: 80
smooth_cost_weight: 0.05
collision_cost_weight: 3.0
collision_clearance: 0.2
animate_path: false
add_randomness: false
调试小技巧: 在MoveIt的Rviz插件里,开启“显示轨迹”和“显示代价”。这样你能直观看到每次迭代轨迹的变化。如果轨迹在障碍物附近“抖动”,说明参数需要微调。
好了,关于STOMP和CHOMP的调优,咱们就聊到这儿。记住:没有万能参数,只有不断试错。你可以在仿真里大胆调,调坏了也不怕。等找到一组好参数,再部署到真机上。
可可精品资料库