Writing a Simple Publisher and Subscriber
用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的更多相关文章
- ROS学习手记 - 8 编写ROS的Publisher and Subscriber
上一节我们完成了 message & srv 文件的创建和加入编译,这次我们要玩简单的Publisher 和 Subscriber 要玩 Publisher 和 Subscriber, 需要具 ...
- Writing a simple Lexer in PHP/C++/Java
catalog . Comparison of parser generators . Writing a simple lexer in PHP . phc . JLexPHP: A PHP Lex ...
- Publisher和Subscriber节点
一.Publisher节点 /*"ros/ros.h"里面包含了ROS系统内最常用的一些头文件,包含此文件,便可以使用ROS的核心功能.*/#include "ros/r ...
- Writing a Simple Service and Client (C++)
此前说的publisher/subscriber都是广播式的,subscriber被动地接收消息,二者没有request/response这种交互. Service Node Client Node ...
- C#的publisher与subscriber,事件发布者与订阅者
说明:示例借鉴自这里,但原版很不友好,于是修改了下,一目了然. 直接上代码: using System; using System.Collections.Generic; using System. ...
- Writing a Simple YARN Application 从hadoop生态抽出yarn ,单独使用yarn
Apache Hadoop 2.9.1 – Hadoop: Writing YARN Applications https://hadoop.apache.org/docs/current/hadoo ...
- ROS验证publisher和subscriber
在前面的两篇博客中我们用C++在ROS中创建了一个发布者和接收者,并使用catkin_make构建了新的节点,下面就需要验证一下,我们写的是否正确. 首先运行roscore roscore 在使用ca ...
- ROS教程
Learning ROS 学习ROS Depending on your learning style and preferences, you can take two approaches to ...
- Publisher/Subscriber(发布/订阅者)消息模式开发流程
该模式的作用是发布者和订阅者 可以相互发送消息 发布者和订阅者都充当 生产者和消费者 发布者 package publisher.to.subscriber; import java.awt.font ...
随机推荐
- java技术树+必读书籍
引子 本篇文章用技术树的形式来展示java相关技术栈.所有技术点有博客的都自带链接,没有的后续加上. 必读书籍推荐: 1.java基础: <effective java>-->四星推 ...
- react-navigation android 导航标题居中
先贴下代码供参考: 安卓默认导航的titile 是在左侧的,为了和iOS保持一致,需要添加 alignSelf:'center',这个 属性 但是会遇到title有点偏右的情况 添加headerRig ...
- C# 指定父層級目錄
lstrcatW(pszpath, "\\..\\..\\"); DWORD dwlen = GetFullPathNameW(pszpath, 0u, null, null); ...
- 前端学习笔记之HTML body内常用标签
阅读目录 一 HTML语义化 二 字符实体 三 h系列标签 四 p标签 五 img标签 六 a标签 七 列表标签 八 table标签 九 form标签 一 HTML语义化 body中的标签是会显示到浏 ...
- 基于JavaMail开发邮件发送器工具类
基于JavaMail开发邮件发送器工具类 在开发当中肯定会碰到利用Java调用邮件服务器的服务发送邮件的情况,比如账号激活.找回密码等功能.本人之前也碰到多次这样需求,为此特意将功能封装成一个简单易用 ...
- HTTP2和HTTPS来不来了解一下?
一.前言 只有光头才能变强 HTTP博文回顾: PC端:HTTP就是这么简单 PC端:HTTP面试题都在这里 微信公众号端:HTTP就是这么简单 微信公众号端:HTTP面试题都在这里 本文力求简单讲清 ...
- Java虚拟机三:OutOfMemoryError异常分析
根据Java虚拟机规范,虚拟机内存中除过程序计数器之外的运行时数据区域都会发生OutOfMemoryError(OOM),本文将通过实际例子验证分析各个数据区域OOM的情况.为了更贴近生产,本次所有例 ...
- Vue.js 学习笔记 第2章 数据绑定和第一个Vue应用
本篇目录: 2.1 Vue实例与数据绑定 2.2 指令与事件 2.3 语法糖 学习任何一种框架,从一个Hello World应用开始是最快了解该框架特性的途径. 我们先从一段简单的HTML代码开始,感 ...
- python 线程(一)理论部分
Python线程 进程有很多优点,它提供了多道编程,可以提高计算机CPU的利用率.既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的. 主要体现在一下几个方面: 进程只能在 ...
- Lenovo System x3650 设置管理接口地址
1.开启服务器. 2.显示<F1> Setup提示后,按 F1.(此提示在屏幕上仅显示几秒钟.必须迅速按 F1.) 如果同时设置了开机密码和管理员密码,则必须输入管理员密码才能访问完整的 ...