Analysis of slam navigation file of ros radar

Posted by New Coder on Mon, 21 Feb 2022 19:58:49 +0100

There are multiple radar function packages under the lidar folder.

It also includes a udev rule conversion script. The radar uses cp2102usb to serial port chip.

Multiple devices are connected to the host through usb, so it is difficult to distinguish the devices corresponding to each port name.

Set rules for the chip of USB to serial port, and filter according to the Vender ID and Product ID of the chip. After reading the chip, make a symbolic link to the corresponding port. Named rplidar et al.

initenv.sh
#!/bin/bash
echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", SYMLINK+="hldslidar"' >/etc/udev/rules.d/hldslidar.rules

echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", GROUP:="dialout",  SYMLINK+="ydlidar"' >/etc/udev/rules.d/ydlidar.rules

echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", GROUP:="dialout",  SYMLINK+="iiilidar"' >/etc/udev/rules.d/iiilidar.rules

echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", GROUP:="dialout",  SYMLINK+="rplidar"' >/etc/udev/rules.d/rplidar.rules

echo  'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0777", GROUP:="dialout",  SYMLINK+="sclidar"' >/etc/udev/rules.d/sclidar.rules

systemctl daemon-reload
service udev reload
sleep 1
service udev restart

robot_ The navigation folder is very important.

robot:
roslaunch robot_navigation lidar.launch  Start the radar
PC: 
roslaunch robot_navigation lidar_rviz.launch  function rviz tool

robot:
roslaunch robot_navigation robot_slam_laser.launch  Lidar slam Mapping
pc: 
roslaunch robot_navigation slam_rviz.launch

robot: Save map
roscd robot_navigation/maps
rosrun map_server map_saver -f map

robot: 
roslaunch robot_navigation robot_navigation.launch   Navigation and obstacle avoidance
pc: 
roslaunch robot_navigation navigation_rviz.launch  

robot: 
roslaunch robot_navigation robot_slam_laser.launch slam_methods:=hector Graph building switching algorithm
pc: 
roslaunch robot_navigation navigation_rviz.launch

robot: 
roslaunch robot_navigation robot_navigation.launch planner:=dwa Path planning algorithm switching

robot: 
roslaunch robot_navigation robot_slam_laser.launch planner:=teb Navigation mapping
pc: 
roslaunch robot_navigation slam_rviz.launch

The document contains:

rviz folder: rviz Related configuration files
maps Folder: files related to map files and map configuration information
param folder: yaml file
launch folder
script folder:Script file

In the launch folder:

includes Folder: of mapping algorithm launch file
lidar Folder: radar launch file
rviz folder: rviz of launch file

robot_slam_laser.launch

robot_slam_laser.launch:

This is mainly the circular call of the launch file, for example, through the robot_ slam_ laser. The launch file called the robot_lidar.launch file.

The advantage of this is modularity. You can avoid repeatedly starting multiple nodes.

<launch>
  <!-- Arguments -->
  
  <arg name="slam_methods" default="gmapping" doc="slam type [gmapping, hector, karto, cartographer]"/><!-- Passable parameters slam_methods,choice SLAM Mapping algorithm -->
  <arg name="open_rviz" default="false"/>
  <arg name="simulation" default= "false"/> <!-- Determine whether to start the physical robot or stage simulator  -->
  <arg name="planner"  default="" doc="opt: dwa, teb"/> <!-- Navigation while creating a map in the environment without map. The optional parameters are dwa,teb Local path planner -->

  <param name="/use_sim_time" value="$(arg simulation)" />  

  <!-- simulation robot with lidar and map -->
  <!-- simulation by true Start the simulation software and run the simulation robot-->
  <group if="$(arg simulation)">
    <include file="$(find robot_simulation)/launch/simulation_one_robot.launch"/>
  </group>

  <!-- robot with lidar -->
  <!--simulation by false start-up launch Under folder robot_lidar.launch-->
  <group unless="$(arg simulation)">
    <include file="$(find robot_navigation)/launch/robot_lidar.launch"/>
  </group>
  <!-- SLAM: Gmapping, Cartographer, Hector, Karto -->
  <!-- according to slam_methods Different mapping algorithms are selected for parameters -->
  <include file="$(find robot_navigation)/launch/includes/$(arg slam_methods).launch">
    <arg name="simulation"            value="$(arg simulation)"/>
  </include>
  <!-- move_base No map environment navigation map building function, incoming planner Parameter is dwa or teb,The navigation stack is started-->
  <group unless="$(eval planner == '')"><!--start-up move_base.launch-->
    <include file="$(find robot_navigation)/launch/move_base.launch" unless="$(eval planner == '')">
        <arg name="planner"            value="$(arg planner)"/>
    </include>
  </group>
    
  <!--because gmapping Will release map Topic: you can navigate normally without starting the map server to read the map locally-->

  <!-- rviz open_rviz Parameter is true Open when rviz-->
  <group if="$(arg open_rviz)"> 
    <node pkg="rviz" type="rviz" name="rviz" required="true"
          args="-d $(find robot_navigation)/rviz/slam.rviz"/><!-- use rviz Profile preset in folder slam.rviz -->
  </group>
  
</launch>

robot_lidar.launch

robot_lidar.launch: start the chassis and radar

<launch>
    <!-- config param -->
    <arg name="pub_imu"       default="False" />
    <arg name="sub_ackermann"       default="False" />
    <arg name="lidar_frame" default="base_laser_link"/>  

    <!-- include The label contains two launch -->
    
    <include file="$(find base_control)/launch/base_control.launch">
        <arg name="pub_imu"            value="$(arg pub_imu)"/>  
        <arg name="sub_ackermann"            value="$(arg sub_ackermann)"/>  
    </include>
	
    <include file="$(find robot_navigation)/launch/lidar.launch">
        <arg name="lidar_frame"            value="$(arg lidar_frame)"/>  
    </include>
    
</launch>

lidar.launch

lidar.launch: the launch file of the radar is started here

