前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ROS2机器人编程简述humble-第二章-Launchers .3.3

ROS2机器人编程简述humble-第二章-Launchers .3.3

作者头像
zhangrelay
发布2023-02-10 09:25:30
5380
发布2023-02-10 09:25:30
举报
ROS2机器人编程简述humble-第二章-Publishing and Subscribing .3.2

ros2 run一次只能开启一个node,如果一次开启一组相关node,需要使用ros2 launch。

支持Python, XML, 和 YAML。

推荐Python。

代码语言:javascript
复制
zhangrelay@LAPTOP-5REQ7K1L:~$ ros2 run -h
usage: ros2 run [-h] [--prefix PREFIX] package_name executable_name ...

Run a package specific executable

positional arguments:
  package_name     Name of the ROS package
  executable_name  Name of the executable
  argv             Pass arbitrary arguments to the executable

options:
  -h, --help       show this help message and exit
  --prefix PREFIX  Prefix command, which should go before the executable. Command
                   must be wrapped in quotes if it contains spaces (e.g. --prefix
                   'gdb -ex run --args').
zhangrelay@LAPTOP-5REQ7K1L:~$ ros2 launch -h
usage: ros2 launch [-h] [-n] [-d] [-p | -s] [-a] [--launch-prefix LAUNCH_PREFIX]
                   [--launch-prefix-filter LAUNCH_PREFIX_FILTER]
                   package_name [launch_file_name] [launch_arguments ...]

Run a launch file

positional arguments:
  package_name          Name of the ROS package which contains the launch file
  launch_file_name      Name of the launch file
  launch_arguments      Arguments to the launch file; '<name>:=<value>' (for
                        duplicates, last one wins)

options:
  -h, --help            show this help message and exit
  -n, --noninteractive  Run the launch system non-interactively, with no terminal
                        associated
  -d, --debug           Put the launch system in debug mode, provides more verbose
                        output.
  -p, --print, --print-description
                        Print the launch description to the console without
                        launching it.
  -s, --show-args, --show-arguments
                        Show arguments that may be given to the launch file.
  -a, --show-all-subprocesses-output
                        Show all launched subprocesses' output by overriding their
                        output configuration using the
                        OVERRIDE_LAUNCH_PROCESS_OUTPUT envvar.
  --launch-prefix LAUNCH_PREFIX
                        Prefix command, which should go before all executables.
                        Command must be wrapped in quotes if it contains spaces
                        (e.g. --launch-prefix 'xterm -e gdb -ex run --args').
  --launch-prefix-filter LAUNCH_PREFIX_FILTER
                        Regex pattern for filtering which executables the --launch-
                        prefix is applied to by matching the executable name.
zhangrelay@LAPTOP-5REQ7K1L:~$

启动程序launch文件是用Python编写的,其功能是声明使用哪些选项或参数执行哪些程序。一个启动器可以包含另一个启动器,允许重用现有的启动器。之所以需要launch,是因为一个机器人应用程序有许多节点,它们都应该同时启动。逐个启动并调整每个节点的特定参数,使节点进行协作可能会很乏味。

软件包的启动器位于软件包的启动launch目录中,其名称通常以launch.py结尾。正如ros2运行时使用软件包中可用的程序一样,ros2启动时也使用可用的启动器。从实现的角度来看,启动器是一个python程序,它包含一个返回LaunchDescription对象的generatelaunchdescription()函数。

LaunchDescription对象包含操作,其中突出显示:

•node操作:运行程序。

•IncludeLaunchDescription操作:包括另一个启动器。

•DeclareLaunchArgument操作:声明启动器参数。

•SetEnvironmentVariable操作:设置环境变量。

书中案例如下:

v1

代码语言:javascript
复制
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():

    pub_cmd = Node(
        package='br2_basics',
        executable='publisher',
        output='screen'
    )
    sub_cmd = Node(
        package='br2_basics',
        executable='subscriber_class',
        output='screen'
    )

    ld = LaunchDescription()
    ld.add_action(pub_cmd)
    ld.add_action(sub_cmd)

    return ld

v2

代码语言:javascript
复制
from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():

    return LaunchDescription([
        Node(
            package='br2_basics',
            executable='publisher',
            output='screen'
        ),
        Node(
            package='br2_basics',
            executable='subscriber_class',
            output='screen'
        )
    ])

