目录
起点
代码更新
添加包依赖
类定义
没有主方法
CMake 变更
运行您的节点
起点
我们假设你有一个常规的 rclcpp::Node
可执行文件,你希望在与其他节点相同的进程中运行它,以实现更高效的通信。
我们将从一个直接继承自 Node
的类开始,并且定义了一个主方法。
namespace palomino
{class VincentDriver : public rclcpp::Node{// ...};
}int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<palomino::VincentDriver>());rclcpp::shutdown();return 0;
}
这通常会在您的 Cmake 中编译为可执行文件。
# ...
add_executable(vincent_driver src/vincent_driver.cpp)
# ...
install(TARGETS vincent_driverDESTINATION lib/${PROJECT_NAME}
)
代码更新
添加包依赖项
您的 package.xml 应该依赖于 rclcpp_components
,类似于
<depend>rclcpp_components</depend>
或者,您可以独立添加一个 build_depend/exec_depend
。
<?xml version="1.0"?>
<!-- XML 版本声明 --><?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<!-- XML 模型声明,定义了 ROS 包的格式 --><package format="3">
<!-- 开始定义一个 ROS 包,格式为 3 --><name>composition</name><!-- 包的名称为 composition --><version>0.33.4</version><!-- 包的版本号为 0.33.4 --><description>Examples for composing multiple nodes in a single process.</description><!-- 包的描述 --><maintainer email="aditya.pande@openrobotics.org">Aditya Pande</maintainer><maintainer email="audrow@openrobotics.org">Audrow Nash</maintainer><!-- 维护者的信息 --><license>Apache License 2.0</license><!-- 许可证信息 --><author email="dthomas@osrfoundation.org">Dirk Thomas</author><author email="mabel@openrobotics.org">Mabel Zhang</author><!-- 作者的信息 --><buildtool_depend>ament_cmake</buildtool_depend><!-- 构建工具依赖项 --><build_depend>example_interfaces</build_depend><build_depend>rclcpp</build_depend><build_depend>rclcpp_components</build_depend><build_depend>rcutils</build_depend><build_depend>std_msgs</build_depend><!-- 构建依赖项 --><exec_depend>example_interfaces</exec_depend><exec_depend>launch_ros</exec_depend><exec_depend>rclcpp</exec_depend><exec_depend>rclcpp_components</exec_depend><exec_depend>rcutils</exec_depend><exec_depend>std_msgs</exec_depend><!-- 执行依赖项 --><test_depend>ament_cmake_pytest</test_depend><test_depend>ament_lint_auto</test_depend><test_depend>ament_lint_common</test_depend><test_depend>launch</test_depend><test_depend>launch_testing</test_depend><test_depend>launch_testing_ros</test_depend><test_depend>launch_testing_ament_cmake</test_depend><test_depend>rmw_implementation_cmake</test_depend><!-- 测试依赖项 --><export><build_type>ament_cmake</build_type></export><!-- 导出构建类型 --></package>
<!-- 结束定义 ROS 包 -->
类定义
您的类定义唯一可能需要更改的是确保类的构造函数https://github.com/ros2/demos/blob/jazzy/composition/src/talker_component.cpp 接受一个 NodeOptions
参数。
VincentDriver(const rclcpp::NodeOptions & options) : Node("vincent_driver", options)
{// ...
}
// 版权声明
// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// 根据 Apache License 2.0(“许可证”)许可;
// 除非遵守许可证,否则不得使用此文件。
// 您可以在以下位置获取许可证副本:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// 除非适用法律要求或书面同意,否则在许可证下分发的软件
// 将按“原样”基础分发,无任何形式的明示或暗示保证。
// 请参阅许可证以了解管理权限和
// 许可证下的限制。// 导入 Talker 组件头文件
#include "composition/talker_component.hpp"// 导入所需的标准库
#include <chrono>
#include <iostream>
#include <memory>
#include <utility>// 导入 ROS 客户端库和标准消息
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"// 使用 std::chrono_literals 命名空间
using namespace std::chrono_literals;// 定义 composition 命名空间
namespace composition
{// 创建一个 Talker “组件”,该组件继承自通用的 rclcpp::Node 基类。
// 组件被构建成共享库,因此不编写自己的主函数。
// 使用组件的共享库的进程将实例化该类作为 ROS 节点。
Talker::Talker(const rclcpp::NodeOptions & options)
: Node("talker", options), count_(0)
{// 在 "chatter" 主题上创建一个 "std_mgs/String" 消息的发布者。pub_ = create_publisher<std_msgs::msg::String>("chatter", 10);// 使用定时器来定期发布消息。timer_ = create_wall_timer(1s, this {return this->on_timer();});
}// 定时器回调函数
void Talker::on_timer()
{// 创建一个独特的消息auto msg = std::make_unique<std_msgs::msg::String>();// 设置消息数据msg->data = "Hello World: " + std::to_string(++count_);// 记录发布信息RCLCPP_INFO(this->get_logger(), "发布: '%s'", msg->data.c_str());// 刷新标准输出std::flush(std::cout);// 将消息放入队列中,由中间件处理。// 此调用是非阻塞的。pub_->publish(std::move(msg));
}} // namespace composition 结束// 导入节点注册宏
#include "rclcpp_components/register_node_macro.hpp"// 使用 class_loader 注册组件。
// 这相当于一个入口点,允许在其库被加载到正在运行的进程时发现组件。
RCLCPP_COMPONENTS_REGISTER_NODE(composition::Talker)
没有主方法了
将您的主方法替换为 pluginlib
风格的宏调用。
#include <rclcpp_components/register_node_macro.hpp>
RCLCPP_COMPONENTS_REGISTER_NODE(palomino::VincentDriver)
小心
如果您要替换的主方法包含 MultiThreadedExecutor
,请务必记下并确保您的容器节点是多线程的。请参阅下面的部分。
CMake 变更
首先,在 CMakeLists.txt 中添加 rclcpp_components
作为依赖项:
find_package(rclcpp_components REQUIRED)
其次,我们将用一个新的目标名称替换我们的 add_executable
为 add_library
。
add_library(vincent_driver_component src/vincent_driver.cpp)
第三,将使用旧目标的其他构建命令替换为作用于新目标的命令。即 ament_target_dependencies(vincent_driver ...)
变为 ament_target_dependencies(vincent_driver_component ...)
第四,添加一个新命令来声明您的组件。
rclcpp_components_register_node(vincent_driver_componentPLUGIN "palomino::VincentDriver"EXECUTABLE vincent_driver
)
第五,最后,将 CMake 中的任何安装命令从操作旧目标更改为安装库版本。例如,不要将任何目标安装到 lib/${PROJECT_NAME}
中。请用库安装替换。
ament_export_targets(export_vincent_driver_component)
install(TARGETS vincent_driver_componentEXPORT export_vincent_driver_componentARCHIVE DESTINATION libLIBRARY DESTINATION libRUNTIME DESTINATION bin
)
运行您的节点
查看组合教程https://docs.ros.org/en/jazzy/Tutorials/Intermediate/Composition.html ,以深入了解节点的组合。快速而简洁的版本是,如果您在 Python 启动文件中有以下内容,
from launch_ros.actions import Node# ..ld.add_action(Node(package='palomino',executable='vincent_driver',# ..
))
你可以将它替换掉
from launch_ros.actions import ComposableNodeContainer
from launch_ros.descriptions import ComposableNode# ..
ld.add_action(ComposableNodeContainer(name='a_buncha_nodes',namespace='',package='rclcpp_components',executable='component_container',composable_node_descriptions=[ComposableNode(package='palomino',plugin='palomino::VincentDriver',name='vincent_driver',# ..extra_arguments=[{'use_intra_process_comms': True}],),]
))
小心
如果您需要多线程,请不要将可执行文件设置为 component_container
,而应将其设置为 component_container_mt