<launch>
    <!--robot bast type use different tf value-->
    <!-- Read robot chassis type -->
    <arg name="base_type"       default="$(env BASE_TYPE)" />
    <!-- robot frame -->
    
    <arg name="base_frame"       default="/base_footprint" />    
    <!-- Read robot radar type -->
    <arg name="lidar_type"       default="$(env LIDAR_TYPE)" />   
    <arg name="lidar_frame" default="base_laser_link"/>  

    <!-- according to lidar_type Type startup node, if yes rplidar,Just start rplidar.launch -->
    <include file="$(find robot_navigation)/launch/lidar/$(arg lidar_type).launch">
        <arg name="lidar_frame"            value="$(arg lidar_frame)"/>
    </include>

    <!-- TF coordinate transformation  -->
    <group if="$(eval base_type == 'NanoRobot')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="-0.01225 0.0 0.18 3.14159265 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == 'NanoRobot_Pro')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="-0.0515 0.0 0.18 -1.5708 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == '4WD')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="0.01 0.0 0.25 3.14159265 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == '4WD_OMNI')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="0.01 0.0 0.25 3.14159265 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == 'NanoCar')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="0.1037 0.0 0.115 3.14159265 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == 'NanoCar_Pro')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="0.1037 0.0 0.165 3.14159265 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>
    <group if="$(eval base_type == 'NanoCar_SE')">
        <node pkg="tf" type="static_transform_publisher" name="base_footprint_to_laser"
            args="0.0955 0.0 0.115 1.5708 0.0 0.0 $(arg base_frame) $(arg lidar_frame) 20">
        </node>
    </group>

</launch>

raplidar.launch

raplidar.launch radar data

The port name uses the name of the udev rule.

<param name="serial_port"         type="string" value="/dev/rplidar"/>
<launch>
    <arg name="lidar_frame" default="lidar"/>   

    <node name="rplidarNode"          pkg="rplidar_ros"  type="rplidarNode" output="screen">
        <param name="serial_port"         type="string" value="/dev/rplidar"/>
        <param name="serial_baudrate"     type="int"    value="115200"/><!--A1/A2 -->
        <!--param name="serial_baudrate"     type="int"    value="256000"--><!--A3 -->
        <param name="frame_id"            type="string" value="$(arg lidar_frame)"/>
        <param name="inverted"            type="bool"   value="false"/>
        <param name="angle_compensate"    type="bool"   value="true"/>
    </node>
</launch>

karto.launch

karto.launch file. The configuration parameters are loaded through yaml file.

<launch>

  <arg name="simulation" default= "false"/> 

  <param name="/use_sim_time" value="$(arg simulation)" />  

  <!-- slam_karto -->

  <node pkg="slam_karto" type="slam_karto" name="slam_karto" output="screen">

    <rosparam command="load" file="$(find robot_navigation)/config/karto_params.yaml" />

  </node>

</launch>

karto_params.yaml

# General Parameters

base_frame: base_footprint

map_update_interval: 5

use_scan_matching: true

use_scan_barycenter: true

minimum_travel_distance: 0.12 

minimum_travel_heading: 0.174             #in radians

scan_buffer_size: 70

scan_buffer_maximum_scan_distance: 3.5

link_match_minimum_response_fine: 0.12

link_scan_maximum_distance: 3.5

loop_search_maximum_distance: 3.5

do_loop_closing: true

loop_match_minimum_chain_size: 10

loop_match_maximum_variance_coarse: 0.4   # gets squared later

loop_match_minimum_response_coarse: 0.8

loop_match_minimum_response_fine: 0.8



# Correlation Parameters - Correlation Parameters

correlation_search_space_dimension: 0.3

correlation_search_space_resolution: 0.01

correlation_search_space_smear_deviation: 0.03



# Correlation Parameters - Loop Closure Parameters

loop_search_space_dimension: 8.0

loop_search_space_resolution: 0.05

loop_search_space_smear_deviation: 0.03



# Scan Matcher Parameters

distance_variance_penalty: 0.3      # gets squared later

angle_variance_penalty: 0.349       # in degrees (gets converted to radians then squared)

fine_search_angle_offset: 0.00349   # in degrees (gets converted to radians)

coarse_search_angle_offset: 0.349   # in degrees (gets converted to radians)

coarse_angle_resolution: 0.0349     # in degrees (gets converted to radians)

minimum_angle_penalty: 0.9

minimum_distance_penalty: 0.5

use_response_expansion: false

In comparison with the above, parameters are directly transmitted through the launch file. The two of them have the same effect.

gmapping.launch

<launch>
  <arg name="set_base_frame" default="base_footprint"/>
  <arg name="set_odom_frame" default="odom"/>
  <arg name="set_map_frame"  default="map"/>
  <arg name="scan_topic" default="/scan" />
  <arg name="simulation" default= "false"/> 
  <param name="/use_sim_time" value="$(arg simulation)" />  
  <!-- Gmapping -->
  <node pkg="gmapping" type="slam_gmapping" name="gmapping" output="screen">
    <param name="base_frame" value="$(arg set_base_frame)"/>
    <param name="odom_frame" value="$(arg set_odom_frame)"/>
    <param name="map_frame"  value="$(arg set_map_frame)"/>
    <param name="map_update_interval" value="2.0"/>
    <param name="maxUrange" value="5.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="50"/>
    <param name="srr" value="0.1"/>
    <param name="srt" value="0.2"/>
    <param name="str" value="0.1"/>
    <param name="stt" value="0.2"/>
    <param name="linearUpdate" value="1.0"/>
    <param name="angularUpdate" value="0.2"/>
    <param name="temporalUpdate" value="0.5"/>
    <param name="resampleThreshold" value="0.5"/>
    <param name="particles" value="100"/>
    <param name="xmin" value="-10.0"/>
    <param name="ymin" value="-10.0"/>
    <param name="xmax" value="10.0"/>
    <param name="ymax" value="10.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>

cartographer.launch

It uses lua scripting language to load configuration files.

-configuration_basename revo_lds_$(arg version).lua" 

revo_lds_melodic.lua

