零.前言
这次使用Move_Base
框架配置配置,就能实现自主导航了。仿真篇结束,后面找机会拿个实物来玩儿。
在整理包,后面会传到github
和gitee
上
一.安装与介绍
1.1 move_base
安装sudo apt-get install ros-noetic-move-base
框架是这样,我们只需要配置
- 定位:
amcl
- 路径规划:局部与全局。其中,局部我们使用符合阿克曼模型的
teb_local_planner
- 地图:
map_server
,来创建代价地图 - 里程计:
odom
已经配置
1.2 amcl
安装:sudo apt-get install ros-noetic-move-base
amcl
是adaptive Monte Carlo Localization,即适应蒙特卡洛定位,也就是我们概率论学的那个思想一样。就不多解释了,因为解释起来篇幅太长。
具体可看:http://wiki.ros.org/amcl?distro=noetic
1.3 teb_local_planner
安装sudo apt-get install ros-noetic-teb_local_planner
对于这个路径规划的原理可以看:http://wiki.ros.org/teb_local_planner
二.配置
先创建一个包:catkin_create_pkg slam_nav roscpp
然后在下面创建ros_ws/src/slam_nav/param
文件夹,并写入以下配置
2.1 costmap_common_params.yaml
只需要改一处,雷达的话题即可
obstacle_range: 2.5 #只有障碍物在这个范围内才会被标记
raytrace_range: 3.0 ##只有在这个范围内不存在的才会被消除
robot_radius: 0.2
inflation_radius: 0.2 #膨胀半径
transform_tolerance: 0.5
observation_sources: scan
scan:
data_type: LaserScan
topic: /ackman/laser/scan #改为你的雷达发布话题
marking: true
clearing: true
map_type: costmap
2.2 global_costmap_params.yaml
global_costmap:
global_frame: map
robot_base_frame: base_footprint
update_frequency: 1.0
publish_frequency: 0.5
static_map: true
transform_tolerance: 0.5
cost_scaling_factor: 10.0
inflation_radius: 0.25
2.3 local_costmap_params.yaml
local_costmap:
global_frame: map
robot_base_frame: base_footprint
update_frequency: 5.0
publish_frequency: 2.0
static_map: false
rolling_window: true
width: 5
height: 5
resolution: 0.05
transform_tolerance: 0.5
cost_scaling_factor: 5
inflation_radius: 0.25
2.4 move_base_params.yaml
shutdown_costmaps: false #当move_base在不活动状态时,是否关掉costmap
controller_frequency: 5.0 #向底盘控制移动话题cmd_vel发送命令的频率.
controller_patience: 3.0
planner_frequency: 0.5
planner_patience: 5.0
#机器人必须移动多远(以米计)才能被视为不摆动。
#如果出现摆动则说明全局规划失败,那么将在超时后执行恢复模块
oscillation_timeout: 10.0
oscillation_distance: 0.1
conservative_reset_dist: 0.1
2.5 teb_local_planner_params.yaml
必须修改的地方:
-
min_turning_radius: # 最小转弯半径 注意车辆运动学中心是后轮中点
-
wheelbase: # 即前后轮距离
-
line_start、line_end # 此处用把小车抽象为一个线段模型,具体可参考:
http://wiki.ros.org/teb_local_planner/Tutorials/Obstacle%20Avoidance%20and%20Robot%20Footprint%20Model
TebLocalPlannerROS:
odom_topic: odom
map_frame: /odom
# Trajectoty 这部分主要是用于调整轨迹
teb_autosize: True #优化期间允许改变轨迹的时域长度
dt_ref: 0.3 #期望的轨迹时间分辨率
dt_hysteresis: 0.03 #根据当前时间分辨率自动调整大小的滞后现象,通常约为。建议使用dt ref的10%
#覆盖全局规划器提供的局部子目标的方向;规划局部路径时会覆盖掉全局路径点的方位角,
#对于车辆的2D规划,可以设置为False,可实现对全局路径的更好跟踪。
global_plan_overwrite_orientation: True
#指定考虑优化的全局计划子集的最大长度,如果为0或负数:禁用;长度也受本地Costmap大小的限制
max_global_plan_lookahead_dist: 3.0
feasibility_check_no_poses: 1 #检测位姿可到达的时间间隔,default:4
#如果为true,则在目标落后于起点的情况下,可以使用向后运动来初始化基础轨迹
#(仅在机器人配备了后部传感器的情况下才建议这样做)
allow_init_with_backwards_motion: False
global_plan_viapoint_sep: -1
#参数在TebLocalPlannerROS::pruneGlobalPlan()函数中被使用
#该参数决定了从机器人当前位置的后面一定距离开始裁剪
#就是把机器人走过的全局路线给裁剪掉,因为已经过去了没有比较再参与计算后面的局部规划
global_plan_prune_distance: 1
exact_arc_length: False
publish_feedback: False
# Robot
max_vel_x: 10
max_vel_x_backwards: 1
max_vel_theta: 5
acc_lim_x: 10
acc_lim_theta: 5
#仅适用于全向轮
# max_vel_y (double, default: 0.0)
# acc_lim_y (double, default: 0.5)
# ********************** Carlike robot parameters ********************
min_turning_radius: 0.9 # 最小转弯半径 注意车辆运动学中心是后轮中点
wheelbase: 0.6 # 即前后轮距离
#设置为true时,ROS话题(rostopic) cmd_vel/angular/z 内的数据是舵机角度,
cmd_angle_instead_rotvel: True
# ********************************************************************
footprint_model: # types: "point", "circular", "two_circles", "line", "polygon" 多边形勿重复第一个顶点,会自动闭合
type: "line"
# radius: 0.2 # for type "circular"
line_start: [-0.3, 0.0] # for type "line"
line_end: [0.3, 0.0] # for type "line"
# front_offset: 0.2 # for type "two_circles"
# front_radius: 0.2 # for type "two_circles"
# rear_offset: 0.2 # for type "two_circles"
# rear_radius: 0.2 # for type "two_circles"
# vertices: [ [0.25, -0.05], [0.18, -0.05], [0.18, -0.18], [-0.19, -0.18], [-0.25, 0], [-0.19, 0.18], [0.18, 0.18], [0.18, 0.05], [0.25, 0.05] ] # for type "polygon"
# GoalTolerance
xy_goal_tolerance: 0.2
yaw_goal_tolerance: 0.1
#自由目标速度。设为False时,车辆到达终点时的目标速度为0。
#TEB是时间最优规划器。缺少目标速度约束将导致车辆“全速冲线”
free_goal_vel: False
# complete_global_plan: True
# Obstacles
min_obstacle_dist: 0.3 # 与障碍的最小期望距离,
include_costmap_obstacles: True #应否考虑到局部costmap的障碍设置为True后才能规避实时探测到的、建图时不存在的障碍物。
costmap_obstacles_behind_robot_dist: 2.0 #考虑后面n米内的障碍物
obstacle_poses_affected: 30 #为了保持距离,每个障碍物位置都与轨道上最近的位置相连。
costmap_converter_spin_thread: True
costmap_converter_rate: 5
# Optimization
no_inner_iterations: 5
no_outer_iterations: 4
optimization_activate: True
optimization_verbose: False
penalty_epsilon: 0.1
weight_max_vel_x: 2
weight_max_vel_theta: 1
weight_acc_lim_x: 1
weight_acc_lim_theta: 1
weight_kinematics_nh: 1000
weight_kinematics_forward_drive: 1
weight_kinematics_turning_radius: 1
weight_optimaltime: 1
weight_obstacle: 50
weight_dynamic_obstacle: 10 # not in use yet
alternative_time_cost: False # not in use yet
selection_alternative_time_cost: False
# Homotopy Class Planner
enable_homotopy_class_planning: False
enable_multithreading: False
simple_exploration: False
max_number_classes: 4
roadmap_graph_no_samples: 15
roadmap_graph_area_width: 5
h_signature_prescaler: 0.5
h_signature_threshold: 0.1
obstacle_keypoint_offset: 0.1
obstacle_heading_threshold: 0.45
visualize_hc_graph: False
# # Recovery
# shrink_horizon_backup: True
# shrink_horizon_min_duration: 10
# oscillation_recovery: True
# oscillation_v_eps: 0.1
# oscillation_omega_eps: 0.1
# oscillation_recovery_min_duration: 10
# oscillation_filter_duration: 10
三.启动
编写launch
,修改map_server
和amcl
的部分话题信息
<launch>
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
<rosparam file="$(find slam_nav)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
<rosparam file="$(find slam_nav)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
<rosparam file="$(find slam_nav)/param/local_costmap_params.yaml" command="load" />
<rosparam file="$(find slam_nav)/param/global_costmap_params.yaml" command="load" />
<rosparam file="$(find slam_nav)/param/teb_local_planner_params.yaml" command="load" />
<rosparam file="$(find slam_nav)/param/move_base_params.yaml" command="load" />
<param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" />
</node>
<node name="map_server" pkg="map_server" type="map_server" args="$(find slam_model)/map/ackman_wall.yaml" output="screen">
<param name="frame_id" value="map"/>
</node>
<arg name="use_map_topic" default="True"/>
<arg name="scan_topic" default="/ackman/laser/scan"/>
<arg name="initial_pose_x" default="0.0"/>
<arg name="initial_pose_y" default="0.0"/>
<arg name="initial_pose_a" default="0.0"/>
<arg name="odom_frame_id" default="odom"/>
<arg name="base_frame_id" default="base_footprint"/>
<arg name="global_frame_id" default="map"/>
<node pkg="amcl" type="amcl" name="amcl">
<param name="use_map_topic" value="$(arg use_map_topic)"/>
<!-- Publish scans from best pose at a max of 10 Hz -->
<param name="odom_model_type" value="diff"/>
<param name="odom_alpha5" value="0.1"/>
<param name="gui_publish_rate" value="10.0"/>
<param name="laser_max_beams" value="810"/>
<param name="laser_max_range" value="-1"/>
<param name="min_particles" value="500"/>
<param name="max_particles" value="5000"/>
<param name="kld_err" value="0.05"/>
<param name="kld_z" value="0.99"/>
<param name="odom_alpha1" value="0.2"/>
<param name="odom_alpha2" value="0.2"/>
<!-- translation std dev, m -->
<param name="odom_alpha3" value="0.2"/>
<param name="odom_alpha4" value="0.2"/>
<param name="laser_z_hit" value="0.5"/>
<param name="laser_z_short" value="0.05"/>
<param name="laser_z_max" value="0.05"/>
<param name="laser_z_rand" value="0.5"/>
<param name="laser_sigma_hit" value="0.2"/>
<param name="laser_lambda_short" value="0.1"/>
<param name="laser_model_type" value="likelihood_field"/>
<!-- <param name="laser_model_type" value="beam"/> -->
<param name="laser_likelihood_max_dist" value="2.0"/>
<param name="update_min_d" value="0.1"/>
<param name="update_min_a" value="0.2"/>
<param name="odom_frame_id" value="$(arg odom_frame_id)"/>
<param name="base_frame_id" value="$(arg base_frame_id)"/>
<param name="global_frame_id" value="$(arg global_frame_id)"/>
<param name="resample_interval" value="1"/>
<!-- Increase tolerance because the computer can get quite busy -->
<param name="transform_tolerance" value="1.0"/>
<param name="recovery_alpha_slow" value="0.0"/>
<param name="recovery_alpha_fast" value="0.0"/>
<param name="initial_pose_x" value="$(arg initial_pose_x)"/>
<param name="initial_pose_y" value="$(arg initial_pose_y)"/>
<param name="initial_pose_a" value="$(arg initial_pose_a)"/>
<remap from="/scan" to="$(arg scan_topic)"/>
<remap from="/tf_static" to="/tf_static"/>
</node>
</launch>
然后先启动ackman_show.launch
再启动这个move_base.launch
rivz
里订阅几个话题:
用2D Nav Goal
即可让小车导航
你甚至可以挡它的路:
四.完结后记
目前实现了整个从模型创建到导航的整体功能的实现,代码里还是含有很多bug,而且很多参数的影响也没有量化的考虑清楚。后面用实际模型的时候再针对性的解决这部分问题,现在已经熟悉整个流程了。