【同一进程组织多个节点】
【同一进程组织多个节点】
注:战队现使用可组合节点组织多节点
使用执行器组织节点
示例
int main(int argc,char** argv){
rclcpp::init();
rclcpp::executors::SingThreadedExecutor executor;
auto node1=std::make_shared<Node>("node1");
auto node2=std::make_shared<Node>("node2");
executor.add_node(producer);
executor.add_node(consumer);
executor.spin();
rclcpp::shutdown();
return 0;
}
零复制传输:直接传递数据地址,不进行数据复制
订阅者接收到数据的内存地址和发布者相同
※适用条件:在同一主机进行数据传输
工程示例
src/include/learn_compose内编写hpp
src/src内编写cpp
发送端
talker.hpp
#ifndef LEARN_COMPOSE__TALKER_COMPONENT_HPP_
#define LEARN_COMPOSE__TALKER_COMPONENT_HPP_
#include"rclcpp/rclcpp.hpp"
#include"std_msgs/msg/int32.hpp"
//命名空间:防止外面的Talker和learn_compose里的Talker发生冲突
namespace learn_compose{
class Talker : public rclcpp::Node{
public:
explicit Talker(const rclcpp::NodeOptions &options);
private:
int32_t count_;
rclcpp::Publisher<std_msgs::msg::Int32>::SharedPtr pub_;
rclcpp::TimerBase::SharedPtr timer_;
};
}//namespace learn_compose
#endif //LEARN_COMPOSE__TALKER_COMPONENT_HPP_
talker.cpp
#include <chrono>
#include "learn_compose/talker.hpp"
namespace learn_compose{
using namespace std::chrono_literals;
Talker::Talker(const rclcpp::NodeOptions &options) : Node("talker",options){
pub_=this->create_publisher<std_msgs::msg::Int32>("count",10);
auto callback=[&]()->void{
//独占式智能指针
std_msgs::msg::Int32::UniquePtr msg(new std_msgs::msg::Int32());
msg->data=count_++;
RCLCPP_INFO(this->get_logger(),"发布数据:%d(0x%1X),msg->data",
reinterpret_cast<std::uintptr_t>(msg.get()));
//reinterpret_cast强制类型转换(偏底层)
pub_->publish(std::move(msg));
};
timer_=this->create_wall_timer(1s,callback);
}
}//namespace learn_compose
接收端
listener.hpp
#ifndef LEARN_COMPOSE__LISTENER_COMPONENT_HPP_
#define LEARN_COMPOSE__LISTENER_COMPONENT_HPP_
#include"rclcpp/rclcpp.hpp"
#include"std_msgs/msg/int32.hpp"
namespace learn_compose{
class Listener : public rclcpp::Node{
public:
explicit Listener(const rclcpp::NodeOptions &options);
private:
rclcpp::Subscription<std_msgs::msg::Int32>::SharedPtr sub_;
};
}//namespace learn_compose
#endif //LEARN_COMPOSE__LISTENER_COMPONENT_HPP_
listener.cpp
#include"learn_compose/listener.hpp"
#include<chrono>
namespace learn_compose{
using namespace std::chrono_literals;
Listener::Listener(const rclcpp::NodeOptions &options) : Node("listener",options){
sub_=this->create_subscription<std_msgs::msg::Int32>(
"count",10,[&](const std_msgs::msg::Int32::UniquePtr msg){
RCLCPP_INFO(this->get_logger(),"收到数据:%d(0x%1X)",msg->data,
reinterpret_cast<std::uintptr_t>(msg.get()));
}
);
}
}//namespace learn_compose
主进程 intra_process_pubsub.cpp
#include"learn_compose/listener.hpp"
#include"learn_compose/talker.hpp"
#include"rclcpp/rclcpp.hpp"
int main(int argc,char** argv){
rclcpp::init(argc,argv);
rclcpp::executors::SingleThreadedExecutor executor;
rclcpp::NodeOptions options;//创建节点选项
options.use_intra_process_comms(true);//使用进程内通信
auto talker=std::make_shared<learn_compose::Talker>(options);
auto listener=std::make_shared<learn_compose::Listener>(options);
executor.add_node(talker);
executor.add_node(listener);
executor.spin();
rclcpp::shutdown();
return 0;
}
CMakeList.txt
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(rclcpp_components REQUIRED)
//包含库(include文件)
include_directories(include)
//一个exe要由三份代码构建
add_executable(intra_process_pubsub
src/intra_process_pubsub.cpp
src/talker.cpp
src/listener.cpp
)
ament_target_dependencies(intra_process_pubsub std_msgs rclcpp rclcpp_components)
install(TARGETS intra_process_pubsub
DESTINATION lib/${PROJECT_NAME})
运行结果
使用组件组合节点
功能
可动态的将不同节点加载到一个进程,也可动态卸载
命令行(利用示例程序)
//查看已经注册的可用组件
$ ros2 component types
composition
composition::Talker
composition::Listener
composition::NodeLikeListener
composition::Server
composition::Client
//启动节点容器(组件管理器)
$ ros2 run rclcpp_components component_container --ros-args -r __node:=component_test
//查看组件列表
$ ros2 component list
/component_test
//将节点加载到组件容器内
$ ros2 component load /component_test composition composition::Talker
Loaded component 1 into '/component_test' container node as '/talker'
$ ros2 component load /component_test composition composition::Listener
Loaded component 2 into '/component_test' container node as '/listener'
/*
修改节点名字 --node-name talker3
修改节点命名空间 --node-namespace /ns
传递参数值 -p name:=value
*/
//卸载节点
$ ros2 component list
/component_test
1 /talker
2 /listener
$ ros2 component unload /component_test 1 2
Unloaded component 1 from '/component_test' container node
Unloaded component 2 from '/component_test' container node
在启动文件动态加载/卸载
# 示例:启动component_test并加载Talker和Listener节点
import launch
from launch_ros.actions import ComposableNodeContainer
from launch_ros.discriptions import ComposableNode
def generate_launch_description():
continer=ComposableNodeContainer(
name='component_test'
namespace=''
package='rclcpp_components'
executable='component_container',
composable_node_description=[
ComposableNode(
package='composition',
plugin='composition::Talker',
name='talker'
),
ComposableNode(
package='composition',
plugin='composition::Listener',
name='listener'
),
],
output='screen',
)
return launch.LaunchDescription([continer])
编写自己的节点
(1)提供const rclcpp::NodeOptions &
作为参数的构造函数
(2)对节点类进行注册
注册节点为组件
cpp文件内
#include"rclcpp_components/register_node_macro.hpp"
RCLCPP_COMPONENTS_REGISTER_NODE(learn_compose::Talker/Listener)
CMakeLists.txt
# 生成动态库
add_library(talker_component SHARED src/talker.cpp)
ament_target_dependencies(talker_component "std_msgs" "rclcpp" "rclcpp_components")
rclcpp_components_register_nodes(talker_component "learn_compose::Talker")
add_library(listener_component SHARED src/listener.cpp)
ament_target_dependencies(listener_component "std_msgs" "rclcpp" "rclcpp_components")
rclcpp_components_register_nodes(listener_component "learn_compose::Listener")
install(TARGETS talker_component listener_component
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)