include "map_builder.lua"
include "trajectory_builder.lua"

options = {
  map_builder = MAP_BUILDER,
  trajectory_builder = TRAJECTORY_BUILDER,
  map_frame = "map",
-- tracking_frame = "base_laser_link",
-- published_frame = "base_laser_link",
-- odom_frame = "odom",
-- provide_odom_frame = true,
-- use_odometry = false,

  tracking_frame = "base_footprint",
  published_frame = "odom",
  odom_frame = "odom",
  provide_odom_frame = false,
  publish_frame_projected_to_2d = false,
  use_odometry = true,
  use_nav_sat = false,
  use_landmarks = false,
  num_laser_scans = 1,
  num_multi_echo_laser_scans = 0,
  num_subdivisions_per_laser_scan = 1,
  num_point_clouds = 0,
  lookup_transform_timeout_sec = 0.2,
  submap_publish_period_sec = 0.3,
  pose_publish_period_sec = 5e-3,
  trajectory_publish_period_sec = 30e-3,
  rangefinder_sampling_ratio = 1.,
  odometry_sampling_ratio = 1.,
  fixed_frame_pose_sampling_ratio = 1.,
  imu_sampling_ratio = 1.,
  landmarks_sampling_ratio = 1.,
}

MAP_BUILDER.use_trajectory_builder_2d = true

TRAJECTORY_BUILDER_2D.submaps.num_range_data = 35
TRAJECTORY_BUILDER_2D.min_range = 0.3
TRAJECTORY_BUILDER_2D.max_range = 8.
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 1.
TRAJECTORY_BUILDER_2D.use_imu_data = false
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.1
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight = 10.
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight = 1e-1

POSE_GRAPH.optimization_problem.huber_scale = 1e2
POSE_GRAPH.optimize_every_n_nodes = 35
POSE_GRAPH.constraint_builder.min_score = 0.65

return options

cartographer.launch

<launch>  
  <arg name="simulation" default= "true"/> 
  <arg name="version" default="$(env ROS_DISTRO)"/><!-- Read environment variables ROS_DISTRO Version of -->
  <param name="/use_sim_time" value="$(arg simulation)" />  
  <!-- cartographer_node -->
  <node name="cartographer_node" pkg="cartographer_ros"  
        type="cartographer_node" args="  
            -configuration_directory $(find robot_navigation)/config  
            -configuration_basename revo_lds_$(arg version).lua"  
        output="screen">  <!--according to version Parameter selection profile for-->
  </node>  
  <group if="$(eval version == 'melodic')"><!--about melodic Version, manually start the following node-->
      <node pkg="cartographer_ros" type="cartographer_occupancy_grid_node" name="cartographer_occupancy_grid_node"/>
  </group>
</launch>

robot_navigation.launch

Two group s, each of which realizes the startup of robot, radar, map and amcl.

<launch>
  <!-- Arguments -->
    <!--The path where the incoming map file is located-->
  <arg name="map_file" default="$(find robot_navigation)/maps/map.yaml"/><!--parameter map_file afferent maps Under file map.yaml file -->
  <!--If the map name and save path are customized, you only need to modify the passed in map map_file Value of-->
  <arg name="simulation" default= "false"/> 
  <arg name="planner"  default="teb" doc="opt: dwa, teb"/> 
  <arg name="open_rviz" default="false"/>
  <arg name="use_dijkstra" default= "true"/> 

  <group if="$(arg simulation)">
    <!-- simulation robot with lidar and map-->
    <!-- simulation Parameter is true,Over there launch Start map service in file -->
    <include file="$(find robot_simulation)/launch/simulation_one_robot_with_map.launch"/>
  </group>

  <group unless="$(arg simulation)">
    <!-- robot with lidar Start chassis and radar-->
    <include file="$(find robot_navigation)/launch/robot_lidar.launch">
          <!--<arg name="robot_name"            value="$(arg robot_name)"/>-->
    </include>
    <!-- Map server Start map server read in map_file Parameter get map file-->
    <node pkg="map_server" name="map_server" type="map_server" args="$(arg map_file)">
      <param name="frame_id" value="map"/>
    </node>
    <!-- AMCL,Start a positioning node amcl -->
    <node pkg="amcl" type="amcl" name="amcl" output="screen">
      <!-- adopt yaml File read configuration file-->
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/amcl_params.yaml" command="load" />
      <!-- Through the following settings, the robot is at the map zero point by default when starting -->
        <!-- If the robot starts from a fixed position and is not the origin, the parameters can be modified -->
      <param name="initial_pose_x"            value="0.0"/>
      <param name="initial_pose_y"            value="0.0"/>
      <param name="initial_pose_a"            value="0.0"/><!--course-->
    </node>
  </group>

  <!-- move_base Navigation stack-->
  <include file="$(find robot_navigation)/launch/move_base.launch" >
    <!--Parameters passed in-->
    <arg name="planner"            value="$(arg planner)"/>
    <arg name="simulation"            value="$(arg simulation)"/>
    <arg name="use_dijkstra"     value="$(arg use_dijkstra)"/>

  </include>

  <!-- rviz -->
  <group if="$(arg open_rviz)"> 
    <node pkg="rviz" type="rviz" name="rviz" required="true"
          args="-d $(find robot_navigation)/rviz/navigation.rviz"/>
  </group>

</launch>

map.yaml

It includes some basic configuration information of the map.

image: map.pgm
resolution: 0.050000
origin: [-10.000000, -10.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196

Meaning of parameters: you can find the corresponding function package in Wiki, and introduce the parameters in English.

image: Map name.
resolution: Map resolution, meters/pixel
origin: The two-dimensional pose of the pixels in the lower left corner of the map is x,y,yaw. Yaw is counterclockwise rotation, yaw=0 Indicates no rotation
occupied_thresh: Pixels larger than this threshold are fully occupied.
free_thresh: Pixels less than this threshold are completely idle.
negate: 
Pixel COLOR value x stay[0,255]Within the scope.
First, set the integer x Convert to a floating point number p,The conversion formula depends on yaml in negate Definition of signs.
If negate=0,be p =(255 - x)/ 255.0. This means that black (0) now has the highest value (1).0)White (255) has the lowest value (0.0). 
If negate=1,be p = x / 255.0. 

