Keep in mind that launch files are supposed to work together and are included in each other. In other words, the only reason we keep them separate is convenience: we want our code to be better structured.
This is all-in-one launch script intended for use by nav2 developers. Attn: in ROS2 examples, this file is called "tb3_simulation_launch.py", but as I do not use the TurtleBot, I have changed the name.
First, and standard for Python files, we have the import section.
from launch import LaunchDescription import launch import launch_ros.actions from launch.actions import DeclareLaunchArgument, ExecuteProcess, IncludeLaunchDescription from launch.conditions import IfCondition from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration, PythonExpression, TextSubstitution from launch_ros.actions import Node import xacro import sys sys.path.append("src/navigation_bot_05/launch") from globals import *
Launch file provides the generate_launch_description() function:
def generate_launch_description():
In the "import" section, you saw the
from globals import *
It is used in launch files, so we can move redundunt code to a globals.py:
# Now in globals.py # package_name = 'navigation_bot_05' # bringup_dir = get_package_share_directory(package_name) # Now in globals.py # launch_dir = os.path.join(bringup_dir, 'launch')
When you see something like "now in globals.py", it simply means that the commented code was used in ROS2 official tutorials (that my code is based on), but I moved it to globals.py.
Next, we create the launch configuration variables:
slam = LaunchConfiguration('slam') namespace = LaunchConfiguration('namespace') use_namespace = LaunchConfiguration('use_namespace') map_yaml_file = LaunchConfiguration('map') use_sim_time = LaunchConfiguration('use_sim_time') params_file = LaunchConfiguration('params_file') default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename') autostart = LaunchConfiguration('autostart') # Launch configuration variables specific to simulation rviz_config_file = LaunchConfiguration('rviz_config_file') use_simulator = LaunchConfiguration('use_simulator') use_robot_state_pub = LaunchConfiguration('use_robot_state_pub') use_rviz = LaunchConfiguration('use_rviz') headless = LaunchConfiguration('headless') world = LaunchConfiguration('world', default=world_path)
As you can see, the launch file can use parameters, for example, we can specify the name of a world file to use: world:=path_to_world_file.
Launch arguments are passed to lunch files that the main launch file calls. Also, we use them to specify the default values for parameters, in case they are not passed explicitely:
# Declare the launch arguments declare_namespace_cmd = DeclareLaunchArgument( 'namespace', default_value='', description='Top-level namespace') declare_use_namespace_cmd = DeclareLaunchArgument( 'use_namespace', default_value='false', description='Whether to apply a namespace to the navigation stack') declare_slam_cmd = DeclareLaunchArgument( 'slam', default_value='False', description='Whether run a SLAM') # maps_path declared in globals.py declare_map_yaml_cmd = DeclareLaunchArgument( 'map', default_value=maps_path, description='Full path to map file to load') declare_use_sim_time_cmd = DeclareLaunchArgument( 'use_sim_time', default_value='True', description='Use simulation (Gazebo) clock if true') # nav2_params_path declared in globals.py declare_params_file_cmd = DeclareLaunchArgument( 'params_file', default_value=nav2_params_path, description='Full path to the ROS2 parameters file to use for all launched nodes') # nav2_bt_navigator_path declared in globals.py declare_bt_xml_cmd = DeclareLaunchArgument( 'default_bt_xml_filename', default_value=nav2_bt_navigator_path, description='Full path to the behavior tree xml file to use') declare_autostart_cmd = DeclareLaunchArgument( 'autostart', default_value='True', description='Automatically startup the nav2 stack') # rviz_path defined in globals.py declare_rviz_config_file_cmd = DeclareLaunchArgument( 'rviz_config_file', default_value=rviz_path, description='Full path to the RVIZ config file to use') declare_use_simulator_cmd = DeclareLaunchArgument( 'use_simulator', default_value='True', description='Whether to start the simulator') declare_use_robot_state_pub_cmd = DeclareLaunchArgument( 'use_robot_state_pub', default_value='True', description='Whether to start the robot state publisher') declare_use_rviz_cmd = DeclareLaunchArgument( 'use_rviz', default_value='True', description='Whether to start RVIZ') declare_simulator_cmd = DeclareLaunchArgument( 'headless', default_value='False', description='Whether to execute gzclient)') # world_path defined in globals.py declare_world_cmd = DeclareLaunchArgument( 'world', default_value=world_path, description='Full path to world model file to load')
Now it is time to create ROS2 nodes:
# Replaced by a single call below # start_gazebo_server_cmd = ExecuteProcess( # condition=IfCondition(use_simulator), # cmd=['gzserver', '-s', 'libgazebo_ros_init.so', world], # cwd=[launch_dir], output='screen') # # start_gazebo_client_cmd = ExecuteProcess( # condition=IfCondition(PythonExpression([use_simulator, ' and not ', headless])), # cmd=['gzclient'], # cwd=[launch_dir], output='screen') # Alternative: # Include the Gazebo launch file, provided by the gazebo_ros package gazebo = IncludeLaunchDescription( PythonLaunchDescriptionSource([os.path.join( get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')]), launch_arguments={ 'gui':'True', 'server':'True' }.items() ) # Replaced by a single call below #start_robot_state_publisher_cmd = Node( # condition=IfCondition(use_robot_state_pub), # package='robot_state_publisher', # executable='robot_state_publisher', # name='robot_state_publisher', # namespace=namespace, # output='screen', # parameters=[{'use_sim_time': use_sim_time}], # remappings=remappings, # arguments=[urdf]) # Alternative: robot_description_config = xacro.process_file(urdf) #xacro_file) params = {'robot_description': robot_description_config.toxml(), 'use_sim_time': use_sim_time} start_robot_state_publisher_cmd = Node( condition=IfCondition(use_robot_state_pub), package='robot_state_publisher', executable='robot_state_publisher', #name='robot_state_publisher', namespace=namespace, output='screen', remappings=remappings, parameters=[params] ) # Run the spawner node from the gazebo_ros package. # The entity name doesn't really matter if you only have a single robot. spawn_entity_cmd = Node(package='gazebo_ros', executable='spawn_entity.py', arguments=['-topic', 'robot_description', '-entity', 'navigation_bot_05'], parameters=[{'use_sim_time': use_sim_time}], output='screen') #robot_localization_node = Node( # package='robot_localization', # executable='ekf_node', # name='ekf_filter_node', # output='screen', # parameters=[os.path.join(pkg_path, 'config/ekf.yaml')]#, {'use_sim_time': use_sim_time }] #) bringup_cmd = IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(launch_dir, 'bringup_launch.py')), launch_arguments={'namespace': namespace, 'use_namespace': use_namespace, 'slam': slam, 'map': map_yaml_file, 'use_sim_time': use_sim_time, 'params_file': params_file, 'default_bt_xml_filename': default_bt_xml_filename, 'autostart': autostart}.items()) bringup_timer_action = launch.actions.TimerAction( period=5.0, actions=[ bringup_cmd ]) rviz_cmd = IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(launch_dir, 'rviz_launch.py')), condition=IfCondition(use_rviz), launch_arguments={'namespace': '', 'use_namespace': 'False', 'rviz_config': rviz_config_file}.items()) rviz_timer_action = launch.actions.TimerAction( period=3.0, actions=[ rviz_cmd ]) params = { 'use_sim_time': use_sim_time} joint_state_publisher_node = Node( package='joint_state_publisher', executable='joint_state_publisher', name='joint_state_publisher', parameters=[params], #condition=launch.conditions.UnlessCondition(LaunchConfiguration('gui')) )
As you can see, some of these nodes use other launch files, for example,
to bring up the RViz, we call rviz_launch.py.
After all nodes are created, we can use them:
# Create the launch description and populate ld = LaunchDescription() # Declare the launch options ld.add_action(declare_namespace_cmd) ld.add_action(declare_use_namespace_cmd) ld.add_action(declare_slam_cmd) ld.add_action(declare_map_yaml_cmd) ld.add_action(declare_use_sim_time_cmd) ld.add_action(declare_params_file_cmd) ld.add_action(declare_bt_xml_cmd) ld.add_action(declare_autostart_cmd) ld.add_action(declare_rviz_config_file_cmd) ld.add_action(declare_use_simulator_cmd) ld.add_action(declare_use_robot_state_pub_cmd) ld.add_action(declare_use_rviz_cmd) ld.add_action(declare_simulator_cmd) ld.add_action(declare_world_cmd) # Add any conditioned actions #ld.add_action(start_gazebo_server_cmd) #ld.add_action(start_gazebo_client_cmd) ld.add_action(gazebo) # Add the actions to launch all of the navigation nodes ld.add_action(start_robot_state_publisher_cmd) ld.add_action(joint_state_publisher_node) ld.add_action(spawn_entity_cmd) #ld.add_action(rviz_cmd) ld.add_action(rviz_timer_action) #ld.add_action(bringup_cmd) ld.add_action(bringup_timer_action) return ld
This file brings up the navigation stack.
First, the import section:
import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import (DeclareLaunchArgument, GroupAction, IncludeLaunchDescription, SetEnvironmentVariable) from launch.conditions import IfCondition from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration, PythonExpression from launch_ros.actions import PushRosNamespace import sys sys.path.append("src/navigation_bot_05/launch") from globals import *
Then the generate_launch_description() (it all should look familiar by now):
def generate_launch_description(): # Now in globals.py # package_name = 'navigation_bot_05' # bringup_dir = get_package_share_directory(package_name) # Now in globals.py # launch_dir = os.path.join(bringup_dir, 'launch') ...
Interesting enough, the way we arranged our launch files, the command line parameters are being passed from "outer" launch files to launch files that are being called, in a rather transparent way:
# Create the launch configuration variables namespace = LaunchConfiguration('namespace') use_namespace = LaunchConfiguration('use_namespace') slam = LaunchConfiguration('slam') map_yaml_file = LaunchConfiguration('map') use_sim_time = LaunchConfiguration('use_sim_time') params_file = LaunchConfiguration('params_file') default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename') autostart = LaunchConfiguration('autostart') stdout_linebuf_envvar = SetEnvironmentVariable( 'RCUTILS_LOGGING_BUFFERED_STREAM', '1')
Declaring launch arguments, same idea as in main file:
declare_namespace_cmd = DeclareLaunchArgument( 'namespace', default_value='', description='Top-level namespace') declare_use_namespace_cmd = DeclareLaunchArgument( 'use_namespace', default_value='false', description='Whether to apply a namespace to the navigation stack') declare_slam_cmd = DeclareLaunchArgument( 'slam', default_value='False', description='Whether run a SLAM') declare_map_yaml_cmd = DeclareLaunchArgument( 'map', default_value=maps_path, description='Full path to map yaml file to load') declare_use_sim_time_cmd = DeclareLaunchArgument( 'use_sim_time', default_value='True', description='Use simulation (Gazebo) clock if true') # nav2_params_path declared in globals.py declare_params_file_cmd = DeclareLaunchArgument( 'params_file', default_value=nav2_params_path, description='Full path to the ROS2 parameters file to use for all launched nodes') # nav2_bt_navigator_path declared in globals.py declare_bt_xml_cmd = DeclareLaunchArgument( 'default_bt_xml_filename', default_value=nav2_bt_navigator_path, description='Full path to the behavior tree xml file to use') declare_autostart_cmd = DeclareLaunchArgument( 'autostart', default_value='true', description='Automatically startup the nav2 stack')
Creating nodes:
# Specify the actions bringup_cmd_group = GroupAction([ PushRosNamespace( condition=IfCondition(use_namespace), namespace=namespace), IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(launch_dir, 'slam_launch.py')), condition=IfCondition(slam), launch_arguments={'namespace': namespace, 'use_sim_time': use_sim_time, 'autostart': autostart, 'params_file': params_file}.items()), IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(launch_dir, 'localization_launch.py')), condition=IfCondition(PythonExpression(['not ', slam])), launch_arguments={'namespace': namespace, 'map': map_yaml_file, 'use_sim_time': use_sim_time, 'autostart': autostart, 'params_file': params_file, 'use_lifecycle_mgr': 'false'}.items()), IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(launch_dir, 'navigation_launch.py')), launch_arguments={'namespace': namespace, 'use_sim_time': use_sim_time, 'autostart': autostart, 'params_file': params_file, 'default_bt_xml_filename': default_bt_xml_filename, 'use_lifecycle_mgr': 'false', 'map_subscribe_transient_local': 'true'}.items()), ]) # Create the launch description and populate ld = LaunchDescription() # Set environment variables ld.add_action(stdout_linebuf_envvar) # Declare the launch options ld.add_action(declare_namespace_cmd) ld.add_action(declare_use_namespace_cmd) ld.add_action(declare_slam_cmd) ld.add_action(declare_map_yaml_cmd) ld.add_action(declare_use_sim_time_cmd) ld.add_action(declare_params_file_cmd) ld.add_action(declare_autostart_cmd) ld.add_action(declare_bt_xml_cmd) # Add the actions to launch all of the navigation nodes ld.add_action(bringup_cmd_group) return ld
Here I keep everything that can be included in more than one file.
import os from ament_index_python.packages import get_package_share_directory global ros_shared_path ros_shared_path = '/opt/ros/foxy/share/' package_name = 'navigation_bot_05' global bringup_dir bringup_dir = get_package_share_directory(package_name) global launch_dir launch_dir = os.path.join(bringup_dir, 'launch') global maps_path maps_path = os.path.join(bringup_dir, '../maps', 'map.yaml') global nav2_bt_navigator_path nav2_bt_navigator_path = os.path.join(ros_shared_path, 'nav2_bt_navigator', 'behavior_trees', 'navigate_w_replanning_and_recovery.xml') global nav2_params_path nav2_params_path = os.path.join(bringup_dir, 'config', 'nav2_params.yaml') # Map fully qualifimap:=d names to relative ones so the node's namespace can be prepended. # In case of the transforms (tf), currently, there doesn't seem to be a better alternative # https://github.com/ros/geometry2/issues/32 # https://github.com/ros/robot_state_publisher/pull/30 # TODO(orduno) Substitute with `PushNodeRemapping` # https://github.com/ros2/launch_ros/issues/56 global remappings remappings = [('/tf', 'tf'), ('/tf_static', 'tf_static')] global rviz_path rviz_path = os.path.join(bringup_dir, 'rviz', 'robot.rviz') global urdf urdf = os.path.join(bringup_dir,'description','robot.urdf.xacro') global world_path world_path = os.path.join(bringup_dir, '../worlds', 'maze.sdf')
As you can see from the name, this launch file is responsible for localization:
import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, SetEnvironmentVariable from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from nav2_common.launch import RewrittenYaml import sys sys.path.append("src/navigation_bot_05/launch") from globals import * def generate_launch_description(): namespace = LaunchConfiguration('namespace') map_yaml_file = LaunchConfiguration('map') use_sim_time = LaunchConfiguration('use_sim_time') autostart = LaunchConfiguration('autostart') params_file = LaunchConfiguration('params_file') lifecycle_nodes = ['map_server', 'amcl'] # Create our own temporary YAML files that include substitutions param_substitutions = { 'use_sim_time': use_sim_time, 'yaml_filename': map_yaml_file} configured_params = RewrittenYaml( source_file=params_file, root_key=namespace, param_rewrites=param_substitutions, convert_types=True) return LaunchDescription([ # Set env var to print messages to stdout immediately SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'), DeclareLaunchArgument( 'namespace', default_value='', description='Top-level namespace'), # maps_path declared in globals.py DeclareLaunchArgument( 'map', default_value=maps_path, description='Full path to map yaml file to load'), DeclareLaunchArgument( 'use_sim_time', default_value='false', description='Use simulation (Gazebo) clock if true'), DeclareLaunchArgument( 'autostart', default_value='true', description='Automatically startup the nav2 stack'), # nav2_params_path declared in globals.py DeclareLaunchArgument( 'params_file', default_value=nav2_params_path, description='Full path to the ROS2 parameters file to use'), Node( package='nav2_map_server', executable='map_server', name='map_server', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_amcl', executable='amcl', name='amcl', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_lifecycle_manager', executable='lifecycle_manager', name='lifecycle_manager_localization', output='screen', emulate_tty=True, # https://github.com/ros2/launch/issues/188 parameters=[{'use_sim_time': use_sim_time}, {'autostart': autostart}, {'node_names': lifecycle_nodes}]) ])
The only thing that looks different is the use of life cycle manager:
lifecycle_nodes = ['map_server', 'amcl'] ...
We list (and then create) nodes it should manage, so we can be sure nodes are started, kept alive and so on.
Ignore this file. It is here, because it is copied from sam_bot, and it will be used in future lessons.
Earlier I said that bringup_launch.py brings up the navigation stack. True, but it does it by calling this launch file, among other things.
# Copyright (c) 2018 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, SetEnvironmentVariable from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from nav2_common.launch import RewrittenYaml import sys sys.path.append("src/navigation_bot_05/launch") from globals import * def generate_launch_description(): # Now in globals.py # package_name = 'navigation_bot_05' # bringup_dir = get_package_share_directory(package_name) namespace = LaunchConfiguration('namespace') use_sim_time = LaunchConfiguration('use_sim_time') autostart = LaunchConfiguration('autostart') params_file = LaunchConfiguration('params_file') default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename') map_subscribe_transient_local = LaunchConfiguration('map_subscribe_transient_local') lifecycle_nodes = ['controller_server', 'planner_server', 'recoveries_server', 'bt_navigator', 'waypoint_follower'] # Map fully qualified names to relative ones so the node's namespace can be prepended. # In case of the transforms (tf), currently, there doesn't seem to be a better alternative # https://github.com/ros/geometry2/issues/32 # https://github.com/ros/robot_state_publisher/pull/30 # TODO(orduno) Substitute with `PushNodeRemapping` # https://github.com/ros2/launch_ros/issues/56 # Now in globals.py #remappings = [('/tf', 'tf'), # ('/tf_static', 'tf_static')] # Create our own temporary YAML files that include substitutions param_substitutions = { 'use_sim_time': use_sim_time, 'default_bt_xml_filename': default_bt_xml_filename, 'autostart': autostart, 'map_subscribe_transient_local': map_subscribe_transient_local} configured_params = RewrittenYaml( source_file=params_file, root_key=namespace, param_rewrites=param_substitutions, convert_types=True) return LaunchDescription([ # Set env var to print messages to stdout immediately SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'), DeclareLaunchArgument( 'namespace', default_value='', description='Top-level namespace'), DeclareLaunchArgument( 'use_sim_time', default_value='True', description='Use simulation (Gazebo) clock if true'), DeclareLaunchArgument( 'autostart', default_value='true', description='Automatically startup the nav2 stack'), # nav2_params_path declared in globals.py DeclareLaunchArgument( 'params_file', default_value=nav2_params_path, description='Full path to the ROS2 parameters file to use'), # nav2_bt_navigator_path declared in globals.py DeclareLaunchArgument( 'default_bt_xml_filename', default_value=nav2_bt_navigator_path, description='Full path to the behavior tree xml file to use'), DeclareLaunchArgument( 'map_subscribe_transient_local', default_value='false', description='Whether to set the map subscriber QoS to transient local'), Node( package='nav2_controller', executable='controller_server', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_planner', executable='planner_server', name='planner_server', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_recoveries', executable='recoveries_server', name='recoveries_server', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_bt_navigator', executable='bt_navigator', name='bt_navigator', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_waypoint_follower', executable='waypoint_follower', name='waypoint_follower', output='screen', parameters=[configured_params], remappings=remappings), Node( package='nav2_lifecycle_manager', executable='lifecycle_manager', name='lifecycle_manager_navigation', output='screen', parameters=[{'use_sim_time': use_sim_time}, {'autostart': autostart}, {'node_names': lifecycle_nodes}]), ])
File to bring up the RViz.
Brings up the functionality for SLAM. Note that we can turn SLAM on and off using "slam" command line parameter.
# Copyright (c) 2020 Samsung Research Russia # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from nav2_common.launch import RewrittenYaml import sys sys.path.append("src/navigation_bot_05/launch") from globals import * def generate_launch_description(): # Input parameters declaration namespace = LaunchConfiguration('namespace') params_file = LaunchConfiguration('params_file') use_sim_time = LaunchConfiguration('use_sim_time') autostart = LaunchConfiguration('autostart') # Variables lifecycle_nodes = ['map_saver'] # Now in globals.py # package_name = 'navigation_bot_05' # bringup_dir = get_package_share_directory(package_name) slam_toolbox_dir = get_package_share_directory('slam_toolbox') slam_launch_file = os.path.join(slam_toolbox_dir, 'launch', 'online_sync_launch.py') # Create our own temporary YAML files that include substitutions param_substitutions = { 'use_sim_time': use_sim_time} configured_params = RewrittenYaml( source_file=params_file, root_key=namespace, param_rewrites=param_substitutions, convert_types=True) # Declare the launch arguments declare_namespace_cmd = DeclareLaunchArgument( 'namespace', default_value='', description='Top-level namespace') declare_params_file_cmd = DeclareLaunchArgument( 'params_file', default_value=os.path.join(bringup_dir, 'config', 'nav2_params.yaml'), description='Full path to the ROS2 parameters file to use for all launched nodes') declare_use_sim_time_cmd = DeclareLaunchArgument( 'use_sim_time', default_value='True', description='Use simulation (Gazebo) clock if true') declare_autostart_cmd = DeclareLaunchArgument( 'autostart', default_value='true', description='Automatically startup the nav2 stack') # Nodes launching commands start_slam_toolbox_cmd = IncludeLaunchDescription( PythonLaunchDescriptionSource(slam_launch_file), launch_arguments={'use_sim_time': use_sim_time}.items()) start_map_saver_server_cmd = Node( package='nav2_map_server', node_executable='map_saver_server', output='screen', emulate_tty=True, # https://github.com/ros2/launch/issues/188 parameters=[configured_params]) start_lifecycle_manager_cmd = Node( package='nav2_lifecycle_manager', node_executable='lifecycle_manager', node_name='lifecycle_manager_slam', output='screen', emulate_tty=True, # https://github.com/ros2/launch/issues/188 parameters=[{'use_sim_time': use_sim_time}, {'autostart': autostart}, {'node_names': lifecycle_nodes}]) ld = LaunchDescription() # Declare the launch options ld.add_action(declare_namespace_cmd) ld.add_action(declare_params_file_cmd) ld.add_action(declare_use_sim_time_cmd) ld.add_action(declare_autostart_cmd) # Running SLAM Toolbox ld.add_action(start_slam_toolbox_cmd) # Running Map Saver Server ld.add_action(start_map_saver_server_cmd) ld.add_action(start_lifecycle_manager_cmd) return ld
The main idea of official ROS2 tutorial was, as I understand it, to not only bring up the Gazebo, but to also do some initial positioning of a robot... Well, now it is just bringing up the Gazebo:
# Copyright (c) 2018 Intel Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from launch import LaunchDescription import launch.actions import launch_ros.actions import sys sys.path.append("src/navigation_bot_05/launch") from globals import * def generate_launch_description(): return LaunchDescription([ spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py', arguments=['-topic', 'robot_description', '-entity', 'navigation_bot_05'], output='screen') # # TODO(orduno) might not be necessary to have it's own package # launch_ros.actions.Node( # package='nav2_gazebo_spawner', # executable='nav2_gazebo_spawner', # output='screen', # arguments=[ # '--robot_name', launch.substitutions.LaunchConfiguration('robot_name'), # '--robot_namespace', launch.substitutions.LaunchConfiguration('robot_name'), # '--turtlebot_type', launch.substitutions.LaunchConfiguration('turtlebot_type'), # '-x', launch.substitutions.LaunchConfiguration('x_pose'), # '-y', launch.substitutions.LaunchConfiguration('y_pose'), # '-z', launch.substitutions.LaunchConfiguration('z_pose')]), ])