ROS教程四——编写Publisher和Subscriber节点(C++篇)

2023-05-16

本教程介绍如何使用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教程五-运行简单的发布者和订阅者。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS教程四——编写Publisher和Subscriber节点(C++篇) 的相关文章

  • ros 中ERROR: cannot download default sources list from: https://raw.githubusercontent.com/ros/rosdist

    ros 中ERROR cannot download default sources list from https raw githubusercontent com ros rosdistro master rosdep sources
  • V-REP安装

    小知识 是当前目录 是父级目录 是根目录 1 下载V REP 官网地址 http www v rep eu downloads html 我用ubuntu16 04下载V REP PRO EDU V3 5 0 Linux tar 2 解压安
  • ROS学习(1)——ROS1和ROS2的区别

    因为机器人是一个系统工程 它包括了机械臂结构 电子电路 驱动程序 通信框架 组装集成 调试和各种感知决策算法等方面 任何一个人甚至是一个公司都不可能完成机器人系统的研发工作 但是我们又希望自己能造出一个机器人跑一跑 验证一下自己的算法 所以
  • ModuleNotFoundError: No module named ‘rosbag‘

    1 ModuleNotFoundError No module named rosbag File opt ros kinetic lib python2 7 dist packages roslib launcher py line 42
  • ROS 笔记(01)— Ubuntu 20.04 ROS 环境搭建

    ROS 官网 https www ros org ROS 中文官网 http wiki ros org cn 1 系统和 ROS 版本 不同的 ROS 版本所需的 ubuntu 版本不同 每一版 ROS 都有其对应版本的 Ubuntu 切记
  • 局域网下ROS多机通信的网络连接配置

    1 在路由器设置中固定各机器IP地址 在浏览器中输入路由器的IP地址 例如TP LINK路由器的IP为 192 168 1 1 进入登录页面后 输入用户名和密码登录 用户名一般为admin 密码为自定义 在 基本设置 gt LAN设置 gt
  • 服务数据的定义和使用

    1 自定义数据服务 在包下创建srv文件夹 在文件夹下创建Person srv 在Person srv下输入以下内容 代表数据类型 string name uint8 age uint8 sex uint8 unknown 0 uint8
  • (ros/qt报错) FATAL: ROS_MASTER_URI is not defined in the environment

    安装qt之后 明明打开roscore但是qt运行跟ros有关的节点时报错 FATAL 1450943695 306401842 ROS MASTER URI is not defined in the environment Either
  • 可视化点云

    我在找到的视差图像上有来自 gpu reprojectImageTo3D 的 3D 点 我现在想显示这个点云 如何将找到的点云转换为OpenCV to sensor msgs PointCloud2 我不需要发布点云 这仅用于调试可视化 是
  • Facebook 个人资料订阅者数量

    API 中是否有一种方法可以查询新配置文件之一的订阅者数量 我说的是新的个人资料 不是页面 就像泰拉 班克斯的这个 http www facebook com XOXOTYTY 我可以在该页面上看到她有 696k 订阅者 更具体地说 当您搜
  • 不使用ros编译roscpp(使用g++)

    我正在尝试在不使用ROS其余部分的情况下编译roscpp 我只需要订阅一个节点 但该节点拥有使用旧版本ROS的节点 并且由于编译问题 我无法将我的程序与他的程序集成 我从git下载了源代码 https github com ros ros
  • 无法在 ROS 中使用本地安装的 Protocol Buffer

    我已经安装了协议缓冲区 https developers google com protocol buffers 本地 ROS包的目录结构如下 CMakeLists txt package xml include addressbook p
  • 在 Ubuntu 18.10 上安装 ROS Melodic

    I can t是唯一对 Cosmic 与 Wayland 和 Melodic 的组合感兴趣的人 我会坦白说 我似乎已经在 XPS 13 9370 上成功管理了此操作 或者至少安装脚本 最终 成功完成 然而 有一个非常棘手的解决方法 无论结果
  • 如何访问 Heroku 中的 docker 容器?

    我已按照此处构建图像的说明进行操作 https devcenter heroku com articles container registry and runtime getting started https devcenter her
  • ROS安装错误(Ubuntu 16.04中的ROS Kinetic)

    中列出的步骤顺序http wiki ros org kinetic Installat 已被关注 尝试在Ubuntu 16 04中安装ROSkinetic 输入以下命令时出错 sudo apt get install ros kinetic
  • ROS 从 python 节点发布数组

    我是 ros python 的新手 我正在尝试从 python ros 节点发布一个一维数组 我使用 Int32MultiArray 但我无法理解多数组中布局的概念 谁能给我解释一下吗 或者还有其他方式发布数组吗 Thanks usr bi
  • 如何使用订阅者选项?

    我现在开始使用 Pubsubhubbub 以及所有关于实时的东西 但我在使用订阅者选项时遇到了问题 我正在尝试用 PHP 开发一个网络应用程序 订阅 RSS 之前发布的 到 Hub http pubsubhubbub appspot com
  • 如何使用 PyQT5 连接和分离外部应用程序或对接外部应用程序?

    我正在使用 ROS 为多机器人系统开发 GUI 但我对界面中最不想做的事情感到困惑 在我的应用程序中嵌入 RVIZ GMAPPING 或其他屏幕 我已经在界面中放置了一个终端 但我无法解决如何向我的应用程序添加外部应用程序窗口的问题 我知道
  • 集群应用程序服务器中的 JMS 主题订阅者如何接收消息?

    假设我创建了一个带有一个订阅者 PropertiesSubscriber 的 JMS 主题 PropertiesTopic PropertiesSubscriber 运行在负载平衡的应用程序服务器集群中 如下图所示 替代文本 http ww
  • 安装 ROS 时 Cmake 未检测到 boost-python

    我一直在尝试在我的 Mac 上安装 ROS 并根据不同版本的 boost 使用不同的库解决了错误 然而 似乎有一个库甚至没有检测到 boost python 这是我得到的错误 CMake Error at usr local share c

