ROS入门(七)——Rviz的使用与建图导航
  iwehdio的博客园:https://www.cnblogs.com/iwehdio/

1、Rviz#

  • Rviz可以与实物或者Gazebo中的模型进行联合使用。在https://www.cnblogs.com/iwehdio/p/12763361.html中,我们看到,机器人模型可以在Rviz中显示,而且相机的图像、激光雷达的扫描结果也能显示。

  • 那我们就想要,在Rviz中对https://www.cnblogs.com/iwehdio/p/12774226.html中自建小车进行显示。

  • 使用Gazebo打开仿真模型后,如果直接打开Rviz,添加话题或者可视化组件,都会报错而无法显示。如报错小车车体 “No transform from [chassis] to [map]”。这是因为Rviz没有收到车体的坐标转换信息即 tf。

  • 不妨从RRbot是怎样做到在Rviz中显示的看起。启动RRbot示例,可以看到,图像和激光雷达以及机器人模型都是正常显示的:

  • 查看坐标转换 tf 中 包含了那些内容:

    $ rostopic echo /tf
    $ rostopic echo /tf_static

    /tf 话题下,发布了link直接的坐标转换关系。

    /tf_static 话题下,发布了机器人与世界、相机、激光雷达之间的坐标转换关系。

  • 更清楚的,可以看一下tf树的结构:

    $ rosrun rqt_tf_tree rqt_tf_tree

    即坐标转换使得机器人的每个组件,最终都能查询到各自之间的坐标转换关系。

  • 回到我们的自建小车上来,同样的,启动Gazebo模型,再查询tf树:

    可以看到,机器人内部的tf都是构造好了的。

  • 但是打开Rviz后,这些话题都不见了。

  • 查找原因,注意到上图的tf树中,除了odom是/gazebo发布的,其他都是由/robot_state_publisher发布的。这是由于,启动mycar_world.launch时,同时也include了mycar_control.launch文件,在这个文件中启动了/robot_state_publisher节点。而mycar_rviz.launch中又一次启动了/robot_state_publisher节点,覆盖了之前的发布。

  • 所以,我们要做的就是,发布/map与/odom的tf,删除并且不再启动/robot_state_publisher节点。

    <!-- 加入 -->
    <node pkg="tf" type="static_transform_publisher" name="odem_broadcaster" args="0 0 0 0 0 0 1 map odom 50" /> 
    <!-- 删除 -->
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher"/>
  • 再次打开Rviz,添加RobotModel、Odometry、Camera和LaserScan,并且保存配置。在mycar_rviz.launch中加入:

    <!-- Show in Rviz   -->
      <node name="rviz" pkg="rviz" type="rviz" args="-d $(find mycar_description)/launch/mycar.rviz"/>

    启动Rviz配置文件,即可在Rviz中显示。

