ROS学习笔记九:用C++编写ROS发布与订阅

来源:互联网 发布:巴洛克记忆音乐知乎 编辑:程序博客网 时间:2024/05/17 22:43

ROS学习笔记九:用C++编写ROS发布与订阅

本节主要介绍如何用C++编写一个简单的ROS发布与订阅。

编写发布节点

在之前创建的例子beginner_tutorials软件包中,在其目录下的src目录中,创建talker.cpp文件:

#include "ros/ros.h"  //ROS中最常用片段的头文件#include "std_msgs/String.h"   //由String.msg自动产生的头文件#include <sstream>   //stringstream头文件/** * 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");   //初始化ROS,在这里可以指定我们节点的名称,一个ROS系统中节点的名称必须是唯一的  /**   * 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);   //告诉mster,n将要在topic chatter上面发布一个std_msgs::String类型的信息,然后master告诉所有节点注意监听主题chatter。第二个参数是发送队列的长度。  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())  {  //ros::ok()在以下情况下会返回false:  1 收到SIGINT信号(ctrl-c);  2 节点网络断开;  3 ros::shutdown()函数被调用;  4 所有的ros::NodeHandles都已经消失。    /**     * 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());   //ROS_INFO系列是printf/cout的替代品    /**     * 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);   //发布信息msg到每一个相连接的节点    ros::spinOnce();    loop_rate.sleep();   //休眠一段时间以达到循环频率10Hz    ++count;  }  return 0;}

编写订阅节点

#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)   //callback函数,收到msg时调用{  ROS_INFO("I heard: [%s]", msg->data.c_str());}int main(int argc, char **argv){  ros::init(argc, argv, "listener");  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;}

编译新建的节点

主要是需要修改CMakeLists.txt文件,现在只是跟着官网教程走了下来,具体要怎么修改、为什么要这样修改,还不是很清楚。
按照官网教程,只需要将下列几行代码添加到CMakeLists.txt文件中include_directories(include ${catkin_INCLUDE_DIRS})之后:

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)

然后在catkin工作空间中运行编译命令:

catkin_make

如果顺利编译的话,将会生成两个可执行程序talker和listener文件,默认生成可执行文件的目录是catkin工作空间的devel space下的lib目录中, ~/ros_tutorials/devel/lib/。

注意需要将可执行文件的依赖添加到信息生成目标中:

add_dependencies(talker beginner_tutorials_generate_messages_cpp)

这样会确保这个软件包的信息头文件在使用之前已经生成。如果使用了工作空间中其他软件包中的信息,你也需要添加相应的生成目标的依赖,因为catkin同时编译所有的项目。

检验创建的节点

首先要确认在carkin_make之后加载了工作空间的环境变量,然后分别在三个新的终端运行如下命令:

roscorerosrun beginner_tutorials talkerrosrun beginner_tutorials listener

祝枫
2016年8月27日于哈尔滨

1 0
原创粉丝点击