随机推荐

  • TkMapper(通用mapper)

    TkMapper的配置及使用 TkMapper主要是做单标查询 xff0c 复杂的多表查询我们还得自己写sql 官方文档 xff1a 点击查看使用的是Springboot框架使用的数据库表ums permision xff1a idpidn
  • python两个 list 获取交集,并集,差集的方法

    1 获取两个list 的交集 方法一 a 61 2 3 4 5 b 61 2 5 8 tmp 61 val for val in a if val in b 列表推导式求的两个列表的交集 print tmp 2 5 方法二 print li
  • 报错:EL1007E: Property or field 'name' cannot be found on null

    SpringBoot集成thymeleaf做开发遇到的错误 Caused by org springframework expression spel SpelEvaluationException EL1007E Property or
  • Docker-1.0>>>>>>初阶学习

    文章目录 Docker学习总结一 Docker的安装 xff1a 二 Docker常用命令1 帮助命令 xff1a 2 镜像命令 xff1a 3 容器命令 xff1a 三 镜像详解四 容器数据卷 xff08 持久化 xff0c 数据共享 x
  • 报错:iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 5000

    Docker启动容器报错 docker Error response from daemon driver failed programming external connectivity on endpoint myrabbit 详细信息
  • 报错:yum install 安装时报yum doesn't have enough cached data to continue

    yum install 安装时报错 One of the configured repositories failed 未知 and yum doesn t have enough cached data to continue At th
  • Logback和Log4j详解

    文章目录 日志框架前言 一 日志简介1 什么是日志 xff1f 2 日志的用途 xff1f 二 常用的日志框架1 日志门面2 logback xff08 更快的执行速度使其成为主流 xff09 2 1 引入依赖2 2 编写xml文件2 3
  • cpu占用过高解决方案实践

    今天在查看项目服务器的时候 xff0c 发现cpu一直占用99 多 xff0c 于是就有了这篇文章 1 找到占用cpu高的进程 通过top命令来查看cpu占用高的进程有哪些 xff0c 如图 xff1a top 这里的pid代表的就是进程i
  • Java Stream流常用功能示例

    Steam流是Java8的新特性 xff0c 今个工作中经常用的功能写法 按条件过滤 collect span class token punctuation span span class token function stream sp
  • Mysql-->Binlog的查看

    一 使用Navicat查看binlog信息 1 查看binlog的信息 span class token keyword show span variables span class token operator like span spa
  • Linux开发环境配置---Java、Maven、Git和Nodejs

    Linux开发环境配置 1 Java环境 span class token comment 1 下载Java软件包 xff0c orcal或者openjdk都可以 xff0c 并上传到linux服务器 span span class tok
  • Linux下安装及简单使用nmap

    nmap是一款非常实用的扫描工具 xff0c 适用于linux windows mac三大主流平台 小编使用centos编译安装nmap 7 01版本 下载包 xff1a wget http nmap span class hljs pre
  • VNC server简单配置vnc

    linux 下VNC的配置 下面的命令可以结合远程shell 来进行 进程查找 xff1a ps ef grep i vnc 系统中一共有两个vnc xff1a 一个是系统管理自带的路径为 xff1a system gt perferenc
  • 元学习

    元学习是要学会任务中的特征表示 xff0c 从而在新任务上泛化 元学习主要解决的是学会如何学习的问题 元学习主要包括 xff1a zero shot One shot Few shot learning 元学习的主要方法包括 xff1a 基
  • windows media Foundation

    转自 xff1a https docs microsoft com en us windows desktop medfound microsoft media foundation sdk Microsoft Media Foundati
  • vscode nodemon打断点

    span class token number 1 span xff0c 修改 span class token keyword package span span class token punctuation span json spa
  • putty远程连接centos7的问题(time out)

    我在使用putty远程连接centos7时 xff0c 碰见了time out以及connection refused 的问题 现在总结一下 xff0c 以免之后再被绊倒 一 xff0c time out 问题分析 xff1a 我遇到的ti
  • Marvell 98DX3236系列交换机Uboot及内核文件烧写

    1 开发环境 开发板硬件相关 1 交换机开发板型号 RD XC3 24G4XG B 2 交换机CPU型号 98DX3236 3 交换机PHY芯片型号 88E1680 开发板软件相关 1 CPLD LC4032V 程序 ac3 24p jed
  • k8s学习笔记-部署Flannel网络

    主机列表 本次实验选择5台主机 xff0c 3台作为master主机 xff0c 2台作为node节点 节点ipOS版本hostname f安装软件192 168 0 1RHEL7 4k8s master01docker etcd flan
  • ROS教程四——编写Publisher和Subscriber节点(C++篇)

    本教程介绍如何使用C 43 43 编写发布者和订阅者节点 1 编写 Publisher Node 节点 是连接到ROS网络的可执行文件的ROS术语 现在将创建一个发布者 xff08 publisher talker xff09 节点 xff