首页 > 代码库 > ROS学习(十二)—— 编写简单的消息发布器和订阅器(C++)
ROS学习(十二)—— 编写简单的消息发布器和订阅器(C++)
一、创建发布器节点
1 节点功能:
不断的在ROS网络中广播消息
2 创建节点
(1)打开工作空间目录
cd ~/catkin_ws/src/beginner_tutorials
<style>p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 创建一个发布器节点("talker"),它将不断的在ROS网络中广播消息。 --> { }</style>
(2)创建src文件夹
mkdir -p ~/catkin_ws/src/beginner_tutorials/src
(3)创建talkler.cpp文件,幷附上代码
#include "ros/ros.h" // ros/ros.h是一个实用的头文件,它引用了ROS系统中大部分常用的头文件,使用它会使得编程很简便。 #include "std_msgs/String.h" // 这引用了std_msgs/String 消息, 它存放在std_msgs package里,是由String.msg文件自动生成的头文件。 // 需要更详细的消息定义,参考msg页面. #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"); // 初始化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. 为这个进程的节点创建一个句柄。第一个创建的NodeHandle会为节点进行初始化,最后一个销毁的会清理节点使用的所有资源。 */ 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. */ /* 1、告诉master我们将要在chatter topic上发布一个std_msgs/String的消息。这样master就会告诉所有订阅了chatter topic的节点,将要有数据发布。 2、第二个参数是发布序列的大小。在这样的情况下,如果我们发布的消息太快,缓冲区中的消息在大于1000个的时候就会开始丢弃先前发布的消息。 3、NodeHandle::advertise() 返回一个 ros::Publisher对象,它有两个作用: 1) 它有一个publish()成员函数可以让你在topic上发布消息; 2) 如果消息类型不对,它会拒绝发布。 */ ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000); //ros::Rate对象可以允许你指定自循环的频率。它会追踪记录自上一次调用Rate::sleep()后时间的流逝,并休眠直到一个频率周期的时间。 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; /* roscpp会默认安装一个SIGINT句柄,它负责处理Ctrl-C键盘操作——使得ros::ok()返回FALSE。 ros::ok()返回false,如果下列条件之一发生: 1)SIGINT接收到(Ctrl-C) 2)被另一同名节点踢出ROS网络 3)ros::shutdown()被程序的另一部分调用 4) 所有的ros::NodeHandles都已经被销毁 */ while (ros::ok()) { /** * This is a message object. You stuff it with data, and then publish it. */ //我们使用一个由msg file文件产生的‘消息自适应’类在ROS网络中广播消息。现在我们使用标准的String消息,它只有一个数据成员"data"。当然你也可以发布更复杂的消息类型。 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); //现在我们已经向所有连接到chatter topic的节点发送了消息 ros::spinOnce(); //在这个例子中并不是一定要调用ros::spinOnce(),因为我们不接受回调。 //然而,如果你想拓展这个程序,却又没有在这调用ros::spinOnce(),你的回调函数就永远也不会被调用。所以,在这里最好还是加上这一语句。 loop_rate.sleep(); //这条语句是调用ros::Rate对象来休眠一段时间以使得发布频率为10hz。 ++count; } return 0; }
二、编写订阅器节点
在src文件中,继续写入listener.cpp文件,幷附上代码
#include "ros/ros.h" #include "std_msgs/String.h" /** * This tutorial demonstrates simple receipt of messages over the ROS system. * 这是一个回调函数,当消息到达chatter topic的时候就会被调用。消息是以 boost shared_ptr指针的形式传输,这就意味着你可以存储它而又不需要复制数据 */ 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. */ //告诉master我们要订阅chatter topic上的消息。当有消息到达topic时,ROS就会调用chatterCallback()函数。 //第二个参数是队列大小,以防我们处理消息的速度不够快,在缓存了1000个消息后,再有新的消息到来就将开始丢弃先前接收的消息。 //NodeHandle::subscribe()返回ros::Subscriber对象,你必须让它处于活动状态直到你不再想订阅该消息。当这个对象销毁时,它将自动退订消息。 //有各种不同的NodeHandle::subscribe()函数,允许你指定类的成员函数,甚至是Boost.Function对象可以调用的任何数据类型。roscpp overview 提供了更为详尽的信息。 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()进入自循环,可以尽可能快的调用消息回调函数。如果没有消息到达,它不会占用很多CPU,所以不用担心。 //一旦ros::ok()返回FALSE,ros::spin()就会立刻跳出自循环。 // 1)这有可能是ros::shutdown()被调用, // 2)或者是用户按下了Ctrl-C,使得master告诉节点要shutdown。也有可能是节点被人为的关闭。 ros::spin(); return 0; }
<style>p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 创建一个发布器节点("talker"),它将不断的在ROS网络中广播消息。 --> { }</style>
ROS学习(十二)—— 编写简单的消息发布器和订阅器(C++)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。