ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

无人机避障必读:EGO-Planner启动参数详解与调优实战

无人机避障必读:EGO-Planner启动参数详解与调优实战 做无人机自主导航的朋友对 ego-planner 应该都不陌生。我第一次在仿真里把它跑起来其实只花了十几分钟但真正让它规规矩矩避障、不抖不飘把启动参数吃透才算入门。很多刚接触的人以为把 launch 文件拉起来默认跑就行结果要么轨迹贴着障碍物擦过去要么速度忽快忽慢像抽风。这篇文章我就围绕 ego-planner 的启动参数从配置到实战避障应用把参数背后的原理、调参思路和踩过的坑一次说清楚。EGO-Planner 这个名字拆开看是 ESDF-free Gradient-based planner它最大的特点是绕开了传统方法里显式建 ESDF欧几里得符号距离场的环节直接对传感器点云做梯度优化所以计算开销小、实时性好。正因为它把很多约束都揉进了优化目标启动参数才显得格外重要参数给得合适轨迹既安全又顺滑给得离谱再好的规划器也会翻车。这篇文章适合刚接触 ego-planner、准备做仿真或实机避障的朋友也能帮已经被默认参数坑过一轮的人少走点弯路。1. EGO-Planner是什么为什么必须抠启动参数1.1 一句话讲清楚它的避障原理EGO-Planner 本质上是把局部路径规划当成一个“带约束的最优化问题”来解。它维护一条由多段多项式拼接而成的轨迹在每一帧根据当前点云信息把“离障碍物距离太近”“速度加速度超限”“路径不够平滑”“偏离目标方向”这几个因素分别写成代价项然后通过梯度下降法迭代调整轨迹的系数让总代价最小。这个思路很像我们日常拉一根橡皮筋目标点往前拽平滑性让它别拐直角障碍物则像一根根橡胶柱子把轨迹往外顶。传统方法会先在空间里建一张密度很高的 ESDF 图再用图搜索找出一条安全路径EGO-Planner 则连这张图都省了直接从点云里提取障碍物周围的梯度信息。这样的好处是实时性强尤其适合快速飞行时高频重规划代价是优化过程非常依赖参数因为这些代价项之间要加权平衡而权重就在启动参数里。1.2 参数模型从“能用”到“好用”的分水岭我见过不少朋友把 ego-planner 跑起来以后第一反应是“这轨迹怎么这么难调”。其实不是算法不行而是没有把参数当成一个整体来理解。启动参数大致可以分成四类第一类是运动学边界类比如最大速度、最大加速度第二类是路径规划类比如地图范围、前视距离、体素分辨率第三类是优化器的权重类比如对平滑、安全距离、目标倾向的重视程度第四类是与上下游接口的通信类比如话题名、坐标系、时间戳容差。这四类参数不是孤立存在的。运动学边界如果设得太小轨迹虽然安全但机动性差如果设得太大优化器很难在短时间内找到同时满足动力学约束的解。优化权重更是直接决定轨迹性格障碍物权重给高了轨迹会绕得很远给低了又容易擦着障碍物边缘走。所以我的习惯是不要“头痛医头”而是先把四类参数的定位理清楚再针对具体场景逐组调。这也是这篇文章想帮你建立起的整体认知。2. 启动参数全景解析从launch文件到参数服务器2.1 一个典型的ego-planner启动文件长什么样EGO-Planner 是基于 ROS 的工程所以启动参数本质上就是 ROS 参数服务器上的一组键值。最直接的入口是 launch 文件。一个常见的单机仿真 launch 文件大概长这样launch arg nameworld default$(find ego_planner)/worlds/basic.world / param nameuse_sim_time valuetrue / node pkgego_planner typeego_planner_node nameego_planner_node outputscreen param nameodometry_topic value/odom / param namepointcloud_topic value/cloud_registered / param namemax_vel value3.0 / param namemax_acc value3.0 / param namemap_size_x value8.0 / param namemap_size_y value8.0 / param namemap_size_z value3.0 / param nameoptimization/w_obs value10.0 / param nameoptimization/w_smooth value1.0 / param nameoptimization/w_goal value1.0 / /node /launch这里只是示例结构。真实工程里会把参数拆到单独的 yaml 文件用rosparam load或rosparam file.../一次性加载。因此你改参数之前第一件事是搞清楚哪些参数是写在 launch 里的哪些是写在 yaml 里的哪些是通过命令行动态传入的。曾经有同学在 launch 里改了速度限制却发现 yaml 后面又 load 了一次同样的键结果后加载的覆盖了手动改的值折腾了半天才反应过来。2.2 核心参数逐项拆解下面我把最影响避障效果的参数列一张表以我常用的这套工程分支为例。不同版本分支命名有差异但角色都是下面这些参数名类型默认值参考作用调整方向max_vel / max_accdouble3.0 / 3.0轨迹动力学限制约束速度加速度上限室内狭窄场景调小到1.5空旷场地可到5map_size_x/y/zdouble8.0 / 8.0 / 3.0规划器感知地图的范围超出范围不建图根据传感器量程设置太大增加无效计算resolutiondouble0.1前端路径搜索/体素分辨率越小越精细但计算量增大0.1一般够用sensing_horizondouble5.0规划轨迹的前视长度决定预判距离高速飞行要增大否则反应不过来clearancedouble0.3与障碍物的期望安全距离静态场景可设0.5动态场景适当减小optimization/w_obsdouble10.0障碍物斥力权重越大越远离障碍拥挤环境可加大空旷环境调小更顺滑optimization/w_smoothdouble1.0平滑项权重越大轨迹越平滑过大会切弯过小会抖动optimization/w_goaldouble1.0目标牵引权重越大越倾向直奔目标偏离目标过远时增大optimization/dtdouble0.1轨迹离散采样时间步长影响优化精度调小到0.05更精细但计算变重optimization/iter_numint10每次优化迭代次数实机资源紧张可减少但别小于5表里的参数我逐个说明一下。max_vel和max_acc不是越高越好它们要和执行机构的真实能力匹配。比如你用的无人机是 3 寸小机最大速度可能连 3m/s 都到不了规划器却按 5m/s 生成轨迹控制器就要天天追着轨迹跑最后的表现就是“失控感”。map_size的坑主要出在体素地图很多版本里这个值还会被感知模块拿去申请内存设得太大点云稀疏的环境会多出大量没意义的空白体素。sensing_horizon和clearance是避障场景里最需要一起调的两个值。sensing_horizon决定轨迹往前看多远相当于反应距离clearance决定期望贴着障碍物多远飞。高速飞行时前视距离不够等看到障碍物再转弯已经晚了。但前视距离设得太大轨迹又会因为远处不稳定的点云而频繁波动。优化权重三个兄弟w_obs、w_smooth、w_goal之间的比例关系比绝对值更重要。我一般先随便给一个组合看轨迹的倾向再去调整比例而不是一开始就追求某一项数值。2.3 参数修改的三种方式与生效范围参数的修改方式直接影响排错思路。第一种是改 yaml 或 launch 后重启节点这种方式最稳妥适合正式实验前固定一组参数。第二种是运行中用rosparam set或rqt_reconfigure动态调整适合在调试阶段快速试探。EGO-Planner 部分节点集成了动态重配置但不是所有参数都能动态改能动态改的一般在代码里用dynamic_reconfigure做了映射。第三种是编译期常量例如一些状态估计滤波器的窗长、线程池大小需要改头文件后重新编译。这里有个优先级和覆盖的问题。ROS 参数服务器上同一个 key 只能有一份值如果 launch 里先param namemax_vel value3.0/后面 yaml 又rosparam load了一个max_vel: 2.0那么最终生效的是后加载的 2.0而 launch 里的 3.0 会被静默覆盖。所以我建议一个工程里只在一个地方定义所有规划参数要么全部在 launch要么全部在 yaml否则排查起来非常痛苦。另一个容易踩的是节点名字带命名空间/ego_planner_node/...但 yaml 里却是全局名max_vel这也会导致参数读不到。用rosparam get /ego_planner_node/max_vel验证一下比反复重启节点高效得多。3. 避障场景下的参数调优实战3.1 静态障碍物安全距离与平滑度的取舍静态场景是最容易调的。比如模拟仓库里的货架、乱石堆目标是要让无人机在不撞的前提下尽量高效通过。我的步骤是先固定运动学边界速度 2.5加速度 2.0这个范围对大多数小无人机都友好。然后调clearance从 0.5 开始看轨迹如果发现某些狭窄通道根本过不去就把clearance降到 0.3 甚至 0.25。这里要注意clearance不是真实施加在轨迹上的硬约束而是优化目标里的期望距离所以调小之后不代表一定能安全通过还要把w_obs从 10 适当加到 15 或 20。然后是平滑度。在静态场景如果轨迹绕的弯特别大优先看看w_goal是不是太小因为目标牵引力不足会让轨迹“过于避让”。我见过一个案例明明障碍物旁边有空隙轨迹却绕了一个大圈原因是w_goal设为 0.5比w_obs低了太多。把w_goal调到 1.5 之后轨迹明显变得更“知趣”。静态场景的核心口诀是安全距离定下限目标权重定绕路程度平滑权重定轨迹气质。这三者调顺了大部分静态场景都能跑得又稳又省。3.2 动态障碍物反应速度和前瞻量的配合动态避障要复杂得多。EGO-Planner 本身是做局部规划它每帧接收点云后重新优化轨迹所以对动态障碍物的响应能力很大程度上取决于规划频率和前视距离。规划频率由时间步长dt和轨迹长度共同决定dt设得太大轨迹离散点太稀遇到突然横穿的目标容易反应不及dt设得太小优化计算时间上涨反而拉低实际规划频率。我一般用dt0.05-0.1配合sensing_horizon在 5 到 8 米之间给高速飞行留出制动距离。还需要注意动态场景不建议把clearance设成固定的大值。因为动态点云每一帧都在变安全距离太大轨迹会因为“看到”远处障碍物而频繁急转弯。更好的做法是把期望安全距离控制在比机身半径大一点的范围比如 0.3 到 0.4 米把反应动作交给更高频率的重规划而不是靠一次规划躲很远。这一点是我在真机上对比过几次才体会到的安全余量给得再大都不如让节点每秒多更新几次来得实在。另外如果有人形的快速目标建议把max_acc稍微放宽否则轨迹因为加速度限制拉不出急停段很可能会从目标身边带着速度“挤”过去。3.3 与感知、点云输入的联调参数ego-planner 虽然不需要建 ESDF但需要稳定、低延迟的点云输入。启动参数里有几个和感知强相关pointcloud_topic、odometry_topic、sensor_range、ground_filter。传感器范围如果设置得比实际激光雷达量程大地图里就会产生大量无效空白浪费计算资源设置得太小前视距离失效动态避障无从谈起。ground_filter是否打开很关键如果不把地面点过滤掉规划器会把地面也当成障碍物顶起来轨迹会被迫抬升影响飞行高度稳定性。还有一个非常容易被忽略的参数时间戳容差。无人机在一个多传感器系统中点云和里程计往往来自不同源如果时间戳对不上规划器会把障碍物放到错误的位置表现出来就是轨迹莫名绕远或者穿障碍。我的排查习惯是先用 plot 工具看/cloud_registered和/odom的时间戳延时如果超过 50 毫秒优先在启动参数里把pointcloud_timeout调大或开启最近邻时间戳匹配而不是先去调优化权重。很多“轨迹诡异”的问题根源根本不在规划器而在上游。4. 从仿真到实机启动参数迁移中的坑4.1 仿真参数为什么不能直接搬到实机仿真里用的一组参数在真机上往往会“水土不服”。我踩过的坑主要有三个第一是延迟不一样仿真里点云和里程计都是理想同步实机却经常有几十毫秒抖动导致同样的参数在实机上变得敏感第二是动力学模型不匹配仿真里的max_vel、max_acc是理想值实机小飞机可能根本拉不到轨迹生成得再漂亮跟踪控制器跟不上也会变成事故第三是噪声水平不一样点云噪声变大以后同等clearance下实机更容易触发避障急转。所以从仿真到实机我建议先把运动学边界降到仿真值的 70% 左右。比如仿真max_vel4.0实机先设 2.8max_acc也从 4.0 降到 3.0。这样虽然飞行姿态变保守但能让传感器噪声、控制延迟这些额外因素先被“喂”进来。等实机验证稳定了再逐步往回调。另一个建议是把iter_num适当增加因为实机点云噪声会让优化曲面更粗糙迭代次数太少可能收敛不到安全解。4.2 实机部署需要额外关注的启动参数除了上面提到的速度边界和迭代次数实机还要特别关注坐标系参数。EGO-Planner 默认在某个地图坐标系下规划如果你的无人机用 EKF 提供了不同 frame_id需要在启动参数里把planning_frame、odometry_frame都对上。我还习惯把轨迹发布话题的帧率适当提高默认如果只有 20Hz跟踪控制器会觉得轨迹更新太慢遇到动态障碍物时会有明显滞后。但帧率提高后 CPU 占用会上升实机板载电脑资源宝贵要平衡着来。还有一个容易被忽略的是map_size。实机传感器量程有限如果把地图范围设得比实际点云覆盖还大规划器会在没有信息的地方自由发挥一旦新障碍物出现轨迹可能突然大改。我通常把map_size设置成和sensing_horizon接近让规划器只处理有效数据减少无谓的全局重规划。另外实机的飞控可能输出非标准的速度单位比如 cm/s这种单位问题不会报错只会让轨迹看起来“软绵绵”或者“炸裂”务必先确认里程计状态量的单位。5. 常见问题与排查技巧实录5.1 配置了没生效命名空间与加载顺序这是群里问得最多的一类问题明明改了参数节点却像没看见一样。第一步不是检查代码而是先rosparam list看参数到底加载到哪个命名空间了。很多时候你改的是/planner_manager/max_vel节点却去读/ego_planner_node/max_vel自然没反应。第二步是检查 yaml 与 launch 的加载顺序我前面说过“后加载覆盖先加载”尤其要注意rosparam file.../的位置最好统一放在节点定义之前。如果参数确实读到了还是没有效果那可能是命名差异。不同版本的 ego-planner 对同一个概念可能用不同名字比如有的叫w_obs有的叫obs_weight。这时候去源码里搜param(xxx可以快速定位节点实际读取的参数名。这套方法虽然土但比对着文档猜效率高很多。我自己排查问题一半以上时间都在跟“参数名不对”“命名空间不对”做斗争。5.2 轨迹抖成鬼畜优化权重与时间步长的纠缠另一个高频问题就是轨迹高频抖动看起来像“鬼畜”。通常有两类原因一类是dt设得太小比如到 0.02同时迭代次数又少优化器还没来得及收敛轨迹每帧都在剧烈变化另一类是w_smooth和w_obs的比例失衡平滑项太弱障碍物斥力稍微变化一点轨迹就猛拐。处理办法是把dt先恢复到 0.1把迭代次数调高到 15 以上确认轨迹稳定后再慢慢往精细调。抖动还有一个来源是点云噪声。如果感知给的点云本身就跳来跳去规划器再稳也没用。我习惯在调试阶段用 rviz 看障碍点云的稳定程度如果点云每帧飘得太厉害就去上游加降采样或滤波参数而不是硬扛。这个现象在室内植被、玻璃幕墙附近特别明显激光点会来回反跳表现成轨迹频繁改变方向。这种问题用调规划参数解决不了一定得回到传感器处理环节。5.3 一键复现的调参测试方法调参最怕“凭感觉”。我自己的做法是写一个脚本把要试的参数组合循环跑一遍每次启动后记录起飞到完成避障的时间、平均速度、最小障碍距离、轨迹长度这些指标再横向对比。比如测试w_obs可以用一段简单的 bash 脚本在仿真里自动改参数并记录for obs in 8 10 12 15; do rosparam set /ego_planner_node/optimization/w_obs $obs sleep 5 # 这里手动发送一次目标点等待规划完成 # 在 rviz 里记录完成时间和轨迹或者用 rostopic echo 提取 done跑完之后把数据画成表格选择指标最好的那组。这个方法看起来笨但比“每次改一个数重启一次肉眼判断好坏”要靠谱得多尤其是在多个参数相互影响的时候。参数组合爆炸的问题可以用控制变量法解决同一时间只动一个维度比如先固定运动学边界只调权重再固定权重只调dt和sensing_horizon。否则两三个参数一起变出了问题你根本不知道是哪个引起的。提示真机测试不要一次性跳到激进参数建议先在仿真里把参数组合跑通再用我前面说的 70% 速度边界做现场验证。调参的目的不是追求某一个值好看而是找一个在多个场景下都不会出大问题的“甜点区间”。最后再分享一个小技巧EGO-Planner 的启动参数不要一个人闷头调。我在团队里把常用场景的参数整理成了一张表每次遇到新环境先按场景类型套用再根据现象微调两三个值。这样既保留了经验也减少了重复劳动。避障应用说到底比的不是谁模型调得花哨而是谁在突发情况里还能稳稳飞过去而这份稳定很多时候就藏在启动参数里的那几个不起眼的值上。
返回列表