3. ROS2基础:节点、话题、服务、参数等核心概念

在深入SLAM建图源码之前,必须先理解ROS2的四大核心通信原语:节点(Node)、话题(Topic)、服务(Service)和参数(Parameter)。SLAM建图系统本质上就是多个节点通过话题交换传感器数据与位姿信息,通过服务触发建图或保存地图,通过参数调整算法行为。本节将用SLAM场景贯穿讲解这些概念。

3.1 节点:功能模块的独立进程

节点是ROS2中最小的计算单元,一个机器人系统通常由几十个节点组成。每个节点负责一项特定任务,例如激光雷达驱动节点、里程计节点、SLAM建图节点、可视化节点等。节点之间相互独立,通过ROS2的通信机制协作,这种设计带来了故障隔离与模块复用的好处。

在SLAM建图中,典型节点包括:

  • /laser_driver:发布激光扫描数据
  • /odometry_node:发布轮式里程计
  • /slam_toolbox:执行建图与定位
  • /rviz2:可视化地图与机器人位姿

创建节点时,需要给节点命名。在ROS2中,节点名是全局唯一的标识符,例如启动SLAM建图节点时,命令中会显式指定节点名:

ros2 run slam_toolbox slam_toolbox_node --ros-args -r __node:=slam_node
易混淆点:节点名 ≠ 可执行文件名。同一个可执行文件可以启动多个不同名称的节点,这在多机器人协同建图中非常常见。

3.2 话题:异步数据流的通道

话题是ROS2中异步、单向、多对多的通信方式。发布者(Publisher)向话题写入消息,订阅者(Subscriber)从话题读取消息。话题适合传输持续更新的数据流,如激光扫描、图像、里程计等。

SLAM建图的核心数据流如下:

/scan (sensor_msgs/LaserScan)
   └──> /slam_toolbox 节点订阅
/odom (nav_msgs/Odometry)
   └──> /slam_toolbox 节点订阅
/tf (tf2_msgs/TFMessage)
   └──> 所有需要坐标变换的节点订阅
/map (nav_msgs/OccupancyGrid)
   └──> /rviz2 可视化节点订阅

话题通信的关键特性是解耦:发布者不知道也不关心谁在订阅,订阅者也不需要知道数据来源。这使得SLAM系统可以灵活替换传感器驱动,例如将2D激光换成3D激光,只要话题类型和消息格式一致,SLAM节点无需修改。

查看当前系统中的话题列表:

ros2 topic list
ros2 topic info /scan
ros2 topic hz /scan   # 查看发布频率
常见误区:话题消息是“瞬态”的,新订阅者只能收到订阅之后发布的数据。如果SLAM节点启动晚于激光驱动,会丢失启动前的数据。因此SLAM建图通常需要先启动传感器驱动,再启动建图节点。

3.3 服务:同步请求-应答通信

与话题的异步流不同,服务采用同步请求-应答模式。客户端(Client)发送请求并等待服务器(Server)处理完毕后返回响应。服务适合一次性、需要确认结果的操作,例如触发建图、保存地图、重置SLAM状态等。

在SLAM建图中,典型服务调用包括:

服务名称 服务类型 功能说明
/slam_toolbox/save_map slam_toolbox/save_map 将当前建图结果保存为地图文件
/slam_toolbox/clear_queue std_srvs/Empty 清除等待处理的激光数据队列
/slam_toolbox/deserialize_map slam_toolbox/deserialize_map 加载已保存的地图数据

调用保存地图服务的命令行方式:

ros2 service call /slam_toolbox/save_map slam_toolbox/save_map "{destination: 'map_data'}"

服务通信的优点是可靠性:客户端能明确知道请求是否成功执行。缺点是阻塞性——如果服务器处理时间较长,客户端会一直等待。因此,服务不适合高频数据流,只适合低频控制指令。

3.4 参数:节点运行时的可配置项