map.pgm

pgm is an image format.

amcl_params.yaml

You can view the parameter information through the ros wiki introduction page of amcl.

use_map_topic: true



odom_frame_id: "odom"

base_frame_id: "base_footprint"

global_frame_id: "map"



## Publish scans from best pose at a max of 10 Hz

odom_model_type: "diff"

odom_alpha5: 0.1

gui_publish_rate: 10.0

laser_max_beams: 60

laser_max_range: 12.0

min_particles: 500

max_particles: 2000

kld_err: 0.05

kld_z: 0.99

odom_alpha1: 0.2

odom_alpha2: 0.2

## translation std dev, m 

odom_alpha3: 0.2

odom_alpha4: 0.2

laser_z_hit: 0.5

aser_z_short: 0.05

laser_z_max: 0.05

laser_z_rand: 0.5

laser_sigma_hit: 0.2

laser_lambda_short: 0.1

laser_model_type: "likelihood_field" # "likelihood_field" or "beam"

laser_likelihood_max_dist: 2.0

update_min_d: 0.25

update_min_a: 0.2



resample_interval: 1



## Increase tolerance because the computer can get quite busy 

transform_tolerance: 1.0

recovery_alpha_slow: 0.001

recovery_alpha_fast: 0.1


move_base.launch

move_base.launch: navigation stack under ros

The default passed in planner parameter is dwa, but robot_navigation.launch calls move_ base. When launching, the parameter passed in is teb. So here the planner parameter is set to teb.

<launch>
  <!-- Arguments -->
  <arg name="cmd_vel_topic" default="cmd_vel" />
  <arg name="odom_topic" default="odom" />
  <arg name="planner"  default="dwa" doc="opt: dwa, teb"/> <!--Default incoming planner Parameter is dwa-->
  <arg name="simulation" default= "false"/> 
  <arg name="use_dijkstra" default= "true"/>  
  

  <arg name="base_type" default= "$(env BASE_TYPE)"/> <!--Different models and configurations-->
  <arg name="move_forward_only" default="false"/><!--Using depth camera for navigation and mapping, there is only forward view and no backward view-->
    <!--The backward operation of the vehicle is prohibited to ensure safe operation-->

  <!-- Two were used group distinguish DWA and TEB Two different local path planning algorithms -->
  <!-- move_base use DWA planner-->
  <group if="$(eval planner == 'dwa')">
    <!-- start-up move_base node -->
    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
      <!-- use global_planner replace default navfn as global planner ,global_planner support A* and dijkstra algorithm-->
      <!--Set the parameters of the incoming node-->
      <param name="base_global_planner" value="global_planner/GlobalPlanner"/>
      <param name="base_local_planner" value="dwa_local_planner/DWAPlannerROS" />
      <!-- <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/global_planner_params.yaml" command="load" />       -->
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/costmap_common_params.yaml" command="load" ns="global_costmap" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/costmap_common_params.yaml" command="load" ns="local_costmap" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/local_costmap_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/global_costmap_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/move_base_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/dwa_local_planner_params.yaml" command="load" />
      <remap from="cmd_vel" to="$(arg cmd_vel_topic)"/>
      <remap from="odom" to="$(arg odom_topic)"/>
        <!-- move_forward_only No negative speed (backward movement) is allowed when -->
      <param name="DWAPlannerROS/min_vel_x" value="0.0" if="$(arg move_forward_only)" />
      <!--default is True,use dijkstra algorithm;set to False,usd A* algorithm-->
      <param name="GlobalPlanner/use_dijkstra " value="$(arg use_dijkstra)" />    
    </node>
  </group>
  <!-- move_base use TEB planner-->
  <group if="$(eval planner == 'teb')">
    <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
      <!-- use global_planner replace default navfn as global planner ,global_planner support A* and dijkstra algorithm-->
      <param name="base_global_planner" value="global_planner/GlobalPlanner"/>
      <param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" />
      <!-- <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/global_planner_params.yaml" command="load" /> -->
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/costmap_common_params.yaml" command="load" ns="global_costmap" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/costmap_common_params.yaml" command="load" ns="local_costmap" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/local_costmap_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/global_costmap_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/move_base_params.yaml" command="load" />
      <rosparam file="$(find robot_navigation)/param/$(env BASE_TYPE)/teb_local_planner_params.yaml" command="load" />
      <remap from="cmd_vel" to="$(arg cmd_vel_topic)"/>
      <remap from="odom" to="$(arg odom_topic)"/>
      <param name="TebLocalPlannerROS/max_vel_x_backwards" value="0.0" if="$(arg move_forward_only)" />
      <!--default is True,use dijkstra algorithm;set to False,usd A* algorithm-->
      <param name="GlobalPlanner/use_dijkstra " value="$(arg use_dijkstra)" />
      <!--stage simulator takes the angle instead of the rotvel as input (twist message)-->

      
    </node>
  </group>
    <!-- move_base -->
</launch>

costmap_common_params.yaml

Costmap of one of the models_ common_ params. Yaml file is as follows.

#---(in meters)---
#The unit is meter

footprint: [ [-0.035,-0.1], [0.18,-0.1], [0.18,0.1], [-0.035,0.1] ]
#Rectangular outline dimension of robot
#Taking the center of the robot as the origin of the coordinate axis, the four coordinate points (x,y) correspond to the four corners of the robot respectively
#The path planner obtains the outline size of the robot and plans the corresponding path

#The meaning of the parameter is through move_base's ros wiki view
transform_tolerance: 0.2

obstacle_layer:

 enabled: true

 obstacle_range: 2.5

 raytrace_range: 3.0

 inflation_radius: 0.05

 track_unknown_space: false

 combination_method: 1

 observation_sources: laser_scan_sensor

 laser_scan_sensor: {data_type: LaserScan, topic: scan, marking: true, clearing: true}

