• 学习ros机器人导航从精读nav2导航launch文件开始


    nav2导航launch文件经过了多层套娃,真的是让初学者哭晕在厕所,今天我们就拆解一下他的launch文件,还原他最简单的状态,看看他到底启动了什么节点。

    一 tb3仿真机器人启动文件:tb3_simulation_launch.py

    1 文件目录结构 

    文件取自:Nav2 — Navigation 2 1.0.0 文档

    2 文件源代码 

    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. """This is all-in-one launch script intended for use by nav2 developers."""
    15. import os
    16. from ament_index_python.packages import get_package_share_directory
    17. from launch import LaunchDescription
    18. from launch.actions import DeclareLaunchArgument, ExecuteProcess, IncludeLaunchDescription
    19. from launch.conditions import IfCondition
    20. from launch.launch_description_sources import PythonLaunchDescriptionSource
    21. from launch.substitutions import LaunchConfiguration, PythonExpression
    22. from launch_ros.actions import Node
    23. def generate_launch_description():
    24. # Get the launch directory
    25. bringup_dir = get_package_share_directory('nav2_bringup')
    26. launch_dir = os.path.join(bringup_dir, 'launch')
    27. # Create the launch configuration variables
    28. slam = LaunchConfiguration('slam')
    29. namespace = LaunchConfiguration('namespace')
    30. use_namespace = LaunchConfiguration('use_namespace')
    31. map_yaml_file = LaunchConfiguration('map')
    32. use_sim_time = LaunchConfiguration('use_sim_time')
    33. params_file = LaunchConfiguration('params_file')
    34. default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename')
    35. autostart = LaunchConfiguration('autostart')
    36. # Launch configuration variables specific to simulation
    37. rviz_config_file = LaunchConfiguration('rviz_config_file')
    38. use_simulator = LaunchConfiguration('use_simulator')
    39. use_robot_state_pub = LaunchConfiguration('use_robot_state_pub')
    40. use_rviz = LaunchConfiguration('use_rviz')
    41. headless = LaunchConfiguration('headless')
    42. world = LaunchConfiguration('world')
    43. # Map fully qualified names to relative ones so the node's namespace can be prepended.
    44. # In case of the transforms (tf), currently, there doesn't seem to be a better alternative
    45. # https://github.com/ros/geometry2/issues/32
    46. # https://github.com/ros/robot_state_publisher/pull/30
    47. # TODO(orduno) Substitute with `PushNodeRemapping`
    48. # https://github.com/ros2/launch_ros/issues/56
    49. remappings = [('/tf', 'tf'),
    50. ('/tf_static', 'tf_static')]
    51. # Declare the launch arguments
    52. declare_namespace_cmd = DeclareLaunchArgument(
    53. 'namespace',
    54. default_value='',
    55. description='Top-level namespace')
    56. declare_use_namespace_cmd = DeclareLaunchArgument(
    57. 'use_namespace',
    58. default_value='false',
    59. description='Whether to apply a namespace to the navigation stack')
    60. declare_slam_cmd = DeclareLaunchArgument(
    61. 'slam',
    62. default_value='False',
    63. description='Whether run a SLAM')
    64. declare_map_yaml_cmd = DeclareLaunchArgument(
    65. 'map',
    66. default_value=os.path.join(bringup_dir, 'maps', 'turtlebot3_world.yaml'),
    67. description='Full path to map file to load')
    68. declare_use_sim_time_cmd = DeclareLaunchArgument(
    69. 'use_sim_time',
    70. default_value='true',
    71. description='Use simulation (Gazebo) clock if true')
    72. declare_params_file_cmd = DeclareLaunchArgument(
    73. 'params_file',
    74. default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
    75. description='Full path to the ROS2 parameters file to use for all launched nodes')
    76. declare_bt_xml_cmd = DeclareLaunchArgument(
    77. 'default_bt_xml_filename',
    78. default_value=os.path.join(
    79. get_package_share_directory('nav2_bt_navigator'),
    80. 'behavior_trees', 'navigate_w_replanning_and_recovery.xml'),
    81. description='Full path to the behavior tree xml file to use')
    82. declare_autostart_cmd = DeclareLaunchArgument(
    83. 'autostart', default_value='true',
    84. description='Automatically startup the nav2 stack')
    85. declare_rviz_config_file_cmd = DeclareLaunchArgument(
    86. 'rviz_config_file',
    87. default_value=os.path.join(bringup_dir, 'rviz', 'nav2_default_view.rviz'),
    88. description='Full path to the RVIZ config file to use')
    89. declare_use_simulator_cmd = DeclareLaunchArgument(
    90. 'use_simulator',
    91. default_value='True',
    92. description='Whether to start the simulator')
    93. declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
    94. 'use_robot_state_pub',
    95. default_value='True',
    96. description='Whether to start the robot state publisher')
    97. declare_use_rviz_cmd = DeclareLaunchArgument(
    98. 'use_rviz',
    99. default_value='True',
    100. description='Whether to start RVIZ')
    101. declare_simulator_cmd = DeclareLaunchArgument(
    102. 'headless',
    103. default_value='False',
    104. description='Whether to execute gzclient)')
    105. declare_world_cmd = DeclareLaunchArgument(
    106. 'world',
    107. # TODO(orduno) Switch back once ROS argument passing has been fixed upstream
    108. # https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/91
    109. # default_value=os.path.join(get_package_share_directory('turtlebot3_gazebo'),
    110. # 'worlds/turtlebot3_worlds/waffle.model'),
    111. default_value=os.path.join(bringup_dir, 'worlds', 'waffle.model'),
    112. description='Full path to world model file to load')
    113. # Specify the actions
    114. start_gazebo_server_cmd = ExecuteProcess(
    115. condition=IfCondition(use_simulator),
    116. cmd=['gzserver', '-s', 'libgazebo_ros_init.so', world],
    117. cwd=[launch_dir], output='screen')
    118. start_gazebo_client_cmd = ExecuteProcess(
    119. condition=IfCondition(PythonExpression([use_simulator, ' and not ', headless])),
    120. cmd=['gzclient'],
    121. cwd=[launch_dir], output='screen')
    122. urdf = os.path.join(bringup_dir, 'urdf', 'turtlebot3_waffle.urdf')
    123. start_robot_state_publisher_cmd = Node(
    124. condition=IfCondition(use_robot_state_pub),
    125. package='robot_state_publisher',
    126. executable='robot_state_publisher',
    127. name='robot_state_publisher',
    128. namespace=namespace,
    129. output='screen',
    130. parameters=[{'use_sim_time': use_sim_time}],
    131. remappings=remappings,
    132. arguments=[urdf])
    133. rviz_cmd = IncludeLaunchDescription(
    134. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'rviz_launch.py')),
    135. condition=IfCondition(use_rviz),
    136. launch_arguments={'namespace': '',
    137. 'use_namespace': 'False',
    138. 'rviz_config': rviz_config_file}.items())
    139. bringup_cmd = IncludeLaunchDescription(
    140. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'bringup_launch.py')),
    141. launch_arguments={'namespace': namespace,
    142. 'use_namespace': use_namespace,
    143. 'slam': slam,
    144. 'map': map_yaml_file,
    145. 'use_sim_time': use_sim_time,
    146. 'params_file': params_file,
    147. 'default_bt_xml_filename': default_bt_xml_filename,
    148. 'autostart': autostart}.items())
    149. # Create the launch description and populate
    150. ld = LaunchDescription()
    151. # Declare the launch options
    152. ld.add_action(declare_namespace_cmd)
    153. ld.add_action(declare_use_namespace_cmd)
    154. ld.add_action(declare_slam_cmd)
    155. ld.add_action(declare_map_yaml_cmd)
    156. ld.add_action(declare_use_sim_time_cmd)
    157. ld.add_action(declare_params_file_cmd)
    158. ld.add_action(declare_bt_xml_cmd)
    159. ld.add_action(declare_autostart_cmd)
    160. ld.add_action(declare_rviz_config_file_cmd)
    161. ld.add_action(declare_use_simulator_cmd)
    162. ld.add_action(declare_use_robot_state_pub_cmd)
    163. ld.add_action(declare_use_rviz_cmd)
    164. ld.add_action(declare_simulator_cmd)
    165. ld.add_action(declare_world_cmd)
    166. # Add any conditioned actions
    167. ld.add_action(start_gazebo_server_cmd)
    168. ld.add_action(start_gazebo_client_cmd)
    169. # Add the actions to launch all of the navigation nodes
    170. ld.add_action(start_robot_state_publisher_cmd)
    171. ld.add_action(rviz_cmd)
    172. ld.add_action(bringup_cmd)
    173. return ld

    二 launch文件究竟启动了什么

    1 第一层套娃启动了什么

    只看launch文件最后面几行。

    1. # Add any conditioned actions
    2. ld.add_action(start_gazebo_server_cmd)
    3. ld.add_action(start_gazebo_client_cmd)
    4. # Add the actions to launch all of the navigation nodes
    5. ld.add_action(start_robot_state_publisher_cmd)
    6. ld.add_action(rviz_cmd)
    7. ld.add_action(bringup_cmd)
    8. return ld

    分别启动了gazebo,机器人模型文件,rviz2,和bringup_cmd,这里关于导航的只有bringup_cmd,其他的只是生成了机器人和在rviz2里面展现出来了,下面只分析最重要的—导航。

    2 第二层套娃启动了什么

    1. bringup_cmd = IncludeLaunchDescription(
    2. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'bringup_launch.py')),
    3. launch_arguments={'namespace': namespace,
    4. 'use_namespace': use_namespace,
    5. 'slam': slam,
    6. 'map': map_yaml_file,
    7. 'use_sim_time': use_sim_time,
    8. 'params_file': params_file,
    9. 'default_bt_xml_filename': default_bt_xml_filename,
    10. 'autostart': autostart}.items())

    bringup_launch.py  文件目录结构

    bringup_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. import os
    15. from ament_index_python.packages import get_package_share_directory
    16. from launch import LaunchDescription
    17. from launch.actions import (DeclareLaunchArgument, GroupAction,
    18. IncludeLaunchDescription, SetEnvironmentVariable)
    19. from launch.conditions import IfCondition
    20. from launch.launch_description_sources import PythonLaunchDescriptionSource
    21. from launch.substitutions import LaunchConfiguration, PythonExpression
    22. from launch_ros.actions import PushRosNamespace
    23. def generate_launch_description():
    24. # Get the launch directory
    25. bringup_dir = get_package_share_directory('nav2_bringup')
    26. launch_dir = os.path.join(bringup_dir, 'launch')
    27. # Create the launch configuration variables
    28. namespace = LaunchConfiguration('namespace')
    29. use_namespace = LaunchConfiguration('use_namespace')
    30. slam = LaunchConfiguration('slam')
    31. map_yaml_file = LaunchConfiguration('map')
    32. use_sim_time = LaunchConfiguration('use_sim_time')
    33. params_file = LaunchConfiguration('params_file')
    34. default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename')
    35. autostart = LaunchConfiguration('autostart')
    36. stdout_linebuf_envvar = SetEnvironmentVariable(
    37. 'RCUTILS_LOGGING_BUFFERED_STREAM', '1')
    38. declare_namespace_cmd = DeclareLaunchArgument(
    39. 'namespace',
    40. default_value='',
    41. description='Top-level namespace')
    42. declare_use_namespace_cmd = DeclareLaunchArgument(
    43. 'use_namespace',
    44. default_value='false',
    45. description='Whether to apply a namespace to the navigation stack')
    46. declare_slam_cmd = DeclareLaunchArgument(
    47. 'slam',
    48. default_value='False',
    49. description='Whether run a SLAM')
    50. declare_map_yaml_cmd = DeclareLaunchArgument(
    51. 'map',
    52. description='Full path to map yaml file to load')
    53. declare_use_sim_time_cmd = DeclareLaunchArgument(
    54. 'use_sim_time',
    55. default_value='false',
    56. description='Use simulation (Gazebo) clock if true')
    57. declare_params_file_cmd = DeclareLaunchArgument(
    58. 'params_file',
    59. default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
    60. description='Full path to the ROS2 parameters file to use for all launched nodes')
    61. declare_bt_xml_cmd = DeclareLaunchArgument(
    62. 'default_bt_xml_filename',
    63. default_value=os.path.join(
    64. get_package_share_directory('nav2_bt_navigator'),
    65. 'behavior_trees', 'navigate_w_replanning_and_recovery.xml'),
    66. description='Full path to the behavior tree xml file to use')
    67. declare_autostart_cmd = DeclareLaunchArgument(
    68. 'autostart', default_value='true',
    69. description='Automatically startup the nav2 stack')
    70. # Specify the actions
    71. bringup_cmd_group = GroupAction([
    72. PushRosNamespace(
    73. condition=IfCondition(use_namespace),
    74. namespace=namespace),
    75. IncludeLaunchDescription(
    76. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'slam_launch.py')),
    77. condition=IfCondition(slam),
    78. launch_arguments={'namespace': namespace,
    79. 'use_sim_time': use_sim_time,
    80. 'autostart': autostart,
    81. 'params_file': params_file}.items()),
    82. IncludeLaunchDescription(
    83. PythonLaunchDescriptionSource(os.path.join(launch_dir,
    84. 'localization_launch.py')),
    85. condition=IfCondition(PythonExpression(['not ', slam])),
    86. launch_arguments={'namespace': namespace,
    87. 'map': map_yaml_file,
    88. 'use_sim_time': use_sim_time,
    89. 'autostart': autostart,
    90. 'params_file': params_file,
    91. 'use_lifecycle_mgr': 'false'}.items()),
    92. IncludeLaunchDescription(
    93. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'navigation_launch.py')),
    94. launch_arguments={'namespace': namespace,
    95. 'use_sim_time': use_sim_time,
    96. 'autostart': autostart,
    97. 'params_file': params_file,
    98. 'default_bt_xml_filename': default_bt_xml_filename,
    99. 'use_lifecycle_mgr': 'false',
    100. 'map_subscribe_transient_local': 'true'}.items()),
    101. ])
    102. # Create the launch description and populate
    103. ld = LaunchDescription()
    104. # Set environment variables
    105. ld.add_action(stdout_linebuf_envvar)
    106. # Declare the launch options
    107. ld.add_action(declare_namespace_cmd)
    108. ld.add_action(declare_use_namespace_cmd)
    109. ld.add_action(declare_slam_cmd)
    110. ld.add_action(declare_map_yaml_cmd)
    111. ld.add_action(declare_use_sim_time_cmd)
    112. ld.add_action(declare_params_file_cmd)
    113. ld.add_action(declare_autostart_cmd)
    114. ld.add_action(declare_bt_xml_cmd)
    115. # Add the actions to launch all of the navigation nodes
    116. ld.add_action(bringup_cmd_group)
    117. return ld

     还是从后看,启动了一个导航组:bringup_cmd_group

    1. # Specify the actions
    2. bringup_cmd_group = GroupAction([
    3. PushRosNamespace(
    4. condition=IfCondition(use_namespace),
    5. namespace=namespace),
    6. IncludeLaunchDescription(
    7. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'slam_launch.py')),
    8. condition=IfCondition(slam),
    9. launch_arguments={'namespace': namespace,
    10. 'use_sim_time': use_sim_time,
    11. 'autostart': autostart,
    12. 'params_file': params_file}.items()),
    13. IncludeLaunchDescription(
    14. PythonLaunchDescriptionSource(os.path.join(launch_dir,
    15. 'localization_launch.py')),
    16. condition=IfCondition(PythonExpression(['not ', slam])),
    17. launch_arguments={'namespace': namespace,
    18. 'map': map_yaml_file,
    19. 'use_sim_time': use_sim_time,
    20. 'autostart': autostart,
    21. 'params_file': params_file,
    22. 'use_lifecycle_mgr': 'false'}.items()),
    23. IncludeLaunchDescription(
    24. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'navigation_launch.py')),
    25. launch_arguments={'namespace': namespace,
    26. 'use_sim_time': use_sim_time,
    27. 'autostart': autostart,
    28. 'params_file': params_file,
    29. 'default_bt_xml_filename': default_bt_xml_filename,
    30. 'use_lifecycle_mgr': 'false',
    31. 'map_subscribe_transient_local': 'true'}.items()),
    32. ])

    导航最核心的部分,定位  导航

    很不容易懂得一个地方,condition=IfCondition(), 条件启动,弄懂这个启动文件又精简很多。

    第一个条件语句块

    1. PushRosNamespace(
    2. condition=IfCondition(use_namespace),
    3. namespace=namespace),

    IfCondition条件语句,IfCondition(use_namespace) use_namespace是真这个语句启动,如果是假这个语句块想当于不存在,结合上下文 use_namespace 默认值false,所以这段语句块相当于不存在。

    第二个条件语句块

    1. IncludeLaunchDescription(
    2. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'slam_launch.py')),
    3. condition=IfCondition(slam),
    4. launch_arguments={'namespace': namespace,
    5. 'use_sim_time': use_sim_time,
    6. 'autostart': autostart,
    7. 'params_file': params_file}.items()),

    这段的意思是是否用slam_launch.py建图。

    slam的默认取值default_value='False',如果按默认启动这段语句也可以忽略。

    如果想导航同时建图需要把slam传入True或者直接把默认值改成True。

    第三个条件语句块

    1. IncludeLaunchDescription(
    2. PythonLaunchDescriptionSource(os.path.join(launch_dir,
    3. 'localization_launch.py')),
    4. condition=IfCondition(PythonExpression(['not ', slam])),
    5. launch_arguments={'namespace': namespace,
    6. 'map': map_yaml_file,
    7. 'use_sim_time': use_sim_time,
    8. 'autostart': autostart,
    9. 'params_file': params_file,
    10. 'use_lifecycle_mgr': 'false'}.items()),

    是否启动定位。

    condition=IfCondition(PythonExpression(['not ', slam])),

    这句很不好理解,直接的意思就是salm取False,整个语句块启动,salm取True,整个语句块不启动。

    这个条件语句和上面的条件语句其实是二选一

    如果slam取True,slam_launch.py建图启动,localization_launch.py 定位不启动。

    如果slam取False,slam_launch.py建图不启动,localization_launch.py 定位启动。

    按默认启动的话只是启动 localization_launch.py

    导航语句块

    1. IncludeLaunchDescription(
    2. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'navigation_launch.py')),
    3. launch_arguments={'namespace': namespace,
    4. 'use_sim_time': use_sim_time,
    5. 'autostart': autostart,
    6. 'params_file': params_file,
    7. 'default_bt_xml_filename': default_bt_xml_filename,
    8. 'use_lifecycle_mgr': 'false',
    9. 'map_subscribe_transient_local': 'true'}.items()),

    通过前面的定位,这里才是启动导航的核心程序 navigation_launch.py

    3 第三层套娃

    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. import os
    15. from ament_index_python.packages import get_package_share_directory
    16. from launch import LaunchDescription
    17. from launch.actions import DeclareLaunchArgument, SetEnvironmentVariable
    18. from launch.substitutions import LaunchConfiguration
    19. from launch_ros.actions import Node
    20. from nav2_common.launch import RewrittenYaml
    21. def generate_launch_description():
    22. # Get the launch directory
    23. bringup_dir = get_package_share_directory('nav2_bringup')
    24. namespace = LaunchConfiguration('namespace')
    25. map_yaml_file = LaunchConfiguration('map')
    26. use_sim_time = LaunchConfiguration('use_sim_time')
    27. autostart = LaunchConfiguration('autostart')
    28. params_file = LaunchConfiguration('params_file')
    29. lifecycle_nodes = ['map_server', 'amcl']
    30. # Map fully qualified names to relative ones so the node's namespace can be prepended.
    31. # In case of the transforms (tf), currently, there doesn't seem to be a better alternative
    32. # https://github.com/ros/geometry2/issues/32
    33. # https://github.com/ros/robot_state_publisher/pull/30
    34. # TODO(orduno) Substitute with `PushNodeRemapping`
    35. # https://github.com/ros2/launch_ros/issues/56
    36. remappings = [('/tf', 'tf'),
    37. ('/tf_static', 'tf_static')]
    38. # Create our own temporary YAML files that include substitutions
    39. param_substitutions = {
    40. 'use_sim_time': use_sim_time,
    41. 'yaml_filename': map_yaml_file}
    42. configured_params = RewrittenYaml(
    43. source_file=params_file,
    44. root_key=namespace,
    45. param_rewrites=param_substitutions,
    46. convert_types=True)
    47. return LaunchDescription([
    48. # Set env var to print messages to stdout immediately
    49. SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
    50. DeclareLaunchArgument(
    51. 'namespace', default_value='',
    52. description='Top-level namespace'),
    53. DeclareLaunchArgument(
    54. 'map',
    55. default_value=os.path.join(bringup_dir, 'maps', 'turtlebot3_world.yaml'),
    56. description='Full path to map yaml file to load'),
    57. DeclareLaunchArgument(
    58. 'use_sim_time', default_value='false',
    59. description='Use simulation (Gazebo) clock if true'),
    60. DeclareLaunchArgument(
    61. 'autostart', default_value='true',
    62. description='Automatically startup the nav2 stack'),
    63. DeclareLaunchArgument(
    64. 'params_file',
    65. default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
    66. description='Full path to the ROS2 parameters file to use'),
    67. Node(
    68. package='nav2_map_server',
    69. executable='map_server',
    70. name='map_server',
    71. output='screen',
    72. parameters=[configured_params],
    73. remappings=remappings),
    74. Node(
    75. package='nav2_amcl',
    76. executable='amcl',
    77. name='amcl',
    78. output='screen',
    79. parameters=[configured_params],
    80. remappings=remappings),
    81. Node(
    82. package='nav2_lifecycle_manager',
    83. executable='lifecycle_manager',
    84. name='lifecycle_manager_localization',
    85. output='screen',
    86. parameters=[{'use_sim_time': use_sim_time},
    87. {'autostart': autostart},
    88. {'node_names': lifecycle_nodes}])
    89. ])

     依然从后面看

    1. Node(
    2. package='nav2_map_server',
    3. executable='map_server',
    4. name='map_server',
    5. output='screen',
    6. parameters=[configured_params],
    7. remappings=remappings),
    8. Node(
    9. package='nav2_amcl',
    10. executable='amcl',
    11. name='amcl',
    12. output='screen',
    13. parameters=[configured_params],
    14. remappings=remappings),
    15. Node(
    16. package='nav2_lifecycle_manager',
    17. executable='lifecycle_manager',
    18. name='lifecycle_manager_localization',
    19. output='screen',
    20. parameters=[{'use_sim_time': use_sim_time},
    21. {'autostart': autostart},
    22. {'node_names': lifecycle_nodes}])
    23. ])

     分别启动了

    executable='map_server',   #地图服务

    executable='amcl',             #amcl定位

    executable='lifecycle_manager',   #生命周期管理

    这里注意  remappings = [('/tf', 'tf'), ('/tf_static', 'tf_static')]

    机器人默认发布的是话题是'/tf'    '/tf_static'   定位和导航需要接收的话题是 'tf'    'tf_static' ,需要重映射话题的节点需要加上 remappings=remappings 这也是容易产生迷惑的地方。

    navigation_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. import os
    15. from ament_index_python.packages import get_package_share_directory
    16. from launch import LaunchDescription
    17. from launch.actions import DeclareLaunchArgument, SetEnvironmentVariable
    18. from launch.substitutions import LaunchConfiguration
    19. from launch_ros.actions import Node
    20. from nav2_common.launch import RewrittenYaml
    21. def generate_launch_description():
    22. # Get the launch directory
    23. bringup_dir = get_package_share_directory('nav2_bringup')
    24. namespace = LaunchConfiguration('namespace')
    25. use_sim_time = LaunchConfiguration('use_sim_time')
    26. autostart = LaunchConfiguration('autostart')
    27. params_file = LaunchConfiguration('params_file')
    28. default_bt_xml_filename = LaunchConfiguration('default_bt_xml_filename')
    29. map_subscribe_transient_local = LaunchConfiguration('map_subscribe_transient_local')
    30. lifecycle_nodes = ['controller_server',
    31. 'planner_server',
    32. 'recoveries_server',
    33. 'bt_navigator',
    34. 'waypoint_follower']
    35. # Map fully qualified names to relative ones so the node's namespace can be prepended.
    36. # In case of the transforms (tf), currently, there doesn't seem to be a better alternative
    37. # https://github.com/ros/geometry2/issues/32
    38. # https://github.com/ros/robot_state_publisher/pull/30
    39. # TODO(orduno) Substitute with `PushNodeRemapping`
    40. # https://github.com/ros2/launch_ros/issues/56
    41. remappings = [('/tf', 'tf'),
    42. ('/tf_static', 'tf_static')]
    43. # Create our own temporary YAML files that include substitutions
    44. param_substitutions = {
    45. 'use_sim_time': use_sim_time,
    46. 'default_bt_xml_filename': default_bt_xml_filename,
    47. 'autostart': autostart,
    48. 'map_subscribe_transient_local': map_subscribe_transient_local}
    49. configured_params = RewrittenYaml(
    50. source_file=params_file,
    51. root_key=namespace,
    52. param_rewrites=param_substitutions,
    53. convert_types=True)
    54. return LaunchDescription([
    55. # Set env var to print messages to stdout immediately
    56. SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
    57. DeclareLaunchArgument(
    58. 'namespace', default_value='',
    59. description='Top-level namespace'),
    60. DeclareLaunchArgument(
    61. 'use_sim_time', default_value='false',
    62. description='Use simulation (Gazebo) clock if true'),
    63. DeclareLaunchArgument(
    64. 'autostart', default_value='true',
    65. description='Automatically startup the nav2 stack'),
    66. DeclareLaunchArgument(
    67. 'params_file',
    68. default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
    69. description='Full path to the ROS2 parameters file to use'),
    70. DeclareLaunchArgument(
    71. 'default_bt_xml_filename',
    72. default_value=os.path.join(
    73. get_package_share_directory('nav2_bt_navigator'),
    74. 'behavior_trees', 'navigate_w_replanning_and_recovery.xml'),
    75. description='Full path to the behavior tree xml file to use'),
    76. DeclareLaunchArgument(
    77. 'map_subscribe_transient_local', default_value='false',
    78. description='Whether to set the map subscriber QoS to transient local'),
    79. Node(
    80. package='nav2_controller',
    81. executable='controller_server',
    82. output='screen',
    83. parameters=[configured_params],
    84. remappings=remappings),
    85. Node(
    86. package='nav2_planner',
    87. executable='planner_server',
    88. name='planner_server',
    89. output='screen',
    90. parameters=[configured_params],
    91. remappings=remappings),
    92. Node(
    93. package='nav2_recoveries',
    94. executable='recoveries_server',
    95. name='recoveries_server',
    96. output='screen',
    97. parameters=[configured_params],
    98. remappings=remappings),
    99. Node(
    100. package='nav2_bt_navigator',
    101. executable='bt_navigator',
    102. name='bt_navigator',
    103. output='screen',
    104. parameters=[configured_params],
    105. remappings=remappings),
    106. Node(
    107. package='nav2_waypoint_follower',
    108. executable='waypoint_follower',
    109. name='waypoint_follower',
    110. output='screen',
    111. parameters=[configured_params],
    112. remappings=remappings),
    113. Node(
    114. package='nav2_lifecycle_manager',
    115. executable='lifecycle_manager',
    116. name='lifecycle_manager_navigation',
    117. output='screen',
    118. parameters=[{'use_sim_time': use_sim_time},
    119. {'autostart': autostart},
    120. {'node_names': lifecycle_nodes}]),
    121. ])

    分别启动的节点

    1. Node(
    2. package='nav2_controller',
    3. executable='controller_server',
    4. output='screen',
    5. parameters=[configured_params],
    6. remappings=remappings),
    7. Node(
    8. package='nav2_planner',
    9. executable='planner_server',
    10. name='planner_server',
    11. output='screen',
    12. parameters=[configured_params],
    13. remappings=remappings),
    14. Node(
    15. package='nav2_recoveries',
    16. executable='recoveries_server',
    17. name='recoveries_server',
    18. output='screen',
    19. parameters=[configured_params],
    20. remappings=remappings),
    21. Node(
    22. package='nav2_bt_navigator',
    23. executable='bt_navigator',
    24. name='bt_navigator',
    25. output='screen',
    26. parameters=[configured_params],
    27. remappings=remappings),
    28. Node(
    29. package='nav2_waypoint_follower',
    30. executable='waypoint_follower',
    31. name='waypoint_follower',
    32. output='screen',
    33. parameters=[configured_params],
    34. remappings=remappings),
    35. Node(
    36. package='nav2_lifecycle_manager',
    37. executable='lifecycle_manager',
    38. name='lifecycle_manager_navigation',
    39. output='screen',
    40. parameters=[{'use_sim_time': use_sim_time},
    41. {'autostart': autostart},
    42. {'node_names': lifecycle_nodes}]),

    executable='controller_server',   #控制服务器节点

    executable='planner_server',      #规划服务器节点

    executable='recoveries_server', #恢复服务器节点

    executable='bt_navigator',          #行为数节点

    executable='waypoint_follower', #航点跟随节点

    executable='lifecycle_manager', #声明周期管理节点

    三 导航启动的所有节点

    1 机器人生成   

    gazebo仿真:gzserver, gzclient

    这一步如果是实体机器人,gezabo程序不需要启动。

    2 发布机器人模型并展示

    executable='robot_state_publisher',

    executable='rviz2',

    3 定位

    executable='map_server',

    executable='amcl',

    4 导航

    ros2 launch nav2_bringup tb3_simulation_launch.py

    executable='controller_server',   #控制服务器节点

    executable='planner_server',      #规划服务器节点

    executable='recoveries_server', #恢复服务器节点

    executable='bt_navigator',          #行为数节点

    executable='waypoint_follower', #航点跟随节点

    executable='lifecycle_manager', #生命周期管理节点

    至此导航仿真拆解完成。

    四 一边建图一边导航

    ros2 launch nav2_bringup tb3_simulation_launch.py slam:=True

    slam:=True 通过condition=IfCondition(slam)影响了上面的第三步 定位,其他节点不变

    1. IncludeLaunchDescription(
    2. PythonLaunchDescriptionSource(os.path.join(launch_dir, 'slam_launch.py')),
    3. condition=IfCondition(slam),
    4. launch_arguments={'namespace': namespace,
    5. 'use_sim_time': use_sim_time,
    6. 'autostart': autostart,
    7. 'params_file': params_file}.items()),

    拆解slam_launch.py

    目录结构

    slam_launch.py

    1. # Copyright (c) 2020 Samsung Research Russia
    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. import os
    15. from ament_index_python.packages import get_package_share_directory
    16. from launch import LaunchDescription
    17. from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
    18. from launch.launch_description_sources import PythonLaunchDescriptionSource
    19. from launch.substitutions import LaunchConfiguration
    20. from launch_ros.actions import Node
    21. from nav2_common.launch import RewrittenYaml
    22. def generate_launch_description():
    23. # Input parameters declaration
    24. namespace = LaunchConfiguration('namespace')
    25. params_file = LaunchConfiguration('params_file')
    26. use_sim_time = LaunchConfiguration('use_sim_time')
    27. autostart = LaunchConfiguration('autostart')
    28. # Variables
    29. lifecycle_nodes = ['map_saver']
    30. # Getting directories and launch-files
    31. bringup_dir = get_package_share_directory('nav2_bringup')
    32. slam_toolbox_dir = get_package_share_directory('slam_toolbox')
    33. slam_launch_file = os.path.join(slam_toolbox_dir, 'launch', 'online_sync_launch.py')
    34. # Create our own temporary YAML files that include substitutions
    35. param_substitutions = {
    36. 'use_sim_time': use_sim_time}
    37. configured_params = RewrittenYaml(
    38. source_file=params_file,
    39. root_key=namespace,
    40. param_rewrites=param_substitutions,
    41. convert_types=True)
    42. # Declare the launch arguments
    43. declare_namespace_cmd = DeclareLaunchArgument(
    44. 'namespace',
    45. default_value='',
    46. description='Top-level namespace')
    47. declare_params_file_cmd = DeclareLaunchArgument(
    48. 'params_file',
    49. default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
    50. description='Full path to the ROS2 parameters file to use for all launched nodes')
    51. declare_use_sim_time_cmd = DeclareLaunchArgument(
    52. 'use_sim_time',
    53. default_value='true',
    54. description='Use simulation (Gazebo) clock if true')
    55. declare_autostart_cmd = DeclareLaunchArgument(
    56. 'autostart', default_value='true',
    57. description='Automatically startup the nav2 stack')
    58. # Nodes launching commands
    59. start_slam_toolbox_cmd = IncludeLaunchDescription(
    60. PythonLaunchDescriptionSource(slam_launch_file),
    61. launch_arguments={'use_sim_time': use_sim_time}.items())
    62. start_map_saver_server_cmd = Node(
    63. package='nav2_map_server',
    64. executable='map_saver_server',
    65. output='screen',
    66. parameters=[configured_params])
    67. start_lifecycle_manager_cmd = Node(
    68. package='nav2_lifecycle_manager',
    69. executable='lifecycle_manager',
    70. name='lifecycle_manager_slam',
    71. output='screen',
    72. parameters=[{'use_sim_time': use_sim_time},
    73. {'autostart': autostart},
    74. {'node_names': lifecycle_nodes}])
    75. ld = LaunchDescription()
    76. # Declare the launch options
    77. ld.add_action(declare_namespace_cmd)
    78. ld.add_action(declare_params_file_cmd)
    79. ld.add_action(declare_use_sim_time_cmd)
    80. ld.add_action(declare_autostart_cmd)
    81. # Running SLAM Toolbox
    82. ld.add_action(start_slam_toolbox_cmd)
    83. # Running Map Saver Server
    84. ld.add_action(start_map_saver_server_cmd)
    85. ld.add_action(start_lifecycle_manager_cmd)
    86. return ld

    加载主要内容

    1. slam_launch_file = os.path.join(slam_toolbox_dir, 'launch', 'online_sync_launch.py')
    2. start_slam_toolbox_cmd = IncludeLaunchDescription(
    3. PythonLaunchDescriptionSource(slam_launch_file),
    4. launch_arguments={'use_sim_time': use_sim_time}.items())
    5. start_map_saver_server_cmd = Node(
    6. package='nav2_map_server',
    7. executable='map_saver_server',
    8. output='screen',
    9. parameters=[configured_params])
    10. start_lifecycle_manager_cmd = Node(
    11. package='nav2_lifecycle_manager',
    12. executable='lifecycle_manager',
    13. name='lifecycle_manager_slam',
    14. output='screen',
    15. parameters=[{'use_sim_time': use_sim_time},
    16. {'autostart': autostart},
    17. {'node_names': lifecycle_nodes}])

    executable='sync_slam_toolbox_node',  #slam工具箱 

    executable='map_saver_server',    #地图存储

    executable='lifecycle_manager',    #生命周期管理

    五 总结

    tb3_simulation_launch.py 通过修改gazebo启动项可以迁移到实体机器人导航,通过设置slam:=True 或者slam:=False可以选择是否启动建图时导航,实体机器人导航需要把use_sim_time:=false(使用系统时间), gezabo仿真导航默认的use_sim_time:=true (使用仿真时间)

  • 相关阅读:
    IDEA指定Maven settings file文件未生效
    在containerd,将 ‘ctr image‘ 转换成 ‘crictl image‘
    推荐《咒术回战》
    数据库1= =
    SpringBoot+Vue社区团购网站(前后端分离)
    JAVA中小型医院网站计算机毕业设计Mybatis+系统+数据库+调试部署
    Koa 源码剖析
    深度分析AMQP以及在rabbitMQ中的应用
    反转字符串中的单词
    Go语言学习(二) 函数
  • 原文地址:https://blog.csdn.net/m0_73694897/article/details/132595252