CMakeLists

代码语言:javascript
复制
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})

效果如:

代码语言:javascript
复制
ros2 launch br2_basics pub_sub_v2_launch.py
[INFO] [launch]: All log files can be found below /home/zhangrelay/.ros/log/2023-01-20-09-06-49-444970-LAPTOP-5REQ7K1L-7896
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [publisher-1]: process started with pid [7897]
[INFO] [subscriber_class-2]: process started with pid [7899]
[subscriber_class-2] [INFO] [1674176809.694879700] [subscriber_node]: Hello 1
[subscriber_class-2] [INFO] [1674176810.195718900] [subscriber_node]: Hello 2
[subscriber_class-2] [INFO] [1674176810.695717000] [subscriber_node]: Hello 3
[subscriber_class-2] [INFO] [1674176811.195712100] [subscriber_node]: Hello 4
[subscriber_class-2] [INFO] [1674176811.695709800] [subscriber_node]: Hello 5
[subscriber_class-2] [INFO] [1674176812.195715200] [subscriber_node]: Hello 6
[subscriber_class-2] [INFO] [1674176812.695273100] [subscriber_node]: Hello 7
[subscriber_class-2] [INFO] [1674176813.195665000] [subscriber_node]: Hello 8
[subscriber_class-2] [INFO] [1674176813.695714300] [subscriber_node]: Hello 9
[subscriber_class-2] [INFO] [1674176814.195719200] [subscriber_node]: Hello 10
[subscriber_class-2] [INFO] [1674176814.695718400] [subscriber_node]: Hello 11
[subscriber_class-2] [INFO] [1674176815.195444600] [subscriber_node]: Hello 12
[subscriber_class-2] [INFO] [1674176815.695682400] [subscriber_node]: Hello 13
[subscriber_class-2] [INFO] [1674176816.195665100] [subscriber_node]: Hello 14
[subscriber_class-2] [INFO] [1674176816.695713200] [subscriber_node]: Hello 15
[subscriber_class-2] [INFO] [1674176817.195601200] [subscriber_node]: Hello 16
[subscriber_class-2] [INFO] [1674176817.695310700] [subscriber_node]: Hello 17
[subscriber_class-2] [INFO] [1674176818.195711000] [subscriber_node]: Hello 18
[subscriber_class-2] [INFO] [1674176818.695683800] [subscriber_node]: Hello 19
[subscriber_class-2] [INFO] [1674176819.195543700] [subscriber_node]: Hello 20
[subscriber_class-2] [INFO] [1674176819.695711400] [subscriber_node]: Hello 21
[subscriber_class-2] [INFO] [1674176820.195726000] [subscriber_node]: Hello 22
[subscriber_class-2] [INFO] [1674176820.695710100] [subscriber_node]: Hello 23
[subscriber_class-2] [INFO] [1674176821.195487200] [subscriber_node]: Hello 24
[subscriber_class-2] [INFO] [1674176821.695709500] [subscriber_node]: Hello 25
[subscriber_class-2] [INFO] [1674176822.195718500] [subscriber_node]: Hello 26
[subscriber_class-2] [INFO] [1674176822.695726100] [subscriber_node]: Hello 27
[subscriber_class-2] [INFO] [1674176823.195704600] [subscriber_node]: Hello 28
[subscriber_class-2] [INFO] [1674176823.695726800] [subscriber_node]: Hello 29
[subscriber_class-2] [INFO] [1674176824.195718300] [subscriber_node]: Hello 30
[subscriber_class-2] [INFO] [1674176824.695579500] [subscriber_node]: Hello 31
[subscriber_class-2] [INFO] [1674176825.195705000] [subscriber_node]: Hello 32
[subscriber_class-2] [INFO] [1674176825.695724000] [subscriber_node]: Hello 33
[subscriber_class-2] [INFO] [1674176826.195724200] [subscriber_node]: Hello 34
[subscriber_class-2] [INFO] [1674176826.695665700] [subscriber_node]: Hello 35

更多内容参考官网:

launch

ROS 2启动文件允许同时启动和配置包含ROS 2节点的多个可执行文件。

1 创建启动文件

