关于ROS中move_base的心得以及理解

又有好几个月没有写博客了,今天风和日丽,于是乎想写一篇关于自己对于move_base的理解、心得。

move_base是ROS下关于机器人路径规划的中心枢纽。它通过订阅激光雷达、map地图、amcl的定位等数据,然后规划出全局和局部路径,再将路径转化为机器人的速度信息,最终实现机器人导航。这里又要盗官网的图了。
关于ROS中move_base的心得以及理解_第1张图片

上面这个图很好的展示了move_base的整个框架,下面我更加详细的介绍一下每个模块的功能及其是如何衔接的。

首先左上角的amcl模块是ROS的导航定位模块,amcl也叫自适应蒙特卡罗定位,amcl通过订阅scan、map和tf信息,发布出机器人的pose,以供move_base使用,这部分具体可以上官网看看,这里就不做详细介绍了,左下角odom,即机器人里程计信息,右上角,map,顾名思义,我们需要的先验地图信息,一般通过slam建图后保存,ROS中主流的slam算法有:

1.gmapping:需要激光雷达scan数据和里程计odom数据,采用的是PF(粒子滤波)。

2.hector :基于优化的算法(解最小二乘问题),优缺点:不需要里程计,但对于雷达帧率要求很高40Hz,估计6自由度位姿,可以适应空中或者地面不平坦的情况。初值的选择对结果影响很大,所以要求雷达帧率较高。

3.Cartographer:累计误差较前两种算法低,能天然的输出协方差矩阵,后端优化的输入项。成本较低的雷达也能跑出不错的效果。

好了,就不展开了,map_server包通过解析slam建好的地图并发布出去。右下角的传感器topic则在局部路径规划时起到作用,这部分就是costmap包起到的作用了,costmap为代价地图,目前主要的有inflation_layer、obstacle_layer、static_layer、voxel_layer四个plugins。分别为膨胀层、障碍物层、静态层和体素层。一般我们的全局路径需要静态层和膨胀层,因为全局规划应该只考虑到地图信息,所以一般都是静态的,而局部路径规划则需要考虑到实时的障碍物信息,所以需要障碍物层和膨胀层,这里你可能会有疑惑,为什么不把静态层放到局部路径规划里呢?因为我们的定位是会存在误差的,比如轮子打滑或其他情况,这个时候amcl会起到纠正作用,如果我们把静态层放到了局部中,这个定位会有问题,而且,假设当前机器人出现了定位的偏差,那么这个引入的静态层肯定是错误的,再加上局部的障碍物层(这里的障碍物层本应该和静态层重合的,但由于定位偏差,不会重合)可能会使得机器人误以为自己在障碍物层内,规划出现问题。

下面我们我们说说move_base核心的部分了,也就是框框内的部分,主要包括global planner和local planner以及一些修复机制,包括rotate_recovery和clear_cost_map_recovery。有人可能会问,global planner是怎么和local planner联通的呢,这里不同的算法可能使用了不同的方法了,但核心都是大致相同了,都是将global planner作为local planner的一个初始参考或者优化方向。这些在深入看两个源码时就会有更加深入的理解了。目前ROS中可以使用的global planner主要包括:A*和Dijkstra。local planner主要有:dwa、trajectory、teb和eband等。目前自我感觉teb local planner效果会好点,有时间会详细的介绍一样该算法的思路,下面我把我的关于move_base的一些配置放到下面。

首先,启动move_base的launch,包括解析map,move_base和amcl定位三个部分,这构成了一个完整的框架,下面我们主要来看move_base.launch里的配置。

<launch>
 
  <param name="use_sim_time" value="false" />
  
  <!-- EDIT THIS LINE TO REFLECT THE NAME OF YOUR OWN MAP FILE 
       Can also be overridden on the command line -->
  <arg name="map" default="test_map.yaml" />
 
  <!-- Run the map server with the desired map -->
  <node name="map_server" pkg="map_server" type="map_server" args="$(find dart_nav)/maps/dart.yaml"/> 
 
  <!-- Start move_base  -->
  <include file="$(find dart_nav)/launch/tb_move_base_test.launch" />
 
  <!-- Fire up AMCL -->
  <include file="$(find dart_nav)/launch/tb_amcl.launch" /> 
 
 
</launch>

下面是move_base.launch内的配置:

<launch>
  <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true">
    <rosparam file="$(find dart_nav)/config1/costmap_common_params.yaml" command="load" ns="global_costmap" />
    <rosparam file="$(find dart_nav)/config1/costmap_common_params.yaml" command="load" ns="local_costmap" />
    <rosparam file="$(find dart_nav)/config1/local_costmap_params.yaml" command="load" />
    <rosparam file="$(find dart_nav)/config1/global_costmap_params.yaml" command="load" />
    <rosparam file="$(find dart_nav)/config1/teb_local_planner_params.yaml" command="load" />
 
     <param name="base_global_planner" value="global_planner/GlobalPlanner"/> 
     <param name="planner_frequency" value="1.0" />
     <param name="planner_patience" value="5.0" />
 
     <param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" />
     <param name="controller_frequency" value="15.0" />
     <param name="controller_patience" value="15.0" />
 <rosparam file="$(find dart_nav)/config1/costmap_conversion_params.yaml" command="load" />
 
  </node>
  
