用c++实现一个publisher/subscriber

publisher

#include "ros/ros.h"
#include "std_msgs/String.h" #include <sstream> /**
* This tutorial demonstrates simple sending of messages over the ROS system.
*/
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;
}
  • 初始化ros system

    ros::init(argc, argv, "talker"); //使得可以通过命令行进行name remapping
  • 告知master程序想向什么topic publish何种type的msg

    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  • publish

    chatter_pub.publish(msg);

几个知识点:

  • ros::init(argc, argv, "talker");中的"talker"是node name。不可以含/,并且该name要全局唯一.

Node names must be unique in a running system The name used here must be a base name, ie. it cannot have a / in it.

  • ros::NodeHandle n;

    第一个handle会对node初始化,最后一个destruct的handle会clean掉该node正在使用的相关资源.

Create a handle to this process' node. The first NodeHandle created will actually do the initialization of the node, and the last one destructed will cleanup any resources the node was using.

  • n.advertise<std_msgs::String>("chatter", 1000)

    第二个参数含义为队列大小,当消费方消费过慢,比如发了1001个msg,还无人sub,那么第一条会被丢弃.

his lets the master tell any nodes listening on chatter that we are going to publish data on that topic. The second argument is the size of our publishing queue. In this case if we are publishing too quickly it will buffer up a maximum of 1000 messages before beginning to throw away old ones.

  • ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

    注意,出了作用域,chatter_pub将不再可以向相应topic发送消息

NodeHandle::advertise() returns a ros::Publisher object, which serves two purposes: 1) it contains a publish() method that lets you publish messages onto the topic it was created with, and 2) when it goes out of scope, it will automatically unadvertise.

  • ros::Rate loop_rate(10);

    10代表10HZ,即每秒10次,这样loop_rate.sleep()的时候自己计算该sleep多久;

  • ros::ok() will return false if:

    • 收到SIGINT信号(ctrl + c)
    • 被同名node踢下网络
    • 程序里调用了ros::shutdown()
    • 所有的ros::NodeHandles都destroy了
  • ros::spinOnce();

    如果不加spinOnce,回调函数将不会被调用.

Calling ros::spinOnce() here is not necessary for this simple program, because we are not receiving any callbacks. However, if you were to add a subscription into this application, and did not have ros::spinOnce() here, your callbacks would never get called. So, add it for good measure.

subscriber

#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;
}
  • 初始化ROS
  • subscribe chatter topic
  • spin,等待msg到达
  • msg到达时,回调函数会被调用

和publisher类似

  • ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);

    只是需要指定一个回调函数,作为收到消息时的处理函数.

    void chatterCallback(const std_msgs::String::ConstPtr& msg),回调传入的是一个boost:share_ptr。你可以存储这个ptr,不用担心其指向的msg被删除.

This is the callback function that will get called when a new message has arrived on the chatter topic. The message is passed in a boost shared_ptr, which means you can store it off if you want, without worrying about it getting deleted underneath you, and without copying the underlying data.

  • ros::spin()

ros::spin() enters a loop, calling message callbacks as fast as possible. Don't worry though, if there's nothing for it to do it won't use much CPU. ros::spin() will exit once ros::ok() returns false

可能类似于select之类的吧,循环并不会太耗cpu。

编译

修改CMakeLists.txt

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)



进入顶层目录执行make.

This will create two executables, talker and listener, which by default will go into package directory of your devel space, located by default at ~/catkin_ws/devel/lib/.

测试publisher和sunscriber





https://askubuntu.com/questions/690631/executables-vs-shared-objects

之前一直用的centos,并且工作项目里bin和lib下的文件是严格区别开来的,一直理解的是可执行程序是executable,而lib下的是动态库shared object.这个理解实际上是有误的.

实际测试,先启动talker,后启动listener,listener只会消费他启动之后收到的监听topic上的消息.

再举个例子,先启动talker,关闭talker,再启动listener,listener不会受到任何消息.

实际上,master并不承担消息中转的作用,他不是消息中间件,各个node只是向他注册消息,告知master自己的身份,想发或想收什么样的消息.node之间还是直接通信的

