ROS(二)自己动手写一个简单的发布(Publisher)、订阅(Subscriber)程序

ROS版本:indigo

Linux版本:Ubuntu14.04

在开始第一个ROS(Robot Operating System)程序之前,确保已经按照官方教程成功安装了ROS。本文建立的是一个非常简单的发布(Publisher)、订阅(Subscriber)程序.

一个简单的发布(Publisher)、订阅(Subscriber)程序
写一个发布(Publisher)节点

节点(node)是连接到ROS网络中可执行的基本单元。我们在这创建一个发布者—“talker”节点,这个节点持续对外发布消息。

首先我们要把目录切换到我们的beginner_tutorials工程包中。

$ cd ~/catkin_ws/src/beginner_tutorials  

因为我们已经编译过这个工程包了,所以会在beginner_tutorials文件夹下看到CmakeList.txt、package.xml文件和include、src这两个目录。接下来进入src子目录

$ cd src 

在src目录中创建一个talker.cpp文件,里面的内容如下:

 #include "ros/ros.h"  
    #include "std_msgs/String.h"  

    #include <sstream>  
    int main(int argc, char **argv)  
    {  
      /** 
       * The ros::init() function needs to see argc and argv so that it can perform 
       * any ROS arguments and name remapping that were provided at the command line. For programmatic 
       * remappings you can use a different version of init() which takes remappings 
       * directly, but for most command-line programs, passing argc and argv is the easiest 
       * way to do it.  The third argument to init() is the name of the node. 
       * 
       * You must call one of the versions of ros::init() before using any other 
       * part of the ROS system. 
       */  
      ros::init(argc, argv, "talker");  

      /** 
       * NodeHandle is the main access point to communications with the ROS system. 
       * The first NodeHandle constructed will fully initialize this node, and the last 
       * NodeHandle destructed will close down the node. 
       */  
      ros::NodeHandle n;  

      /** 
       * The advertise() function is how you tell ROS that you want to 
       * publish on a given topic name. This invokes a call to the ROS 
       * master node, which keeps a registry of who is publishing and who 
       * is subscribing. After this advertise() call is made, the master 
       * node will notify anyone who is trying to subscribe to this topic name, 
       * and they will in turn negotiate a peer-to-peer connection with this 
       * node.  advertise() returns a Publisher object which allows you to 
       * publish messages on that topic through a call to publish().  Once 
       * all copies of the returned Publisher object are destroyed, the topic 
       * will be automatically unadvertised. 
       * 
       * The second parameter to advertise() is the size of the message queue 
       * used for publishing messages.  If messages are published more quickly 
       * than we can send them, the number here specifies how many messages to 
       * buffer up before throwing some away. 
       */  
      ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);  

      ros::Rate loop_rate(10);  

      /** 
       * A count of how many messages we have sent. This is used to create 
       * a unique string for each message. 
       */  
      int count = 0;  
      while (ros::ok())  
      {  
        /** 
         * This is a message object. You stuff it with data, and then publish it. 
         */  
        std_msgs::String msg;  

        std::stringstream ss;  
        ss << "hello world " << count;  
        msg.data = ss.str();  

        ROS_INFO("%s", msg.data.c_str());  

        /** 
         * The publish() function is how you send messages. The parameter 
         * is the message object. The type of this object must agree with the type 
         * given as a template parameter to the advertise<>() call, as was done 
         * in the constructor above. 
         */  
        chatter_pub.publish(msg);  

        ros::spinOnce();  

        loop_rate.sleep();  
        ++count;  
      }  


      return 0;  
    }  

写一个订阅(Subscriber)节点
还是在src目录下,创建一个listener.cpp文件。内容如下:

#include "ros/ros.h"  
    #include "std_msgs/String.h"  

    /** 
     * This tutorial demonstrates simple receipt of messages over the ROS system. 
     */  
    void chatterCallback(const std_msgs::String::ConstPtr& msg)  
    {  
      ROS_INFO("I heard: [%s]", msg->data.c_str());  
    }  

    int main(int argc, char **argv)  
    {  
      /** 
       * The ros::init() function needs to see argc and argv so that it can perform 
       * any ROS arguments and name remapping that were provided at the command line. For programmatic 
       * remappings you can use a different version of init() which takes remappings 
       * directly, but for most command-line programs, passing argc and argv is the easiest 
       * way to do it.  The third argument to init() is the name of the node. 
       * 
       * You must call one of the versions of ros::init() before using any other 
       * part of the ROS system. 
       */  
      ros::init(argc, argv, "listener");  

      /** 
       * NodeHandle is the main access point to communications with the ROS system. 
       * The first NodeHandle constructed will fully initialize this node, and the last 
       * NodeHandle destructed will close down the node. 
       */  
      ros::NodeHandle n;  

      /** 
       * The subscribe() call is how you tell ROS that you want to receive messages 
       * on a given topic.  This invokes a call to the ROS 
       * master node, which keeps a registry of who is publishing and who 
       * is subscribing.  Messages are passed to a callback function, here 
       * called chatterCallback.  subscribe() returns a Subscriber object that you 
       * must hold on to until you want to unsubscribe.  When all copies of the Subscriber 
       * object go out of scope, this callback will automatically be unsubscribed from 
       * this topic. 
       * 
       * The second parameter to the subscribe() function is the size of the message 
       * queue.  If messages are arriving faster than they are being processed, this 
       * is the number of messages that will be buffered up before beginning to throw 
       * away the oldest ones. 
       */  
      ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);  

      /** 
       * ros::spin() will enter a loop, pumping callbacks.  With this version, all 
       * callbacks will be called from within this thread (the main one).  ros::spin() 
       * will exit when Ctrl-C is pressed, or the node is shutdown by the master. 
       */  
      ros::spin();  

      return 0;  
    }  

编译创建的节点
在编译我们创建的节点之前,我们还需要编辑Cmakelist.txt文件(注意:是beginner_tutorials项目包下的CMakelist文件),告诉编辑器我们需要编辑什么文件,需要什么依赖。

$ gedit CMakeLists.txt

在文件末尾添加如下语句:

include_directories(include ${catkin_INCLUDE_DIRS})  

add_executable(talker src/talker.cpp)  
target_link_libraries(talker ${catkin_LIBRARIES})  
add_dependencies(talker beginner_tutorials_generate_messages_cpp)  

add_executable(listener src/listener.cpp)  
target_link_libraries(listener ${catkin_LIBRARIES})  
add_dependencies(listener beginner_tutorials_generate_messages_cpp)  

将目录切换到工作区目录,并执行catkin_make运行命令:

 $ cd ~/catkin_ws  
    $ catkin_make  

不出意外的话,会出现如下界面:
这里写图片描述
至此,程序已经创建完成,而接下来我们要检查一下我们创建的程序是否正确。
测试程序的正确性
首先,我们得要启动ROS核心程序roscore。

$ roscore  

在使用我们的程序之前,需要先把程序注册

$ cd ~/catkin_ws  
$ source ./devel/setup.bash

运行talker节点:

$ rosrun beginner_tutorials talker

在另一个终端下运行listener节点:

$ rosrun beginner_tutorials listener  