2、建图与导航#

  • 在ROS中,进行导航需要使用到的三个包是:
    (1) move_base:根据参照的消息进行路径规划,使移动机器人到达指定的位置;
    (2) gmapping:根据激光数据(或者深度数据模拟的激光数据)建立地图;
    (3) amcl:根据已经有的地图进行定位。

  • 首先是 gmapping,gmapping 订阅和发布的话题如下:

    接收了坐标系之间的转换关系(odom与base_link)和激光雷达的数据,发布了map与odom之间的坐标转换,进行机器人的定位和建立的地图数据。

  • 然后是move_base,它接收了地图数据等,通过代价地图等进行路径规划:

  • 最后是AMCL,通过已有的数据进行定位:

    接收了激光雷达、地图数据和坐标系之间的转换关系,输出修正后的定位数据。

  • gampping 的配置:

  1. gmapping 配置文件:主要是修改最上方的,激光雷达话题、base_link的框架名、odom的框架名。下方的其他数据主要是与实际建图效果有关的参数配置。

    <launch>
      <arg name="scan_topic"  default="mycar/laser/scan" />
      <arg name="base_frame"  default="footprint"/>
      <arg name="odom_frame"  default="odom"/>
    
      <node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">
        <param name="base_frame" value="$(arg base_frame)"/>   
        <param name="odom_frame" value="$(arg odom_frame)"/>   
        <param name="map_update_interval" value="1.0"/>        
        <param name="maxUrange" value="20.0"/>                
        <param name="maxRange" value="25.0"/>                 
        <param name="sigma" value="0.05"/>
        <param name="kernelSize" value="1"/>
        <param name="lstep" value="0.05"/>
        <param name="astep" value="0.05"/>
        <param name="iterations" value="5"/>
        <param name="lsigma" value="0.075"/>
        <param name="ogain" value="3.0"/>
        <param name="lskip" value="0"/>
        <param name="minimumScore" value="200"/>
        <param name="srr" value="0.01"/>
        <param name="srt" value="0.02"/>
        <param name="str" value="0.01"/>
        <param name="stt" value="0.02"/>
        <param name="linearUpdate" value="0.5"/>
        <param name="angularUpdate" value="0.436"/>
        <param name="temporalUpdate" value="-1.0"/>
        <param name="resampleThreshold" value="0.5"/>
        <param name="particles" value="80"/>
        <param name="xmin" value="-25.0"/>
        <param name="ymin" value="-25.0"/>
        <param name="xmax" value="25.0"/>
        <param name="ymax" value="25.0"/>
    
        <param name="delta" value="0.05"/>
        <param name="llsamplerange" value="0.01"/>
        <param name="llsamplestep" value="0.01"/>
        <param name="lasamplerange" value="0.005"/>
        <param name="lasamplestep" value="0.005"/>
        <remap from="scan" to="$(arg scan_topic)"/>
      </node>
    </launch>
  2. 启动gmapping的launch文件。

    <launch>
      <include file="$(find mycar_slam)/launch/include/robot_gmapping.launch.xml"/>
    
     <include file="$(find mycar_navigation)/launch/include/move_base.launch.xml"/>
    
    </launch>

    不用move_base也可以用键盘控制节点代替。

  3. 运行效果:

  • move_base的配置:

    1. move_base的启动文件:

      <!-- 
          ROS navigation stack with velocity smoother and safety (reactive) controller
      -->
      <launch>
        <!--include file="$(find navigation_sim_demo)/launch/include/velocity_smoother.launch.xml"/-->
        <!--include file="$(find navigation_sim_demo)/launch/include/safety_controller.launch.xml"/-->
        
        <arg name="odom_frame_id"   default="odom"/>
        <arg name="base_frame_id"   default="footprint"/>
        <arg name="global_frame_id" default="map"/>
        <arg name="odom_topic" default="/odom" />
        <arg name="laser_topic" default="/mycar/laser/scan" />
      
        <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
          <rosparam file="$(find mycar_navigation)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
          <rosparam file="$(find mycar_navigation)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />   
          <rosparam file="$(find mycar_navigation)/param/local_costmap_params.yaml" command="load" />   
          <rosparam file="$(find mycar_navigation)/param/global_costmap_params.yaml" command="load" />
          <rosparam file="$(find mycar_navigation)/param/dwa_local_planner_params.yaml" command="load" />
          <rosparam file="$(find mycar_navigation)/param/move_base_params.yaml" command="load" />
          <rosparam file="$(find mycar_navigation)/param/global_planner_params.yaml" command="load" />
          <rosparam file="$(find mycar_navigation)/param/navfn_global_planner_params.yaml" command="load" />
          
          <!-- reset frame_id parameters using user input data -->
          <param name="global_costmap/global_frame" value="$(arg global_frame_id)"/>
          <param name="global_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
          <param name="local_costmap/global_frame" value="$(arg odom_frame_id)"/>
          <param name="local_costmap/robot_base_frame" value="$(arg base_frame_id)"/>
          <param name="DWAPlannerROS/global_frame_id" value="$(arg odom_frame_id)"/>
      
          <remap from="odom" to="$(arg odom_topic)"/>
          <remap from="scan" to="$(arg laser_topic)"/>
          <remap from="cmd_vel" to="/mycar/cmd_vel"/>
      
        </node>
      </launch>

      主要是显示更改odom、map和base_link的框架名,然后更改odom和激光雷达的话题名。下面读入了move_base的配置文件。最后要主要将链接的控制话题进行重映射,连接到本机器人的控制。

    2. move_base的配置文件:

      costmap_common_params.yaml:主要是要更改所读入的传感器的数据类型和话题,其他参数进行适当调节。

      max_obstacle_height: 2.40  # assume something like an arm is mounted on top of the robot
      
      # Obstacle Cost Shaping (http://wiki.ros.org/costmap_2d/hydro/inflation)
      robot_radius: 0.25  # distance a circular robot should be clear of the obstacle (kobuki: 0.18)
      # footprint: [[x0, y0], [x1, y1], ... [xn, yn]]  # if the robot is not circular
      
      map_type: voxel
      
      voxel_layer:
        enabled:              true
        max_obstacle_height:  2.2
        origin_z:             0.0
        z_resolution:         0.1
        z_voxels:             22
        unknown_threshold:    15
        mark_threshold:       0
        combination_method:   1
        track_unknown_space:  true    #true needed for disabling global path planning through unknown space
        obstacle_range: 2.5
        raytrace_range: 3.0
        publish_voxel_map: true
        observation_sources:  scan 
        scan:
          data_type: LaserScan
          topic: /mycar/laser/scan
          marking: true
          clearing: true
          min_obstacle_height: 0.1
          max_obstacle_height: 0.3
      
      #cost_scaling_factor and inflation_radius were now moved to the inflation_layer ns
      inflation_layer:
        enabled:              true
        cost_scaling_factor:  2.58  # exponential rate at which the obstacle cost drops off (default: 10)
        inflation_radius:     1.0  # max. distance from an obstacle at which costs are incurred for planning paths.
      
      static_layer:
        enabled:              true

      dwa_local_planner_params.yaml:对参数进行适当调节。

      DWAPlannerROS:
      
      # Robot Configuration Parameters
        max_vel_x: 0.5
        min_vel_x: 0.0
      
        max_vel_y: 0.0
        min_vel_y: 0.0
      
        # The velocity when robot is moving in a straight line
        max_trans_vel:  0.55
        min_trans_vel:  0.1
        trans_stopped_vel: 0.1
      
        max_rot_vel: 5.0
        min_rot_vel: 0.8
        rot_stopped_vel: 0.8
      
        acc_lim_x: 1.0
        acc_lim_theta: 2.0
        acc_lim_y: 0.0
      
      # Goal Tolerance Parametes
        yaw_goal_tolerance: 0.3
        xy_goal_tolerance: 0.15
        # latch_xy_goal_tolerance: false
      
      # Forward Simulation Parameters
        sim_time: 4.0
        vx_samples: 20
        vy_samples: 0
        vtheta_samples: 40
      
      # Trajectory Scoring Parameters
        path_distance_bias: 32.0
        goal_distance_bias: 24.0
        occdist_scale: 0.1
        forward_point_distance: 0.325
        stop_time_buffer: 0.2
        scaling_speed: 0.25
        max_scaling_factor: 0.2
      
      # Oscillation Prevention Parameters
        oscillation_reset_dist: 0.05
      
      # Debugging
        publish_traj_pc : true
        publish_cost_grid_pc: true
        global_frame_id: odom

      global_costmap_params.yaml:更改全局和base_link的框架名称,其他参数进行适当调节。

      global_costmap:
         global_frame: /map
         robot_base_frame: /footprint
         update_frequency: 2.0
         publish_frequency: 0.5
         static_map: true
         rolling_window: false
         transform_tolerance: 0.5
         plugins:
           - {name: static_layer,            type: "costmap_2d::StaticLayer"}
           - {name: voxel_layer,             type: "costmap_2d::VoxelLayer"}
           - {name: inflation_layer,         type: "costmap_2d::InflationLayer"}

      global_planner_params.yaml:对参数进行适当调节。

      GlobalPlanner:                                  # Also see: http://wiki.ros.org/global_planner
        old_navfn_behavior: false                     # Exactly mirror behavior of navfn, use defaults for other boolean parameters, default false
        use_quadratic: true                           # Use the quadratic approximation of the potential. Otherwise, use a simpler calculation, default true
        use_dijkstra: false                            # Use dijkstra's algorithm. Otherwise, A*, default true
        use_grid_path: false                          # Create a path that follows the grid boundaries. Otherwise, use a gradient descent method, default false
        
        allow_unknown: true                           # Allow planner to plan through unknown space, default true
                                                      #Needs to have track_unknown_space: true in the obstacle / voxel layer (in costmap_commons_param) to work
        planner_window_x: 0.0                         # default 0.0
        planner_window_y: 0.0                         # default 0.0
        default_tolerance: 0.0                        # If goal in obstacle, plan to the closest point in radius default_tolerance, default 0.0
        
        publish_scale: 100                            # Scale by which the published potential gets multiplied, default 100
        planner_costmap_publish_frequency: 0.0        # default 0.0
        
        lethal_cost: 253                              # default 253
        neutral_cost: 50                              # default 50
        cost_factor: 3.0                              # Factor to multiply each cost from costmap by, default 3.0
        publish_potential: true                       # Publish Potential Costmap (this is not like the navfn pointcloud2 potential), default true

      local_costmap_params.yaml:更改全局和base_link的框架名称,其他参数进行适当调节。

      local_costmap:
         global_frame: /map
         robot_base_frame: /footprint
         update_frequency: 5.0
         publish_frequency: 2.0
         static_map: false
         rolling_window: true
         width: 4.0
         height: 4.0
         resolution: 0.05
         origin_x: 5.0
         origin_y: 0
         transform_tolerance: 0.5
         plugins:
          - {name: voxel_layer,      type: "costmap_2d::VoxelLayer"}
          - {name: inflation_layer,     type: "costmap_2d::InflationLayer"}

      move_base_params.yaml:对参数进行适当调节。

      # Move base node parameters. For full documentation of the parameters in this file, please see
      #
      #  http://www.ros.org/wiki/move_base
      #
      shutdown_costmaps: false
      
      controller_frequency: 5.0
      controller_patience: 3.0
      
      
      planner_frequency: 1.0
      planner_patience: 5.0
      
      oscillation_timeout: 10.0
      oscillation_distance: 0.2
      
      # local planner - default is trajectory rollout
      base_local_planner: "dwa_local_planner/DWAPlannerROS"
      
      base_global_planner: "navfn/NavfnROS" #alternatives: global_planner/GlobalPlanner, carrot_planner/CarrotPlanner

      navfn_global_planner_params.yaml:对参数进行适当调节。

      NavfnROS:
        visualize_potential: false    #Publish potential for rviz as pointcloud2, not really helpful, default false
        allow_unknown: true          #Specifies whether or not to allow navfn to create plans that traverse unknown space, default true
                                      #Needs to have track_unknown_space: true in the obstacle / voxel layer (in costmap_commons_param) to work
        planner_window_x: 0.0         #Specifies the x size of an optional window to restrict the planner to, default 0.0
        planner_window_y: 0.0         #Specifies the y size of an optional window to restrict the planner to, default 0.0
        
        default_tolerance: 0.0        #If the goal is in an obstacle, the planer will plan to the nearest point in the radius of default_tolerance, default 0.0
                                      #The area is always searched, so could be slow for big values
    3. 主要是在costmap_common_params.yaml中配置传感器发布的话题。以及在其他文件中配置map、base_link的框架名。

    4. 在gmapping中配置move_base的效果就是,可以进行路径规划,使用2D Nav goal指定所要到达的目标。

  • AMCL的配置:

    1. amcl 的配置文件:更改激光雷达话题名,和odom、base_link和map的框架名。对其他参数进行适当调节。

      <launch>
        <arg name="use_map_topic"   default="true"/>
        <arg name="scan_topic"      default="/mycar/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="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)"/>
        </node>
      </launch>
    2. launch启动文件:引入Map server已经建立的地图,指定初始位置并启动move_base。

      <launch>
        <!-- Map server--> 
        <arg name="map_file" default="$(find slam_sim_demo)/maps/Software_Museum.yaml"/>
        <node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" />
      
        <!-- Localization -->
        <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="custom_amcl_launch_file" default="$(find mycar_navigation)/launch/include/robot_amcl.launch.xml"/> 
      
        <include file="$(arg custom_amcl_launch_file)">
          <arg name="initial_pose_x" value="$(arg initial_pose_x)"/>
          <arg name="initial_pose_y" value="$(arg initial_pose_y)"/>
          <arg name="initial_pose_a" value="$(arg initial_pose_a)"/>
        </include>
      
        <!-- Move base -->
       <include file="$(find mycar_navigation)/launch/include/move_base.launch.xml"/>
      
      </launch>
    3. 地图的格式是 .pgm 格式,配置文件为 .yaml格式:

      image: Software_Museum.pgm
      resolution: 0.050000
      origin: [-25.000000, -25.000000, 0.000000]
      negate: 0
      occupied_thresh: 0.65
      free_thresh: 0.196
    4. AMCL的运行效果:

3、利用rosbag记录地图#

  • 在启动Gazebo和Rviz以及相关的建图程序后,执行以下命令激励激光雷达(更改为自己发布的激光雷达话题)和tf话题发布的所有消息:

    $ rosbag record -o data.bag  /tf /mycar/laser/scan /tf_static
  • 使用rosbag play回放数据,--clock 表示时间信息:

    $ rosbag play --clock data_2018-08-10-18-27-20.bag
  • 利用回放的数据建图(这里使用gmapping时,一定要将激光雷达的话题和底盘和tf配置为自己设置的):

    $ rosparam set use_sim_time true
    $ roslaunch mycar_slam gmapping_demo.launch
  • 保存建好的地图:

    $ rosrun map_server map_saver
  • 发布地图话题:

    $ rosrun map_server map_server map.yaml
  • 然后就可以在Rviz中订阅/map话题了。


参考:中科院软件所-机器人操作系统入门(ROS入门教程):https://www.bilibili.com/video/BV1mJ411R7Ni?p=44

iwehdio的博客园:https://www.cnblogs.com/iwehdio/

作者: iwehdio

出处:https://www.cnblogs.com/iwehdio/p/12821390.html

——————来源于结束于否定之否定。——————