inflation_layer:

  enabled:              true

  cost_scaling_factor:  10.0  # exponential rate at which the obstacle cost drops off (default: 10)

  inflation_radius:     0.1  # max. distance from an obstacle at which costs are incurred for planning paths.



static_layer:

  enabled:              true

  map_topic:            "/map"

local_costmap_params.yaml

The obstacle avoidance function of robot is realized by local costmap. There are no obstacles in the global map. Find the obstacles through the local map and re plan the route.

#Specify the frequency of publication and update
local_costmap:

  global_frame: map

  robot_base_frame: base_footprint

  update_frequency: 5.0

  publish_frequency: 5.0

  rolling_window: true#sliding window
  #3 * 3 sliding window centered on the position of the robot
  #The smaller the box is set, the worse the path planning effect is, and the greater the calculation burden of the robot is
  width: 3
  height: 3

  resolution: 0.05

  transform_tolerance: 0.5

  plugins:#Set up a map layer
  #Static layer
   - {name: static_layer,        type: "costmap_2d::StaticLayer"}
  #Obstacle layer: the obstacles that do not exist in the map but are actually scanned will be recognized in the obstacle layer.
   - {name: obstacle_layer,      type: "costmap_2d::ObstacleLayer"}

global_costmap_params.yaml

#Set some information such as publishing frequency
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

  plugins:

    - {name: static_layer,            type: "costmap_2d::StaticLayer"}

    - {name: obstacle_layer,          type: "costmap_2d::VoxelLayer"}

    - {name: inflation_layer,         type: "costmap_2d::InflationLayer"}

move_base_params.yaml:

#Make some frequency settings

#Control frequency of chassis
controller_frequency: 2.0
controller_patience: 15.0

#Path planning frequency
planner_frequency: 0.2
planner_patience: 5.0

conservative_reset_dist: 3.0

#Maximum allowable oscillation time when the robot vibrates continuously at one point
oscillation_timeout: 10.0
oscillation_distance: 0.2

clearing_rotation_allowed: false 
    
#clearing_ rotation_ When allowed is True, the robot is trapped and will turn around 360 degrees to find a way out (lidar is not required for 360)
#Ackerman structure does not have the ability to turn in place and needs to be disabled

dwa_local_planner_params.yaml

DWAPlannerROS:

# Robot Configuration Parameters
#Set the maximum and minimum speed of robot navigation
#Absolute value of maximum speed in x direction, unit: m/s
  max_vel_x: 0.25
#The absolute value of the minimum value in the x direction. If it is negative, it means you can go back
  min_vel_x: -0.25
#y-axis speed, only for mcnamm wheel
  max_vel_y: 0.0

  min_vel_y: 0.0


# The velocity when robot is moving in a straight line
#Maximum angular velocity in rad/s
  max_vel_trans:  0.26

  min_vel_trans:  0.13


  max_vel_theta: 1.0

  min_vel_theta: 0.5

#Absolute value of acceleration in x direction, m/s2
  acc_lim_x: 2.5
#Absolute value of acceleration in y direction, which can only be configured for omni-directional moving machines
  acc_lim_y: 0.0
#Absolute value of rotational acceleration rad/s2
  acc_lim_theta: 3.2 


# Goal Tolerance Parametes
#It allows the deviation of the coordinates (in meters) of the target reached by the robot. Too small may cause the robot to constantly adjust to the accurate target position near the target position
  xy_goal_tolerance: 0.1
#Tolerance of angle
  yaw_goal_tolerance: 0.2

  latch_xy_goal_tolerance: false


# Forward Simulation Parameters

  sim_time: 2.0

  vx_samples: 20

  vy_samples: 0

  vtheta_samples: 40

  controller_frequency: 10.0


# Trajectory Scoring Parameters

  path_distance_bias: 32.0

  goal_distance_bias: 20.0

  occdist_scale: 0.02

  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
    

  prune_plan: false

  use_dwa: true

  restore_defaults: false

teb_local_planner_params.yaml

TebLocalPlannerROS:

 odom_topic: odom

 # Trajectory

 teb_autosize: True

 dt_ref: 0.3

 dt_hysteresis: 0.1

 max_samples: 500

 global_plan_overwrite_orientation: True

 allow_init_with_backwards_motion: True

 max_global_plan_lookahead_dist: 3.0

 global_plan_viapoint_sep: -1

 global_plan_prune_distance: 1

 exact_arc_length: False

 feasibility_check_no_poses: 2

 publish_feedback: False

 # Robot       
#Max x forward speed
 max_vel_x: 0.2
#Maximum x reverse speed
 max_vel_x_backwards: 0.2

 max_vel_y: 0.0
#Maximum steering angular speed
 max_vel_theta: 0.53 # the angular velocity is also bounded by min_turning_radius in case of a carlike robot (r = v / omega)
#Maximum x acceleration
 acc_lim_x: 0.5
#Maximum angular velocity
 acc_lim_theta: 0.5

 # ********************** Carlike robot parameters ********************
#Set parameters for minimum turning radius
 min_turning_radius: 0.375        # Min turning radius of the carlike robot (compute value using a model or adjust with rqt_reconfigure manually)
#Track parameters
 wheelbase: 0.145                 # Wheelbase of our robot

 #Convert the received angle message into an operational angle change
 cmd_angle_instead_rotvel: False  # stage simulator takes the angle instead of the rotvel as input (twist message)