参数是节点的本地配置项,以键值对形式存储。SLAM建图算法中有大量可调参数,例如地图分辨率、激光最大扫描距离、匹配阈值、位姿图优化频率等。通过参数调整,可以在不修改代码的情况下适配不同环境。

SLAM建图常用参数示例:

slam_toolbox:
  ros__parameters:
    map_resolution: 0.05        # 地图分辨率(米/像素)
    max_laser_range: 12.0        # 激光最大有效距离
    minimum_time_interval: 0.5   # 两次扫描匹配最小时间间隔
    transform_publish_period: 0.05  # TF发布周期(秒)
    use_scan_matching: true      # 是否启用扫描匹配
    loop_search_maximum_distance: 3.0  # 回环检测最大搜索距离

参数可以在启动时通过YAML文件加载,也可以在运行时动态修改:

# 启动时加载参数文件
ros2 run slam_toolbox slam_toolbox_node --ros-args --params-file slam_params.yaml

# 运行时查看参数
ros2 param get /slam_node map_resolution

# 运行时修改参数
ros2 param set /slam_node max_laser_range 15.0
参数与话题的区别:参数是节点内部的配置,不参与节点间数据流;话题是节点间通信的载体。修改参数不会触发消息传递,但会影响节点后续处理数据的方式。

3.5 核心概念关系图解

下图展示了SLAM建图场景中,节点、话题、服务、参数之间的协作关系。激光驱动节点通过话题持续发布扫描数据,SLAM节点订阅这些话题,同时读取参数配置算法行为,并通过服务接口响应外部控制指令,最终将地图通过话题发布给可视化节点。

SLAM建图场景下ROS2核心概念关系图 激光驱动节点 /laser_driver SLAM建图节点 /slam_toolbox 扫描匹配 + 回环检测 里程计节点 /odometry_node 可视化节点 /rviz2 话题 /scan (LaserScan) 话题 /odom (Odometry) 话题 /map (OccupancyGrid) 服务 /save_map 请求-应答模式 参数配置 map_resolution=0.05 发布 订阅 发布 发布 订阅 调用 读取 话题(异步数据流) 服务(同步请求) 参数(本地配置) 节点

3.6 综合案例:启动一个最小SLAM建图系统

将上述概念串联起来,启动一个完整的SLAM建图系统通常需要以下步骤:

  1. 启动传感器驱动节点(发布/scan话题)
  2. 启动里程计节点(发布/odom话题)
  3. 启动SLAM建图节点(订阅/scan和/odom,发布/map)
  4. 启动可视化节点(订阅/map和/tf)
# 终端1:启动激光雷达驱动
ros2 run laser_driver laser_node

# 终端2:启动SLAM建图
ros2 run slam_toolbox slam_toolbox_node --ros-args --params-file slam_params.yaml

# 终端3:启动可视化
ros2 run rviz2 rviz2

系统运行后,可以通过ros2 node list查看所有活跃节点,通过ros2 topic list查看所有话题,通过ros2 service list查看可用服务。这些命令是调试SLAM系统的基础工具。

3.7 误区与复盘

误区一:混淆话题与服务的使用场景。有初学者试图用服务传输激光数据,导致系统阻塞严重。激光数据是高频持续流,必须使用话题;而保存地图是低频操作,适合使用服务。
误区二:忽略参数的类型和范围。SLAM参数如map_resolution如果设置过小(如0.01),会导致地图内存爆炸;设置过大(如0.5),则地图精度不足。修改参数前应查阅对应SLAM算法的文档说明。
复盘要点:理解ROS2通信机制的核心在于“数据流思维”——先识别系统中哪些数据是持续流动的(用话题),哪些是偶发请求(用服务),哪些是节点内部配置(用参数)。SLAM建图源码中,90%以上的代码逻辑都在处理话题数据的回调函数中,因此阅读源码时重点关注订阅了哪些话题、在回调中如何处理数据、何时发布新话题。