zoukankan      html  css  js  c++  java
  • 节点和Topic通信

    1、简介

    对于实时性、 周期性的消息, 使用topic来传输是
    最佳的选择。 topic是一种点对点的单向通信方式, 这里的指的是node, 也就是说node
    间可以通过topic方式来传递信息。 topic要经历下面几步的初始化过程: 首先, publisher节点
    subscriber节点都要到节点管理器进行注册, 然后publisher会发布topicsubscriber
    master的指挥下会订阅该topic, 从而建立起sub-pub之间的通信。 注意整个过程是单向的。 其
    结构示意图如下:

     

    总结三点:
    1. topic通信方式是异步的, 发送时调用publish()方法, 发送完成立即返回, 不用等待反
    馈。
    2. subscriber通过回调函数的方式来处理消息。
    3. topic可以同时有多个subscribers, 也可以同时有多个publishersROS中这样的例子
    有: /rosout/tf等等。

    /**
     * 该例程将发布chatter话题,消息类型String
     */
     
    #include <sstream>
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    int main(int argc, char **argv)
    {
      // ROS节点初始化
      ros::init(argc, argv, "talker");
      
      // 创建节点句柄
      ros::NodeHandle n;
      
      // 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
      ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
    
      // 设置循环的频率
      ros::Rate loop_rate(10);
    
      int count = 0;
      while (ros::ok())
      {
        // 初始化std_msgs::String类型的消息
        std_msgs::String msg;
        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();
    
        // 发布消息
        ROS_INFO("%s", msg.data.c_str());
        chatter_pub.publish(msg);
    
        // 循环等待回调函数
        ros::spinOnce();
        
        // 按照循环频率延时
        loop_rate.sleep();
        ++count;
      }
    
      return 0;
    }

    /**
     * 该例程将订阅chatter话题,消息类型String
     */
     
    #include "ros/ros.h"
    #include "std_msgs/String.h"
    
    // 接收到订阅的消息后,会进入消息回调函数
    void chatterCallback(const std_msgs::String::ConstPtr& msg)
    {
      // 将接收到的消息打印出来
      ROS_INFO("I heard: [%s]", msg->data.c_str());
    }
    
    int main(int argc, char **argv)
    {
      // 初始化ROS节点
      ros::init(argc, argv, "listener");
    
      // 创建节点句柄
      ros::NodeHandle n;
    
      // 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
      ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
    
      // 循环等待回调函数
      ros::spin();
    
      return 0;
    }

     

     

     用指令发布/订阅topic消息msg

     

    Publisher和Subscriber节点详解

    一、Publisher节点
    
    /*"ros/ros.h"里面包含了ROS系统内最常用的一些头文件,包含此文件,便可以使用ROS的核心功能。*/
    #include "ros/ros.h" 
    /*"std_msgs/String"是由std_msgs包自动生成的头文件,定义了String信息类型,包含此文件,我们就可以使用String类型*/
     #include "std_msgs/String.h" #include <sstream> 
    /*** This tutorial demonstrates simple sending of messages over the ROS system. */ 
    int main(int argc, char **argv) { /**
      * ros::init()函数需要两个系统命令行参数argc和argv,
      * 由此可以执行命令行传来的任何ROS参数和节点的重命名
    
      * 第三个参数是节点的名字,
      * 注意这里只能使用基本命名,
      * 即名字里不能含有'/'
    
      * 在使用ROS的其他部分之前,你必须调用ros::init()
      **/ ros::init(argc, argv, "talker"); /**
       * NodeHandle 是节点同ROS系统交流的主要接口
       * NodeHandle 在构造的时候会完整地初始化本节点 
       * NodeHandle 析构的时候会关闭此节点
       */ 
      ros::NodeHandle n; /**
       * 我们通过advertise() 函数指定我们如何在给定的topic上发布信息
       * 它会触发对ROS master的调用,master会记录话题发布者和订阅者
       * 在advertise()函数执行之后,master会通知每一个订阅此话题的节点
       * 两节点间由此可以建立直接的联系
    
       * advertise()会返回一个Publisher对象,使用这个对象的publish方法我们就可以在此话题上发布信息
       * 当返回的Publisher对象的所有引用都被销毁的时候,本节点将不再是该话题的发布者
    
       * 此函数是一个带模板的函数,需要传入具体的类型进行实例化
       * 传入的类型就是要发布的信息的类型,在这里是String
    
       * 第一个参数是话题名称
    
       * 第二个参数是信息队列的长度,相当于信息的一个缓冲区
       * 在我们发布信息的速度大于处理信息的速度时
       * 信息会被缓存在先进先出的信息队列里
       */
      ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000); /**
       * Rate loop_rate()构造了一个Rate类的对象
       * 用来指定我们发布信息的频率,单位为hz,即每秒多少次
       * 在我们调用Rate对象的sleep()方法之前,信息发布的频率不会发生变化
      **/ 
      ros::Rate loop_rate(10); /**
       * 一个记录我们发布的信息数量的计数器
       * 它用来为每条信息产生不一样的字符串
       * 如'1 message','2 message'这样
       */ 
      int count = 0; /**
       * roscpp默认会构造一个咱SIGINT的处理器来处理系统信号
       * 当出现以下情况之一的时候ros:ok()会返回false:
       *   1.接受到了一个SIGINT信号(Ctrl-C)
       *   2.在程序中调用了ros::shutdown()
       *   3.所有的ros::NodeHandle对象及引用都被销毁
      **/ 
      while (ros::ok()) { /**
         * 这是一个message对象,我们向其中填入数据,然后可以发布它
         */
       std_msgs::String msg; /**
         * 我们发布的信息的格式为"hello world 1/2/3..."
         */ std::stringstream ss;
         ss << "hello world " << count; 
        msg.data = ss.str(); /**
         * ROS_INFO是对ROS系统对printf/cout的替代
         */ 
        ROS_INFO("%s", msg.data.c_str()); /**
         * publish()函数用来发布信息
         * 信息类型必须为前一步实例化advertised()时使用的模板参数的类型
         * 这里为String
         */
         chatter_pub.publish(msg); /**
         * 在这个简单的应用中,我们没有使用任何回调函数
         * 所以ros::spinOnce()的调用不是必须的
         * 但是一直在代码里调用ros::spinOnce()是个好习惯
         * 它可以保证你指定的回调函数会被调用
         */ 
        ros::spinOnce(); /**
         * 调用Rate对象的sleep方法来使我们前面指定的信息发布频率10Hz生效
         */ loop_rate.sleep(); 
        ++count; 
        } 
        return 0;
     }
    #include "ros/ros.h" 
    #include "std_msgs/String.h" /**
     * 传给NodeHandle.subscribe()的回调函数
     * 它的参数是一个share_ptr类型的只能指针,功能这里不细讲
     */ void chatterCallback(const std_msgs::String::ConstPtr& msg) 
      { ROS_INFO("I heard: [%s]", msg->data.c_str()); }
     int main(int argc, char **argv)
     { ros::init(argc, argv, "listener");
     ros::NodeHandle n; /**
       * 参数1:话题名称
       * 参数2:信息队列长度
       * 参数3:回调函数,每当一个信息到来的时候,这个函数会被调用
       * 返回一个ros::Subscriber类的对象,当此对象的所有引用都被销毁是,本节点将不再是该话题的订阅者
       */ ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); /**
       * 调用ros::spin()函数,进入一个循环
       * 不断地接受信息,然后执行回调函数,知道ros::ok()返回false
       */ ros::spin(); return 0; }
  • 相关阅读:
    关于Python安装PIL库失败的原因
    SSH免密登录及配置完成后仍需要输入密码的解决办法
    Github+Hexo博客搭建教程(三)
    Github+Hexo博客搭建教程(二)
    Github+Hexo博客搭建教程(一)
    winform中控件的简单数据绑定
    分享一个跨线程访问控件的很实用的方法
    自定义两个控件,一个是显示图标和文字的矩形,一个是带边框的label(但是不是label)
    写一个给字符串根据长度添加换行符的处理方法
    Winform DataGridView控件在业务逻辑上的简单使用
  • 原文地址:https://www.cnblogs.com/long5683/p/9941569.html
Copyright © 2011-2022 走看看