(注意:在运行listener节点时应再把程序注册一遍,即

$ cd ~/catkin_ws  
$ source ./devel/setup.bash

这时候会看到如下信息:
这里写图片描述
如图能看见发布和订阅的节点正在正常运行。一个在发送一个在接收。
这说明订阅节点(listener)已经成功的接收到了发布节点(talker)发布的信息。至此,整个程序结束!

### 回答1: ROS中的publishersubscriber是用于实现节点之间通信的两个重要概念。 publisher一个节点,它可以将数据发布一个特定的主题(topic)上。其他节点可以订阅这个主题,以接收该节点发布的数据。publishersubscriber之间的通信是异步的,即publisher不需要等待subscriber的响应。 subscriber是一个节点,它可以订阅一个特定的主题(topic),以接收其他节点发布的数据。当有新的数据发布到该主题上时,subscriber会自动接收并处理这些数据。subscriber可以订阅多个主题,以接收来自不同节点的数据。 通过使用publishersubscriber,ROS节点可以实现分布式计算,从而更好地完成各种任务。 ### 回答2: ROS (Robot Operating System)是一个开源机器人操作系统,它提供了一系列工具和库,使得机器人的开发、测试和部署更加简单、高效。ROS的核心概念之一就是发布/订阅模式(Publisher-Subscriber),这是ROS实现消息传递机制的基础。 ROS Publisher发布者)是指向ROS消息总线发布消息的节点。节点可以向一个或者多个主题(Topic)发布消息。主题是让多个节点之间进行通信的一种机制。当一个Publisher节点发布了一条消息后,所有订阅了该主题的Subscriber就会接收到这条消息。发布者将消息发布到主题上时,需要指定主题的名称和消息类型。ROS提供了各种不同类型的消息,如字符串、数组、图像等。发布者节点用于发布消息会向主题发送一个消息头(Header),包含时间戳(Stamp)、FRAME_ID等信息,并在这个消息头中注册一些回调函数,以便接收机制可以使用这些信息来更优雅、有效的处理消息。 ROS Subscriber(订阅者)是指向ROS消息总线订阅消息的节点。Subscriber将使用主题的名称和消息类型来订阅特定的主题。当主题被发布发布消息时,所有订阅主题的Subscriber节点都将接收到这条消息。Subscriber节点使用回调函数处理消息。回调函数是将由节点执行的函数,这些函数会在消息到达时被调用。当Subscriber节点收到一条消息时,它会触发回调函数,并将接收到的消息作为参数传递给回调函数。回调函数然后处理消息,并根据需要执行其他操作。Subscriber节点的实现可以是同步的,也可以是异步的。同步的Subscriber节点会在每次接收到消息后立即处理,异步的Subscriber节点可能会在更长的时间内缓冲消息,以便将消息打包成一组或仅处理特定类别的消息。 总之,ROS PublisherSubscriber是ROS中非常重要的概念,它们允许节点之间通过主题交换消息,实现ROS系统的消息传递机制。通过发布/订阅模式,节点之间可以共享数据,实现对机器人各个部分的控制和监视。同时,发布/订阅模式提供了一种透明的、分布式的、去中心化的消息通信机制,允许ROS系统在各种硬件和操作系统平台上运行,并与外部系统长期保持稳定连接。 ### 回答3: ROS PublisherSubscriber是ROBOT OPERATING SYSTEM(ROS)中经常使用的两种通信方式,用于在ROS系统中的不同模块之间进行信息传递和数据共享。 PublisherROS中的一种发布者,它可以将数据发布到指定话题(topic)上。发布者可以是一个传感器,比如激光雷达,也可能是某个算法模块,比如机器人路径规划。发布者将数据发送到话题,然后该话题上的所有订阅者都可以接收到该数据。 Subscriber是ROS中的一种订阅者,它可以订阅某个话题上的数据。一旦订阅订阅了某个话题,它就可以在该话题上接收该话题上所有的数据。订阅者可能是一个控制模块,用于接收激光雷达数据,并控制机器人的行动。当订阅者收到数据后,它会进行特定的处理,如执行行动或更新机器人的状态等。 ROS PublisherSubscriber的优点在于它们提供了一种分布式系统的通信方式,这使得多个系统之间的数据共享变得更加容易和方便。在ROS系统中,一个发布者可以同时向多个话题发布数据,而订阅者也可以订阅多个话题上的数据。这使得ROS在机器人控制和其他领域中都具有广泛的应用。 在ROS中,PublisherSubscriber的使用非常简单。开发人员只需要在ROS节点中定义一个发布者和一个订阅者即可。ROS提供了许多现成的库和工具,可以帮助开发人员轻松创建发布者和订阅者,使得开发过程更加简单和快速。 总之,ROS PublisherSubscriber是ROS系统中非常重要的两个组件,它们可以方便地完成机器人控制、感知和决策等任务。这些组件的优点在于可以实现分布式通信,从而促进信息的共享和机器人系统的自主性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值