使用语义分割导航(NVIDIA Jetson)
本教程演示如何在代价地图(costmap)中利用立体相机进行语义分割,所用的是自定义 semantic_segmentation_layer 插件 和一套适用于 Gazebo Baylands 世界的预训练分割模型。本教程由 Pedro Gonzalez 撰写,首发于 robot.com。

假定 ROS 2 和 Nav2 依赖包已安装或在本地构建。此外,你还需要:
source /opt/ros/<ros2-distro>/setup.bashsudo apt install ros-$ROS_DISTRO-nav2-minimal-tb4*sudo apt install ros-$ROS_DISTRO-ros-gz-simsudo apt install ros-$ROS_DISTRO-ros-gz-interfaces接下来需要编译 semantic_segmentation_layer 软件包。将仓库克隆到 ROS 2 工作空间的 source 目录,选择与所用发行版对应的分支,然后构建:
# 在你的工作空间 source 目录中,将 rolling 替换为你的 ROS 发行版。提供有 humble、jazzy 和 rolling 分支。git clone -b rolling https://github.com/kiwicampus/semantic_segmentation_layer.gitcd <your workspace path>colcon build --symlink-install # 在你的工作空间路径下执行本教程的代码托管在 nav2_semantic_segmentation_demo 目录中,建议在搭建开发环境时一并克隆并构建。
最后,还需要安装以下依赖:
- ONNX Runtime:用于运行语义分割模型推理
- OpenCV:用于图像处理
教程后续步骤将介绍如何安装这些依赖。
注意:语义分割层插件目前要求深度图像与彩色图像完全对齐(例如来自立体相机或深度相机)。也可以借助基于 AI 的深度估计方法,从单目相机生成深度信息。
语义分割概述
Section titled “语义分割概述”什么是语义分割?
Section titled “什么是语义分割?”语义分割是一项计算机视觉任务,目的是为图像中的每个像素分配一个类别标签。与仅通过边界框定位目标的目标检测不同,语义分割能够提供对场景的像素级理解。
现代语义分割通常基于深度学习方法实现,尤其是卷积神经网络(CNN)和视觉 Transformer(vision transformer)。这些模型在海量像素级标注的图像数据集上完成训练。 在训练过程中,模型学会识别不同类别之间的模式和特征差异(例如草地的纹理与人行道的光滑表面)。常见的网络架构包括 U-Net、DDRNet 和 SegFormer。
本教程提供了预训练模型,因此可以跳过训练步骤,直接进行 Nav2 集成。 如果需要训练自己的模型,可使用 Simple Segmentation Toolkit 快速构建原型,它支持基于 SAM 的自动标注(无需手动标注)。

训练完成后,语义分割模型的输出通常是一张与输入尺寸相同的图像,其中每个像素保存着该像素属于各类别的概率。 以本教程提供的模型为例,它包含 3 个类别——人行道(sidewalk)、草地(grass)和背景(background),因此原始输出是一个 3 通道张量,每个通道对应一个类别的概率。 对于类别更多的模型(例如 100 类),输出则为 100 通道张量。最后,对每个像素选取概率最高的类别,并将该概率值作为置信度。 上述逻辑通常在推理之后的后处理阶段执行,本教程中由 ROS 2 语义分割节点完成。
理想情况下,所选类别的置信度应为 1,其余类别为 0,但实际中这种情况极为少见。置信度较低的像素往往意味着分类可能有误。 因此,类别和置信度都是决定如何为像素分配代价的重要依据,语义分割层会综合考虑这两个因素。详见其 README 中的实现说明。
0- 搭建仿真环境
Section titled “0- 搭建仿真环境”要使用语义分割进行导航,首先需要搭建一个带有相机传感器的机器人仿真环境。本教程使用 Gazebo 中的 Baylands 户外世界和 TurtleBot 4 机器人。 仿真环境已在 nav2_semantic_segmentation_demo 目录中配置完毕,如尚未克隆并构建该仓库,请先执行以下操作:
# 在你的工作空间 source 目录下git clone https://github.com/ros-navigation/navigation2_tutorials.gitcd <your workspace path>colcon build --symlink-install --packages-up-to semantic_segmentation_sim
source install/setup.bash测试仿真是否正确启动:
ros2 launch semantic_segmentation_sim simulation_launch.py headless:=0你应该会看到 Gazebo 启动,TurtleBot 4 出现在 Baylands 世界中。

