博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ROS主题发布订阅
阅读量:5895 次
发布时间:2019-06-19

本文共 10500 字,大约阅读时间需要 35 分钟。

     节点是一个可执行程序,它连接到了ROS的网络系统中。我们将会创建一个发布者,也就是说话者节点,它将会持续的广播一个信息。

     改变目录到之前所建立的那个包下:

 
cd ~/catkin_ws/src/beginner_tutorials

 

     在beginner_tutorials包下面建立一个src文件夹:

mkdir -p ~/catkin_ws/src/beginner_tutorials/src

     创建文件src/talker.cpp:

gedit src/talker.cpp

 

     将下面的内容复制进去:

#include "ros/ros.h"      #include "std_msgs/String.h"            #include 
/** * 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
("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; }

 

 

     解释一下代码:

#include "ros/ros.h"

 

ros/ros.h包括了使用ROS系统最基本的头文件。

 
#include "std_msgs/String.h"

这条代码包括了std_msgs/String消息,它存在于std_msgs包中。这是有std_msgs中的String.msg文件自动产生的。

ros::init(argc, argv, "talker");

 

初始化ROS,它允许ROS通过命令行重新命名,现在还不太重要。这里也是我们确切说明节点名字的地方,在运行的系统中,节点的名字必须唯一

 
ros::NodeHandle n;

为处理的节点创建了一个句柄,第一个创建的节点句柄将会初始化这个节点,最后一个销毁的节点将会释放节点所使用的所有资源。

 
ros::Publisher chatter_pub = n.advertise
("chatter", 1000);

 

告诉主机,我们将会在一个名字为chatter的话题上发布一个std_msgs/String类型的消息,这就使得主机告诉了所有订阅了chatter 话题的节点,我们将在这个话题上发布数据。第二个参数是发布队列的大小,它的作用是缓冲。当我们发布消息很快的时候,它将能缓冲1000条信息。如果慢了 的话就会覆盖前面的信息。

NodeHandle::advertise()将会返回ros::Publisher对象,该对象有两个作用,首先是它包括一个publish()方法可以在制定的话题上发布消息,其次,当超出范围之外的时候就会自动的处理。

 

ros::Rate loop_rate(10);

 

一个ros::Rate对象允许你制定循环的频率。它将会记录从上次调用Rate::sleep()到现在为止的时间,并且休眠正确的时间。在这个例子中,设置的频率为10hz。

 
int count = 0;      while (ros::ok())      {

 

默认情况下,roscpp将会安装一个SIGINT监听,它使当Ctrl-C按下时,ros::ok()将会返回false。

ros::ok()在以下几种情况下也会返回false:(1)按下Ctrl-C时(2)我们被一个同名同姓的节点从网络中踢出(3)ros::shutdown()被应用程序的另一部分调用(4)所有的ros::NodeHandles都被销毁了。一旦ros::ok()返回false,所有的ROS调用都会失败。

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

 

我们使用message-adapted类在ROS中广播信息,这个类一般是从msg文件中产生的。我们现在使用的是标准的字符串消息,它只有一个data数据成员,当然更复杂的消息也是可以的。

 
  1. chatter_pub.publish(msg);

现在我们向话题chatter发布消息。

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

 

ROS_INFO是cout和printf的替代品。

ros::spinOnce();

 

在这个简单的程序中调用ros::spinOnce();是不必要的,因为我们没有收到任何的回调信息。然而如果你为这个应用程序添加一个订阅者,并且在这里没有调用ros::spinOnce(),你的回调函数将不会被调用。所以这是一个良好的风格。

 

loop_rate.sleep();

 

休眠一下,使程序满足前面所设置的10hz的要求。      下面总结一下创建一个发布者节点的步骤:(1)初始化ROS系统(2)告诉主机我们将要在chatter话题上发布std_msgs/String类型的消息(3)循环每秒发送10次消息。

 

 

打开一个终端,进入到beginner_tutorials包下面:

cd ~/catkin_ws/src/beginner_tutorials

 

     编辑文件src/listener.cpp

 

gedit 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;      }

 

 

 

 

 

 

 

void chatterCallback(const std_msgs::String::ConstPtr& msg)      {        ROS_INFO("I heard: [%s]", msg->data.c_str());      }

 

当一个消息到达chatter话题时,这个回调函数将会被调用。

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

 

订阅chatter话题,当一个新的消息到达时,ROS将会调用chatterCallback()函数。第二个参数是对列的长度,如果我们处理消息的速度不够快,会将收到的消息缓冲下来,一共可以缓冲1000条消息,满1000之后,后面的到达的消息将会覆盖前面的消息。

 

NodeHandle::subscribe()将会返回一个ros::Subscriber类型的对象,当订阅对象被销毁以后,它将会自动从chatter话题上撤销。

 

ros::spin();

 

ros::spin()进入了一个循环,可以尽快的调用消息的回调函数。不要担心,如果它没有什么事情可做时,它也不会浪费太多的CPU。当ros::ok()返回false时,ros::spin()将会退出。这就意味着,当ros::shutdown()被调用,或按下CTRL+C等情况,都可以退出。下面总结一下写一个订阅者的步骤:(1)初始化ROS系统(2)订阅chatter话题(3)Spin,等待消息的到来(4)当一个消息到达时,chatterCallback()函数被调用。

 

     下面看一下如何构建节点。这时候你的CMakeLists.txt看起来应该是下面这个样子,包括前面所做的修改,注释部分可以除去:

 

cmake_minimum_required(VERSION 2.8.3)      project(beginner_tutorials)            ## Find catkin and any catkin packages      find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)            ## Declare ROS messages and services      add_message_files(DIRECTORY msg FILES Num.msg)      add_service_files(DIRECTORY srv FILES AddTwoInts.srv)            ## Generate added messages and services      generate_messages(DEPENDENCIES std_msgs)            ## Declare a catkin package      catkin_package()

 

 

     将下面几行代码添加到CMakeLists.txt的最后。最终你的CMakeLists.txt文件看起来样该是下面这个样子:

[html]
  1. cmake_minimum_required(VERSION 2.8.3)  
  2. project(beginner_tutorials)  
  3.   
  4. ## Find catkin and any catkin packages  
  5. find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)  
  6.   
  7. ## Declare ROS messages and services  
  8. add_message_files(FILES Num.msg)  
  9. add_service_files(FILES AddTwoInts.srv)  
  10.   
  11. ## Generate added messages and services  
  12. generate_messages(DEPENDENCIES std_msgs)  
  13.   
  14. ## Declare a catkin package  
  15. catkin_package()  
  16.   
  17. ## Build talker and listener  
  18. include_directories(include ${catkin_INCLUDE_DIRS})  
  19.   
  20. add_executable(talker src/talker.cpp)  
  21. target_link_libraries(talker ${catkin_LIBRARIES})  
  22. add_dependencies(talker beginner_tutorials_generate_messages_cpp)  
  23.   
  24. add_executable(listener src/listener.cpp)  
  25. target_link_libraries(listener ${catkin_LIBRARIES})  
  26. add_dependencies(listener beginner_tutorials_generate_messages_cpp)  

这将会创建两个可执行文件,talker和listener。它们将会产生在~/catkin_ws/devel/lib/share/<package name>目录下,下面开始构建,在你的工作空间根目录下输入:

[html]
    1. catkin_make 

       

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

     首先运行roscore

[html]
  1. roscore  

     打开一个新的终端在里面运行talker:

cd ~/catkin_ws/devel/lib/beginner_tutorials ./talker

 

     打开一个新的终端在里面运行listener:

cd ~/catkin_ws/devel/lib/beginner_tutorials./listener

 

     说明了我们的程序是正确的。

 

转载于:https://www.cnblogs.com/CZM-/p/5876799.html

你可能感兴趣的文章
通过script标签实现JSONP跨域调用
查看>>
用jQuery实现Ajax
查看>>
***微信公众平台开发: 获取用户基本信息+OAuth2.0网页授权
查看>>
上传图片预览
查看>>
vim编辑器
查看>>
程序设计的一些原理
查看>>
iTerm的安装以及配置
查看>>
explore my oracle support using firefox 3.6
查看>>
《社交网站界面设计(原书第2版)》——1.7 反模式的重要性
查看>>
2016上半年DDoS攻击报告:DDoS攻击的规模和攻击频率都在不断攀升
查看>>
混合云、区块链、认知技术,还有哪一样前沿技术是IBM没提到的吗?
查看>>
呼叫中心现场管理人员注意事项
查看>>
nagios监控远程windows服务器
查看>>
lagp,lacp详解
查看>>
J2ee项目性能调优-垃圾收集器(gc)
查看>>
LVS之DR模式原理与实践
查看>>
自动化运维之SaltStack(概述及简单配置实例)
查看>>
导出excel
查看>>
struts2+extjs
查看>>
MariaDB初识
查看>>