1. 程式人生 > >ROS:move_base除錯

ROS:move_base除錯

move_base是ROS下關於機器人路徑規劃的中心樞紐。它通過訂閱鐳射雷達、map地圖、amcl的定位等資料,然後規劃出全域性和區域性路徑,再將路徑轉化為機器人的速度資訊,最終實現機器人導航。這裡又要盜官網的圖了。

上面這個圖很好的展示了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)進行優化,也就是最小化誤差,這裡的誤差項為速度,加速度,避障,追蹤全域性路徑等等,最後優化出最優的區域性路徑.