260514
我们 01-SLAM-建图与定位 这部分搞定了,接下来就可以开始 02-Nav2-导航接入 了。
Nav2 可以让我们的机器人在 SLAM 建模后的环境中导航到指定的位置。
我们先修改一下我们的 Mode,需要新增一个 NAV2 的模式:
class Mode(IntEnum):
STOP = 0
CRUISE = 1
MANUAL = 2
FOLLOW = 3
NAV2 = 4
嗯...奇怪,貌似我们的 python 文件中有两个 Mode 的定义:

我们都整合到同一个文件好了,就叫 schemas.py 吧。
在 src/kibot_one_control/kibot_one_control/schems.py 中写入如下的内容:
from enum import IntEnum
class Mode(IntEnum):
STOP = 0
CRUISE = 1
MANUAL = 2
FOLLOW = 3
NAV2 = 4
然后在我们的这两个文件里引入:

嗯...文件名有点问题,应该是 schemas.py,而不是 schems.py。
我们继续进行替换,除了我们的 python 文件以外,我们的 .msg, .srv 文件也要改一下。
首先是 src/kibot_one_interface/msg/Mode.msg,我们改成下面这样的:
uint8 STOP = 0
uint8 CRUISE = 1
uint8 MANUAL = 2
uint8 FOLLOW = 3
uint8 NAV2 = 4
嗯...不太对,我们还有一个 src/kibot_one_interface/msg/ModeState.msg,内容如下:
uint8 STOP = 0
uint8 CRUISE = 1
uint8 MANUAL = 2
uint8 FOLLOW = 3
uint8 current_mode
因此,我们的 Mode.msg 实际上是多余的,删掉吧。
src/kibot_one_interface/CMakeLists.txt 中也要删掉这个文件的引用:
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/ModeState.msg"
"srv/Mode.srv"
DEPENDENCIES geometry_msgs
)
然后把我们的 src/kibot_one_interface/msg/ModeState.msg 改成这样:
uint8 STOP = 0
uint8 CRUISE = 1
uint8 MANUAL = 2
uint8 FOLLOW = 3
uint8 NAV2 = 4
uint8 current_mode
然后我们看了一下,我们的 .srv 文件倒是没必要改。
然后是 src/kibot_one_control/kibot_one_control/mode_control.py,我们将其中的 _pub_timer_callback 函数改成下面这样的:
def _pub_timer_callback(self) -> None:
current_mode = self._get_current_mode()
match current_mode:
case Mode.STOP:
self.linear_velocity = Twist()
case Mode.CRUISE:
pass
case Mode.MANUAL:
self.linear_velocity = Twist()
case Mode.FOLLOW:
pass
case Mode.NAV2: # 增加 NAV2 Mode
pass
if current_mode not in [Mode.MANUAL, Mode.FOLLOW, Mode.NAV2]: # 增加 NAV2 Mode
self.mode_vel_publisher.publish(self.linear_velocity)
然后,由于我们预期的链路是这样的:
Nav2 controller_server -> /cmd_vel_raw -> cmd_vel_watchdog -> /cmd_vel -> Gazebo
所以需要让 Nav2 输出到 /cmd_vel_raw 中。
因此,我们可以创建下面这个 Nav2 的配置为文件 src/kibot_one_sim/config/nav2_params.yaml:
bt_navigator:
ros__parameters:
use_sim_time: true
global_frame: map
robot_base_frame: base_link
odom_topic: /odom
bt_loop_duration: 10
default_server_timeout: 20
wait_for_service_timeout: 1000
navigators: ["navigate_to_pose"]
navigate_to_pose:
plugin: "nav2_bt_navigator::NavigateToPoseNavigator"
controller_server:
ros__parameters:
use_sim_time: true
controller_frequency: 20.0
min_x_velocity_threshold: 0.001
min_y_velocity_threshold: 0.5
min_theta_velocity_threshold: 0.001
failure_tolerance: 0.3
odom_topic: /odom
progress_checker_plugins: ["progress_checker"]
goal_checker_plugins: ["goal_checker"]
controller_plugins: ["FollowPath"]
progress_checker:
plugin: "nav2_controller::SimpleProgressChecker"
required_movement_radius: 0.2
movement_time_allowance: 10.0
goal_checker:
plugin: "nav2_controller::SimpleGoalChecker"
xy_goal_tolerance: 0.25
yaw_goal_tolerance: 0.25
stateful: true
FollowPath:
plugin: "nav2_regulated_pure_pursuit_controller::RegulatedPurePursuitController"
desired_linear_vel: 0.25
lookahead_dist: 0.5
min_lookahead_dist: 0.3
max_lookahead_dist: 0.9
lookahead_time: 1.5
rotate_to_heading_angular_vel: 0.8
transform_tolerance: 0.2
use_velocity_scaled_lookahead_dist: false
min_approach_linear_velocity: 0.05
approach_velocity_scaling_dist: 0.6
use_collision_detection: true
max_allowed_time_to_collision_up_to_carrot: 1.0
use_regulated_linear_velocity_scaling: true
use_cost_regulated_linear_velocity_scaling: false
regulated_linear_scaling_min_radius: 0.9
regulated_linear_scaling_min_speed: 0.05
use_rotate_to_heading: true
allow_reversing: false
rotate_to_heading_min_angle: 0.785
max_angular_accel: 1.5
max_robot_pose_search_dist: 10.0
planner_server:
ros__parameters:
use_sim_time: true
expected_planner_frequency: 5.0
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner::NavfnPlanner"
tolerance: 0.5
use_astar: false
allow_unknown: true
behavior_server:
ros__parameters:
use_sim_time: true
costmap_topic: local_costmap/costmap_raw
footprint_topic: local_costmap/published_footprint
cycle_frequency: 10.0
behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"]
global_frame: odom
robot_base_frame: base_link
transform_tolerance: 0.2
simulate_ahead_time: 2.0
max_rotational_vel: 0.8
min_rotational_vel: 0.2
rotational_acc_lim: 1.5
spin:
plugin: "nav2_behaviors::Spin"
backup:
plugin: "nav2_behaviors::BackUp"
drive_on_heading:
plugin: "nav2_behaviors::DriveOnHeading"
wait:
plugin: "nav2_behaviors::Wait"
local_costmap:
local_costmap:
ros__parameters:
use_sim_time: true
update_frequency: 5.0
publish_frequency: 2.0
global_frame: odom
robot_base_frame: base_link
rolling_window: true
width: 3
height: 3
resolution: 0.05
robot_radius: 0.37
always_send_full_costmap: true
plugins: ["obstacle_layer", "inflation_layer"]
obstacle_layer:
plugin: "nav2_costmap_2d::ObstacleLayer"
enabled: true
observation_sources: scan
scan:
topic: /scan
max_obstacle_height: 2.0
clearing: true
marking: true
data_type: LaserScan
raytrace_max_range: 12.0
raytrace_min_range: 0.0
obstacle_max_range: 8.0
obstacle_min_range: 0.0
inf_is_valid: true
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
enabled: true
cost_scaling_factor: 3.0
inflation_radius: 0.45
global_costmap:
global_costmap:
ros__parameters:
use_sim_time: true
update_frequency: 1.0
publish_frequency: 1.0
global_frame: map
robot_base_frame: base_link
resolution: 0.05
robot_radius: 0.37
track_unknown_space: true
always_send_full_costmap: true
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
static_layer:
plugin: "nav2_costmap_2d::StaticLayer"
enabled: true
map_topic: /map
map_subscribe_transient_local: true
obstacle_layer:
plugin: "nav2_costmap_2d::ObstacleLayer"
enabled: true
observation_sources: scan
scan:
topic: /scan
max_obstacle_height: 2.0
clearing: true
marking: true
data_type: LaserScan
raytrace_max_range: 12.0
raytrace_min_range: 0.0
obstacle_max_range: 8.0
obstacle_min_range: 0.0
inf_is_valid: true
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
enabled: true
cost_scaling_factor: 3.0
inflation_radius: 0.45
我们来拆一下,我们写了哪些东西的配置。
总的来说,整个结构可以理解为:
nav2_params.yaml
├── bt_navigator # 接收 NavigateToPose action,管理导航行为树
├── controller_server # 跟踪路径,输出速度
├── planner_server # 根据地图规划全局路径
├── behavior_server # 处理恢复行为,比如旋转、后退、等待
├── local_costmap # 机器人附近的局部代价地图
└── global_costmap # 全局地图上的代价地图