ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
43

Multiple robots simulation and navigation

asked 2012-08-14 22:20:00 -0600

Jakub gravatar image

How to launch multiple robots in gazebo simulator and how to setup navigation stacks for such a simulation?

There were already some questions and answers for the subject, like: here, and here, and here. This is my question and answer to summarize the discussion in one place.

edit retag flag offensive close merge delete

Comments

1

Hi @Jacub, thanks for this extraordinary contributions on forum. There is a similar problem (extended version) which can probably be solved only by you (given your expertise).( http://robotics.stackexchange.com/que... )

PrasadNR gravatar image PrasadNR  ( 2016-11-02 14:06:16 -0600 )edit
1

Hi @Jacub,thank you for give us a so wonderful tutorial about Multiple robots simulation and navigation, but I still have some trouble about this. I could do single-robot navigation in gazebo, but when i add the the namespace in the launch file,there may be a error in the amcl.

  • List item
huang_y gravatar image huang_y  ( 2017-05-16 22:33:38 -0600 )edit
1

@PrasadNR and @huang_y you should make your own questions because, although related, they appear to be different than this question.

jayess gravatar image jayess  ( 2017-07-26 14:32:51 -0600 )edit
1

I was able to run multiple TB3 simulation and navigation on ROS Melodic. I noticed that the robots are not aware of each other and they collide with each other. What is needed to make the robots avoid collisions with each other?

Anas Kanhouch gravatar image Anas Kanhouch  ( 2021-04-06 09:03:23 -0600 )edit
1

@Anas Kanhouch please don't use an answer to ask a question as this isn't a forum. Please create a new question and reference this one instead so that you get more visibility and have a better chance of getting your question answered (this question is almost 9 years old at this point).

jayess gravatar image jayess  ( 2021-04-06 15:56:24 -0600 )edit

sure noted @jayess

Anas Kanhouch gravatar image Anas Kanhouch  ( 2022-02-03 01:10:00 -0600 )edit

Check out this article for multi robot in ROS2 with nav2 stack: https://medium.com/@arshad.mehmood/a-...

Arshad gravatar image Arshad  ( 2023-05-21 10:00:48 -0600 )edit

5 Answers

Sort by ยป oldest newest most voted
62

answered 2012-08-14 22:33:45 -0600

Jakub gravatar image

updated 2012-08-15 00:53:40 -0600

The answer is based on the turtlebot robot, but of course it can be used with any robot(s).

For multiple robots the key point is to manage the namespaces and tf_prefixes. Although usually we will set them to the same value for each robot in this example I will you different for purpose.

In setting up the navigation stack(s) each robot must operate in it's own namespace, but they do have to share the map (and usually robot_description). So the effect we want to achieve is:

                                  /map
       /robot1/robot_state_publisher    /robot2/robot_state_publisher
       /robot1/robot_pose_ekf           /robot2/robot_pose_ekf
       /robot1/amcl                     /robot2/amcl
       /robot1/move_base                /robot2/move_base

Simulation

First of all we have to launch the simulation, in our case gazebo. To make things more readable I split launch files in few files.

Launch file for one robot. We name it one_robot.launch:

<launch>
    <arg name="robot_name"/>
    <arg name="init_pose"/>

    <node name="spawn_minibot_model" pkg="gazebo" type="spawn_model"
     args="$(arg init_pose) -urdf -param /robot_description -model $(arg robot_name)"
     respawn="false" output="screen" />

    <node pkg="robot_state_publisher" type="state_publisher" 
          name="robot_state_publisher" output="screen"/>

    <!-- The odometry estimator, throttling, fake laser etc. go here -->
    <!-- All the stuff as from usual robot launch file -->
</launch>

Two things to mention for above launch file:

  • create two arguments to pass for robot initialization: name and position
  • notice that -param /robot_description is with the slash i.e. fully-qualified, as it will be shared.

Having the robot declaration we can now play with the namespaces. Your main launch file for multiple robots should look like (robots.launch):

<launch>
  <!-- No namespace here as we will share this description. 
       Access with slash at the beginning -->
  <param name="robot_description"
    command="$(find xacro)/xacro.py $(find turtlebot_description)/urdf/turtlebot.urdf.xacro" />

  <!-- BEGIN ROBOT 1-->
  <group ns="robot1">
    <param name="tf_prefix" value="robot1_tf" />
    <include file="$(find your_pkg)/launch/one_robot.launch" >
      <arg name="init_pose" value="-x 1 -y 1 -z 0" />
      <arg name="robot_name"  value="Robot1" />
    </include>
  </group>

  <!-- BEGIN ROBOT 2-->
  <group ns="robot2">
    <param name="tf_prefix" value="robot2_tf" />
    <include file="$(find your_pkg)/launch/one_robot.launch" >
      <arg name="init_pose" value="-x -1 -y 1 -z 0" />
      <arg name="robot_name"  value="Robot2" />
    </include>
  </group>
</launch>

Last thing of course is to include it in your simulation launch file:

<launch>
  <param name="/use_sim_time" value="true" />

  <!-- start world -->
  <node name="gazebo" pkg="gazebo" type="gazebo" 
   args="$(find your_pkg)/worlds/your.world" respawn="false" output="screen" />

  <!-- start gui -->
  <node name="gazebo_gui" pkg="gazebo" type="gui" respawn="false" output="screen"/>

  <!-- include our robots -->
  <include file="$(find your_pkg)/launch/robots.launch"/>
</launch>

Navigation

For setting up the navigation stack we follow the tutorial RobotSetup, but we have to add the namespace tricks for it.

We use the same approach of splitting files. First the move_base.launch for one robot, as from tutorial:

<launch>    
  <!--- Run AMCL -->
  <include file="$(find amcl)/examples/amcl_diff.launch" />

  <!-- Define your move_base node -->
  <node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen">
    <rosparam file="$(find your_pkg)/costmap_common_params.yaml" command="load" ns="global_costmap"/>
    <rosparam file="$(find your_pkg)/costmap_common_params.yaml" command ...
(more)
edit flag offensive delete link more

Comments

1

Wonderful! exactly what I was looking for my simulation, but if I want to move the different joints of my robots, which topic should I use? because I run "rostopic echo /robot1/joint_states" I got "WARNING: no messages received and simulated time is active.Is /clock being published?" Thanks a lot

Brioche gravatar image Brioche  ( 2012-08-20 22:50:49 -0600 )edit
1

This tutorial is base on TurtleBot, for which joint_state_publisher is included in gazebo_ros_create pluging (see the Hacking section). For your robot of course you have add joint_state_publisher in one_robot.launch (definition of your robot).

Jakub gravatar image Jakub  ( 2012-08-22 18:32:55 -0600 )edit
1

Thank you, @Jakub, for sharing this! :)

