编写ROS2的组件(Component)

0 介绍

0.1 ROS1的Node和Nodelet

在ROS1中,你可以将你的代码编写成Node或者Nodelet。Node被编译成可执行文件,Nodelet被编译成一个共享库,然后由一个container进程在运行时加载。

0.2 ROS2的统一API-组件

在ROS2中,推荐使用组件(Component)来编写代码,类似于ROS1中的Nodelet。使用组件可以方便地将通用的概念(比如,生命周期管理,等)添加到现有代码中。

在ROS2中避免了ROS1中最大的缺点,即具有不同API,因为这两种方法都使用相同的API。

0.3 使用组件的收益

在ROS2中,仍然可以使用类Node方式的编写自己的main函数,但对于通常情况不建议这样做;

优势 劣势
ROS1 Node 单个Node与系统的其他部分解耦,促进了故障隔离、更快的开发、模块化和代码重用; 以性能为代价;
ROS1 Nodelet 多节点的高效率的组合; -
ROS2 Component 通过解决一些需要对Node进行重构的根本问题来改进Nodelet的设计; -

将多个节点运行在同一个进程中,可以降低开销并且可选择更高效的通信方式(甚至达到0拷贝的效率),参考,Setting up efficient intra-process communication — ROS 2 Documentation: Iron documentation

通过使用std::unique_ptrs来发布和订阅,它允许消息的所有权在系统中安全地移动。您也可以使用const &和std::shared_ptr来发布和订阅,但在这种情况下不会发生零拷贝。参考,https://github.com/ros2/demos/blob/iron/intra_process_demo/src/two_node_pipeline/two_node_pipeline.cpp ,和https://github.com/ros2/demos/blob/iron/intra_process_demo/include/image_pipeline/camera_node.hpp

1 编写ROS2的Component

一个Component通常是rclcpp::Node的子类。由于它不控制线程,因此在构造函数中不应执行任何长时间运行或阻塞的任务。

1.1 更新CMakeLists

添加find_package(rclcpp_components REQUIRED)

一旦组件被创建,它必须在索引中注册才能被工具发现,参考rclcpp_components_register_node部分;

将CMake中对旧target进行的任何安装命令更改为安装库的版本,例如,不要将任何target安装到lib/${PROJECT_NAME}/路径,而是替换为库的安装方式,参考install部分;

find_package(rclcpp_components REQUIRED)

add_library(radar_component SHARED
  src/radar_component.cpp
  src/utils.cpp
  src/crc64.cpp
  src/serial_port_base.cpp
  src/radar_24ghz4d_reader.cpp
)
target_compile_features(radar_component PUBLIC c_std_99 cxx_std_17)
ament_target_dependencies(radar_component
  "rclcpp_components"
  "rclcpp"
  "message_filters"
  "pcl_msgs"
  "PCL"
)
target_link_libraries(radar_component
  glog
)
rclcpp_components_register_node(radar_component
  PLUGIN "Radar24GHz4DReader"
  EXECUTABLE radar_component_node
)


ament_export_targets(export_radar_component)
install(TARGETS radar_component
  EXPORT export_radar_component
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION bin
)

1.2 更新package.xml

添加 <depend>rclcpp_components</depend>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>message_filters</depend>
  <depend>pcl_msgs</depend>
  <depend>PCL</depend>
  <depend>rclcpp_components</depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

1.3 更新源码

1.3.1 注册组件

你需要更改class的定义,在构造函数中接受一个NodeOptions参数;

Radar24GHz4DReader::Radar24GHz4DReader(const rclcpp::NodeOptions &options)
        : Node("radar_24ghz4d_reader", options) {
    // ...
}

删除main函数,替换为一个pluginlib风格的宏调用;参考,https://github.com/ros2/demos/blob/iron/composition/src/talker_component.cpp

