ROS2--在单进程中加入多个节点
前言
阅读本章之前,确保已经了解ROS2中构件(Component)的概念,如果不了解,欢迎移步ROS2 Composition
一个小问题自测:构件与节点之间的区别?在容器进程中运行的单元是构件还是节点?
执行demo
本文通过执行几个demo,来直观展示composition的常见使用方式。
run-time 动态加载
foxy源码demos中的composition已经实现了一些构件,不妨确认一下:
$ ros2 component type
compositioncomposition::Talkercomposition::Listenercomposition::Servercomposition::Client
我们将多个节点加载到单个进程的步骤是:首先创建一个容器进程,然后通过ros2 的api向这个容器进程中动态加载。
创建容器进程:ros2 run rclcpp_components component_container
确认容器进程正在运行:ros2 component list
在另一个终端中,输入命令加载构件:ros2 component load /ComponentManager composition composition::<component_name>
我们此时可以看到容器进程终端有相应的内容输出。
编译期加载
同样的shared lib也可以在代码中在编译期加载,可以看一下manual_composition.cpp的源码:
// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.#include <memory>#include "composition/client_component.hpp"
#include "composition/listener_component.hpp"
#include "composition/talker_component.hpp"
#include "composition/server_component.hpp"
#include "rclcpp/rclcpp.hpp"int main(int argc, char * argv[])
{// Force flush of the stdout buffer.setvbuf(stdout, NULL, _IONBF, BUFSIZ);// Initialize any global resources needed by the middleware and the client library.// This will also parse command line arguments one day (as of Beta 1 they are not used).// You must call this before using any other part of the ROS system.// This should be called once per process.rclcpp::init(argc, argv);// 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);// spin will block until work comes in, execute work as it becomes available, and keep blocking.// It will only be interrupted by Ctrl-C.exec.spin();rclcpp::shutdown();return 0;
}
代码很简单,不多赘述。随后执行:ros2 run composition manual_composition
运行时从静态库加载
大致的思路是通过静态库新建一个node实例,从而达到加载的目的。代码如下:
// Copyright 2016 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.#include <memory>
#include <string>
#include <vector>#include "class_loader/class_loader.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_components/node_factory.hpp"#define DLOPEN_COMPOSITION_LOGGER_NAME "dlopen_composition"int main(int argc, char * argv[])
{// Force flush of the stdout buffer.setvbuf(stdout, NULL, _IONBF, BUFSIZ);if (argc < 2) {fprintf(stderr, "Requires at least one argument to be passed with the library to load\n");return 1;}rclcpp::init(argc, argv);rclcpp::Logger logger = rclcpp::get_logger(DLOPEN_COMPOSITION_LOGGER_NAME);rclcpp::executors::SingleThreadedExecutor exec;rclcpp::NodeOptions options;std::vector<class_loader::ClassLoader *> loaders;std::vector<rclcpp_components::NodeInstanceWrapper> node_wrappers;std::vector<std::string> libraries;for (int i = 1; i < argc; ++i) {libraries.push_back(argv[i]);}for (auto library : libraries) {RCLCPP_INFO(logger, "Load library %s", library.c_str());auto loader = new class_loader::ClassLoader(library);auto classes = loader->getAvailableClasses<rclcpp_components::NodeFactory>();for (auto clazz : classes) {RCLCPP_INFO(logger, "Instantiate class %s", clazz.c_str());auto node_factory = loader->createInstance<rclcpp_components::NodeFactory>(clazz);auto wrapper = node_factory->create_node_instance(options);auto node = wrapper.get_node_base_interface();node_wrappers.push_back(wrapper);exec.add_node(node);}loaders.push_back(loader);}exec.spin();for (auto wrapper : node_wrappers) {exec.remove_node(wrapper.get_node_base_interface());}node_wrappers.clear();rclcpp::shutdown();return 0;
}
需要注意的是我们需要在命令行中显式地指出使用的静态库:
ros2 run composition dlopen_composition
ros2 pkg prefix composition/lib/libtalker_component.so
ros2 pkg prefix composition/lib/liblistener_component.so
这样就把talker和listener组件加载到了容器进程中。
我们看到从代码中加载的构件也是需要新起一个线程作为容器进程。
使用launch实现Composition
可以通过ros2 launch
指令批量加载构件:ros2 launch composition composition_demo.launch.py
Advanced Topic
上面介绍的是一些基础用法,现在来看一些进阶的做法。
Unloading Component
假设我们在容器中加载了listener和talker,我们可以通过构件的id来卸载他们:
$ ros2 component unload /ComponentManager 1 2
Unloaded component 1 from '/ComponentManager' container
Unloaded component 2 from '/ComponentManager' container
Remapping container name and namespace
我们可以通过命令行参数重命名容器进程:
ros2 component rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns
那么在加载构件的终端中,我们就可以使用:
ros2 component load /ns/MyContainer composition composition::Listener
Remapping component name and namespace
类似地,我们可以remapping构件的名字和命名空间:
$ ros2 run rclcpp_components component_container
$ ros2 component load /ComponentManager composition composition::Talker --node-name talker2
$ ros2 component load /ComponentManager composition composition::Talker --node-namespace /ns
$ ros2 component load /ComponentManager composition composition::Talker --node-name talker3 --node-namespace /ns2
看一下输出:
$ ros2 component list
/ComponentManager1 /talker22 /ns/talker3 /ns2/talker3
ROS2--在单进程中加入多个节点相关推荐
- ROS2承上启下【05】:在单个进程中布置多个节点
一.关于组件的背景知识 1.1 ROS 1 - 节点与 Nodelets 在 ROS 1 中,您可以将代码编写为 ROS 节点或 ROS nodelet. ROS 1 节点被编译成可执行文件.另一方面 ...
- asp.net中web.config配置节点大全详解
web.config 文件查找规则: (1)如果在当前页面所在目录下存在web.config文件,查看是否存在所要查找的结点名称,如果存在返回结果并停止查找. (2)如果当 ...
- 【 C 】在单链表中插入一个新节点的尝试(二)
在上篇博文中:[ C ]在单链表中插入一个新节点的尝试(一),我们最后提到了如果向单链表的开头(起始位置)插入一个节点,上篇博文中给出的程序显然完成不了这任务. 这篇博文中,我们将解决这个问题,给出一 ...
- 【 C 】在单链表中插入一个新节点的尝试(一)
根据<C和指针>中讲解链表的知识,记录最终写一个在单链表中插入一个新节点的函数的过程,这个分析过程十分的有趣,准备了两篇博文,用于记录这个过程. 链表是以结构体和指针为基础的,所以结构体和 ...
- [转]NS2仿真过程中解决动画仿真节点未定义问题
原文地址:http://blog.myspace.cn/e/400266384.htm 其实,这个问题已经出现很长时间了,但是直到昨天问题才得到解决. 问题描述 用NS2运行无线仿真,然后运行动画程序 ...
- 二叉树中如何求根节点到任意节点的路径?
二叉树中如何求任一节点的路径呢? 思路 使用先序遍历,处理的时候让节点入栈,并且加上标志位即可. 使用另外的result保存最终的路径. 函数 void pre_order(TreeNode * no ...
- 【深度学习】网络中隐含层神经元节点的个数(需要学习的特征数目)
http://blog.csdn.net/zouxy09/article/details/9983399 1.网络中隐含层神经元节点的个数(需要学习的特征数目),采集的密度(也就是convolutio ...
- Elasticsearch 集群中增加专用master节点
Elasticsearch 集群中增加专用master节点 文章目录 Elasticsearch 集群中增加专用master节点 1.增加master节点 2.排除原来的节点的选举权 3.data节点 ...
- 数据结构与算法--两个链表中第一个公共节点
链表中第一个公共节点 公节点定义:同一个节点在两个链表中,并不是节点值相同 题目:输入两个节点,找出他们的第一个公共节点,节点定义如需 /*** 链表元素节点** @author liaojiamin ...
最新文章
- 【微信小程序企业级开发教程】微信小程序目录结构
- python turtle画彩虹-Python turtle 绘制彩色螺旋线
- 在C语言中以编程的方式获取函数名
- sql语句多个表补齐四位_SQL学习笔记 - CTE通用表表达式和WITH用法
- 【REST SOAP】REST和SOAP Web Service的区别比较
- ASP.NET CORE 项目实战 ---图形验证码的实现
- 如何才能做出一个顶级的客户端
- 整个计算机系统结构图,计算机系统结构复习(16页)-原创力文档
- libcmtd.lib(wincrt0.obj) : error LNK2019: 无法解析的外部符号 WinMain,该符号在函数 __tmainCRTStartup 中被引用
- yuv420转yuv422(yuyv)
- css判断手机端还是pc端,JavaScript判断设备是手机端还是PC端,并加载不同的css/js文件...
- 24点计算器问题[C++实现]
- php微信公众号模板消息主动推送
- vue 菜单路由重复点击报错
- 职业“小三劝退师”,真的能拯救你的婚姻吗?
- DB2 SQL错误查询 LOAD时报的日志特别好用
- 成为PHP大牛的绝招 —— 君子生非异也,善假于物也
- 个人读书思维导图笔记之mysql-innodb之操作函数相关
- 有限元(FEM)基本知识速阅
- 全球大健康领袖集聚上海浦东,上海燕博会又要有大动作?
热门文章
- 为什么要实现Serializable
- 服务sql server(MSSQLSERVER)意外停止。这发生了2次。
- Xcode Command Line Tools命令
- 鸿蒙手机壁纸有条纹,百变图标(鸿蒙)
- 上海PHICOMM斐讯短短五年时间市场为何能扩大成这样?
- 【第80篇】Lion:优化算法的符号发现
- linux:作业控制 jobs命令 kill命令 bg和fg命令
- Leetcode-搜索-130.被围绕的区域(中等)
- 汉子编码比字母编码长_编码比您想象的更具创意
- python 类中的 __getitem__方法