Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
tb4_simulation_launch.py
1 # Copyright (C) 2024 Open Navigation LLC
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """This is all-in-one launch script intended for use by nav2 developers."""
16 
17 import os
18 import tempfile
19 
20 from ament_index_python.packages import get_package_share_directory
21 from launch import LaunchDescription
22 from launch.actions import (AppendEnvironmentVariable, DeclareLaunchArgument, ExecuteProcess,
23  IncludeLaunchDescription, OpaqueFunction, RegisterEventHandler)
24 from launch.conditions import IfCondition
25 from launch.event_handlers import OnShutdown
26 from launch.launch_description_sources import PythonLaunchDescriptionSource
27 from launch.substitutions import Command, LaunchConfiguration, PythonExpression
28 from launch_ros.actions import Node
29 from nav2_common.launch import LaunchConfigAsBool
30 
31 # Define local map types
32 MAP_POSES_DICT = {
33  'depot': {
34  'x': -8.00, 'y': 0.00, 'z': 0.01,
35  'R': 0.00, 'P': 0.00, 'Y': 0.00
36  },
37  'warehouse': {
38  'x': 2.00, 'y': -19.65, 'z': 0.01,
39  'R': 0.00, 'P': 0.00, 'Y': 1.57
40  }
41 }
42 MAP_TYPE = 'depot' # Change this to 'warehouse' for warehouse map
43 
44 
45 def generate_launch_description() -> LaunchDescription:
46  # Get the launch directory
47  bringup_dir = get_package_share_directory('nav2_bringup')
48  launch_dir = os.path.join(bringup_dir, 'launch')
49  # This checks that tb4 exists needed for the URDF / simulation files.
50  # If not using TB4, its safe to remove.
51  sim_dir = get_package_share_directory('nav2_minimal_tb4_sim')
52  desc_dir = get_package_share_directory('nav2_minimal_tb4_description')
53 
54  # Create the launch configuration variables
55  slam = LaunchConfigAsBool('slam')
56  namespace = LaunchConfiguration('namespace')
57  map_yaml_file = LaunchConfiguration('map')
58  keepout_mask_yaml_file = LaunchConfiguration('keepout_mask')
59  speed_mask_yaml_file = LaunchConfiguration('speed_mask')
60  graph_filepath = LaunchConfiguration('graph')
61  use_sim_time = LaunchConfigAsBool('use_sim_time')
62  params_file = LaunchConfiguration('params_file')
63  autostart = LaunchConfigAsBool('autostart')
64  use_composition = LaunchConfigAsBool('use_composition')
65  use_intra_process_comms = LaunchConfigAsBool('use_intra_process_comms')
66  use_respawn = LaunchConfigAsBool('use_respawn')
67  use_keepout_zones = LaunchConfigAsBool('use_keepout_zones')
68  use_speed_zones = LaunchConfigAsBool('use_speed_zones')
69 
70  # Launch configuration variables specific to simulation
71  rviz_config_file = LaunchConfiguration('rviz_config_file')
72  use_simulator = LaunchConfigAsBool('use_simulator')
73  use_robot_state_pub = LaunchConfigAsBool('use_robot_state_pub')
74  use_rviz = LaunchConfigAsBool('use_rviz')
75  headless = LaunchConfigAsBool('headless')
76  world = LaunchConfiguration('world')
77  pose = {
78  'x': LaunchConfiguration('x_pose', default=MAP_POSES_DICT[MAP_TYPE]['x']),
79  'y': LaunchConfiguration('y_pose', default=MAP_POSES_DICT[MAP_TYPE]['y']),
80  'z': LaunchConfiguration('z_pose', default=MAP_POSES_DICT[MAP_TYPE]['z']),
81  'R': LaunchConfiguration('roll', default=MAP_POSES_DICT[MAP_TYPE]['R']),
82  'P': LaunchConfiguration('pitch', default=MAP_POSES_DICT[MAP_TYPE]['P']),
83  'Y': LaunchConfiguration('yaw', default=MAP_POSES_DICT[MAP_TYPE]['Y']),
84  }
85  robot_name = LaunchConfiguration('robot_name')
86  robot_sdf = LaunchConfiguration('robot_sdf')
87 
88  remappings = [('/tf', 'tf'), ('/tf_static', 'tf_static')]
89 
90  # Declare the launch arguments
91  declare_namespace_cmd = DeclareLaunchArgument(
92  'namespace', default_value='', description='Top-level namespace'
93  )
94 
95  declare_slam_cmd = DeclareLaunchArgument(
96  'slam', default_value='False', description='Whether run a SLAM'
97  )
98 
99  declare_map_yaml_cmd = DeclareLaunchArgument(
100  'map',
101  default_value=os.path.join(bringup_dir, 'maps', f'{MAP_TYPE}.yaml'),
102  description='Full path to map file to load',
103  )
104 
105  declare_keepout_mask_yaml_cmd = DeclareLaunchArgument(
106  'keepout_mask',
107  default_value=os.path.join(bringup_dir, 'maps', f'{MAP_TYPE}_keepout.yaml'),
108  description='Full path to keepout mask file to load',
109  )
110 
111  declare_speed_mask_yaml_cmd = DeclareLaunchArgument(
112  'speed_mask',
113  default_value=os.path.join(bringup_dir, 'maps', f'{MAP_TYPE}_speed.yaml'),
114  description='Full path to speed mask file to load',
115  )
116 
117  declare_graph_file_cmd = DeclareLaunchArgument(
118  'graph',
119  default_value=os.path.join(bringup_dir, 'graphs', f'{MAP_TYPE}_graph.geojson'),
120  )
121 
122  declare_use_sim_time_cmd = DeclareLaunchArgument(
123  'use_sim_time',
124  default_value='true',
125  description='Use simulation (Gazebo) clock if true',
126  )
127 
128  declare_params_file_cmd = DeclareLaunchArgument(
129  'params_file',
130  default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
131  description='Full path to the ROS2 parameters file to use for all launched nodes',
132  )
133 
134  declare_autostart_cmd = DeclareLaunchArgument(
135  'autostart',
136  default_value='true',
137  description='Automatically startup the nav2 stack',
138  )
139 
140  declare_use_composition_cmd = DeclareLaunchArgument(
141  'use_composition',
142  default_value='True',
143  description='Whether to use composed bringup',
144  )
145 
146  declare_use_intra_process_comms_cmd = DeclareLaunchArgument(
147  'use_intra_process_comms',
148  default_value='False',
149  description='Whether to use intra process communication',
150  )
151 
152  declare_use_respawn_cmd = DeclareLaunchArgument(
153  'use_respawn',
154  default_value='False',
155  description='Whether to respawn if a node crashes. Applied when composition is disabled.',
156  )
157 
158  declare_use_keepout_zones_cmd = DeclareLaunchArgument(
159  'use_keepout_zones', default_value='True',
160  description='Whether to enable keepout zones or not'
161  )
162 
163  declare_use_speed_zones_cmd = DeclareLaunchArgument(
164  'use_speed_zones', default_value='True',
165  description='Whether to enable speed zones or not'
166  )
167 
168  declare_rviz_config_file_cmd = DeclareLaunchArgument(
169  'rviz_config_file',
170  default_value=os.path.join(bringup_dir, 'rviz', 'nav2_default_view.rviz'),
171  description='Full path to the RVIZ config file to use',
172  )
173 
174  declare_use_simulator_cmd = DeclareLaunchArgument(
175  'use_simulator',
176  default_value='True',
177  description='Whether to start the simulator',
178  )
179 
180  declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
181  'use_robot_state_pub',
182  default_value='True',
183  description='Whether to start the robot state publisher',
184  )
185 
186  declare_use_rviz_cmd = DeclareLaunchArgument(
187  'use_rviz', default_value='True', description='Whether to start RVIZ'
188  )
189 
190  declare_simulator_cmd = DeclareLaunchArgument(
191  'headless', default_value='True', description='Whether to execute gzclient)'
192  )
193 
194  declare_world_cmd = DeclareLaunchArgument(
195  'world',
196  default_value=os.path.join(sim_dir, 'worlds', f'{MAP_TYPE}.sdf'),
197  description='Full path to world model file to load',
198  )
199 
200  declare_robot_name_cmd = DeclareLaunchArgument(
201  'robot_name', default_value='nav2_turtlebot4', description='name of the robot'
202  )
203 
204  declare_robot_sdf_cmd = DeclareLaunchArgument(
205  'robot_sdf',
206  default_value=os.path.join(desc_dir, 'urdf', 'standard', 'turtlebot4.urdf.xacro'),
207  description='Full path to robot sdf file to spawn the robot in gazebo',
208  )
209 
210  start_robot_state_publisher_cmd = Node(
211  condition=IfCondition(use_robot_state_pub),
212  package='robot_state_publisher',
213  executable='robot_state_publisher',
214  name='robot_state_publisher',
215  namespace=namespace,
216  output='screen',
217  parameters=[
218  {'use_sim_time': use_sim_time, 'robot_description': Command(['xacro', ' ', robot_sdf])}
219  ],
220  remappings=remappings,
221  )
222 
223  rviz_cmd = IncludeLaunchDescription(
224  PythonLaunchDescriptionSource(os.path.join(launch_dir, 'rviz_launch.py')),
225  condition=IfCondition(use_rviz),
226  launch_arguments={
227  'namespace': namespace,
228  'use_sim_time': use_sim_time,
229  'rviz_config': rviz_config_file,
230  }.items(),
231  )
232 
233  bringup_cmd = IncludeLaunchDescription(
234  PythonLaunchDescriptionSource(os.path.join(launch_dir, 'bringup_launch.py')),
235  launch_arguments={
236  'namespace': namespace,
237  'slam': slam,
238  'map': map_yaml_file,
239  'keepout_mask': keepout_mask_yaml_file,
240  'speed_mask': speed_mask_yaml_file,
241  'graph': graph_filepath,
242  'use_sim_time': use_sim_time,
243  'params_file': params_file,
244  'autostart': autostart,
245  'use_composition': use_composition,
246  'use_intra_process_comms': use_intra_process_comms,
247  'use_respawn': use_respawn,
248  'use_keepout_zones': use_keepout_zones,
249  'use_speed_zones': use_speed_zones,
250  'container_name': 'nav2_container',
251  }.items(),
252  )
253 
254  # The SDF file for the world is a xacro file because we wanted to
255  # conditionally load the SceneBroadcaster plugin based on whether we're
256  # running in headless mode. But currently, the Gazebo command line doesn't
257  # take SDF strings for worlds, so the output of xacro needs to be saved into
258  # a temporary file and passed to Gazebo.
259  world_sdf = tempfile.mktemp(prefix='nav2_', suffix='.sdf')
260  world_sdf_xacro = ExecuteProcess(
261  cmd=['xacro', '-o', world_sdf, ['headless:=', headless], world])
262  gazebo_server = ExecuteProcess(
263  cmd=['gz', 'sim', '-r', '-s', world_sdf],
264  output='screen',
265  condition=IfCondition(use_simulator)
266  )
267 
268  remove_temp_sdf_file = RegisterEventHandler(event_handler=OnShutdown(
269  on_shutdown=[
270  OpaqueFunction(function=lambda _: os.remove(world_sdf))
271  ]))
272 
273  set_env_vars_resources = AppendEnvironmentVariable(
274  'GZ_SIM_RESOURCE_PATH',
275  os.path.join(sim_dir, 'worlds'))
276  gazebo_client = IncludeLaunchDescription(
277  PythonLaunchDescriptionSource(
278  os.path.join(get_package_share_directory('ros_gz_sim'),
279  'launch',
280  'gz_sim.launch.py')
281  ),
282  condition=IfCondition(PythonExpression(
283  [use_simulator, ' and not ', headless])),
284  launch_arguments={'gz_args': ['-v4 -g ']}.items(),
285  )
286 
287  gz_robot = IncludeLaunchDescription(
288  PythonLaunchDescriptionSource(
289  os.path.join(sim_dir, 'launch', 'spawn_tb4.launch.py')),
290  launch_arguments={'namespace': namespace,
291  'use_simulator': use_simulator,
292  'use_sim_time': use_sim_time,
293  'robot_name': robot_name,
294  'robot_sdf': robot_sdf,
295  'x_pose': pose['x'],
296  'y_pose': pose['y'],
297  'z_pose': pose['z'],
298  'roll': pose['R'],
299  'pitch': pose['P'],
300  'yaw': pose['Y']}.items())
301 
302  # Create the launch description and populate
303  ld = LaunchDescription()
304 
305  # Declare the launch options
306  ld.add_action(declare_namespace_cmd)
307  ld.add_action(declare_slam_cmd)
308  ld.add_action(declare_map_yaml_cmd)
309  ld.add_action(declare_keepout_mask_yaml_cmd)
310  ld.add_action(declare_speed_mask_yaml_cmd)
311  ld.add_action(declare_graph_file_cmd)
312  ld.add_action(declare_use_sim_time_cmd)
313  ld.add_action(declare_params_file_cmd)
314  ld.add_action(declare_autostart_cmd)
315  ld.add_action(declare_use_composition_cmd)
316  ld.add_action(declare_use_intra_process_comms_cmd)
317 
318  ld.add_action(declare_rviz_config_file_cmd)
319  ld.add_action(declare_use_simulator_cmd)
320  ld.add_action(declare_use_robot_state_pub_cmd)
321  ld.add_action(declare_use_rviz_cmd)
322  ld.add_action(declare_simulator_cmd)
323  ld.add_action(declare_world_cmd)
324  ld.add_action(declare_robot_name_cmd)
325  ld.add_action(declare_robot_sdf_cmd)
326  ld.add_action(declare_use_respawn_cmd)
327  ld.add_action(declare_use_keepout_zones_cmd)
328  ld.add_action(declare_use_speed_zones_cmd)
329 
330  ld.add_action(set_env_vars_resources)
331  ld.add_action(world_sdf_xacro)
332  ld.add_action(remove_temp_sdf_file)
333  ld.add_action(gz_robot)
334  ld.add_action(gazebo_server)
335  ld.add_action(gazebo_client)
336 
337  # Add the actions to launch all of the navigation nodes
338  ld.add_action(start_robot_state_publisher_cmd)
339  ld.add_action(rviz_cmd)
340  ld.add_action(bringup_cmd)
341 
342  return ld