harsha gravatar image harsha  ( 2013-01-10 05:25:25 -0600 )edit
1

can this b useful in global mapping and global localization for multipl robots?

Xittx gravatar image Xittx  ( 2013-02-22 05:32:06 -0600 )edit
1

Very Cool, but I'm trying with ROS Hydro and I cannot achive to have separete nodes for camera plugins. What should I do? Thks

Joao Luis gravatar image Joao Luis  ( 2014-08-12 13:26:46 -0600 )edit
1

Now if only there was something like this for use in a real environment instead of Gazebo.

AmateurHour gravatar image AmateurHour  ( 2018-07-17 15:45:33 -0600 )edit
1

Thanks for your explanation. I'm going to refer to it for my project of using multiple robot arms with MoveIt! (my question on that). Question: what do I do after hacking the cpp file? Rebuild?

raequin gravatar image raequin  ( 2018-07-27 09:21:54 -0600 )edit
2

Hi, thanks for this solution but it's not working with ROS noetic, can someone post an updated answer?

shubham-shahh gravatar image shubham-shahh  ( 2021-08-12 06:17:30 -0600 )edit
2

answered 2015-04-18 15:19:41 -0600

YunfeiLu gravatar image

Hi, I met a problem when I test your launch file,

  • IOError: [Errno 2] No such file or directory: '/opt/ros/indigo/share/turtlebot_description/urdf/turtlebot.urdf.xacro' while processing /home/yunfeilu330/catkin_ws/src/beginner_tutorials/launch/robots.launch: Invalid tag: Cannot load command parameter [robot_description]: command [/opt/ros/indigo/share/xacro/xacro.py /opt/ros/indigo/share/turtlebot_description/urdf/turtlebot.urdf.xacro] returned with code [1].

