整个流程是:
1 先用单个机器人完成环境建图
2 配置两个机器人的主从机
3 配置两个机器人的turtlebot_bringup、amcl、key_teleop、move_base
需要的前置知识:ROS的命名空间,TFtree
先列一下参考文章:
古月居博客的多机器人导航
ROS配置多机器人导航
多机器人导航与编队(一)
多机器人导航与编队(二)
需要修改的文件:
turtlebot_bringup minimal.launch robot.launch.xml
turtlebot_teleop keboard_teleop.launch
turtlebot_navigation amcl.launch, movebase.launch,hokuyo_laser.launch
kobuki_node base.yaml
turtlebot_bringup minimal.launch:需要加入 命名空间 group ns=“robot1”
<launch>
<group ns="robot1">
<arg name="base" default="$(env TURTLEBOT_BASE)" doc="mobile base type [create, roomba]"/>
<arg name="battery" default="$(env TURTLEBOT_BATTERY)" doc="kernel provided locatio for battery info, use /proc/acpi/battery/BAT0 in 2.6 or earlier kernels." />
<arg name="stacks" default="$(env TURTLEBOT_STACKS)" doc="stack type displayed in visualisation/simulation [circles, hexagons]"/>
<arg name="3d_sensor" default="$(env TURTLEBOT_3D_SENSOR)" doc="3d sensor types [kinect, asux_xtion_pro]"/>
<arg name="simulation" default="$(env TURTLEBOT_SIMULATION)" doc="set flags to indicate this turtle is run in simulation mode."/>
<arg name="serialport" default="$(env TURTLEBOT_SERIAL_PORT)" doc="used by create to configure the port it is connected on [/dev/ttyUSB0, /dev/ttyS0]"/>
<param name="/use_sim_time" value="$(arg simulation)"/>
<include file="$(find turtlebot_bringup)/launch/includes/robot.launch.xml">
<arg name="base" value="$(arg base)" />
<arg name="stacks" value="$(arg stacks)" />
<arg name="3d_sensor" value="$(arg 3d_sensor)" />
include>
<include file="$(find turtlebot_bringup)/launch/includes/mobile_base.launch.xml">
<arg name="base" value="$(arg base)" />
<arg name="serialport" value="$(arg serialport)" />
include>
<include unless="$(eval arg('battery') == 'None')" file="$(find turtlebot_bringup)/launch/includes/netbook.launch.xml">
<arg name="battery" value="$(arg battery)" />
include>
group>
launch>
keboard_teleop.launch 加入group命名空间
<launch>
<group ns="robot1">
<node pkg="turtlebot_teleop" type="turtlebot_teleop_key" name="turtlebot_teleop_keyboard" output="screen">
<param name="scale_linear" value="0.5" type="double"/>
<param name="scale_angular" value="1.5" type="double"/>
<remap from="turtlebot_teleop_keyboard/cmd_vel" to="cmd_vel_mux/input/teleop"/>
node>
group>
launch>
robot.launch.xml:添加到
robot_state_publisher
下
作用是给tf添加前缀
<launch>
<arg name="base"/>
<arg name="stacks"/>
<arg name="3d_sensor"/>
<include file="$(find turtlebot_bringup)/launch/includes/description.launch.xml">
<arg name="base" value="$(arg base)" />
<arg name="stacks" value="$(arg stacks)" />
<arg name="3d_sensor" value="$(arg 3d_sensor)" />
include>
<param name="robot/name" value="$(optenv ROBOT turtlebot)"/>
<param name="robot/type" value="turtlebot"/>
<node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
<param name="publish_frequency" type="double" value="5.0" />
<param name="tf_prefix" value="robot1" />
node>
<node pkg="diagnostic_aggregator" type="aggregator_node" name="diagnostic_aggregator" >
<rosparam command="load" file="$(find turtlebot_bringup)/param/$(arg base)/diagnostics.yaml" />
node>
launch>
amcl.launch 修改map路径,并发布连接上map
到robot1/odom
的tf,加入group ns
<launch>
<group ns="robot1">
<arg name="map_file" default="/home/gglin/map/map.yaml"/>
<node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" >
<param name="frame_id" value="map" />
node>
<node pkg="tf" type="static_transform_publisher" name="map_to_odom" args="0.0 0.0 0.0 0 0 0.0 map robot1/odom 1000"/>
<arg name="custom_amcl_launch_file" default="$(find multi_robots_navgation)/launch/includes/robot1_amcl.launch.xml"/>
<arg name="initial_pose_x" default="0.0"/>
<arg name="initial_pose_y" default="0.0"/>
<arg name="initial_pose_a" default="0.0"/>
<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>
<include file="$(find multi_robots_navgation)/launch/includes/robot1_move_base.launch.xml">
include>
group>
launch>
其包含的 robot1_amcl.launch.xml 如下 修改odom_frame_id
和odom_frame_id
<launch>
<arg name="use_map_topic" default="false"/>
<arg name="scan_topic" default="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="robot1/odom"/>
<arg name="base_frame_id" default="robot1/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)"/>
<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="60"/>
<param name="laser_max_range" value="26.0"/>
<param name="min_particles" value="500"/>
<param name="max_particles" value="2000"/>
<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"/>
<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_likelihood_max_dist" value="2.0"/>
<param name="update_min_d" value="0.2"/>
<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"/>
<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>
amcl包含的robot1_move_base.launch.xml 如下,修改的地方 odom_frame_id
base_frame_id
<launch>
<include file="$(find multi_robots_navgation)/launch/includes/velocity_smoother.launch.xml"/>
<include file="$(find multi_robots_navgation)/launch/includes/safety_controller.launch.xml"/>
<arg name="odom_frame_id" default="robot1/odom"/>
<arg name="base_frame_id" default="robot1/base_footprint"/>
<arg name="global_frame_id" default="map"/>
<arg name="odom_topic" default="odom" />
<arg name="laser_topic" default="scan" />
<arg name="custom_param_file" default="$(find multi_robots_navgation)/param/dummy.yaml"/>
<node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
<rosparam file="$(find multi_robots_navgation)/param/costmap_common_params.yaml" command="load" ns="global_costmap" />
<rosparam file="$(find multi_robots_navgation)/param/costmap_common_params.yaml" command="load" ns="local_costmap" />
<rosparam file="$(find multi_robots_navgation)/param/local_costmap_params.yaml" command="load" />
<rosparam file="$(find multi_robots_navgation)/param/global_costmap_params.yaml" command="load" />
<rosparam file="$(find multi_robots_navgation)/param/dwa_local_planner_params.yaml" command="load" />
<rosparam file="$(find multi_robots_navgation)/param/move_base_params.yaml" command="load" />
<rosparam file="$(find multi_robots_navgation)/param/global_planner_params.yaml" command="load" />
<rosparam file="$(find multi_robots_navgation)/param/navfn_global_planner_params.yaml" command="load" />
<rosparam file="$(arg custom_param_file)" command="load" />
<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="cmd_vel" to="navigation_velocity_smoother/raw_cmd_vel"/>
<remap from="odom" to="$(arg odom_topic)"/>
<remap from="scan" to="$(arg laser_topic)"/>
node>
launch>
hokuyo_laser.launch 添加group ns 和 发布静态tf
<launch>
<group ns="robot1">
<node name="hokuyo" pkg="hokuyo_node" type="hokuyo_node" respawn="false" output="screen">
<param name="calibrate_time" type="bool" value="false"/>
<param name="port" type="string" value="/dev/hokuyo"/>
<param name="frame_id" type="string" value="robot1/laser"/>
<param name="intensity" type="bool" value="false"/>
node>
<node pkg="tf" type="static_transform_publisher" name="base_to_laser" args="0.0 0.0 0.18 0 0.0 0.0 robot1/base_link robot1/laser 100"/>
group>
launch>
base.yaml: 修改odom_frame
和base_frame
##############################################################################
# Firmware Source
##############################################################################
device_port: /dev/kobuki
# published joint states
wheel_left_joint_name: wheel_left_joint
wheel_right_joint_name: wheel_right_joint
# battery voltage at full charge (100%) (float, default: 16.5)
battery_capacity: 16.5
# battery voltage at first warning (15%) (float, default: 13.5)
battery_low: 14.0
# battery voltage at critical level (5%) (float, default: 13.2)
battery_dangerous: 13.2
# If a new command isn't received within this many seconds, the base is stopped (double, default: 0.6)
cmd_vel_timeout: 0.6
# Causes node to publish TF for odom_frame to base_frame. Disable only if you plan to use robot_pose_ekf
# (see use_imu_heading description) (bool, default: true)
publish_tf: true
# Use imu readings for heading instead of encoders. That's the normal operation mode for Kobuki, as its
# gyro is very reliable. Disable only if you want to fuse encoders and imu readings in a more sophisticated
# way, for example filtering and fussing with robot_pose_ekf (bool, default: true)
use_imu_heading: true
# Name of the odometry TF frame (string, default: odom)
odom_frame: robot1/odom
# Name of the base TF frame (string, default: base_footprint)
base_frame: robot1/base_footprint
正常的tf应该类似这样