#Use the simulator to simulate the Ackerman model, and CMD_ angle_ instead_ Change rotvel to true,
#CMD accepted by "Car" model in stage simulator_ The z-axis angular velocity in the vel topic is not the given angular velocity of the robot, but the steering angle of the steering structure.
#cmd_angle_instead_rotvel: False, the angular velocity is the real angular velocity of the fixed robot
 # ********************************************************************

 footprint_model: # types: "point", "circular", "two_circles", "line", "polygon"

   type: "line"

   line_start: [0.05, 0.0] # for type "line"

   line_end: [0.10, 0.0] # for type "line"

 # GoalTolerance

 xy_goal_tolerance: 0.1

 yaw_goal_tolerance: 0.2

 free_goal_vel: False

 complete_global_plan: True

 # Obstacles

 min_obstacle_dist: 0.12 # This value must also include our robot's expansion, since footprint_model is set to "line".

 inflation_dist: 0.6

 include_costmap_obstacles: True

 costmap_obstacles_behind_robot_dist: 1.5

 obstacle_poses_affected: 15
    

 dynamic_obstacle_inflation_dist: 0.6

 include_dynamic_obstacles: True 


 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

 obstacle_cost_exponent: 4

 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 # must be > 0

 weight_shortest_path: 0

 weight_obstacle: 100

 weight_inflation: 0.2

 weight_dynamic_obstacle: 10 # not in use yet

 weight_dynamic_obstacle_inflation: 0.2

 weight_viapoint: 1

 weight_adapt_factor: 2


 # Homotopy Class Planner


 enable_homotopy_class_planning: False

 enable_multithreading: True

 max_number_classes: 4

 selection_cost_hysteresis: 1.0

 selection_prefer_initial_plan: 0.95

 selection_obst_cost_scale: 1.0

 selection_alternative_time_cost: False


 roadmap_graph_no_samples: 15

 roadmap_graph_area_width: 5

 roadmap_graph_area_length_scale: 1.0

 h_signature_prescaler: 0.5

 h_signature_threshold: 0.1

 obstacle_heading_threshold: 0.45

 switching_blocking_period: 0.0

 viapoints_all_candidates: True

 delete_detours_backwards: True

 max_ratio_detours_duration_best_duration: 3.0

 visualize_hc_graph: False

 visualize_with_time_as_z_axis_scale: False


# Recovery


 shrink_horizon_backup: True

 shrink_horizon_min_duration: 10

 oscillation_recovery: False

 oscillation_v_eps: 0.1

 oscillation_omega_eps: 0.1

 oscillation_recovery_min_duration: 10

 oscillation_filter_duration: 10

Multipoint navigation

Multipoint navigation:
Ordinary navigation can only publish one target point.
Before reaching the target point, if a new target point is released, the original target point will be abandoned and go directly to the new target point.
Multi-target point navigation is to go to the target point in turn according to the release order of the target point.

stage Simulation: roslaunch robot_navigation robot_navigation.launch simulation:=true
 Running on a solid robot does not require input simulation:=true

To launch the multipoint navigation tool: roslaunch robot_navigation multi_points_navigation.launch
 start-up rviz: roslaunch robot_navigation multi_navigation.launch

rviz There is an extra 2 D Nav Goal Button can continuously assign multiple target points to the robot, and the robot will go to each target point in turn

multi_points_navigation.launch

multi_points_navigation.launch, multi-point navigation

<launch>

    <!--<node name="robot_pose_publisher" pkg="robot_pose_publisher" type="robot_pose_publisher" />-->
    <!--Started a multi_goal_point.py Node of-->
    <node name="multi_mark" pkg="robot_navigation" type="multi_goal_point.py" output="screen" />

</launch>

multi_navigation.launch

<launch>
  <!-- rviz -->
    <node pkg="rviz" type="rviz" name="rviz" required="true"
          args="-d $(find robot_navigation)/rviz/multi_navigation.rviz"/>
</launch>

multi_goal_point.py:

Core idea:

Through the rviz button, publish the goal topic instead of / move_base_simple/goal topic, because / move_ base_ The simple / goal topic will be directly sent to movebase to directly generate a new navigation target.

Cache the goal through markerArray and move_base triggers status callback to execute the next target point according to the navigation result of each point.

move in circles.

#!/usr/bin/python


from visualization_msgs.msg import Marker
from visualization_msgs.msg import MarkerArray
import rospy
import math
from geometry_msgs.msg import PointStamped,PoseStamped
import actionlib
from move_base_msgs.msg import *
import tf

def status_callback(msg):#When receiving the move base navigation result, judge whether to read the next point and continue publishing; Or mark the last point at present

    global goal_pub, index,markerArray
    global add_more_point,try_again

    if(msg.status.status == 3):#The status is 3 and the navigation is successful to the target point
        try_again = 1
        if add_more_point == 0:
            print 'Goal reached'

        if index < count:

            pose = PoseStamped()
            pose.header.frame_id = "map"
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index].pose.position.x#Give pose a new value
            #Read a new target point from markerArray
            pose.pose.position.y = markerArray.markers[index].pose.position.y
            pose.pose.orientation.w = 1
            goal_pub.publish(pose)#Publish to move base

            index += 1
        elif index == count:#Execute to the last point
            add_more_point = 1
    else:
    # status value and its meaning
    # uint8 PENDING         = 0   # The goal has yet to be processed by the action server
    # uint8 ACTIVE          = 1   # The goal is currently being processed by the action server
    # uint8 PREEMPTED       = 2   # The goal received a cancel request after it started executing
    #                             #   and has since completed its execution (Terminal State)
    # uint8 SUCCEEDED       = 3   # The goal was achieved successfully by the action server (Terminal State)
    # uint8 ABORTED         = 4   # The goal was aborted during execution by the action server due
    #                             #    to some failure (Terminal State)
    # uint8 REJECTED        = 5   # The goal was rejected by the action server without being processed,
    #                             #    because the goal was unattainable or invalid (Terminal State)
    # uint8 PREEMPTING      = 6   # The goal received a cancel request after it started executing
    #                             #    and has not yet completed execution
    # uint8 RECALLING       = 7   # The goal received a cancel request before it started executing,
    #                             #    but the action server has not yet confirmed that the goal is canceled
    # uint8 RECALLED        = 8   # The goal received a cancel request before it started executing
    #                             #    and was successfully cancelled (Terminal State)
    # uint8 LOST            = 9   # An action client can determine that a goal is LOST. This should not be
    #                             #    sent over the wire by an action server
        #If it is a failure
        print 'Goal cannot reached has some error :',msg.status.status," try again!!!!"
        if try_again == 1:#Send the target point to move base and ask it to try again
            pose = PoseStamped()
            pose.header.frame_id = "map"
            pose.header.stamp = rospy.Time.now()
            pose.pose.position.x = markerArray.markers[index-1].pose.position.x
            pose.pose.position.y = markerArray.markers[index-1].pose.position.y
            pose.pose.orientation.w = 1
            goal_pub.publish(pose)
            try_again = 0
        else:#If you have tried again but still can't arrive, skip it and execute the next point
            if index < len(markerArray.markers):
                pose = PoseStamped()
                pose.header.frame_id = "map"
                pose.header.stamp = rospy.Time.now()
                pose.pose.position.x = markerArray.markers[index].pose.position.x
                pose.pose.position.y = markerArray.markers[index].pose.position.y
                pose.pose.orientation.w = 1
                goal_pub.publish(pose)
                index += 1