了解如何创建一个启动文件,该文件将同时启动节点及其配置。

代码语言:javascript
复制
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='turtlesim',
            namespace='turtlesim1',
            executable='turtlesim_node',
            name='sim'
        ),
        Node(
            package='turtlesim',
            namespace='turtlesim2',
            executable='turtlesim_node',
            name='sim'
        ),
        Node(
            package='turtlesim',
            executable='mimic',
            name='mimic',
            remappings=[
                ('/input/pose', '/turtlesim1/turtle1/pose'),
                ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
            ]
        )
    ])

package

代码语言:javascript
复制
<exec_depend>ros2launch</exec_depend>

2 启动和监视多个节点

获取有关启动文件工作方式的更高级概述。

代码语言:javascript
复制
import launch
import launch_ros.actions

def generate_launch_description():
    return launch.LaunchDescription([
        launch_ros.actions.Node(
            package='demo_nodes_cpp',
            executable='talker',
            name='talker'),
  ])

3 使用替换

在描述可重用的启动文件时,使用替换来提供更大的灵活性。

代码语言:javascript
复制
from launch_ros.actions import Node

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, ExecuteProcess, TimerAction
from launch.conditions import IfCondition
from launch.substitutions import LaunchConfiguration, PythonExpression


def generate_launch_description():
    turtlesim_ns = LaunchConfiguration('turtlesim_ns')
    use_provided_red = LaunchConfiguration('use_provided_red')
    new_background_r = LaunchConfiguration('new_background_r')

    turtlesim_ns_launch_arg = DeclareLaunchArgument(
        'turtlesim_ns',
        default_value='turtlesim1'
    )
    use_provided_red_launch_arg = DeclareLaunchArgument(
        'use_provided_red',
        default_value='False'
    )
    new_background_r_launch_arg = DeclareLaunchArgument(
        'new_background_r',
        default_value='200'
    )

    turtlesim_node = Node(
        package='turtlesim',
        namespace=turtlesim_ns,
        executable='turtlesim_node',
        name='sim'
    )
    spawn_turtle = ExecuteProcess(
        cmd=[[
            'ros2 service call ',
            turtlesim_ns,
            '/spawn ',
            'turtlesim/srv/Spawn ',
            '"{x: 2, y: 2, theta: 0.2}"'
        ]],
        shell=True
    )
    change_background_r = ExecuteProcess(
        cmd=[[
            'ros2 param set ',
            turtlesim_ns,
            '/sim background_r ',
            '120'
        ]],
        shell=True
    )
    change_background_r_conditioned = ExecuteProcess(
        condition=IfCondition(
            PythonExpression([
                new_background_r,
                ' == 200',
                ' and ',
                use_provided_red
            ])
        ),
        cmd=[[
            'ros2 param set ',
            turtlesim_ns,
            '/sim background_r ',
            new_background_r
        ]],
        shell=True
    )

    return LaunchDescription([
        turtlesim_ns_launch_arg,
        use_provided_red_launch_arg,
        new_background_r_launch_arg,
        turtlesim_node,
        spawn_turtle,
        change_background_r,
        TimerAction(
            period=2.0,
            actions=[change_background_r_conditioned],
        )
    ])

4 使用事件处理程序

使用事件处理程序监视进程的状态或定义一组复杂的规则,这些规则可用于动态修改启动文件。

代码语言:javascript
复制
from launch_ros.actions import Node

from launch import LaunchDescription
from launch.actions import (DeclareLaunchArgument, EmitEvent, ExecuteProcess,
                            LogInfo, RegisterEventHandler, TimerAction)
from launch.conditions import IfCondition
from launch.event_handlers import (OnExecutionComplete, OnProcessExit,
                                OnProcessIO, OnProcessStart, OnShutdown)
from launch.events import Shutdown
from launch.substitutions import (EnvironmentVariable, FindExecutable,
                                LaunchConfiguration, LocalSubstitution,
                                PythonExpression)


