用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. linux文件的基本属性

    Linux 文件基本属性 Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限.为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规 ...

  2. Ubuntu16.04 下搭建git服务器及gitweb+nginx配置

    本文转自:http://blog.csdn.net/water_horse/article/details/68958140 1.安装所需软件 fengjk@water:~$ sudo apt-get ...

  3. zabbix监控elasticsearch

    1.环境概述 虚拟机系统:CentOS Linux release 7.3.1611 (Core) 宿主机系统:Mac Sierra version 10.12.3 nginx:1.10.3 php: ...

  4. 测试修改hosts文件py小工具

    import sys,osparm_list=sys.argvHOST_PATH=r'C:\liuliang\flask_test\test\hosts'class HostFile(object): ...

  5. apigateway-kong(二)admin-api(结合实例比官网还详细)

    部署好kong之后,则需要将我们自己的接口加入到kong中管理,kong提供了比较全面的restful api,每个版本会有所不同,下面的记录基于kong v0.13.x kong的8001端口是re ...

  6. TensorFlow之DNN(一):构建“裸机版”全连接神经网络

    博客断更了一周,干啥去了?想做个聊天机器人出来,去看教程了,然后大受打击,哭着回来补TensorFlow和自然语言处理的基础了.本来如意算盘打得挺响,作为一个初学者,直接看项目(不是指MINIST手写 ...

  7. Actor模型-Akka

    英文原文链接,译文链接,原文作者:Arun Manivannan ,译者:有孚 写过多线程的人都不会否认,多线程应用的维护是件多么困难和痛苦的事.我说的是维护,这是因为开始的时候还很简单,一旦你看到性 ...

  8. PHP全栈学习笔记13

    php与ajax技术 web2.0的到来,ajax逐渐成为主流,什么是ajax,ajax的开发模式,优点,使用技术.(ajax概述,ajax使用的技术,需要注意的 问题,在PHP应用ajax技术的应用 ...

  9. Python调用ansible API系列(四)动态生成hosts文件

    方法一:通过最原始的操作文件的方式 #!/usr/bin/env python # -*- coding: utf-8 -*- """ 通过操作文件形式动态生成ansib ...

  10. 学习 JavaScript (五)核心概念:语句

    语句 语句被称作是流控制语句,通常有标志性的一个或者多个关键字,if . do-while. while.for. for-in. label. break.continue.with.switch. ...