It seems that I don't have turtlebot.urdf.xacro, then what should I use to instead?

edit flag offensive delete link more

Comments

I got the same error, how did u fix it ? thank you

Ramez gravatar image Ramez  ( 2015-06-24 10:20:14 -0600 )edit

You can use a command like this to load the urdf file <arg name="urdf_file" default="$(find xacro)/xacro.py '$(find turtlebot_description)/robots/$(arg base)_$(arg stacks)_$(arg 3d_sensor).urdf.xacro'"/>

base, stacks and 3d_sensor are arguments that you can pass to it.

sina.cb gravatar image sina.cb  ( 2015-07-08 13:16:08 -0600 )edit

My arguments look like this <arg name="base" value="$(optenv TURTLEBOT_BASE kobuki)"/> <arg name="stacks" value="$(optenv TURTLEBOT_STACKS hexagons)"/> <arg name="3d_sensor" value="$(optenv TURTLEBOT_3D_SENSOR kinect)"/>

sina.cb gravatar image sina.cb  ( 2015-07-08 13:16:39 -0600 )edit
1

answered 2012-08-15 02:03:56 -0600

maurizio gravatar image

updated 2012-08-15 07:29:40 -0600

WRT your notes, I got stuck since I didn't get neither /Robot1/joint_states nor /Robot2/joint_states, I had to add the option -unpause like the following:

 <node name="spawn_minibot_model" pkg="gazebo" type="spawn_model"
     args="$(arg init_pose) -urdf -unpause -param /robot_description -model $(arg robot_name)"
     respawn="false" output="screen" />

I am almost done, but I have a problem with the map, following your notes I have. I guess there is still a problem with namespace, in particular It asks for /base/link but it shouldn't,

[ WARN] [1345042406.057976802, 32.122000000]: You have set map parameters, but also requested to use the static map. Your parameters will be overwritten by those given by the map server
[ INFO] [1345042406.058039834, 32.122000000]: Received a 640 X 544 map at 0.050000 m/pix

[ WARN] [1345042411.112545628, 37.177000000]: Waiting on transform from /base_link to /map to become available before running costmap, tf error: 
[ WARN] [1345042416.151239313, 42.215000000]: Waiting on transform from /base_link to /map to become available before running costmap, tf error: 
[ WARN] [1345042421.160855380, 47.224000000]: Waiting on transform from /base_link to /map to become available before running costmap, tf error: 
[ WARN] [1345042426.241246711, 52.305000000]: Waiting on transform from /base_link to /map to become available before running costmap, tf error:

THE AMCL FILE IS LIKE THIS (I have tried both setting use_map_topic either to true or false but doesn't work. If true, I have also tried to add the line <remap from="map" to="/map"/> but nothing):

<launch>

  <arg name="use_map_topic" default="true"/>
  <arg name="scan_topic" default="narrow_scan" />

  <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="60"/>
    <param name="laser_max_range" value="12.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"/>
    <!-- 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.25"/>
    <param name="update_min_a" value="0.2"/>
    <param name="odom_frame_id" value="odom"/>
    <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"/>
    <remap from="scan" to="$(arg scan_topic)"/>    
  </node>

</launch>

THIS IS POSE_ROBOT_EKF

 <node  pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf" >
    <param name="freq" value="30.0"/>
    <param name="sensor_timeout" value="1.0"/>
    <param name="publish_tf" value="true"/>
    <param name ...
(more)
edit flag offensive delete link more

Comments

1

If you use robot_pose_efk in your turtlebot then you should connect to odom_combined. Try to add: <param name="base_frame_id" value="base_footprint"/> <param name="odom_frame_id" value="odom_combined"/> <param name="global_frame_id" value="/map" />

Jakub gravatar image Jakub  ( 2012-08-15 05:28:03 -0600 )edit
1

do I have to set it in the robot_pose_ekf part or wherever in the file? I tried in the robot_pose_ekf, in the amcl file but nothing works... I am posting the portion of robot_pose_ekf in my answer

maurizio gravatar image maurizio  ( 2012-08-15 05:30:17 -0600 )edit
1

No. You should add it to your amcl node. Instead of previous odom_frame_id=odom

Jakub gravatar image Jakub  ( 2012-08-15 05:31:25 -0600 )edit
2

Done: it says "Waiting on transform from /base_link to /map to become available before running costmap, tf err"

maurizio gravatar image maurizio  ( 2012-08-15 05:39:39 -0600 )edit
1

Once again in amcl.launch try with adding those two remappings: <remap from="static_map" to="/static_map" /> <remap from="map" to="/map" />

Jakub gravatar image Jakub  ( 2012-08-15 05:43:52 -0600 )edit
1

It is always asking for: "Waiting on transform from /base_link to /map to become available". I don't understand why it says /base_link... why?

maurizio gravatar image maurizio  ( 2012-08-15 05:45:34 -0600 )edit
1

Yes, that's the point. Most probably in your global or local costmap parameters you have /base_link instead of simply base_link without the slash. So global should have: /map and base_link, and local should have odom_combined and base_link.

Jakub gravatar image Jakub  ( 2012-08-15 05:50:33 -0600 )edit
1

do I have to ckeck the code of the nodes? In particular do you know the files?

maurizio gravatar image maurizio  ( 2012-08-15 05:54:30 -0600 )edit

I copy the local_map.yaml file above, as far as I understand I should remove '/' from baselink right?

maurizio gravatar image maurizio  ( 2012-08-15 05:58:59 -0600 )edit
1

answered 2015-09-16 23:28:41 -0600

Usman Arif gravatar image

My navigation part asks for robot1/odom to map transform. I provide it through

<node pkg="tf" type="static_transform_publisher" name="odom_map_broadcaster" args="0 0 0 0 0 0 robot1/odom map 100"/>

but when i try and do it for my 2nd robot i.e. robot2/odom to map one of the two transforms stay and the other one crashes. So I only get either robot1/odom to map or robot2/odom to map transform at a time, and depending upon that only one navigation works the other one doesn't.

A similar problem is discussed in the answers but those solutions aren't working for me. Need help, stuck for days :)

edit flag offensive delete link more

Comments

5

you need to do the opposite transform. map to robot1/odom and map to robot2/odom. you can have only one parent but many children

MasterTsoutsos gravatar image MasterTsoutsos  ( 2019-02-09 08:13:21 -0600 )edit

I also ran into a problem related to TF. I am using gmapping SLAM instead of amcl; gmapping slam creates the map and also localizes. I have the following error:

Timed out waiting for transform from base_footprint to map to become available before running costmap, tf error: canTransform: source_frame base_footprint does not exist.. canTransform returned after 0.1 timeout was 0.1.

Here is a question I posted with more details. Please help.

hunterlineage1 gravatar image hunterlineage1  ( 2023-02-21 00:56:02 -0600 )edit
0

answered 2021-10-26 05:31:26 -0600

Souvik Basak gravatar image

I am implementing this technique in ridgeback robots by Clear path robotics. It is launching the 2 robots in gazebo world but I am cannot control them inidividually. Publishing in one cmd_vel moves both the robots. I am aslo getting a error that control manager service already exist. I tried giving them different namespaces, But still it is not working. Please help, I am attaching my launch files one_robot.launch

<launch> <arg name="x" default="0"/> <arg name="y" default="0"/> <arg name="z" default="1"/> <arg name="yaw" default="0"/> <arg name="robot_name" default="ridgeback"/>

<node name="urdf_spawner" pkg="gazebo_ros" type="spawn_model" args="-urdf -model $(arg robot_name) -param /robot_description -x $(arg x) -y $(arg y) -z $(arg z) -Y $(arg yaw)"/> respawn="false" output="screen" />

<node pkg="robot_state_publisher" type="state_publisher" 
      name="robot_state_publisher" output="screen"/>

<!-- The odometry estimator, throttling, fake laser etc. go here -->
<!-- All the stuff as from usual robot launch file -->

  <rosparam param="/gazebo_ros_control/pid_gains">
    front_left_wheel:
      p: 1
      i: 0.1
      d: 0
    front_right_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_left_wheel:
      p: 1
      i: 0.1
      d: 0
    rear_right_wheel:
      p: 1
      i: 0.1
      d: 0
  </rosparam>

<!-- control -->
   <rosparam command="load" file="$(find ridgeback_control)/config/control.yaml" ns="/$(arg robot_name)"/>

  <group if="$(optenv RIDGEBACK_CONTROL_EXTRAS 0)" >
    <rosparam command="load" file="$(env RIDGEBACK_CONTROL_EXTRAS_PATH)" />
  </group>

  <node name="controller_spawner_$(arg robot_name)"  pkg="controller_manager" type="spawner"
        args=" --namespace=/$(arg robot_name) ridgeback_joint_publisher ridgeback_velocity_controller --shutdown-timeout 50 " />

  <node pkg="robot_localization" type="ekf_localization_node" name="ekf_localization" />

  <node pkg="topic_tools" type="relay" name="cmd_vel_relay"
        args="/cmd_vel ridgeback_velocity_controller/cmd_vel" />

  <arg name="joy_dev" default="/dev/input/js0" />
  <arg name="joystick" default="true" />

  <group ns="bluetooth_teleop" if="$(arg joystick)">

<group unless="$(optenv RIDGEBACK_PS3 0)" >
  <rosparam command="load" file="$(find ridgeback_control)/config/teleop_ps4.yaml" />
</group>

<group if="$(optenv RIDGEBACK_PS3 0)" >
  <rosparam command="load" file="$(find ridgeback_control)/config/teleop_ps3.yaml" />
  <param name="joy_node/dev" value="$(arg joy_dev)" />
</group>

<node pkg="joy" type="joy_node" name="joy_node" />

<node pkg="teleop_twist_joy" type="teleop_node" name="teleop_twist_joy">
  <remap from="cmd_vel" to="/cmd_vel" />
</node>

</group>

<arg name="config" default="linear"/>

<node pkg="interactive_marker_twist_server" type="marker_server" name="twist_marker_server"> <remap from="twist_marker_server/cmd_vel" to="/cmd_vel"/> <rosparam command="load" file="$(find interactive_marker_twist_server)/config/$(arg config).yaml"/> </node> </launch>

robots.launch

<launch>
    <arg name="debug" default="false"/>
    <arg name="gui" default="true"/>
    <arg name="pause" default="false"/>
    <arg name="world" value="$(find hybrid_astar)/world/hospital_04.world"/>

    <include file="$(find gazebo_ros)/launch/empty_world.launch">
        <arg name="world_name" default="$(arg world)"/>
        <arg name="debug" value="$(arg debug)"/>
        <arg name="gui" value="$(arg gui)"/>
        <arg name="paused" value="$(arg pause)"/>
        <arg name="use_sim_time" value="true"/>
    </include> 

  <!-- <param name="/use_sim_time" value="true" />


  <node name="gazebo" pkg="gazebo_ros" type="gazebo" 
   args="$(find hybrid_astar)/world/empty_wall.world" respawn="false" output="screen" /> ...
(more)
edit flag offensive delete link more

Comments

Please don't use an answer to ask a question. This isn't a forum. Please create a new question and reference this one instead. This will also give your question more visibility

jayess gravatar image jayess  ( 2021-10-26 18:40:35 -0600 )edit

Question Tools

29 followers

Stats

Asked: 2012-08-14 22:20:00 -0600

Seen: 51,871 times

Last updated: May 21 '23