def generate_launch_description():
    turtlesim_ns = LaunchConfiguration('turtlesim_ns')
    use_provided_red = LaunchConfiguration('use_provided_red')
    new_background_r = LaunchConfiguration('new_background_r')

    turtlesim_ns_launch_arg = DeclareLaunchArgument(
        'turtlesim_ns',
        default_value='turtlesim1'
    )
    use_provided_red_launch_arg = DeclareLaunchArgument(
        'use_provided_red',
        default_value='False'
    )
    new_background_r_launch_arg = DeclareLaunchArgument(
        'new_background_r',
        default_value='200'
    )

    turtlesim_node = Node(
        package='turtlesim',
        namespace=turtlesim_ns,
        executable='turtlesim_node',
        name='sim'
    )
    spawn_turtle = ExecuteProcess(
        cmd=[[
            FindExecutable(name='ros2'),
            ' service call ',
            turtlesim_ns,
            '/spawn ',
            'turtlesim/srv/Spawn ',
            '"{x: 2, y: 2, theta: 0.2}"'
        ]],
        shell=True
    )
    change_background_r = ExecuteProcess(
        cmd=[[
            FindExecutable(name='ros2'),
            ' param set ',
            turtlesim_ns,
            '/sim background_r ',
            '120'
        ]],
        shell=True
    )
    change_background_r_conditioned = ExecuteProcess(
        condition=IfCondition(
            PythonExpression([
                new_background_r,
                ' == 200',
                ' and ',
                use_provided_red
            ])
        ),
        cmd=[[
            FindExecutable(name='ros2'),
            ' param set ',
            turtlesim_ns,
            '/sim background_r ',
            new_background_r
        ]],
        shell=True
    )

    return LaunchDescription([
        turtlesim_ns_launch_arg,
        use_provided_red_launch_arg,
        new_background_r_launch_arg,
        turtlesim_node,
        RegisterEventHandler(
            OnProcessStart(
                target_action=turtlesim_node,
                on_start=[
                    LogInfo(msg='Turtlesim started, spawning turtle'),
                    spawn_turtle
                ]
            )
        ),
        RegisterEventHandler(
            OnProcessIO(
                target_action=spawn_turtle,
                on_stdout=lambda event: LogInfo(
                    msg='Spawn request says "{}"'.format(
                        event.text.decode().strip())
                )
            )
        ),
        RegisterEventHandler(
            OnExecutionComplete(
                target_action=spawn_turtle,
                on_completion=[
                    LogInfo(msg='Spawn finished'),
                    change_background_r,
                    TimerAction(
                        period=2.0,
                        actions=[change_background_r_conditioned],
                    )
                ]
            )
        ),
        RegisterEventHandler(
            OnProcessExit(
                target_action=turtlesim_node,
                on_exit=[
                    LogInfo(msg=(EnvironmentVariable(name='USER'),
                            ' closed the turtlesim window')),
                    EmitEvent(event=Shutdown(
                        reason='Window closed'))
                ]
            )
        ),
        RegisterEventHandler(
            OnShutdown(
                on_shutdown=[LogInfo(
                    msg=['Launch was asked to shutdown: ',
                        LocalSubstitution('event.reason')]
                )]
            )
        ),
    ])

5 管理大型项目

为大型项目构建启动文件,以便在不同的情况下尽可能地重用它们。请参阅不同启动工具的用法示例,如参数、YAML文件、重映射、名称空间、默认参数和RViz配置。

代码语言:javascript
复制
import os

from ament_index_python.packages import get_package_share_directory

from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource


def generate_launch_description():
   turtlesim_world_1 = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/turtlesim_world_1.launch.py'])
      )
   turtlesim_world_2 = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/turtlesim_world_2.launch.py'])
      )
   broadcaster_listener_nodes = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/broadcaster_listener.launch.py']),
      launch_arguments={'target_frame': 'carrot1'}.items(),
      )
   mimic_node = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/mimic.launch.py'])
      )
   fixed_frame_node = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/fixed_broadcaster.launch.py'])
      )
   rviz_node = IncludeLaunchDescription(
      PythonLaunchDescriptionSource([os.path.join(
         get_package_share_directory('launch_tutorial'), 'launch'),
         '/turtlesim_rviz.launch.py'])
      )

   return LaunchDescription([
      turtlesim_world_1,
      turtlesim_world_2,
      broadcaster_listener_nodes,
      mimic_node,
      fixed_frame_node,
      rviz_node
   ])
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ROS2机器人编程简述humble-第二章-Publishing and Subscribing .3.2
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档