</launch>

如上所示,我使用的是global_planner这个包,它默认使用的是dijkstra,当然也可以使用A*全局路径规划,局部路径规划我使用的是teb,同样需要配置上面第3行到第7行的一些yaml,这些yaml是costmap和planner的一些配置文件。我们来主要看一下local_costmap_params.yaml和global_costmap_params.yaml。这里配置了上面提到的各个层(layers)的使用。

local_costmap_params.yaml:

local_costmap:
   global_frame: /odom
   robot_base_frame: /base_link
   update_frequency: 3.0
   publish_frequency: 1.0
   static_map: false
   rolling_window: true
   width: 6.0
   height: 6.0
   resolution: 0.05
   transform_tolerance: 1.0
   map_type: costmap
   plugins:
     - {name: obstacle_layer, type: "costmap_2d::VoxelLayer"}
#     - {name: social_layer,        type: "social_navigation_layers::ProxemicLayer"}   
#     - {name: social_pass_layer,        type: "social_navigation_layers::PassingLayer"}  
#     - {name: static_layer, type: "costmap_2d::StaticLayer"} 
     - {name: inflation_layer, type: "costmap_2d::InflationLayer"}
 
  #Configuration for the sensors that the costmap will use to update a map   
   obstacle_layer:
     observation_sources: scan  
     scan: {data_type: LaserScan, topic: /scan, marking: true, clearing: true, expected_update_rate: 0} 
   inflation_layer: 
      inflation_radius: 0.35

这里由于是局部层,所以我们要把static_map设为fasle,我们并不希望使用静态的地图,因为这不利于我们的局部避障,rollung_window设为true。下面的plugins就为各个层的设置了,在局部路径规划中我们只需要考虑障碍物的信息就可以了,不需要考虑我们之前slam建立的静态地图,所有我们添加了两个图层,即障碍物层和障碍物的膨胀层,下面这个很重要,我们需要声明我们的障碍物层的数据来源,即scan,要把topic对应你的scan的topic,否则你可能发现rviz里的local_costmap没有数据,这就是你没有声明的原因。最后两行为设置膨胀层的半径大小。

global_planner_params.yaml:

global_costmap:
   global_frame: /map
   robot_base_frame: /base_footprint
   update_frequency: 1.0
   publish_frequency: 0
   static_map: true
   rolling_window: false
   resolution: 0.05
   transform_tolerance: 1.0
   map_type: costmap
   plugins:
#     - {name: obstacle_layer, type: "costmap_2d::VoxelLayer"}
     - {name: static_layer, type: "costmap_2d::StaticLayer"} 
   
     - {name: inflation_layer, type: "costmap_2d::InflationLayer"}
   inflation_layer: 
      inflation_radius: 0.35

如上,由于在全局路径规划中,我们只应该考虑静态地图,即我们之前slam建立好的地图,所以我们把static_map设为true,rolling_window设为false,再看plugins:有两个层,静态层和膨胀层,这样就完成了global的yaml的配置,如果你需要把障碍物层也添加到全局地图中,plugins加入,同时别忘了在下面声明数据来源,但我个人不推荐将障碍物层加入到global中来。

下面就是我使用的teb的local_planner的yaml了:

TebLocalPlannerROS:
 
 odom_topic: odom
 map_frame: /odom
 
 # Trajectory
 
 teb_autosize: True
 dt_ref: 0.3
 dt_hysteresis: 0.1
 global_plan_overwrite_orientation: True
 max_global_plan_lookahead_dist: 3.0
 feasibility_check_no_poses: 5
 
 # Robot
 
 max_vel_x: 0.4
 max_vel_x_backwards: 0.15
 max_vel_theta: 0.4
 acc_lim_x: 2.0
 acc_lim_theta: 1.0
 min_turning_radius: 0.0
# footprint_model/type: "circular"
# footprint_model/radius: 0.40 # for type "circular"
 
 # GoalTolerance
 
 xy_goal_tolerance: 0.15
 yaw_goal_tolerance: 0.2
 free_goal_vel: False
 
 # Obstacles
 
 min_obstacle_dist: 0.45
 include_costmap_obstacles: True
 costmap_obstacles_behind_robot_dist: 1.0
 obstacle_poses_affected: 30
 costmap_converter_plugin: ""
 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: 300   #50
 weight_dynamic_obstacle: 10 # not in use yet
 alternative_time_cost: False # not in use yet
 
 # Homotopy Class Planner
 
 enable_homotopy_class_planning: False
 enable_multithreading: True
 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

这里没什么好说的,简单介绍一下teb算法,teb是一个基于图优化的局部路径规划,了解slam的应该都知道BA(bundle adjustment),这里类似,是通过把路径问题构建成一个图优化的问题,然后通过g2o开源库求解优化,teb中是通过对全局路径规划的点(A*或dijkstra)进行优化,也就是最小化误差,这里的误差项为速度,加速度,避障,追踪全局路径等等,最后优化出最优的局部路径,最近在研究teb的算法,有时间再开一个博客,上面大多都是自己的想法,如果有什么问题或错误,欢迎纠正。
————————————————
原文链接:https://blog.csdn.net/shenghuaijing3314/article/details/80005629

你可能感兴趣的:(ROS,算法,定位,slam)