Nav2 Navigation Stack - jazzy  jazzy
ROS 2 Navigation Stack
cloned_multi_tb3_simulation_launch.py
1 # Copyright (c) 2023 LG Electronics.
2 # Copyright (c) 2024 Open Navigation LLC
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 
17 import os
18 from pathlib import Path
19 import tempfile
20 
21 from ament_index_python.packages import get_package_share_directory
22 from launch import LaunchDescription
23 from launch.actions import (
24  AppendEnvironmentVariable,
25  DeclareLaunchArgument,
26  ExecuteProcess,
27  GroupAction,
28  IncludeLaunchDescription,
29  LogInfo,
30  OpaqueFunction,
31  RegisterEventHandler,
32 )
33 from launch.conditions import IfCondition
34 from launch.event_handlers import OnShutdown
35 from launch.launch_description_sources import PythonLaunchDescriptionSource
36 from launch.substitutions import LaunchConfiguration, TextSubstitution
37 from nav2_common.launch import ParseMultiRobotPose
38 
39 
40 def generate_launch_description():
41  """
42  Bring up the multi-robots with given launch arguments.
43 
44  Launch arguments consist of robot name(which is namespace) and pose for initialization.
45  Keep general yaml format for pose information.
46  ex) robots:='robot1={x: 1.0, y: 1.0, yaw: 1.5707}; robot2={x: 1.0, y: 1.0, yaw: 1.5707}'
47  ex) robots:='robot3={x: 1.0, y: 1.0, z: 1.0, roll: 0.0, pitch: 1.5707, yaw: 1.5707};
48  robot4={x: 1.0, y: 1.0, z: 1.0, roll: 0.0, pitch: 1.5707, yaw: 1.5707}'
49  """
50  # Get the launch directory
51  bringup_dir = get_package_share_directory('nav2_bringup')
52  launch_dir = os.path.join(bringup_dir, 'launch')
53  sim_dir = get_package_share_directory('nav2_minimal_tb3_sim')
54 
55  # Simulation settings
56  world = LaunchConfiguration('world')
57 
58  # On this example all robots are launched with the same settings
59  map_yaml_file = LaunchConfiguration('map')
60  params_file = LaunchConfiguration('params_file')
61  autostart = LaunchConfiguration('autostart')
62  rviz_config_file = LaunchConfiguration('rviz_config')
63  use_robot_state_pub = LaunchConfiguration('use_robot_state_pub')
64  use_rviz = LaunchConfiguration('use_rviz')
65  log_settings = LaunchConfiguration('log_settings', default='true')
66 
67  # Declare the launch arguments
68  declare_world_cmd = DeclareLaunchArgument(
69  'world',
70  default_value=os.path.join(sim_dir, 'worlds', 'tb3_sandbox.sdf.xacro'),
71  description='Full path to world file to load',
72  )
73 
74  declare_map_yaml_cmd = DeclareLaunchArgument(
75  'map',
76  default_value=os.path.join(bringup_dir, 'maps', 'tb3_sandbox.yaml'),
77  description='Full path to map file to load',
78  )
79 
80  declare_params_file_cmd = DeclareLaunchArgument(
81  'params_file',
82  default_value=os.path.join(
83  bringup_dir, 'params', 'nav2_multirobot_params_all.yaml'
84  ),
85  description='Full path to the ROS2 parameters file to use for all launched nodes',
86  )
87 
88  declare_autostart_cmd = DeclareLaunchArgument(
89  'autostart',
90  default_value='false',
91  description='Automatically startup the stacks',
92  )
93 
94  declare_rviz_config_file_cmd = DeclareLaunchArgument(
95  'rviz_config',
96  default_value=os.path.join(bringup_dir, 'rviz', 'nav2_namespaced_view.rviz'),
97  description='Full path to the RVIZ config file to use.',
98  )
99 
100  declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
101  'use_robot_state_pub',
102  default_value='True',
103  description='Whether to start the robot state publisher',
104  )
105 
106  declare_use_rviz_cmd = DeclareLaunchArgument(
107  'use_rviz', default_value='True', description='Whether to start RVIZ'
108  )
109 
110  # Start Gazebo with plugin providing the robot spawning service
111  world_sdf = tempfile.mktemp(prefix='nav2_', suffix='.sdf')
112  world_sdf_xacro = ExecuteProcess(
113  cmd=['xacro', '-o', world_sdf, ['headless:=', 'False'], world])
114  start_gazebo_cmd = ExecuteProcess(
115  cmd=['gz', 'sim', '-r', '-s', world_sdf],
116  output='screen',
117  )
118 
119  remove_temp_sdf_file = RegisterEventHandler(event_handler=OnShutdown(
120  on_shutdown=[
121  OpaqueFunction(function=lambda _: os.remove(world_sdf))
122  ]))
123 
124  robots_list = ParseMultiRobotPose('robots').value()
125 
126  # Define commands for launching the navigation instances
127  bringup_cmd_group = []
128  for robot_name in robots_list:
129  init_pose = robots_list[robot_name]
130  group = GroupAction(
131  [
132  LogInfo(
133  msg=[
134  'Launching namespace=',
135  robot_name,
136  ' init_pose=',
137  str(init_pose),
138  ]
139  ),
140  IncludeLaunchDescription(
141  PythonLaunchDescriptionSource(
142  os.path.join(launch_dir, 'rviz_launch.py')
143  ),
144  condition=IfCondition(use_rviz),
145  launch_arguments={
146  'namespace': TextSubstitution(text=robot_name),
147  'use_namespace': 'True',
148  'rviz_config': rviz_config_file,
149  }.items(),
150  ),
151  IncludeLaunchDescription(
152  PythonLaunchDescriptionSource(
153  os.path.join(bringup_dir, 'launch', 'tb3_simulation_launch.py')
154  ),
155  launch_arguments={
156  'namespace': robot_name,
157  'use_namespace': 'True',
158  'map': map_yaml_file,
159  'use_sim_time': 'True',
160  'params_file': params_file,
161  'autostart': autostart,
162  'use_rviz': 'False',
163  'use_simulator': 'False',
164  'headless': 'False',
165  'use_robot_state_pub': use_robot_state_pub,
166  'x_pose': TextSubstitution(text=str(init_pose['x'])),
167  'y_pose': TextSubstitution(text=str(init_pose['y'])),
168  'z_pose': TextSubstitution(text=str(init_pose['z'])),
169  'roll': TextSubstitution(text=str(init_pose['roll'])),
170  'pitch': TextSubstitution(text=str(init_pose['pitch'])),
171  'yaw': TextSubstitution(text=str(init_pose['yaw'])),
172  'robot_name': TextSubstitution(text=robot_name),
173  }.items(),
174  ),
175  ]
176  )
177 
178  bringup_cmd_group.append(group)
179 
180  set_env_vars_resources = AppendEnvironmentVariable(
181  'GZ_SIM_RESOURCE_PATH', os.path.join(sim_dir, 'models'))
182  set_env_vars_resources2 = AppendEnvironmentVariable(
183  'GZ_SIM_RESOURCE_PATH',
184  str(Path(os.path.join(sim_dir)).parent.resolve()))
185 
186  # Create the launch description and populate
187  ld = LaunchDescription()
188  ld.add_action(set_env_vars_resources)
189  ld.add_action(set_env_vars_resources2)
190 
191  # Declare the launch options
192  ld.add_action(declare_world_cmd)
193  ld.add_action(declare_map_yaml_cmd)
194  ld.add_action(declare_params_file_cmd)
195  ld.add_action(declare_use_rviz_cmd)
196  ld.add_action(declare_autostart_cmd)
197  ld.add_action(declare_rviz_config_file_cmd)
198  ld.add_action(declare_use_robot_state_pub_cmd)
199 
200  # Add the actions to start gazebo, robots and simulations
201  ld.add_action(world_sdf_xacro)
202  ld.add_action(start_gazebo_cmd)
203  ld.add_action(remove_temp_sdf_file)
204 
205  ld.add_action(LogInfo(msg=['number_of_robots=', str(len(robots_list))]))
206 
207  ld.add_action(
208  LogInfo(condition=IfCondition(log_settings), msg=['map yaml: ', map_yaml_file])
209  )
210  ld.add_action(
211  LogInfo(condition=IfCondition(log_settings), msg=['params yaml: ', params_file])
212  )
213  ld.add_action(
214  LogInfo(
215  condition=IfCondition(log_settings),
216  msg=['rviz config file: ', rviz_config_file],
217  )
218  )
219  ld.add_action(
220  LogInfo(
221  condition=IfCondition(log_settings),
222  msg=['using robot state pub: ', use_robot_state_pub],
223  )
224  )
225  ld.add_action(
226  LogInfo(condition=IfCondition(log_settings), msg=['autostart: ', autostart])
227  )
228 
229  for cmd in bringup_cmd_group:
230  ld.add_action(cmd)
231 
232  return ld