14 KiB
14 KiB
Navigation2 详解:nav2_bringup 与 nav2_gps_waypoint_follower_demo
1. Navigation2 整体介绍
Navigation2(简称Nav2)是ROS2生态中最成熟的开源导航框架,是ROS1 Navigation Stack的官方继任者,专为移动机器人自主导航设计。
1.1 核心功能
- 定位:支持AMCL、SLAM(Cartographer、SLAM Toolbox等)、GPS/RTK等多源定位
- 全局路径规划:支持A*、Dijkstra、NavFn等多种规划算法
- 局部路径跟踪:支持DWA、TEB、MPPI、Pure Pursuit等跟踪算法
- 避障与行为树:通过行为树实现复杂导航逻辑,支持动态障碍物规避
- 重规划与恢复行为:导航失败时自动执行恢复策略(旋转、回退、清图等)
- 多机器人支持:支持命名空间隔离的多机器人导航
1.2 整体架构
Nav2采用模块化插件式设计,核心模块包括:
├── 感知层
│ ├── 传感器数据处理(LiDAR、Camera、IMU、GPS等)
│ └── 障碍物检测/语义分割
├── 定位层
│ ├── AMCL(蒙特卡洛定位)
│ ├── SLAM 建图
│ └── 多传感器融合定位
├── 地图层
│ ├── 代价地图(全局/局部)
│ ├── 图层插件(静态层、障碍层、膨胀层、社会层等)
├── 规划层
│ ├── 全局路径规划器
│ └── 平滑器
├── 控制层
│ ├── 局部路径规划器
│ └── 轨迹跟踪控制器
├── 行为决策层
│ ├── 行为树执行器
│ └── 恢复行为管理器
└── 接口层
├── RViz 可视化
├── Action/Topic API
└── 配置参数系统
2. nav2_bringup 包详解
nav2_bringup是Nav2的官方启动集成包,提供了开箱即用的启动文件、配置模板和参数集合,是快速部署Nav2系统的入口。
2.1 代码结构
nav2_bringup/
├── bringup/ # 启动相关核心目录
│ ├── launch/ # 启动文件集合
│ │ ├── bringup_launch.py # 主启动文件,集成所有导航模块
│ │ ├── localization_launch.py # 单独启动定位模块(AMCL/SLAM)
│ │ ├── navigation_launch.py # 单独启动导航模块(规划/控制/行为树)
│ │ ├── rviz_launch.py # 启动RViz可视化
│ │ ├── slam_launch.py # 启动SLAM建图
│ │ └── urdf_launch.py # 加载机器人URDF模型
│ ├── params/ # 参数配置文件目录
│ │ ├── nav2_params.yaml # 导航全模块默认参数
│ │ ├── nav2_params_no_odom.yaml # 无里程计场景参数
│ │ ├── nav2_slam_params.yaml # SLAM模式参数
│ │ └── robot_localization/ # 传感器融合参数模板
│ └── rviz/ # RViz配置文件
│ └── nav2_default_view.rviz # Nav2默认RViz配置
├── docker/ # Docker部署相关文件
├── scripts/ # 辅助脚本
├── CMakeLists.txt
├── package.xml
└── README.md
2.2 核心启动文件说明
2.2.1 bringup_launch.py
这是最常用的一站式启动文件,集成了完整的导航流程,支持参数配置:
# 关键参数
'namespace': '', # 多机器人命名空间
'use_sim_time': False, # 是否使用仿真时间
'rviz_config_file': '', # RViz配置文件路径
'params_file': '', # 导航参数文件路径
'autostart': True, # 启动后自动激活导航栈
'use_composition': True, # 使用组件化节点(减少进程数,提高性能)
'use_respawn': False, # 节点崩溃时自动重启
'map': '', # 静态地图文件路径(.yaml/.pgm)
'slam': False, # 是否启用SLAM模式
'localization_type': 'amcl' # 定位方式:amcl/slam_toolbox等
启动示例:
# 仿真环境启动导航
ros2 launch nav2_bringup bringup_launch.py use_sim_time:=True map:=/path/to/map.yaml
# 真机环境启用SLAM建图
ros2 launch nav2_bringup bringup_launch.py slam:=True params_file:=/path/to/my_params.yaml
2.2.2 localization_launch.py
单独启动定位模块,适合只需要定位不需要完整导航的场景:
# 仅启动AMCL定位
ros2 launch nav2_bringup localization_launch.py map:=/path/to/map.yaml use_sim_time:=True
2.2.3 navigation_launch.py
单独启动导航模块(规划/控制/行为树),适合定位已由其他系统提供的场景:
# 仅启动导航模块,使用已有的定位信息
ros2 launch nav2_bringup navigation_launch.py params_file:=/path/to/my_params.yaml
2.3 配置文件详解
nav2_params.yaml是核心参数配置文件,采用分层结构,每个模块单独配置:
amcl:
ros__parameters:
base_frame_id: "base_footprint" # 机器人基坐标系
global_frame_id: "map" # 全局坐标系
odom_frame_id: "odom" # 里程计坐标系
max_particles: 2000 # 最大粒子数
min_particles: 500 # 最小粒子数
update_min_a: 0.2 # 角度变化超过0.2rad时更新
update_min_d: 0.25 # 位移超过0.25m时更新
bt_navigator:
ros__parameters:
use_sim_time: False
bt_xml_filename: "navigate_w_replanning_and_recovery.xml" # 行为树文件
global_costmap:
global_costmap:
ros__parameters:
update_frequency: 1.0
publish_frequency: 1.0
global_frame: map
robot_base_frame: base_footprint
resolution: 0.05
plugins:
- {name: static_layer, type: "costmap_2d::StaticLayer"}
- {name: obstacle_layer, type: "costmap_2d::ObstacleLayer"}
- {name: inflation_layer, type: "costmap_2d::InflationLayer"}
local_costmap:
local_costmap:
ros__parameters:
update_frequency: 5.0
publish_frequency: 2.0
global_frame: odom
robot_base_frame: base_footprint
width: 3
height: 3
resolution: 0.05
rolling_window: true # 局部代价地图随机器人移动
planner_server:
ros__parameters:
expected_planner_frequency: 1.0
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner" # 默认使用NavFn规划器
use_astar: true # 启用A*算法
controller_server:
ros__parameters:
controller_frequency: 20.0
min_x_velocity_threshold: 0.001
min_y_velocity_threshold: 0.5
controller_plugins: ["FollowPath"]
FollowPath:
plugin: "nav2_regulated_pure_pursuit_controller/RegulatedPurePursuitController" # 默认使用Pure Pursuit控制器
2.4 最佳实践
- 不要直接修改默认参数文件:将nav2_params.yaml复制到自己的工作空间进行修改,通过
params_file参数传入 - 组件化启动:默认启用
use_composition:=True可以显著减少内存占用和通信开销 - 分层配置:将通用参数和机器人特定参数分开存放,便于维护
- 仿真与真机分离:使用
use_sim_time参数区分仿真和真机环境,分别配置不同的参数值
3. nav2_gps_waypoint_follower_demo 详解
这是Nav2官方提供的室外导航示例,演示了如何结合GPS/RTK定位实现全局航点跟随功能,适用于无人车、巡检机器人等室外场景。
3.1 代码结构
该包位于navigation2_tutorials仓库中,结构如下:
nav2_gps_waypoint_follower_demo/
├── bringup/
│ ├── launch/
│ │ ├── gps_waypoint_follower_launch.py # Demo主启动文件
│ │ ├── rviz.launch.py # RViz启动
│ │ └── dual_ekf.launch.py # 双EKF传感器融合启动
│ ├── params/
│ │ ├── dual_ekf.yaml # 传感器融合参数
│ │ ├── nav2_params.yaml # 导航参数(适配GPS场景)
│ │ └── waypoint_follower_params.yaml # 航点跟随器参数
│ ├── rviz/
│ │ └── gps_waypoint.rviz # GPS导航专用RViz配置
│ └── worlds/
│ └── gps_world.world # 仿真世界文件(含GPS插件)
├── config/
│ └── sample_waypoints.yaml # 示例航点配置文件
├── src/
│ └── gps_waypoint_logger.cpp # 航点到达日志节点(可选)
├── CMakeLists.txt
├── package.xml
└── README.md
3.2 核心组件说明
GPS航点跟随系统主要由三个核心部分组成:
- 传感器融合模块(robot_localization):融合GPS、IMU、轮式里程计数据,输出全局定位
- 导航栈模块:基于全局定位进行路径规划和跟踪
- 航点跟随器:按照预设的GPS航点序列依次导航
3.2.1 双EKF传感器融合
demo使用两个扩展卡尔曼滤波器(EKF)实现多传感器融合:
# dual_ekf.yaml 核心配置
ekf_filter_node_odom:
ros__parameters:
frequency: 30.0
sensor_timeout: 0.1
two_d_mode: true
publish_tf: true
odom_frame: odom
base_link_frame: base_link
world_frame: odom
# 融合IMU和轮式里程计,输出odom->base_link变换
imu0: /imu/data
odom0: /wheel/odometry
ekf_filter_node_map:
ros__parameters:
frequency: 30.0
sensor_timeout: 0.1
two_d_mode: true
publish_tf: true
odom_frame: odom
base_link_frame: base_link
world_frame: map
# 融合GPS数据,输出map->odom变换
odom1: /gps/fix
odom1_differential: false
odom1_relative: false
- 第一个EKF(odom系):融合IMU和轮式里程计,提供短时间内高精度的局部定位,无漂移
- 第二个EKF(map系):融合GPS数据,提供全局绝对定位,修正长期漂移
3.2.2 导航参数适配(nav2_params.yaml)
GPS导航场景需要对默认导航参数进行调整:
amcl:
ros__parameters:
# GPS导航场景下禁用AMCL,使用EKF融合提供定位
use_sim_time: False
# AMCL相关参数全部注释或删除
global_costmap:
global_costmap:
ros__parameters:
# GPS模式下不使用静态地图,使用动态生成的代价地图
plugins:
- {name: obstacle_layer, type: "costmap_2d::ObstacleLayer"}
- {name: inflation_layer, type: "costmap_2d::InflationLayer"}
# 代价地图大小足够覆盖所有航点范围
width: 1000
height: 1000
resolution: 0.1
rolling_window: false # 全局代价地图固定,不随机器人移动
origin_x: -500
origin_y: -500
planner_server:
ros__parameters:
# 使用适合长距离规划的算法
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner"
use_astar: true
allow_unknown: true # 允许在未知区域规划路径
controller_server:
ros__parameters:
# 使用适合高速行驶的控制器
FollowPath:
plugin: "nav2_mppi_controller/MPPIController" # 或者TEB控制器
max_vel_x: 5.0 # 室外场景允许更高速度
3.2.3 航点跟随器配置
# waypoint_follower_params.yaml
waypoint_follower:
ros__parameters:
loop: False # 航点是否循环执行
waypoint_timeout: 300.0 # 单个航点导航超时时间(秒)
stop_on_failure: True # 某个航点导航失败时停止
action_server_name: "follow_waypoints"
# 航点到达阈值
goal_tolerance_x: 0.5
goal_tolerance_y: 0.5
goal_tolerance_yaw: 0.25
3.3 航点配置
sample_waypoints.yaml是预设的GPS航点文件,格式如下:
waypoints:
- latitude: 37.7749
longitude: -122.4194
yaw: 0.0 # 到达后的朝向(弧度)
frame_id: "wgs84" # GPS坐标系
- latitude: 37.7750
longitude: -122.4195
yaw: 1.57
frame_id: "wgs84"
- latitude: 37.7751
longitude: -122.4196
yaw: 3.14
frame_id: "wgs84"
航点使用WGS84坐标系(标准GPS坐标),也可以配置为UTM坐标系。
3.4 运行流程
- 启动仿真/真机驱动:加载机器人模型、传感器驱动、GPS插件
- 启动传感器融合:
ros2 launch nav2_gps_waypoint_follower_demo dual_ekf.launch.py - 启动导航栈:
ros2 launch nav2_gps_waypoint_follower_demo gps_waypoint_follower_launch.py - 加载航点:
ros2 run nav2_waypoint_follower waypoint_follower --ros-args -p waypoint_file:=/path/to/sample_waypoints.yaml - 启动航点跟随:通过RViz发送FollowWaypoints action请求,或者用命令行启动:
ros2 action send_goal /follow_waypoints nav2_msgs/action/FollowWaypoints "{waypoints: []}"
3.5 关键注意事项
- GPS信号质量:室外场景下需要确保GPS信号良好,RTK定位能达到厘米级精度,普通GPS只有米级精度,可能影响导航效果
- 坐标系转换:需要正确配置WGS84到UTM再到机器人本地坐标系的转换参数
- 航点规划:航点之间需要有可行路径,避免有障碍物阻挡
- 动态障碍物:室外场景需要配置合适的障碍物检测和避障参数
- TF树检查:确保
map->odom->base_link的TF变换正确发布,这是GPS导航的基础
4. 常用调试技巧
- 查看TF树:
ros2 run tf2_tools view_frames,检查坐标系变换是否正确 - 检查定位质量:
ros2 topic echo /gps/fix查看GPS信号质量,ros2 topic echo /odometry/filtered查看融合后的定位输出 - 可视化调试:在RViz中显示全局/局部代价地图、规划路径、当前目标点等信息
- 参数动态调整:使用
ros2 param命令动态修改参数,无需重启导航栈 - 日志分析:查看
/tf,/cmd_vel,/plan等话题的输出,排查导航失败原因