Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
localization_launch.py
1 # Copyright (c) 2018 Intel Corporation
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 import os
16 
17 from ament_index_python.packages import get_package_share_directory
18 from launch import LaunchDescription
19 from launch.actions import DeclareLaunchArgument, GroupAction, SetEnvironmentVariable
20 from launch.conditions import IfCondition
21 from launch.substitutions import (AndSubstitution, EqualsSubstitution, LaunchConfiguration,
22  NotEqualsSubstitution, PythonExpression)
23 from launch_ros.actions import LoadComposableNodes, Node, PushROSNamespace, SetParameter
24 from launch_ros.descriptions import ComposableNode, ParameterFile
25 from nav2_common.launch import LaunchConfigAsBool, RewrittenYaml
26 
27 
28 def get_lifecycle_nodes(context):
29  lifecycle_nodes = []
30  if LaunchConfigAsBool('serve_static_map').perform(context) == 'True':
31  lifecycle_nodes.append('map_server')
32  if LaunchConfigAsBool('use_localization').perform(context) == 'True':
33  lifecycle_nodes.append('amcl')
34  return tuple(lifecycle_nodes)
35 
36 
37 def generate_launch_description() -> LaunchDescription:
38  # Get the launch directory
39  bringup_dir = get_package_share_directory('nav2_bringup')
40 
41  namespace = LaunchConfiguration('namespace')
42  map_yaml_file = LaunchConfiguration('map')
43  use_sim_time = LaunchConfigAsBool('use_sim_time')
44  use_localization = LaunchConfigAsBool('use_localization')
45  serve_static_map = LaunchConfigAsBool('serve_static_map')
46  params_file = LaunchConfiguration('params_file')
47  use_composition = LaunchConfigAsBool('use_composition')
48  use_intra_process_comms = LaunchConfigAsBool('use_intra_process_comms')
49  container_name = LaunchConfiguration('container_name')
50  container_name_full = (namespace, '/', container_name)
51  use_respawn = LaunchConfigAsBool('use_respawn')
52  log_level = LaunchConfiguration('log_level')
53 
54  # Map fully qualified names to relative ones so the node's namespace can be prepended.
55  remappings = [('/tf', 'tf'), ('/tf_static', 'tf_static')]
56 
57  configured_params = ParameterFile(
58  RewrittenYaml(
59  source_file=params_file,
60  root_key=namespace,
61  param_rewrites={},
62  convert_types=True,
63  ),
64  allow_substs=True,
65  )
66 
67  stdout_linebuf_envvar = SetEnvironmentVariable(
68  'RCUTILS_LOGGING_BUFFERED_STREAM', '1'
69  )
70 
71  declare_namespace_cmd = DeclareLaunchArgument(
72  'namespace', default_value='', description='Top-level namespace'
73  )
74 
75  declare_map_yaml_cmd = DeclareLaunchArgument(
76  'map', default_value='', description='Full path to map yaml file to load'
77  )
78 
79  declare_use_sim_time_cmd = DeclareLaunchArgument(
80  'use_sim_time',
81  default_value='false',
82  description='Use simulation (Gazebo) clock if true',
83  )
84 
85  declare_use_localization_cmd = DeclareLaunchArgument(
86  'use_localization',
87  default_value='True',
88  description='Whether to launch localization',
89  )
90 
91  declare_serve_static_map_cmd = DeclareLaunchArgument(
92  'serve_static_map',
93  default_value=use_localization,
94  description='Whether to serve the static map',
95  )
96 
97  declare_params_file_cmd = DeclareLaunchArgument(
98  'params_file',
99  default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
100  description='Full path to the ROS2 parameters file to use for all launched nodes',
101  )
102 
103  declare_use_composition_cmd = DeclareLaunchArgument(
104  'use_composition',
105  default_value='False',
106  description='Use composed bringup if True',
107  )
108 
109  declare_use_intra_process_comms_cmd = DeclareLaunchArgument(
110  'use_intra_process_comms',
111  default_value='False',
112  description='Use intra process communications if True',
113  )
114 
115  declare_container_name_cmd = DeclareLaunchArgument(
116  'container_name',
117  default_value='nav2_container',
118  description='the name of container that nodes will load in if use composition',
119  )
120 
121  declare_use_respawn_cmd = DeclareLaunchArgument(
122  'use_respawn',
123  default_value='False',
124  description='Whether to respawn if a node crashes. Applied when composition is disabled.',
125  )
126 
127  declare_log_level_cmd = DeclareLaunchArgument(
128  'log_level', default_value='info', description='log level'
129  )
130 
131  load_nodes = GroupAction(
132  condition=IfCondition(PythonExpression(['not ', use_composition])),
133  actions=[
134  PushROSNamespace(namespace),
135  SetParameter('use_sim_time', use_sim_time),
136  Node(
137  condition=IfCondition(
138  AndSubstitution(
139  serve_static_map,
140  EqualsSubstitution(LaunchConfiguration('map'), ''),
141  )
142  ),
143  package='nav2_map_server',
144  executable='map_server',
145  name='map_server',
146  output='screen',
147  respawn=use_respawn,
148  respawn_delay=2.0,
149  parameters=[configured_params],
150  arguments=['--ros-args', '--log-level', log_level],
151  remappings=remappings,
152  ),
153  Node(
154  condition=IfCondition(
155  AndSubstitution(
156  serve_static_map,
157  NotEqualsSubstitution(LaunchConfiguration('map'), ''),
158  )
159  ),
160  package='nav2_map_server',
161  executable='map_server',
162  name='map_server',
163  output='screen',
164  respawn=use_respawn,
165  respawn_delay=2.0,
166  parameters=[configured_params, {'yaml_filename': map_yaml_file}],
167  arguments=['--ros-args', '--log-level', log_level],
168  remappings=remappings,
169  ),
170  Node(
171  condition=IfCondition(use_localization),
172  package='nav2_amcl',
173  executable='amcl',
174  name='amcl',
175  output='screen',
176  respawn=use_respawn,
177  respawn_delay=2.0,
178  parameters=[configured_params],
179  arguments=['--ros-args', '--log-level', log_level],
180  remappings=remappings,
181  ),
182  ],
183  )
184  # LoadComposableNode for map server twice depending if we should use the
185  # value of map from a CLI or launch default or user defined value in the
186  # yaml configuration file. They are separated since the conditions
187  # currently only work on the LoadComposableNodes commands and not on the
188  # ComposableNode node function itself
189  load_composable_nodes = GroupAction(
190  condition=IfCondition(use_composition),
191  actions=[
192  PushROSNamespace(namespace),
193  SetParameter('use_sim_time', use_sim_time),
194  LoadComposableNodes(
195  target_container=container_name_full,
196  condition=IfCondition(
197  AndSubstitution(
198  serve_static_map,
199  EqualsSubstitution(LaunchConfiguration('map'), ''),
200  )
201  ),
202  composable_node_descriptions=[
203  ComposableNode(
204  package='nav2_map_server',
205  plugin='nav2_map_server::MapServer',
206  name='map_server',
207  parameters=[configured_params],
208  remappings=remappings,
209  extra_arguments=[{'use_intra_process_comms': use_intra_process_comms}],
210  ),
211  ],
212  ),
213  LoadComposableNodes(
214  target_container=container_name_full,
215  condition=IfCondition(
216  AndSubstitution(
217  serve_static_map,
218  NotEqualsSubstitution(LaunchConfiguration('map'), ''),
219  )
220  ),
221  composable_node_descriptions=[
222  ComposableNode(
223  package='nav2_map_server',
224  plugin='nav2_map_server::MapServer',
225  name='map_server',
226  parameters=[
227  configured_params,
228  {'yaml_filename': map_yaml_file},
229  ],
230  remappings=remappings,
231  extra_arguments=[{'use_intra_process_comms': use_intra_process_comms}],
232  ),
233  ],
234  ),
235  LoadComposableNodes(
236  condition=IfCondition(use_localization),
237  target_container=container_name_full,
238  composable_node_descriptions=[
239  ComposableNode(
240  package='nav2_amcl',
241  plugin='nav2_amcl::AmclNode',
242  name='amcl',
243  parameters=[configured_params],
244  remappings=remappings,
245  extra_arguments=[{'use_intra_process_comms': use_intra_process_comms}],
246  ),
247  ],
248  ),
249  ],
250  )
251 
252  # Create the launch description and populate
253  ld = LaunchDescription()
254 
255  # Set environment variables
256  ld.add_action(stdout_linebuf_envvar)
257 
258  # Declare the launch options
259  ld.add_action(declare_namespace_cmd)
260  ld.add_action(declare_map_yaml_cmd)
261  ld.add_action(declare_use_sim_time_cmd)
262  ld.add_action(declare_use_localization_cmd)
263  ld.add_action(declare_serve_static_map_cmd)
264  ld.add_action(declare_params_file_cmd)
265  ld.add_action(declare_use_composition_cmd)
266  ld.add_action(declare_use_intra_process_comms_cmd)
267  ld.add_action(declare_container_name_cmd)
268  ld.add_action(declare_use_respawn_cmd)
269  ld.add_action(declare_log_level_cmd)
270 
271  # Add the actions to launch all of the localiztion nodes
272  ld.add_action(load_nodes)
273  ld.add_action(load_composable_nodes)
274 
275  return ld