首页 > 系统相关 >ROS - 一个进程中创建多个ROS节点

ROS - 一个进程中创建多个ROS节点

时间:2024-09-08 16:49:45浏览次数:5  
标签:nh ROS 创建 msg ros NodeHandle 节点

文章目录

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

相关文章

  • kubelet监控worker节点如何实现
    Kubelet是Kubernetes中的关键组件,负责在每个工作节点(workernode)上管理容器和Pod。监控工作节点的状态和性能是Kubelet的重要功能之一。以下是Kubelet监控工作节点的实现原理和方式:1.NodeStatusReporting心跳机制:Kubelet定期向KubernetesAPIServer发送心跳信......
  • k8s节点维护注意事项
    在Kubernetes中,对节点进行维护时,需要遵循一些最佳实践和注意事项,以确保集群的稳定性和可用性。以下是一些关键的注意事项:1.提前计划维护窗口选择合适的时间:选择一个低负载时段进行维护,以减少对用户的影响。通知团队:提前通知相关团队和用户,确保他们了解维护时间和可能的影响......
  • 虚拟机安装Ubuntu16并安装Ros(Kinetic)
    1.虚拟机安装镜像教程参考:https://www.cnblogs.com/su1961117443/p/12419892.html或者https://www.bilibili.com/video/BV1zt411G7Vn?p=2可以安装vmtools,界面显示窗口自适应。2.ROS各个版本注:因为ubuntu是16.04的,所以这里我们安装Kinetic版本的ROS.参考链接:https://blog.csdn.ne......
  • 复制Monkeytype:如何创建一个高效的打字练习应用
    要想创建一个高效的打字练习应用,核心在于打造一个用户友好、功能全面且富有互动性的体验。Monkeytype作为一个备受欢迎的打字练习平台,为许多人提高打字速度和准确率提供了帮助。如何复制Monkeytype的成功经验,打造一个类似的高效打字练习应用呢?界面设计是关键。一个好的打字练习应......
  • cross-plateform 跨平台应用程序-01-概览
    跨平台系列cross-plateform跨平台应用程序-01-概览cross-plateform跨平台应用程序-02-有哪些主流技术栈?cross-plateform跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?cross-plateform跨平台应用程序-04-ReactNative介绍cross-plateform跨平台应用程序-05-Flut......
  • JDBC创建数据库实例
    在本教程将演示如何在JDBC应用程序中创建数据库。在执行以下示例之前,请确保您已经准备好以下操作:具有数据库管理员权限,以在给定模式中创建数据库。要执行以下示例,需要用实际用户名和密码替换这里用户名(username)和密码(password)。MySQL或数据库已启动并运行。所需步骤使......
  • 节点NotReady可能的原因?会导致哪些问题?
    在Kubernetes集群中,节点状态为NotReady表示该节点无法正常工作,可能会导致各种问题。以下是节点NotReady的常见原因以及可能引发的问题:可能的原因网络问题原因:节点与控制平面或其他节点之间的网络连接不稳定或中断。影响:无法进行心跳检测和状态更新。资源不足原......
  • pod创建Pending状态的原因
    在Kubernetes(K8s)中,Pod的状态可能会变为“Pending”,这通常表示Pod尚未能够成功调度或启动。以下是一些常见原因:1.资源不足节点资源不足:如果集群中的节点没有足够的CPU、内存或其他资源来满足Pod的请求,Pod将处于Pending状态。节点标签和选择器不匹配:如果Pod使用了节点选择器(nod......
  • tkinter搭建GUI软件框架并创建不同的Frame界面实现不同的功能
    引言    在本篇博客中,小编要带大家解决的问题是如何创建一个软件窗口对象,并在窗口顶部菜单中通过按钮实现不同Frame界面的切换,在不同的Frame页面中实现访问路径等不同的功能,其中每行代码代表的意思,小编也在相应代码后面进行了注释,此外,代码在排版上也非常规范,各位小可爱......
  • 简述Pod创建过程
    在Kubernetes(K8s)中,Pod是最基本的部署单位,其创建过程涉及多个步骤。以下是Pod创建的简要流程:1.定义Pod规范用户通过YAML或JSON文件定义Pod的规格(spec),包括容器镜像、环境变量、存储卷等信息。2.提交请求用户使用kubectl命令行工具或K8sAPI将Pod的定义提交给Kubernetes集群。......