Writing a Simple Publisher and Subscriber的更多相关文章

  1. ROS学习手记 - 8 编写ROS的Publisher and Subscriber

    上一节我们完成了 message & srv 文件的创建和加入编译,这次我们要玩简单的Publisher 和 Subscriber 要玩 Publisher 和 Subscriber, 需要具 ...

  2. Writing a simple Lexer in PHP/C++/Java

    catalog . Comparison of parser generators . Writing a simple lexer in PHP . phc . JLexPHP: A PHP Lex ...

  3. Publisher和Subscriber节点

    一.Publisher节点 /*"ros/ros.h"里面包含了ROS系统内最常用的一些头文件,包含此文件,便可以使用ROS的核心功能.*/#include "ros/r ...

  4. Writing a Simple Service and Client (C++)

    此前说的publisher/subscriber都是广播式的,subscriber被动地接收消息,二者没有request/response这种交互. Service Node Client Node ...

  5. C#的publisher与subscriber,事件发布者与订阅者

    说明:示例借鉴自这里,但原版很不友好,于是修改了下,一目了然. 直接上代码: using System; using System.Collections.Generic; using System. ...

  6. Writing a Simple YARN Application 从hadoop生态抽出yarn ,单独使用yarn

    Apache Hadoop 2.9.1 – Hadoop: Writing YARN Applications https://hadoop.apache.org/docs/current/hadoo ...

  7. ROS验证publisher和subscriber

    在前面的两篇博客中我们用C++在ROS中创建了一个发布者和接收者,并使用catkin_make构建了新的节点,下面就需要验证一下,我们写的是否正确. 首先运行roscore roscore 在使用ca ...

  8. ROS教程

    Learning ROS 学习ROS Depending on your learning style and preferences, you can take two approaches to ...

  9. Publisher/Subscriber(发布/订阅者)消息模式开发流程

    该模式的作用是发布者和订阅者 可以相互发送消息 发布者和订阅者都充当 生产者和消费者 发布者 package publisher.to.subscriber; import java.awt.font ...

随机推荐

  1. BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治

    BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治 Description     在得知了自己农 ...

  2. ubuntu ssh 免密码登录

    1 ssh 是什么? ssh 是一种 加密协议,ssh 是两个加密的密码,一个是公钥一个是私钥,公钥加密的信息只有是要才能解密.ssh协议可用于服务之间的通信.例如:登录验证,git的授权等等 2 s ...

  3. 从字节码和JVM的角度解析Java核心类String的不可变特性

    1. 前言 最近看到几个有趣的关于Java核心类String的问题. String类是如何实现其不可变的特性的,设计成不可变的好处在哪里. 为什么不推荐使用+号的方式去形成新的字符串,推荐使用Stri ...

  4. CentOS7解决firefox无法启用ibus中文输入的问题

    最近换电脑,要换掉使用了6年的旧环境,开始折腾重装系统: 下了minimal版本的CentOS7.4,然后开始一点点装想用的东西,多少找到一点十年前折腾LFS的感觉:然后竟然被输入法拌住了半天,事后回 ...

  5. poj 3687

    Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them ...

  6. 谈谈volatile关键字以及常见的误解

    转载请保留以下声明 作者:赵宗晟 出处:https://www.cnblogs.com/zhao-zongsheng/p/9092520.html 近期看到C++标准中对volatile关键字的定义, ...

  7. java编写词法分析器

    词法分析器就是通过扫描一段程序判断是否是关键字.标识符.常数.分界符.运算符.一般分为一符一种和经典五中: 这里我用的是经典五中,此词法分析器是用java编写的: /* 保留字|关键字:1 操作符|运 ...

  8. 安卓开发笔记(三十):自定义Button

    在笔者本人看了很多博客和书之后,发现很少博主对于自定义控件能够进行一个比较全面的思路讲解,大多数都是只讲了一些细节,但并没有讲如何把代码进行整体的实现.因此这里讲讲整体的自定义button实现的详细过 ...

  9. 给女朋友讲解什么是Optional【JDK 8特性】

    前言 只有光头才能变强 前两天带女朋友去图书馆了,随手就给她来了一本<与孩子一起学编程>的书,于是今天就给女朋友讲解一下什么是Optional类. 至于她能不能看懂,那肯定是看不懂的.(学 ...

  10. 从源码解读线程(Thread)和线程池(ThreadPoolExecutor)的状态

    线程是比进程更加轻量级的调度执行单位,理解线程是理解并发编程的不可或缺的一部分:而生产过程中不可能永远使用裸线程,需要线程池技术,线程池是管理和调度线程的资源池.因为前不久遇到了一个关于线程状态的问题 ...