def click_callback(msg):#rviz given a multi-target point, it will trigger
    global markerArray,count
    global goal_pub,index
    global add_more_point

    marker = Marker()
    marker.header.frame_id = "map"
    marker.header.stamp = rospy.Time.now()
    # marker.type = marker.TEXT_VIEW_FACING
    marker.type = marker.CYLINDER
    marker.action = marker.ADD
    marker.scale.x = 0.2
    marker.scale.y = 0.2
    marker.scale.z = 0.5
    marker.color.a = 1.0
    marker.color.r = 0.0
    marker.color.g = 1.0
    marker.color.b = 0.0
    marker.pose.orientation.x = 0.0
    marker.pose.orientation.y = 0.0
    marker.pose.orientation.z = 0.0
    marker.pose.orientation.w = 1.0
    marker.pose.position.x = msg.pose.position.x#Read out the location information in msg and send it to the marker message
    marker.pose.position.y = msg.pose.position.y
    marker.pose.position.z = msg.pose.position.z

    markerArray.markers.append(marker)

    # Renumber the marker IDs
    id = 0
    for m in markerArray.markers:
       m.id = id
       id += 1

    # Publish the MarkerArray
    mark_pub.publish(markerArray)#release

    #first goal: when publishing multi-target points for the first time, directly publish the topic
    if count==0:#When there is no target point
        pose = PoseStamped()#Read the topic to the pose message
        pose.header.frame_id = "map"
        pose.header.stamp = rospy.Time.now()
        pose.pose.position.x = msg.pose.position.x
        pose.pose.position.y = msg.pose.position.y
        pose.pose.position.z = msg.pose.position.z
        pose.pose.orientation.x = msg.pose.orientation.x
        pose.pose.orientation.y = msg.pose.orientation.y
        pose.pose.orientation.z = msg.pose.orientation.z
        pose.pose.orientation.w = msg.pose.orientation.w
        goal_pub.publish(pose)#Through goal_pub Publishing
        #goal_pub publishes the goal topics required by move base. Contains the position and angle information of the target point
        index += 1

        #add_ more_ When point = 1, issue a status=3 in ros and trigger status_callback, so that the new target point can be released again
        #To solve the problem of publishing new navigation points after all navigation points are completed
    if add_more_point and count > 0:
        add_more_point = 0
        move =MoveBaseActionResult()
        move.status.status = 3
        move.header.stamp = rospy.Time.now()
        goal_status_pub.publish(move)
    quaternion = (msg.pose.orientation.x, msg.pose.orientation.y, msg.pose.orientation.z, msg.pose.orientation.w)
    theta = tf.transformations.euler_from_quaternion( quaternion)[2]
    count += 1#count plus 1 for each click
    # print 'add a path goal point %f %f %f'%(msg.pose.position.x,msg.pose.position.y,theta*180.0/3.14)


markerArray = MarkerArray()#Define a variable

count = 0       #total goal num counts the number of published target points
index = 0       #current goal point index counts which target point is currently executed
add_more_point = 0 # after all goal arrive, if add some more goal flag bit
try_again = 1  # try the fail goal once again

rospy.init_node('multi_goal_point_demo') #Create node

mark_pub = rospy.Publisher('/path_point_array', MarkerArray,queue_size=100)#Publisher publishes MarkARRAY type data
click_goal_sub = rospy.Subscriber('/goal',PoseStamped,click_callback)#The subscriber subscribes to the goal topic, publishes the topic published by multi-target points in rviz, and enters the click every time it receives the goal_ callback
goal_pub = rospy.Publisher('/move_base_simple/goal',PoseStamped,queue_size=1)#Publisher publish / move_base_simple/goal topic.
#Trigger move_base navigation topic
goal_status_sub = rospy.Subscriber('/move_base/result',MoveBaseActionResult,status_callback)#Subscribe to the results of movebase navigation.
#after all goal arrive, if add some more goal
#we deleberate pub a topic to trig the goal sent
goal_status_pub = rospy.Publisher('/move_base/result',MoveBaseActionResult,queue_size=1)
rospy.spin()#Publish / move in node_ base/result
#

Multipoint automatic cruise

Simulation: roslaunch robot_navigation robot_navigation.launch simulation:=true
 Running on a solid robot does not require input simulation:=true parameter

rviz: roslaunch robot_navigation navigation_rviz.launch

pc Open terminal: rostopic echo /move_base_simple/goal
(subscribe/move_base_simple/goal topic of conversation)

By "2" D Nav Goal"Button to set the cruise point and record the output content.
pose:
	position:
	    x:
	    y:
	    z
	orizntation:
	    x
	    v
	    z:
	
open robot_navigation Under function pack way_point.launch Document modification goallistx,y,z

Number of cruises:
roslaunch robot_navigation way_point.launch loopTimes loopTimes:=2
loopTimes The parameter is the number of cruises. 2. The robot stops after cruising back and forth twice at the cruising point; 0, cruise all the time.

Each time a cruise point is reached during cruise, the target of the next cruise point is output ID,When the number of cruises reaches, it will be output Loop: 2 Times Finshed Information.

way_point.launch

