ROS教程四——编写Publisher和Subscriber节点(C++篇)
本教程介绍如何使用C ++编写发布者和订阅者节点
1、编写 Publisher Node
“节点”是连接到ROS网络的可执行文件的ROS术语。现在将创建一个发布者(publisher “talker”)节点,该节点将不断广播消息。将目录更改为在之前的教程中创建catkin工作区中的beginner_tutorials包:
roscd beginner_tutorials
1.1 代码
在beginner_tutorials包目录中创建一个src目录:
mkdir -p src
该目录将包含beginner_tutorials包的所有源文件。
在beginner_tutorials包中创建src / talker.cpp文件,内容如下:
#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;
}
1.2 代码解释
#include "ros/ros.h"#ros/ros.h是一个快捷的包括,包括使用ROS系统最常见的公共部分所需的所有头文件。
#include "std_msgs/String.h"#这包括std_msgs / String消息,该消息驻留在std_msgs包中。这是从该包中的String.msg文件自动生成的标头
ros::init(argc, argv, "talker");
初始化ROS。允许ROS通过命令行进行名称重映射 - 现在不重要。这也是指定节点名称的地方。节点名称在运行的系统中必须是唯一的。这里使用的名称必须是基本名称,即不能包含路径。
ros::NodeHandle n;
为此进程的节点创建句柄。首先创建的NodeHandle实际上将执行节点的初始化,其次退出时将清除节点使用的任何资源。
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
告诉主机将在主题 chatter 中发布类型为std_msgs / String的消息。主机告诉任何监听 chatter节点的节点,chatter节点将发布该主题的数据。第二个参数是发布队列的大小,在这种情况下,如果发布得太快,缓冲最多1000条消息,之后将开始丢弃旧消息。
NodeHandle :: advertise()返回一个ros :: Publisher对象,它有两个目:
1)它包含一个publish()方法,允许你将消息发布到它创建的主题上;
2)当它超出范围时,它会自动退出。
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:
a SIGINT is received (Ctrl-C)
we have been kicked off the network by another node with the same name
ros::shutdown() has been called by another part of the application.
all ros::NodeHandles have been destroyed
一旦ros :: ok()返回false,所有ROS调用都将失败。
std_msgs::String msg;std::stringstream ss;ss << "hello world " << count;msg.data = ss.str();
使用消息适配类在ROS上广播消息,通常消息从msg文件生成。更复杂的数据类型是可能的,但是现在我们将使用标准的String消息,它有一个成员:“data”。
chatter_pub.publish(msg);
现在将消息广播给任何已连接的节点。
ROS_INFO("%s", msg.data.c_str());
ROS_INFO及其相关是printf / cout的替代品。相关文档查看 rosconsole documentation 。
ros::spinOnce();
这个简单程序可以不需要调用ros :: spinOnce(),因为没有收到任何回调。但是,如果要在此应用程序中添加订阅,且此处没有ros :: spinOnce(),则永远不会调用您的回调。所以,它是作为一个衡量存在。
loop_rate.sleep();
使用ros :: Rate对象达到10Hz的发布速度。
以上归结如下:
1、 初始化ROS系统;
2、将把chatter主题上的std_msgs / String消息发布给master
3、循环发布消息,每秒10次
2、 编写 the Subscriber Node
2.1 代码
在beginner_tutorials包中创建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;
}
2.2 代码解释
现在一点一点地分解它,忽略一些已经在上面解释过的部分。
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{ROS_INFO("I heard: [%s]", msg->data.c_str());
}
这是一个回调函数,当一个新的消息到达chatter主题时将被调用。消息在boost shared_ptr中传递,这意味着您可以根据需要将其存储起来,而不必担心它会被删除,并且不会复制基础数据。
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
订阅聊天主题。每当有新消息到达时,ROS都会调用chatterCallback()函数。第二个参数是队列大小,以防我们无法足够快地处理消息。在这种情况下,如果队列达到1000条消息,将在新消息到达时开始丢弃旧消息。
NodeHandle :: subscribe()返回一个ros :: Subscriber对象,必须保留该对象,直到取消订阅。订阅对象被销毁后,将自动取消订阅chatter主题。
有一些版本的NodeHandle :: subscribe()函数允许您指定类成员函数,甚至可以指定Boost.Function对象可调用的任何函数。相关信息请查阅 roscpp overview。
ros::spin();
ros :: spin()进入一个循环,尽可能快地调用消息回调函数。如果没有什么可以做的话就不会占用太多的CPU。ros :: spin()将退出一次ros :: ok()返回false,这意味着已经调用了ros :: shutdown(),默认的Ctrl-C处理程序。
还有其他方法可以回调,但我们不会担心这些问题。roscpp_tutorials中有一些演示应用程序来演示这一点。更多roscpp信息请查阅 roscpp overview。
编写Subscribe总结如下:
1、初始化ROS系统;
2、订阅chatter主题;
3、spin,等待消息到达;
4、当消息到达时,将调用chatterCallback()函数
3、编译nodes
使用catkin_create_pkg创建了一个package.xml和一个CMakeLists.txt文件。
生成的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的底部:
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)
生成的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(FILES Num.msg)
add_service_files(FILES AddTwoInts.srv)## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)## Declare a catkin package
catkin_package()## Build talker and listener
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)
这将创建两个可执行文件,talker和listener,默认情况下将进入devel空间的package目录,默认位于〜/ catkin_ws / devel / lib / <package name>。
注意,必须将可执行目标的依赖项添加到生成目标:
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
这样可以确保在使用之前生成此包的头文件。如果使用catkin工作区内其他包的消息,则需要将依赖项添加到其各自的生成目标,因为catkin并行构建所有项目。从* Groovy *开始,可以使用以下变量来依赖所有必需的目标:
target_link_libraries(talker ${catkin_LIBRARIES})
可以直接调用可执行文件,也可以使用rosrun来调用它们。它们不会放在'<prefix> / bin'中,因为在将软件包安装到系统时会(污染)PATH。如果希望在安装时将可执行文件放在PATH上,则可以设置安装目标,查阅: catkin/CMakeLists.txt。
现在运行catkin_make:
# In your catkin workspace
$ cd ~/catkin_ws
$ catkin_make
注意:或者如果您要添加新的pkg,您可能需要通过--force-cmake选项告诉catkin强制制作。请参阅catkin/Tutorials/using_a_workspace#With_catkin_make.
已经写了一个简单的发布者和订阅者,让我们来查看ROS教程五-运行简单的发布者和订阅者。
ROS教程四——编写Publisher和Subscriber节点(C++篇)相关推荐
- ROS教程四——编写Publisher和Subscriber节点(Python篇)
本教程介绍如何在python中编写发布者和订阅者节点 1.编写Publisher节点 "节点"是连接到ROS网络的可执行文件的ROS术语.在这里,我们将创建广播消息的 publis ...
- ROS教程五——运行 Publisher和Subscriber
本教程检查运行简单的发布者和订阅者. 1.运行Publisher 确保roscore已启动并运行: $ roscore catkin特别规定如果使用的是catkin,请确保在调用catkin_make ...
- 小白学习ROS(3)创建Publisher和Subscriber节点
创建Publisher和Subscriber节点进行通讯 1.前言 在创建Publisher和Subscriber节点之前,先给介绍一个创建ROS包以及程序编写非常方便的一个ide,真的特别方便,尤其 ...
- ROS基础四之roscpp/rospy节点编写
roscpp/rospy节点编写 subscriber/advertiser编写 roscpp实例 rospy实例 server/client编写 roscpp实例 rospy实例 actionlib ...
- ROS教程中Publisher和Subscriber (Python)的说明
Publisher和Subscriber[Python]的说明 1.编写发布节点 2.编写订阅节点 3.编译现在的节点 1.编写发布节点 $ roscd beginner_tutorials #切换到 ...
- 【从零开始的ROS四轴机械臂控制】(四)- ros、gazebo与opencv,图像处理节点
[从零开始的ROS四轴机械臂控制(四)] 七.图像处理节点 1.节点功能与实现方法 2.iamge_process 相关程序 部分程序解释 3.节点运行与测试 七.图像处理节点 1.节点功能与实现方法 ...
- 【ROS入门学习05|自定义话题消息,并且编程实现publisher和subscriber】
这里是学习ROS第一次涉及到代码的部分.主要根据古月居视频教程整理出来的干货.本人是干货爱好者. 文章目录 前言 一.话题模型 二.自定义话题消息 1.定义msg文件 2.在功能包(learning_ ...
- ROS学习----Publisher与Subscriber
1.Publisher(发布者)与subscriber(订阅者)关系. Publisher的主要作用是对于指定话题发布特定数据类型的消息. 下面是利用代码实现一个节点,节点创建一个Publisher并 ...
- ROS教程——1.6 如何使用TF变换
转载自:ROS教程--1.6 如何使用TF变换 ROS教程--1.6 如何使用TF变换 原创 huicanlin Robot404 2019-07-03 15:10 1.6.1 ROS的变换系统(TF ...
最新文章
- linux蓝牙设备无法打开,linux 下 无线 wifi 蓝牙 无法启用
- Kubernetes存储之ConfigMap
- SDNU 1167.花生采摘(排序)
- 计算机三种引用方式,单元格的引用方式有哪几种
- 【37.68%】【hdu 5918】Sequence I
- VSCode REMOTE SSH
- HDU-2553N皇后问题(dfs)
- 在win10在使用cmder代替Linux是怎样的体验
- The _imagingft C module is not installed
- Good Bye 2016 //智商再次下线,边界爆炸.....
- 165体重_身高165的女性体重多少比较合适?过胖和过瘦都不太好
- 中国移动苏州研发中心前端笔试(2)
- mysql图文混排设计方案_平面设计图文混排技巧,看完再也不用担心排版了
- STM32涉及到的汇编基础知识
- MongoDB实验练习题
- java tld_Java Web自定义标签tld文件的简单使用
- HTML标签-排版标签、媒体标签、列表标签、表格标签、表单标签、语义化标签、字符实体
- VC6 限定鼠标移动范围
- vue大屏展示高度自适应
- 第四套人民币荧光冠号大全
热门文章
- Best_Cow_Line
- 关于VS2012使用make_pair编译提示“error C2664: “std::make_pair”: 不能将参数 1 从“int”转换为“int ””
- [单源最短路]逃离僵尸岛
- acadres.dll文件丢失怎么办?怎么去修复?
- 晚上看了轮子哥的知乎想法,我失眠了
- 获取大量合伙人并疯狂裂变的秘密,思路引导出路,布局聚焦格局!
- 快速克隆已有的WindowsToGo到另一个盘
- 卡尔福安卓智能导航,好用又方便
- 怎么快速将服务器上的文件取回本地,迅雷离线文件取回本地的图文步骤
- 用计算机画画的意义,尺子对于绘画的意义是什么,为什么绘画领域很少用尺子?...