ARTICLE DETAIL

资讯详情

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

Navigation2 全局规划器组件级测试完整指南:PlannerTester 的代价地图世界模型、路径质量校验与随机化回归测试

Navigation2 全局规划器组件级测试完整指南:PlannerTester 的代价地图世界模型、路径质量校验与随机化回归测试 机器人ROS自动驾驶【免费下载链接】navigation2ROS 2 Navigation Framework and System项目地址https://gitcode.com/gh_mirrors/na/navigation2点击查看免费下载本指南围绕 Navigation2ROS 2 Navigation Framework中全局规划器Global Planner的组件级测试方案展开以 nav2_system_tests/src/planning/README.md 为核心骨架深入剖析PlannerTester节点如何用代价地图表达世界、请求规划服务并校验路径质量。读完本文你将掌握该测试体系的工作原理、PlannerTester的核心接口与生命周期、单次与随机化测试的判定逻辑以及如何基于仓库源码将其复用于新的全局规划插件NavFn、Smac、Theta* 等的回归验证。全局规划器随机测试输出示例蓝色球体为起点、绿色球体为目标点、红色线段为计算出的路径、灰色格子为障碍物一、测试架构总览PlannerTester 的职责与定位PlannerTester是一个为全局规划器专门设计的组件级测试节点它承担三项核心职责见 planner_tester.hpp提供世界表示以代价地图costmap的形式表达环境规划器据此搜索路径发送规划请求向全局规划器发起路径生成请求ComputePathToPose语义的createPlan调用接收并校验路径接收返回的nav_msgs::msg::Path检查其是否与障碍物碰撞、起终点是否与请求一致。该测试体系刻意采用简化版世界模型 简化版代价地图来隔离变量不依赖完整仿真环境、不依赖传感器数据流只验证给定一张代价地图规划器能否给出正确、无碰撞的路径这一核心契约因此非常适合作为全局规划器的单元级/组件级回归测试基线。从源码结构看测试目录 nav2_system_tests/src/planning 中共有两类参与者PlannerTester继承nav2::LifecycleNode扮演测试驱动者负责构造世界、管理生命周期、发起请求并做断言NavFnPlannerTester继承nav2_planner::PlannerServer直接复用真实生产代码中的规划服务端planner_server确保测试对象与线上实现一致而不是另写一套测试专用规划器。其中NavFnPlannerTester通过公开onConfigure/onActivate/onDeactivate/onCleanup四个生命周期钩子允许测试代码显式驱动规划服务端的状态机这为隔离测试环境提供了便利。二、世界模型代价地图与六种内置测试场景文档明确指出目前世界被表示为一张代价地图测试使用简化版世界模型与代价地图。仓库中这一抽象由 nav2_util/include/nav2_util/costmap.hpp 的nav2_util::Costmap实现它支持两种来源静态地图通过set_static_map()从nav_msgs::msg::OccupancyGrid填充内置测试数据通过set_test_costmap()加载硬编码的测试代价地图。内置测试代价地图共六种通过枚举TestCostmap定义枚举值场景含义open_space完全空旷的 10x10 栅格无障碍bounded有边界约束的地图bottom_left_obstacle左下角放置障碍物top_left_obstacle左上角放置障碍物maze1迷宫场景 1maze2迷宫场景 2这六种场景覆盖了无障→单障碍→复杂迷宫的难度梯度test_planner_costmaps_node.cpp 中的testSimpleCostmaps测试会依次对全部六种场景执行一次defaultPlannerTest并断言全部成功。Costmap还提供一组静态常量用于映射常见代价语义no_information未知对应代价 255、lethal_obstacle致命障碍、inscribed_inflated_obstacle、medium_cost、free_space。构造参数包括trinary_costmap是否三值化、track_unknown_space是否跟踪未知区域、lethal_threshold致死阈值与unknown_cost_value未知代价取值。PlannerTester构造函数中给出的默认值planner_tester.cpp为trinary_costmap_ truetrack_unknown_space_ falselethal_threshold_ 100unknown_cost_value_ -1默认测试地图类型TestCostmap::open_space三、PlannerTester 的核心接口与生命周期管理PlannerTester对外暴露的主要方法如下完整声明见 planner_tester.hpp方法作用activate()/deactivate()激活/反激活测试器负责启动节点、规划器与 TF 广播loadDefaultMap()从TEST_MAP环境变量指定的地图图片加载真实地图并生成代价地图loadSimpleCostmap(TestCostmap)直接加载某一种内置测试代价地图defaultPlannerTest(path)用固定起终点执行单次路径测试判据为无碰撞且终点一致defaultPlannerRandomTests(n, fail_ratio)执行 n 次随机起终点测试失败率超阈值则判失败isPathValid(...)封装IsPathValid服务调用校验给定路径的合法性3.1 激活流程activateactivate()会按顺序完成以下初始化planner_tester.cpp启动独立线程旋转 ROS 节点nav2::NodeThread创建Costmap并默认加载open_space测试地图10x10 空栅格启动机器人位姿 TF 广播map → base_link初始位置为(1.0, 1.0)每 100ms 发布一次创建NavFnPlannerTester规划服务端并声明三个关键参数GridBased.use_astar true启用 A* 变体而非纯 Dijkstraexpected_planner_frequency -1.0不约束规划频率避免测试因频率告警失败costmap_update_timeout 0.0不等待代价地图更新超时发布map话题OccupancyGrid用于可视化/调试创建is_path_valid服务客户端依次驱动规划服务端完成onConfigure与onActivate。注意其中NavFnPlannerTester是真实规划服务端nav2_planner::PlannerServer的子类这意味着测试直接走生产代码的配置与规划路径具备很高的可信度。3.2 世界加载的两种方式方式一真实地图loadDefaultMap。从环境变量TEST_MAP读取地图图片路径使用nav2_map_server的loadMapFromFile加载加载参数在 planner_tester.cpp 中硬编码为分辨率resolution 1.0negate false占用阈值occupancy_threshold 0.65空闲阈值free_threshold 0.196原点偏移origin {0.0, 0.0, 0.0}地图模式MapMode::Trinary三值化。若TEST_MAP未设置会抛出运行时异常并给出明确提示。加载成功后通过 1 秒周期的定时器持续在map话题上发布地图并将using_fake_costmap_置为false。方式二内置测试代价地图loadSimpleCostmap。直接调用costmap_-set_test_costmap(testCostmapType)速度快、无 I/O 依赖适合作为 CI 常规测试路径。四、单次路径测试defaultPlannerTest 的起终点约定defaultPlannerTestplanner_tester.cpp执行一次固定起终点的规划并校验结果起终点根据世界来源不同而不同内置测试地图using_fake_costmap_为 true起点(1.0, 1.0)→ 目标(8.0, 8.0)在 10x10 栅格内留出边界确保起点与目标均位于空闲区域真实地图起点(390.0, 10.0)→ 目标(10.0, 390.0)以世界坐标系表述规划器内部会自行转换到地图坐标系。随后调用plannerTest(robot_position, goal, path)完成实际执行updateRobotPosition()把机器人位姿写入 TF并睡眠 50ms 让变换生效createPlan(goal, path)先通过planner_tester_-setCostmap(costmap_.get())把测试世界同步进规划服务端再调用planners_[GridBased]-createPlan(...)生成路径planner_tester.hpp若路径点数为 0即使无异常抛出同样判定失败成功后进入质量校验isCollisionFree(path) isWithinTolerance(...)。五、随机化回归测试defaultPlannerRandomTests这是文档强调的可以顺序传入随机起点与目标点并检查路径是否碰撞的能力实现在 planner_tester.cpp随机源使用std::random_devicestd::mt19937采样范围uniform_int_distribution(1, size_x-1)/(1, size_y-1)避开地图边界自由点筛选反复采样直到该栅格costmap_-is_free(x, y)为真保证起点和目标点必然落在可通行区域这一筛选也解释了图中为何不存在起点在障碍物内的情况执行每轮调用plannerTest并累计失败数同时记录num_fail与总耗时high_resolution_clock判据num_fail / number_tests acceptable_fail_ratio则整体失败。acceptable_fail_ratio默认 0.110%可在调用时覆盖。配套的 test_planner_random_node.cpp 中testWithHundredRandomEndPoints每次执行 100 轮随机测试、可重试 3 次容忍偶发失败任一成功即通过用EXPECT_EQ(true, success)断言。从测试输出看README 中给出的 example_result.png蓝色球体为起点绿色球体为目标点红色线段为规划出的路径灰色格子为障碍物。图中存在少量只有起点/终点而无红线的孤儿球体——文档注明这是 NavFn 算法偶发无法生成路径所致这也是引入acceptable_fail_ratio容错机制的根源。六、路径质量校验碰撞检测与起终点一致性6.1 碰撞检测 isCollisionFree逐点遍历路径对每个位姿用costmap_-is_free(round(x), round(y))检查所在栅格是否空闲任一栅格不空闲即告失败并打印整条路径planner_tester.cpp。6.2 起终点一致性 isWithinTolerance当前实现为简化版源码注释标注Work in progress仅校验路径首点等于请求起点、末点等于请求目标planner_tester.cpp。接口预留了deviation_tolerance与reference_path参数defaultPlannerTest默认容差 1.0为将来与参考路径做偏差比较留好了扩展点。6.3 辅助工具printPath()以x / y三位精度逐点打印路径用于失败时定位问题栅格isPathValid()则封装了对IsPathValid服务的调用见下节。七、IsPathValid 服务封装与参数语义PlannerTester::isPathValidplanner_tester.cpp构造nav2_msgs::srv::IsPathValid::Request并异步调用is_path_valid服务spin_until_future_complete超时 100ms。请求字段与语义如下字段语义测试中的典型取值path待校验的路径手工构造或规划器输出max_cost允许的最大代价高于此值视为不可通行默认 253consider_unknown_as_obstacle是否把未知区域NO_INFORMATION255当作障碍false/true双向验证layer_name指定代价地图图层空串表示使用完整代价地图/non_existent_layerfootprint机器人足迹多边形形如[[x,y],...]空串表示按单栅格[[0.5,0.5],...]方形足迹stop_at_first_collision遇到首个碰撞点即停止返回 1 个非法点索引还是检查全部true/falsemax_lookahead_distance最大前瞻距离-1.0表示校验整条路径-1.0/2.0/0.5test_planner_is_path_valid.cpp 对这些字段做了系统化覆盖测试值得关注的断言组合包括空路径successfalse, is_validfalse穿过障碍的路径is_validfalse且invalid_pose_indices非空、首个非法点索引0未知区域语义同一路径在consider_unknown_as_obstaclefalse时有效切换为true后无效max_cost 阈值max_cost0时即使路径几何上合法也判为无效自定义足迹合法方形足迹通过畸形字符串invalid_footprint_string导致successfalse图层名layer_name使用完整代价地图并通过不存在的图层名返回失败stop_at_first_collisiontrue时invalid_pose_indices.size()1false时1max_lookahead_distance短前瞻距离校验的是路径子段可能避开远处的障碍。八、多插件回归测试一条代码覆盖五种全局规划器test_planner_plugins.cpp 以GridBased.plugin参数切换规划插件用同一套测试逻辑覆盖仓库中的五种全局规划器nav2_navfn_planner::NavfnPlannernav2_smac_planner::SmacPlanner2Dnav2_smac_planner::SmacPlannerHybridnav2_smac_planner::SmacPlannerLatticenav2_theta_star_planner::ThetaStarPlanner测试维度包括路径有效性起点/终点重合length0、极短路径0.00001、低于栅格分辨率0.09、临界分辨率0.102、高于分辨率1.5五档距离末端朝向语义GridBased.use_final_approach_orientationfalse时路径末点朝向应等于目标朝向为true时末点朝向应等于接近方向单点路径则退化为起点朝向取消机制注入always_cancelled取消回调并设GridBased.terminal_checking_interval1断言抛出nav2_core::PlannerCancelled插件名合法性空插件名返回空路径frame_id 仍为map不存在的插件名fake抛出nav2_core::InvalidPlanner消息Planner id fake is invalid。这组测试说明PlannerTester体系天然支持插件无关的回归验证——新增全局规划插件时只需像上述测试一样指定其plugin名称即可复用全部判据。九、构建与运行方式9.1 测试目标与依赖CMakeLists.txt 定义四个测试目标目标源文件类型test_planner_costmapstest_planner_costmaps_node.cpp planner_tester.cpplaunch 集成测试test_planner_randomtest_planner_random_node.cpp planner_tester.cpplaunch 集成测试test_planner_pluginsplanner_tester.cpp test_planner_plugins.cppgtestTIMEOUT 30stest_planner_is_path_validplanner_tester.cpp test_planner_is_path_valid.cppgtest链接依赖包括nav2_planner::planner_server_core、nav2_map_server::map_io、nav2_util::nav2_util_core、nav2_msgs、nav2_ros_common、nav_msgs、rclcpp_lifecycle、tf2_ros等与上文分析的架构一致。9.2 环境变量与 Launch 入口两个集成测试通过 launch 文件驱动test_planner_random_launch.py、test_planner_costmaps_launch.py执行时注入两个环境变量TEST_EXECUTABLE测试二进制路径由 CMake 以$TARGET_FILE:...注入TEST_MAP地图图片路径由 CMake 以${PROJECT_SOURCE_DIR}/maps/map.pgm注入即 nav2_system_tests/maps 下的地图。启动命令为cmd[testExecutable, --ros-args -p use_sim_time:True]即测试以仿真时钟模式运行。9.3 手动运行示例在已构建的 ROS 2 工作空间中可单独运行对应测试# 运行六种内置代价地图的单次路径测试 TEST_MAP$(pwd)/maps/map.pgm \ ./test_planner_costmaps_node --ros-args -p use_sim_time:True # 运行 100 次随机起终点回归测试 TEST_MAP$(pwd)/maps/map.pgm \ ./test_planner_random_node --ros-args -p use_sim_time:True # 运行多插件NavFn / Smac2D / SmacHybrid / SmacLattice / Theta*回归测试 ./test_planner_plugins # 运行 IsPathValid 服务语义测试 ./test_planner_is_path_valid所有测试退出码为 0 即代表全部断言通过。十、已知限制与注意事项结合 README 的两条注释与源码中的 TODO 标记使用该测试体系时需明确以下前提机器人尺寸为 1x1 栅格代价地图不做障碍膨胀碰撞检测是路径点所在栅格是否空闲级别的判断未考虑真实机器人足迹。因此该测试验证的是规划算法本身的正确性不代表带足迹/膨胀的真实导航场景后者需依赖 nav2_costmap_2d 的膨胀层与足迹碰撞检查IsPathValid的footprint参数可在此方向上补充覆盖NavFn 算法偶发失败部分起点/终点组合下规划器返回空路径或路径切角进入障碍源码注释指出navfn 会偶尔切角这正是随机测试引入acceptable_fail_ratio0.1与 3 次重试的原因朝向支持不完整defaultPlannerTest系列目前只比较位置x/y不校验起点/终点朝向源码以TODO(orduno) #443标记了支持考虑机器人朝向的规划器这一扩展方向随机测试不适用于内置测试代价地图defaultPlannerRandomTests对using_fake_costmap_场景直接返回 false 并提示尚未实现随机测试需配合真实地图使用。结语把 PlannerTester 用于你的全局规划器验证PlannerTester的价值在于它把世界构造—规划请求—质量断言封装成可复用的测试骨架世界层面可用六种内置代价地图或TEST_MAP真实地图规划层面直接驱动生产级PlannerServer校验层面覆盖碰撞、起终点一致性、IsPathValid全参数语义与多插件回归。对 Navigation2 的贡献者而言新增或修改全局规划插件后跑一遍 test_planner_plugins 即可获得跨五类规划器的行为基线对二次开发者而言也可以参照 PlannerTester 的接口为自己的规划器搭建同类组件级回归测试。赞分享机器人ROS自动驾驶【免费下载链接】navigation2ROS 2 Navigation Framework and System项目地址https://gitcode.com/gh_mirrors/na/navigation2点击查看免费下载相关推荐Navigation2 规划器基准测试基于随机地图与随机目标点的全局规划器客观对比指南Navigation2 规划器基准测试基于随机地图与随机目标点的全局规划器客观对比指南 导读 tools/planner_benchmarking 是 Nav机器人ROS自动驾驶如何使用radare2测试套件面向开发者的完整质量保证与回归测试指南如何使用radare2测试套件面向开发者的完整质量保证与回归测试指南 radare2是一款功能强大的UNIX like逆向工程框架和命令行工具集其测试套件是逆向工程网络安全4步终极解决方案让老旧Mac焕发新生的OpenCore Legacy Patcher完整指南4步终极解决方案让老旧Mac焕发新生的OpenCore Legacy Patcher完整指南 你是否曾看着手中的老款Mac电脑感叹它明明性能尚可却被苹果官操作系统固件驱动开发上一篇抖音批量下载助手轻松备份创作者作品集的高效解决方案下一篇3步解决Video DownloadHelper配套应用问题完整安装与配置指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表