#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(Radar24GHz4DReader)
注:
1 RCLCPP_COMPONENTS_REGISTER_NODE应该在每个库中的每个组件中出现一次;
2 RCLCPP_COMPONENTS_REGISTER_NODE应该出现在一个单独的转译单元中;
3 NodeClass(即,示例中的Radar24GHz4DReader)的有效参数应该:
  ① 有一个接受一个rclcpp::NodeOptions实例的构造函数;
  ② 有一个方法,签名为:
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_base_interface
4 NodeClass(即,示例中的Radar24GHz4DReader)不需要继承自rclcpp::Node,但这是最简单的方式;
  非继承(组合)方式的实现,可参考,https://github.com/ros2/demos/blob/iron/composition/src/node_like_listener_component.cpp

参考,https://github.com/ros2/rclcpp/blob/iron/rclcpp_components/include/rclcpp_components/register_node_macro.hpp

2 常用的组件命令行工具

2.1 列出可用组件(ros2 component types)

. $HOME/ros2_ws/install/setup.bash && ros2 component types
# 输出
uav@uav-G5-5500:~$ ros2 component types
**-sns-radar-ros2
  Radar24GHz4DReader
composition
  composition::Talker
  composition::Listener
  composition::NodeLikeListener
  composition::Server
  composition::Client
examples_rclcpp_minimal_subscriber
  WaitSetSubscriber
  StaticWaitSetSubscriber
  TimeTriggeredWaitSetSubscriber
demo_nodes_cpp_native
  demo_nodes_cpp_native::Talker
image_tools
  image_tools::Cam2Image
  image_tools::ShowImage
teleop_twist_joy
  teleop_twist_joy::TeleopTwistJoy
joy
  joy::Joy
  joy::GameController
depthimage_to_laserscan
  depthimage_to_laserscan::DepthImageToLaserScanROS
quality_of_service_demo_cpp
  quality_of_service_demo::MessageLostListener
  quality_of_service_demo::MessageLostTalker
  quality_of_service_demo::QosOverridesListener
  quality_of_service_demo::QosOverridesTalker
logging_demo
  logging_demo::LoggerConfig
  logging_demo::LoggerUsage
action_tutorials_cpp
  action_tutorials_cpp::FibonacciActionClient
  action_tutorials_cpp::FibonacciActionServer
demo_nodes_cpp
  demo_nodes_cpp::OneOffTimerNode
  demo_nodes_cpp::ReuseTimerNode
  demo_nodes_cpp::ServerNode
  demo_nodes_cpp::ClientNode
  demo_nodes_cpp::IntrospectionServiceNode
  demo_nodes_cpp::IntrospectionClientNode
  demo_nodes_cpp::ListParameters
  demo_nodes_cpp::ParameterBlackboard
  demo_nodes_cpp::SetAndGetParameters
  demo_nodes_cpp::ParameterEventsAsyncNode
  demo_nodes_cpp::EvenParameterNode
  demo_nodes_cpp::SetParametersCallback
  demo_nodes_cpp::ContentFilteringPublisher
  demo_nodes_cpp::ContentFilteringSubscriber
  demo_nodes_cpp::Talker
  demo_nodes_cpp::LoanedMessageTalker
  demo_nodes_cpp::SerializedMessageTalker
  demo_nodes_cpp::Listener
  demo_nodes_cpp::SerializedMessageListener
  demo_nodes_cpp::ListenerBestEffort
tf2_ros
  tf2_ros::StaticTransformBroadcasterNode
robot_state_publisher
  robot_state_publisher::RobotStatePublisher

2.2 查看运行中的容器和组件(ros2 component list)

# 在控制台1,启动Radar组件;
. $HOME/ros2_ws/install/setup.bash
ros2 launch **-sns-radar-ros2 radar_component_launch.py

# 在控制台2,查看组件列表;
. $HOME/ros2_ws/install/setup.bash
ros2 component list
# 输出:
/radar_container
  1  /radar_front

其中,组件容器的名称,和组件的名称,是在radar_component_launch.py中定义的;

from launch import LaunchDescription
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode


# reference: https://docs.ros.org/en/iron/How-To-Guides/Launching-composable-nodes.html
def generate_launch_description():
    container = ComposableNodeContainer(
        name = 'radar_container',
        namespace = '',
        package = 'rclcpp_components',
        executable = 'component_container',
        composable_node_descriptions = [
            ComposableNode(
                package = '**-sns-radar-ros2',
                plugin = 'Radar24GHz4DReader',
                name = 'radar_front',
                parameters = [
                    {'device': '/dev/ttyUSB0'},
                    {'baudrate': '921600'}
                ],
                extra_arguments = [{'use_intra_process_comms': True}]
            )
        ],
        output = 'both',
    )

    return LaunchDescription([container])

2.3 加载组件

2.3.1 使用命令行工具加载组件(ros2 component load)

# 在控制台1,启动component_container;
ros2 run rclcpp_components component_container
uav@uav-G5-5500:~$ ros2 component list
/ComponentManager


# 在控制台2,查看组件列表,和加载Radar组件;
ros2 component list
# 输出:/ComponentManager
# 加载Radar组件;
ros2 component load /ComponentManager **-sns-radar-ros2 Radar24GHz4DReader --parameter device:=/dev/ttyUSB1 --parameter baudrate:=\"921600\"
# 控制台2的输出如下:
meter device:=/dev/ttyUSB1 --parameter baudrate:=\"921600\"
/opt/ros/iron/lib/python3.10/site-packages/ros2param/api/__init__.py:28: UserWarning: get_parameter_value() is deprecated. Use rclpy.parameter.get_parameter_value instead
  warnings.warn('get_parameter_value() is deprecated. '
Loaded component 1 into '/ComponentManager' container node as '/radar_24ghz4d_reader'
# 查看组件列表;
ros2 component list
# 输出如下:
/ComponentManager
  1  /radar_24ghz4d_reader

2.3.2 硬编码组合组件

参考,https://github.com/ros2/demos/blob/iron/composition/src/manual_composition.cpp

  // Create an executor that will be responsible for execution of callbacks for a set of nodes.
  // With this version, all callbacks will be called from within this thread (the main one).
  rclcpp::executors::SingleThreadedExecutor exec;
  rclcpp::NodeOptions options;

  // Add some nodes to the executor which provide work for the executor during its "spin" function.
  // An example of available work is executing a subscription callback, or a timer callback.
  auto talker = std::make_shared<composition::Talker>(options);
  exec.add_node(talker);
  auto listener = std::make_shared<composition::Listener>(options);
  exec.add_node(listener);
  auto server = std::make_shared<composition::Server>(options);
  exec.add_node(server);
  auto client = std::make_shared<composition::Client>(options);
  exec.add_node(client);

注:
硬编码组合的组件不会反映在ros2 component list命令行工具的输出中。

2.3.3 使用dlopen_composition工具在运行时组合组件

# 示例1,运行示例组件
ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so


# 示例2,运行Radar组件
ros2 run composition dlopen_composition $HOME/ros2_ws/build/**-sns-radar-ros2/libradar_component.so

dlopen_composition的实现,请参考,https://github.com/ros2/demos/blob/iron/composition/src/dlopen_composition.cpp

注:
使用dlopen_composition工具组合的组件不会反映在ros2 component list命令行工具的输出中。

2.3.4 使用launch组合组件

ros2 launch composition composition_demo_launch.py

composition_demo_launch.py的文件内容,请参考,https://github.com/ros2/demos/blob/iron/composition/launch/composition_demo_launch.py

以Radar组件为例,编写launch文件;

    container = ComposableNodeContainer(
        name = 'radar_container',
        namespace = '',
        package = 'rclcpp_components',
        executable = 'component_container',
        composable_node_descriptions = [
            ComposableNode(
                package = '**-sns-radar-ros2',
                plugin = 'Radar24GHz4DReader',
                name = 'radar_front',
                parameters = [
                    {'device': '/dev/ttyUSB0'},
                    {'baudrate': '921600'}
                ],
                extra_arguments = [{'use_intra_process_comms': True}]
            )
        ],
        output = 'both',
    )

2.4 卸载组件(ros2 component unload)

使用唯一标识符从容器中卸载组件;

ros2 component unload /ComponentManager 1 2

3 重映射名称和命名空间

独特的命名空间允许系统启动两个相似的节点,而不会出现组件名称(和topic名称)的冲突;

重映射包括对容器,和组件的名称/命名空间的重映射;

重映射不会影响已加载的组件;

3.1 名称和命名空间的要求

命名要求 示例 日志
容器的名称 ①不能省略;②不能为空;③节点名称不得包含字母或_以外的字符; 错误的:①不设置;②name = '',;③name = '/radar_container', ComposableNodeContainer.__init__() missing 2 required keyword-only arguments: 'name' and 'namespace';②[ERROR] [launch]: Caught exception in launch (see debug for traceback): Invalid node name: node name must not be empty:;③[ERROR] [launch_ros.actions.node]: Error while expanding or validating node name or namespace for 'package=rclcpp_components, executable=component_container, name=/radar_container, namespace=radar_ns/':[ERROR] [launch]: Caught exception in launch (see debug for traceback): Invalid node name: node name must not contain characters other than alphanumerics or '_': '/radar_container'
容器的命名空间 ①不能省略;②可以为空,namespace = '',namespace = '/',等效 错误的:不设置; ComposableNodeContainer.__init__() missing 1 required keyword-only argument: 'namespace'
组件的名称 ①不能包含/;②可以省略,和name = '',等效,此时都使用硬编码的名称 错误的:name = '/radar_front', [component_container-1] [WARN] [1714290155.258453849] [rcl]: Node name not remapped to invalid name: '/radar_front'
组件的命名空间 可以省略,和namespace = '/',namespace = '',,等效,此时都使用/ 可用的:namespace = '/radar/front', [INFO] [launch_ros.actions.load_composable_nodes]: Loaded node '/radar/front/radar_front' in container '/radar_ns/radar_container'

一个可用的launch文件示例,如下:

def generate_launch_description():
    container = ComposableNodeContainer(
        name = 'radar_container',
        namespace = 'radar_ns/',
        package = 'rclcpp_components',
        executable = 'component_container',
        # arguments=['/dev/ttyUSB0', '921600'],
        composable_node_descriptions = [
            ComposableNode(
                package = '**-sns-radar-ros2',
                plugin = 'Radar24GHz4DReader',
                name = 'radar_front',
                namespace = '/radar/front',
                parameters = [
                    {'device': '/dev/ttyUSB0'},
                    {'baudrate': '921600'}
                ],
                # arguments=['/dev/ttyUSB0', '921600'],
                extra_arguments = [{'use_intra_process_comms': True}]
            )
        ],
        output = 'both',
    )

    return LaunchDescription([container])

查看组件列表,如下:

~$ ros2 component list
/radar_ns/radar_container
  1  /radar/front/radar_front

3.2 重映射容器的名称和命名空间

# 重映射容器名称为MyContainer,命名空间为/ns
ros2 run rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns


# 查看组件列表
ros2 component list
# 输出:/ns/MyContainer

--ros-args -r __node:=MyContainer -r __ns:=/ns参数对应launch文件中ComposableNodeContainer部分的的namenamespace

// 如果未设置重映射,则节点的名字使用源码中构造Node时,传入的第一个参数,一般为硬编码写入的;
SerialPortBase::SerialPortBase(const std::string &_node, const rclcpp::NodeOptions &options)
        : Node(_node, options) {
    LOG(INFO) << __FUNCTION__ << " start.";
    return;
}

3.3 重映射组件的名称和命名空间

向容器/ns/MyContainer中加载Radar组件,并重映射名称为radar_left,命名空间为/radar_ns;

ros2 component load /ns/MyContainer **-sns-radar-ros2 Radar24GHz4DReader --parameter device:=/dev/ttyUSB1 --parameter baudrate:=\"921600\" --node-name radar_left --node-namespace /radar_ns


# 查看组件列表
ros2 component list
# 输出:
/ns/MyContainer
  1  /radar_24ghz4d_reader
  2  /radar_ns/radar_left

--node-name radar_left --node-namespace /radar_ns参数对应launch文件中ComposableNode部分的namenamespace

4 传递参数给组件

4.1 传递parameters参数

4.1.1 通过控制台/launch文件传递parameters参数

请参考2.3.1的--parameter(可简写为-p);

在组件中读取参数的方式,如下:

    std::string device("");
    std::string baudrate("");
    declare_parameter<std::string>("device", "/dev/ttyUSB0");
    declare_parameter<std::string>("baudrate", "921600");
    get_parameter("device", device);
    get_parameter("baudrate", baudrate);

--parameter参数对应launch文件中的parameters

更多关于parameters的示例,请参考,https://github.com/guyuehome/ros2_21_tutorials/blob/master/learning_launch/launch/parameters.launch.py ,或者Managing large projects — ROS 2 Documentation: Iron documentation

4.1.2 通过yaml文件传递parameters参数

import os

from ament_index_python.packages import get_package_share_directory

from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
   config = os.path.join(
      get_package_share_directory('launch_tutorial'),
      'config',
      'turtlesim.yaml'
      )

   return LaunchDescription([
      Node(
         package='turtlesim',
         executable='turtlesim_node',
         namespace='turtlesim2',
         name='sim',
         parameters=[config]
      )
   ])

该launch文件加载YAML配置文件,并启动节点;

使用YAML文件,可以方便的维护大量的参数;

此外,YAML文件可以导出当前ros2 param,参考ros2 param dump命令,或者Understanding parameters — ROS 2 Documentation: Iron documentation

一个示例的yaml文件,如下:

/turtlesim2/sim:
   ros__parameters:
      background_b: 255
      background_g: 86
      background_r: 150

我们也可以使用通配符语法。/**将为每个节点分配所有参数,忽略节点名称和命名空间的不同:

/**:
   ros__parameters:
      background_b: 255
      background_g: 86
      background_r: 150

4.2 传递arguments控制台参数

4.2.1 对Node传递arguments控制台参数

Node方式,即,编写main函数,编译和启动executable,而不是加载plugin;

示例launch文件如下:

from launch import LaunchDescription
from launch_ros.actions import Node


def generate_launch_description():
    return LaunchDescription([
        Node(
            package='**-sns-radar-ros2',
            # namespace='',
            executable='radar_node',
            name='radar_front',
            parameters = [
                {'device': '/dev/ttyUSB0'},
                {'baudrate': '921600'}
            ],
            arguments=['/dev/ttyUSB0', '921600']
        )
    ])

最终,启动类似如下的进程:

/home/uav/ros2_ws/install/**-sns-radar-ros2/lib/**-sns-radar-ros2/radar_node /dev/ttyUSB0 921600 --ros-args -r __node:=radar_front --params-file /tmp/launch_params_mr8xyxum --params-file /tmp/launch_params_pow02994

在Node中读取控制台参数的方式,示例如下:

    if (argc < 3) {
        LOG(ERROR) << argv[0] << " /dev/tty* <BaudRate>";
        exit(1);
    }

    rclcpp::init(argc, argv);
    Radar24GHz4DReader reader;
    reader.SetSerialDevice(argv[1]);
    reader.SetBaudRate(argv[2]);
注:
如果使用ros2 run方式启动节点,上述的launch启动方式,等价于:
ros2 run **-sns-radar-ros2 radar_node /dev/ttyUSB0 921600

4.2.2 对组件传递arguments控制台参数

对组件传递控制台参数是没有意义的;事实上,组件不支持传递控制台参数arguments

def generate_launch_description():
    container = ComposableNodeContainer(
        name = 'radar_container',
        namespace = '',
        package = 'rclcpp_components',
        executable = 'component_container',
        arguments=['/dev/ttyUSB0', '921600'],
        composable_node_descriptions = [
            ComposableNode(
                package = '**-sns-radar-ros2',
                plugin = 'Radar24GHz4DReader',
                name = 'radar_front',
                parameters = [
                    {'device': '/dev/ttyUSB0'},
                    {'baudrate': '921600'}
                ],
                arguments=['/dev/ttyUSB0', '921600'],
                extra_arguments = [{'use_intra_process_comms': True}]
            )
        ],
        output = 'both',
    )

    return LaunchDescription([container])

如果编写如上的launch文件,运行launch文件时,控制台会打印错误日志,如下:

[ERROR] [launch]: Caught exception in launch (see debug for traceback): Caught exception when trying to load file of format [py]: ComposableNode.__init__() got an unexpected keyword argument 'arguments'

删除第2个arguments=['/dev/ttyUSB0', '921600'],,再次运行launch文件,启动类似如下的进程:

/opt/ros/iron/lib/rclcpp_components/component_container /dev/ttyUSB0 921600 --ros-args -r __node:=radar_container -r __ns:=/

component_container容器进程接收了/dev/ttyUSB0 921600控制台参数,进程不对这些参数做处理,因此传递该参数是无意义的;

4.3 传递extra_arguments附加参数

ros2 component load命令行工具支持将附加参数传递给组件管理器,以在节点的构造函数中使用。

到目前为止,唯一支持的命令行传递的附加参数选项是,使用进程内通信来实例化节点,如下:

ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true

4.4 参数相关的命令行工具

命令行 功能
ros2 param list 查看所有节点的参数
ros2 param get <node_name> <parameter_name> 查看参数的类型和当前值
ros2 param set <node_name> <parameter_name> <_value> 在运行时更改参数
ros2 param dump <node_name> 查看节点的所有参数
ros2 param load <node_name> <parameter_file> 将参数从文件加载到当前运行的节点
ros2 run <package_name> <executable_name> --ros-args --params-file <file_name> 在启动节点时加载参数文件

5 使用launch方式启动组件

5.1 更新package.xml

对于带有launch文件的包,最好在package.xml文件中添加exec_depend依赖项,如下:

<exec_depend>ros2launch</exec_depend>

这有助于确保在构建软件包后,ros2 launch命令可用。它还确保能够识别所有的launch文件格式。

5.2 编写launch文件

launch文件的格式 优势 劣势
Python 更大的灵活性(Python是一种脚本语言,因此您可以在launch文件中使用Python及其库);因为ros2/launch(一般的launch功能)和ros2/launch_ros(ROS2特定的launch功能)是用Python编写的,因此你可以访问可能不会由XML和YAML暴露的更加底层的launch功能; 更复杂和冗长
XML 在ROS1中,launch文件是用XML编写的; -
YAML - -

5.2.1 启动新的container

import launch
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode


def generate_launch_description():
    """Generate launch description with multiple components."""
    container = ComposableNodeContainer(
            name='image_container',
            namespace='',
            package='rclcpp_components',
            executable='component_container',
            composable_node_descriptions=[
                ComposableNode(
                    package='image_tools',
                    plugin='image_tools::Cam2Image',
                    name='cam2image',
                    remappings=[('/image', '/burgerimage')],
                    parameters=[{'width': 320, 'height': 240, 'burger_mode': True, 'history': 'keep_last'}],
                    extra_arguments=[{'use_intra_process_comms': True}]),
                ComposableNode(
                    package='image_tools',
                    plugin='image_tools::ShowImage',
                    name='showimage',
                    remappings=[('/image', '/burgerimage')],
                    parameters=[{'history': 'keep_last'}],
                    extra_arguments=[{'use_intra_process_comms': True}])
            ],
            output='both',
    )

    return launch.LaunchDescription([container])

5.2.2 加载组件到已有的container

from launch import LaunchDescription
from launch_ros.actions import LoadComposableNodes, Node
from launch_ros.descriptions import ComposableNode

def generate_launch_description():
    container = Node(
        name='image_container',
        package='rclcpp_components',
        executable='component_container',
        output='both',
    )

    load_composable_nodes = LoadComposableNodes(
        target_container='image_container',
        composable_node_descriptions=[
            ComposableNode(
                package='image_tools',
                plugin='image_tools::Cam2Image',
                name='cam2image',
                remappings=[('/image', '/burgerimage')],
                parameters=[{'width': 320, 'height': 240, 'burger_mode': True, 'history': 'keep_last'}],
                extra_arguments=[{'use_intra_process_comms': True}],
            ),
            ComposableNode(
                package='image_tools',
                plugin='image_tools::ShowImage',
                name='showimage',
                remappings=[('/image', '/burgerimage')],
                parameters=[{'history': 'keep_last'}],
                extra_arguments=[{'use_intra_process_comms': True}]
            ),
        ],
    )

    return LaunchDescription([container, load_composable_nodes])

5.2.3 通过控制台指令传递参数

参考,Using Python, XML, and YAML for ROS 2 Launch Files — ROS 2 Documentation: Iron documentation

ros2 launch <package_name> <launch_file_name> background_r:=255

但实际测试的结果,如下;

执行指令:

ros2 launch $HOME/ros2_ws/src/**-sns-radar-ros2/launch/radar_component_launch.py device:=/dev/ttyUSB1 baudrate:=\"100\"

启动了如下进程:

/usr/bin/python3 /opt/ros/iron/bin/ros2 launch /home/uav/ros2_ws/src/**-sns-radar-ros2/launch/radar_component_launch.py device:=/dev/ttyUSB1 baudrate:="100"

测试结果:并未修改parameters

也可能是测试的方式有误,因为这个功能并非必须,不再深究;

6 其它

6.1 多线程支持

参考,Writing a Composable Node (C++) — ROS 2 Documentation: Iron documentation
如果您需要多线程,设置container为:
executable='component_container_mt',而不是executable='component_container'

6.2 使用rqt_graph检查系统节点

参考,Creating a launch file — ROS 2 Documentation: Iron documentation

当系统运行时,打开一个控制台并运行rqt_graph,以图形化的方式查看节点之间的关系,方框中是topic,椭圆框中是节点,如下:

image

x 参考文档

x.1 Composition — ROS 2 Documentation: Iron documentation

x.2 Setting up efficient intra-process communication — ROS 2 Documentation: Iron documentation

x.3 Managed nodes

x.4 Writing a Composable Node (C++) — ROS 2 Documentation: Iron documentation

x.5 Managing large projects — ROS 2 Documentation: Iron documentation

x.6 Creating a launch file — ROS 2 Documentation: Iron documentation

x.7 Using Python, XML, and YAML for ROS 2 Launch Files — ROS 2 Documentation: Iron documentation

x.8 Using ROS 2 launch to launch composable nodes — ROS 2 Documentation: Iron documentation

x.9 Understanding parameters — ROS 2 Documentation: Iron documentation

x.10 ros2/demos at iron

x.11 ros2/ros2cli at iron

x.12 Add callback for initalization of loaded components in rclcpp_components · Issue #2110 · ros2/rclcpp

x.13 ros2/launch: Tools for launching multiple processes and for writing tests involving multiple processes.

x.14 ros2/launch_ros: Tools for launching ROS nodes and for writing tests involving ROS nodes.

x.15 ros_tutorials/roscpp_tutorials at iron · ros/ros_tutorials

x.16 ros2/tutorials at rosidl_tutorials

x.17 guyuehome/ros2_21_tutorials

x.18 Launch - ROS2入门教程

posted on 2024-04-29 19:48  _bob  阅读(631)  评论(0编辑  收藏  举报