<launch>
    <!-- For Simulation -->
    <arg name="sim_mode" default="false" />
    <param name="/use_sim_time" value="$(arg sim_mode)"/>
    <arg name="loopTimes"       default="0" />
    <!-- move base -->
    <!--launch File startup way_point.py node-->
    <node pkg="robot_navigation" type="way_point.py" respawn="false" name="way_point" output="screen">
        <!-- params for move_base Write a preset location-->
        <param name="goalListX" value="[2.0, 4.0, 3.0]" />
        <param name="goalListY" value="[3.0, 2.0, 2.0]" />
        <param name="goalListZ" value="[0.0, 0.0, 0.0]" />
        <param name="loopTimes" value="$(arg loopTimes)"/>
        <param name="map_frame" value="map" />
    </node>
    

</launch>

multi_goal_point.py

Core idea:

First preset a series of path points, and then publish them in turn. Only after the previous point arrives, can the next point be issued.

#!/usr/bin/python

import rospy
import string
import math
import time
import sys

from std_msgs.msg import String
from move_base_msgs.msg import MoveBaseActionResult
from actionlib_msgs.msg import GoalStatusArray
from geometry_msgs.msg import PoseStamped
import tf
class MultiGoals:
    def __init__(self, goalListX, goalListY, goalListZ,loopTimes, map_frame):
        #Subscriber, subscribe to move_base/result, move base, the navigation result topic is published. Each time the navigation result topic is received, it will enter the statusCB callback
        self.sub = rospy.Subscriber('move_base/result', MoveBaseActionResult, self.statusCB, queue_size=10)
        #Publisher, publish move_base_simple/goal,move_ The target topics that base really receives
        self.pub = rospy.Publisher('move_base_simple/goal', PoseStamped, queue_size=10)   
        # params & variables
        self.goalListX = goalListX
        self.goalListY = goalListY
        self.goalListZ = goalListZ
        self.loopTimes = loopTimes
        self.loop = 1
        self.wayPointFinished = False 
        self.goalId = 0#The serial number of the current target point of execution
        self.goalMsg = PoseStamped()
        self.goalMsg.header.frame_id = map_frame
        self.goalMsg.pose.orientation.z = 0.0
        self.goalMsg.pose.orientation.w = 1.0
        # Publish the first goal
        time.sleep(1)
        #Pay xyz in goalList to goalMsg message respectively
        self.goalMsg.header.stamp = rospy.Time.now()
        self.goalMsg.pose.position.x = self.goalListX[self.goalId]
        self.goalMsg.pose.position.y = self.goalListY[self.goalId]
        self.goalMsg.pose.orientation.x = 0.0
        self.goalMsg.pose.orientation.y = 0.0
        if abs(self.goalListZ[self.goalId]) > 1.0:
            self.goalMsg.pose.orientation.z = 0.0
            self.goalMsg.pose.orientation.w = 1.0
        else:
            w = math.sqrt(1 - (self.goalListZ[self.goalId]) ** 2)
            self.goalMsg.pose.orientation.z = self.goalListZ[self.goalId]
            self.goalMsg.pose.orientation.w = w
        self.pub.publish(self.goalMsg) #After the assignment of goalMsg, it is published to move ase through the publisher
        rospy.loginfo("Current Goal ID is: %d", self.goalId)  #Output log
        self.goalId = self.goalId + 1 #When the target point is sent out, it will wait for the statusCB callback

        #When the robot reaches a target point, it enters the statusCB function
    def statusCB(self, data):
        if self.loopTimes and (self.loop > self.loopTimes):
            rospy.loginfo("Loop: %d Times Finshed", self.loopTimes)
            self.wayPointFinished = True
        if data.status.status == 3 and (not self.wayPointFinished): # reached, and the path cruise is not over
            self.goalMsg.header.stamp = rospy.Time.now()                
            self.goalMsg.pose.position.x = self.goalListX[self.goalId]
            self.goalMsg.pose.position.y = self.goalListY[self.goalId]
            if abs(self.goalListZ[self.goalId]) > 1.0:
                self.goalMsg.pose.orientation.z = 0.0
                self.goalMsg.pose.orientation.w = 1.0
            else:
                w = math.sqrt(1 - (self.goalListZ[self.goalId]) ** 2)
                self.goalMsg.pose.orientation.z = self.goalListZ[self.goalId]
                self.goalMsg.pose.orientation.w = w
            self.pub.publish(self.goalMsg) #Read the next point and publish it
            rospy.loginfo("Current Goal ID is: %d", self.goalId)              
            if self.goalId < (len(self.goalListX)-1):
                self.goalId = self.goalId + 1
            else:
                self.goalId = 0
                self.loop += 1


if __name__ == "__main__":
    try:    
        # ROS Init    
        rospy.init_node('way_point', anonymous=True)

        # Get params get the goalListXYZ passed in from the launch file
        goalListX = rospy.get_param('~goalListX', '[2.0, 2.0]')
        goalListY = rospy.get_param('~goalListY', '[2.0, 4.0]')
        goalListZ = rospy.get_param('~goalListZ', '[0.0, 0.0]')
        map_frame = rospy.get_param('~map_frame', 'map' )
        loopTimes = int(rospy.get_param('~loopTimes', '0')) 

        goalListX = goalListX.replace("[","").replace("]","")
        goalListY = goalListY.replace("[","").replace("]","")
        goalListZ = goalListZ.replace("[","").replace("]","")
        goalListX = [float(x) for x in goalListX.split(",")]
        goalListY = [float(y) for y in goalListY.split(",")]
        goalListZ = [float(z) for z in goalListZ.split(",")]#Processing into an array
        if len(goalListX) == len(goalListY) == len(goalListZ) & len(goalListY) >=2:  #Judge the length of three arrays, etc
            # Constract MultiGoals Obj 
            rospy.loginfo("Multi Goals Executing...")
            mg = MultiGoals(goalListX, goalListY, goalListZ, loopTimes, map_frame)#Cycle times map base coordinates
            rospy.spin()
        else:
            rospy.errinfo("Lengths of goal lists are not the same")
    except KeyboardInterrupt:
        print("shutting down")

Topics: ROS slam Autonomous vehicles