编写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
部分的的name
和namespace
;
// 如果未设置重映射,则节点的名字使用源码中构造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
部分的name
和namespace
;
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,椭圆框中是节点,如下:
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.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入门教程