文章目录
1、概述
在 ROS (Robot Operating System) 中,每个进程通常只能通过 ros::init 初始化一个节点。ROS 的设计是基于一个进程对应一个节点的理念。如果你需要多个节点,通常需要使用多个进程,每个进程各自初始化自己的 ROS 节点。
不过,有一些方法可以绕过这一限制,具体取决于你为何需要在一个进程中创建多个节点。以下是一些替代方案:
-
方法 1:创建多个命名空间
-
方法 2:使用多线程
-
方法 3:节点间通信(分离进程)
2、方法 1:创建多个命名空间
虽然一个进程只能初始化一次 ROS 节点,但你可以使用不同的命名空间或创建子节点来模拟多个节点的功能。你可以使用 ros::NodeHandle 的不同命名空间创建不同的 NodeHandle 实例来管理多个逻辑节点。
#include <ros/ros.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "multi_node_example");
// 创建全局节点句柄
ros::NodeHandle nh_global;
// 创建两个不同命名空间的 NodeHandle
ros::NodeHandle nh1("namespace1");
ros::NodeHandle nh2("namespace2");
// 在命名空间1中发布
ros::Publisher pub1 = nh1.advertise<std_msgs::String>("topic1", 1000);
// 在命名空间2中发布
ros::Publisher pub2 = nh2.advertise<std_msgs::String>("topic2", 1000);
ros::Rate loop_rate(10);
while (ros::ok()) {
// 在两个不同命名空间发布消息
std_msgs::String msg;
msg.data = "Hello from node1!";
pub1.publish(msg);
msg.data = "Hello from node2!";
pub2.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
在这种情况下,虽然进程中只有一个实际的 ROS 节点,但你可以通过不同的命名空间创建类似多节点的逻辑结构。
3、方法 2:使用多线程
如果你需要在一个进程中分离逻辑来实现多节点的效果,可以通过多线程来实现不同节点的功能。虽然依然只有一个 ROS 节点,但你可以在不同的线程中执行不同的功能。
#include <ros/ros.h>
#include <thread>
void thread1Function() {
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("thread1_topic", 1000);
ros::Rate loop_rate(10);
while (ros::ok()) {
std_msgs::String msg;
msg.data = "Message from thread 1";
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
}
void thread2Function() {
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<std_msgs::String>("thread2_topic", 1000);
ros::Rate loop_rate(10);
while (ros::ok()) {
std_msgs::String msg;
msg.data = "Message from thread 2";
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
}
int main(int argc, char **argv) {
ros::init(argc, argv, "multi_thread_node");
std::thread thread1(thread1Function);
std::thread thread2(thread2Function);
thread1.join();
thread2.join();
return 0;
}
这个例子展示了如何在同一个进程中运行多个发布者,每个发布者运行在自己的线程中,并发布到不同的话题上。
4、方法 3:节点间通信(分离进程)
如果你真正需要多个 ROS 节点,最佳实践仍然是将它们分开到不同的进程中。每个进程可以通过 ros::init 初始化自己的节点,节点之间通过 ROS 的话题、服务或动作通信。
你可以使用 launch 文件来同时启动多个节点:
launch 文件示例:
<launch>
<node name="node1" pkg="your_package" type="node1_executable" output="screen"/>
<node name="node2" pkg="your_package" type="node2_executable" output="screen"/>
</launch>
这样,你可以启动多个独立的节点,它们都可以运行在不同的进程中并相互通信。
4、实际验证不可行方案1:两次调用 ros::init
通过实际验证,此方案并未达到创建两个ROS节点的效果。
在这个例子中,我们定义了两个回调函数nodeOneCallback和nodeTwoCallback,它们分别由两个独立的节点使用。每个节点使用ros::init初始化,并使用ros::NodeHandle创建订阅者来接收消息。然后,我们使用ros::AsyncSpinner来启动无限循环,处理来自不同节点的回调函数。
#include <ros/ros.h>
#include <ros/callback_queue.h>
#include "std_msgs/String.h"
void Callback1(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("Node std_msgs::String1 is running.");
}
void Callback2(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("Node std_msgs::String2 is running.");
}
// 第一个节点的回调函数
void nodeOneCallback()
{
ROS_INFO("Node One is running.");
}
// 第二个节点的回调函数
void nodeTwoCallback()
{
ROS_INFO("Node Two is running.");
}
int main(int argc, char **argv)
{
// 初始化节点一
ros::init(argc, argv, "node_one");
// 创建全局节点句柄
ros::NodeHandle nh_global;
ros::NodeHandle nh_one("namespace1");
ros::CallbackQueue callback_queue_one;
nh_one.setCallbackQueue(&callback_queue_one);
// 初始化节点二
ros::init(argc, argv, "node_two");
ros::NodeHandle nh_two("namespace2");
ros::CallbackQueue callback_queue_two;
nh_two.setCallbackQueue(&callback_queue_two);
// 创建一个节点一的订阅者,并设置回调函数
ros::Subscriber sub_one = nh_one.subscribe("/topic_one", 10, &Callback1);
// 创建一个节点二的订阅者,并设置回调函数
ros::Subscriber sub_two = nh_two.subscribe("/topic_two", 10, Callback2);
// 启动回调队列处理循环
ros::AsyncSpinner spinner_one(1, &callback_queue_one);
ros::AsyncSpinner spinner_two(1, &callback_queue_two);
spinner_one.start();
spinner_two.start();
ros::waitForShutdown();
return 0;
}
CMakeList.txt
cmake_minimum_required(VERSION 3.0.2)
project(twice_RosInit)
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS "-O3")
## 4. Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs)
## 1. Build talker and listener
include_directories(include ${catkin_INCLUDE_DIRS})
# 添加Eigen头文件
add_executable(twice_RosInit
twice_RosInit.cpp)
# target_link_libraries(eigenMatrix ${Boost_LIBRARIES})
target_link_libraries(twice_RosInit ${Boost_FILESYSTEM_LIBRARY} ${catkin_LIBRARIES})
实际运行后,通过rosnode list 命令查看,只有一个ROS节点在运行:
rosnode list
运行结果:
node_one
标签:nh,ROS,创建,msg,ros,NodeHandle,节点
From: https://blog.csdn.net/BullKing8185/article/details/141968179