1- 搭建语义分割推理节点
Section titled “1- 搭建语义分割推理节点”语义分割节点使用 ONNX 模型对相机图像执行实时推理。节点订阅相机图像,完成推理后,发布分割掩码(segmentation mask)、置信度图(confidence map)和标签信息。 运行该节点前,需安装 semantic_segmentation_node 软件包中 requirements.txt 列出的依赖:
pip install -r <your workspace path>/src/navigation2_tutorials/nav2_semantic_segmentation_demo/semantic_segmentation_node/requirements.txt --break-system-packages分割节点通过一个本体(ontology)YAML 文件进行配置,定义以下内容:
- 要检测的类别:每个类别包含名称和可视化颜色。类别定义顺序须与模型输出一致,0 始终为背景类别。
- 模型设置:包括设备(CPU/CUDA)和图像预处理参数。为获得更好的兼容性,本教程默认使用 CPU 推理;若需使用 GPU,可根据硬件安装 onnxruntime-gpu 及其依赖,并将设备设为
cuda。
示例配置文件(config/ontology.yaml):
ontology: classes: - name: sidewalk color: [255, 0, 0] # BGR format - name: grass color: [0, 255, 0] # BGR format
model: device: cpu # cuda or cpu该节点发布多个话题:
/segmentation/mask:分割掩码图像(mono8,像素值 = 类别 ID)/segmentation/confidence:置信度图(mono8,0–255)/segmentation/label_info:包含类别元数据的标签信息消息/segmentation/overlay:在原始图像上叠加分割结果的可视化图像(可选)
启动分割节点(在仿真运行的情况下):
ros2 run semantic_segmentation_node segmentation_node验证分割话题是否在发布:
ros2 topic list | grep segmentationros2 topic echo /segmentation/label_info --once可以看到标签信息消息中包含了本体文件所定义的类别。
2- 使用语义分割层配置 Nav2
Section titled “2- 使用语义分割层配置 Nav2”接下来配置 Nav2,使其在代价地图中使用语义分割层。具体做法是将该层插件添加到全局和局部代价地图中,并为不同分割类别配置代价分配。关键参数包括:
- 观测源(Observation Sources):定义要订阅的相机/分割话题
- 类别类型(Class Types):定义地形类别(可通行(traversable)、中间(intermediate)、危险(danger))
- 代价分配(Cost Assignment):将语义类别映射到导航代价
- 时间参数(Temporal Parameters):控制观测在代价地图中持续的时间
目前,该代价地图插件仅支持来自立体相机的点云,且点云须与彩色图像对齐(因而也与分割掩码对齐)。
以下是局部代价地图的示例配置:
local_costmap: local_costmap: ros__parameters: plugins: ["semantic_segmentation_layer", "inflation_layer"] semantic_segmentation_layer: plugin: "semantic_segmentation_layer::SemanticSegmentationLayer" enabled: True observation_sources: camera camera: segmentation_topic: "/segmentation/mask" confidence_topic: "/segmentation/confidence" labels_topic: "/segmentation/label_info" pointcloud_topic: "/rgbd_camera/depth/points" max_obstacle_distance: 5.0 min_obstacle_distance: 0.3 tile_map_decay_time: 2.0 class_types: ["traversable", "intermediate", "danger"] traversable: classes: ["sidewalk"] base_cost: 0 max_cost: 0 intermediate: classes: ["background"] base_cost: 127 max_cost: 127 danger: classes: ["grass"] base_cost: 254 max_cost: 254教程在 semantic_segmentation_sim 软件包中提供了预先配置好的 nav2_params.yaml 文件,可直接参考该文件来配置 Nav2 代价地图。
3- 一键运行全部组件
Section titled “3- 一键运行全部组件”教程提供了一个完整的启动文件,可同时启动仿真、语义分割节点和 Nav2 导航栈。执行 segmentation_simulation_launch.py 即可:
ros2 launch semantic_segmentation_sim segmentation_simulation_launch.pyBaylands 仿真和 RViz 将随之启动。此时可通过 RViz 发送导航目标,机器人在 Baylands 世界中导航时会优先选择人行道并避开草地:

为了更直观地了解插件的工作过程,可在 RViz 中启用分割瓦片地图(tile map)可视化——它会显示每个瓦片上的分割观测点云,并按置信度着色。 此外,该层 README 中的示意图展示了观测如何在代价地图瓦片上累积,以及最终如何转化为每个瓦片的代价。

注意:为简化流程,本教程在
map和odom坐标系之间发布了静态变换。在实际应用中,应使用适当的定位系统(如 GPS)来获取map=>odom变换。
本教程演示了如何将语义分割集成到 Nav2 中——借助适用于 Gazebo Baylands 世界的预训练模型和自定义语义分割层插件,实现基于地形的导航。
如需进一步探索,可使用 Simple Segmentation Toolkit 训练自己的模型,并根据具体应用场景调整代价地图参数。
祝地形感知导航顺利!