前面几期我们讲的都是一些入门相关的内容——
ROS wiki系列|ROS wiki初探(自用)
ROS wiki系列|Documentation-ROS部分讲解
ROS wiki系列|ROS入门基础概念讲解
今天咱们就来说说怎么用ROS wiki里的教程来学点东西(开始撸袖子)
首先打开我们之前已经讲过的ROS wiki中的教程页面:ROS-tutorials,前面已经讲过了这里面核心ROS教程部分是分为了新手级别和老手级别,鉴于咱们这是个入门的系列教程,接下来还是主要围绕beginner level的这些教程来进行学习(才不是我只会新手的教程呢 哼 好吧……其实是Σ( ° △ °|||))
今天咱们从最基础的开始,首先学习ROS中Node也就是节点这个概念相关的一些教程。
相关教程:
1.http://wiki.ros.org/ROS/Tutorials/UnderstandingNodes

2.http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29

1.Understanding ROS Nodes

这个教程主要是介绍了ROS中图的概念,并且讨论了roscore、rosnode和rosrun命令行工具的使用。
这里有一个关于图概念的快速概括

节点:节点是使用ROS与其他节点通信的可执行文件。
消息:订阅或发布话题时使用的ROS数据类型。
话题:节点可以向话题发布消息,也可以订阅话题以接收消息。
Master:为ROS命名的服务(即帮助节点找到彼此)
rosout:相当于stdout/stderr的ROS
roscore:Master + rosout +参数服务器(参数服务器稍后介绍)

节点实际上只不过是ROS包中的可执行文件。ROS节点使用ROS客户端库与其他节点通信。节点可以发布或订阅主题,也可以提供或使用服务。

ROS客户端库允许用不同编程语言编写的节点进行通信:
rospy = python客户端库
roscpp = c++客户端库

roscore

roscore是使用ROS时应该运行的第一个东西
运行roscore之后,正常情况下会在终端看到:

如果roscore没有成功运行,可以检查一下网络配置,如果没有成功运行且提示权限不足,需要给./ros文件夹赋予权限:sudo chown -R <your_username> ~/.ros

rosnode

在运行roscore的情况下,我们可以使用rosnode命令行工具来看看roscore都做了什么,这里我们再打开一个终端
ROS wiki当中也提示我们
注意:打开新终端时,您的环境将被重置,并且您的~ /.bashrc文件是有源的。如果您在运行rosnode等命令时遇到问题,则可能需要将一些环境设置文件添加到~/.bashrc或手动重新获取它们。
rosnode显示有关当前正在运行的 ROS 节点的信息。
运行rosnode list,终端将会显示正在运行的节点,我们可以看到目前只有一个节点在运行,也就是/rosout,这个节点在收集和记录节点的调试输出时始终在运行。
接下来我们可以使用rosnode info查看特定节点的信息,

我们可以通过rosnode info看到节点的相关信息,例如节点发布的话题、订阅的话题、提供的服务等等。

rosrun

rosrun允许使用包名直接在包中运行节点(而不必知道包的路径)。
使用方法:rosrun [package_name] [node_name]
我们可以用rosrun指令来启动小海龟例程,再打开一个新终端,运行rosrun turtlesim turtlesim_node,正常情况下将会弹出一个小海龟的弹窗(这里说明一下:小海龟的样子有好多种,还有三个头的,开海龟节点有点开盲盒那味,不知道大家还有没有开过形状更奇怪的呢?)
开启小海龟节点后,我们再次运行rosnode list,这下我们将会看到两个节点:/rosout和/turtlesim

此外,ROS还有一个强大的特性是可以从命令行重新分配名称
关闭turtlesim弹窗停止节点(或者返回到终端使用Ctrl+C退出进程),我们来试下重新运行,当然这次不太一样,我们用重映射参数来更改节点名:rosrun [package_name] [node_name] __name:=[new_node_name]
运行rosrun turtlesim turtlesim_node __name:=my_turtle后我们再次使用rosnode list,这个时候我们会看到两个节点:/my_turtle和/rosout,这就意味着我们重命名节点名成功啦!
注意:如果您仍然在列表中看到/turtlesim,这可能意味着您使用Ctrl+C在终端中停止了节点,而不是关闭窗口,或者您没有在网络设置-单机配置中定义的$ROS_HOSTNAME环境变量。您可以尝试使用rosnode cleanup清理rosnode列表。

现在我们再来试下rosnode的另一个命令rosnode ping [node_name]来确认一下节点是不是已经正常启动,运行rosnode ping my_turtle后,我们将在终端看到:

搞定,节点成功启动啦!

这个页面的内容总结一下:
roscore = ros+core: master(为ros提供名称服务)+ rosout (stdout/stderr) +参数服务器
rosnode = ros+node:获取节点信息的ros工具。
rosrun = ros+run:从给定的包中运行一个节点。

so,到这里我想你应该知道节点是啥、节点的作用是啥、怎么用命令行工具roscore、rosnode和rosrun了,懂了就要动手开干,接下来就来讲讲怎么写一个节点(再次撸袖子)

2.Writing a Simple Publisher and Subscriber (C++)

这个部分是讲怎么用C++来写一个节点,当然python也可以,道理差不多所以就挑C++的来讲,很简单的(手动狗头)

Writing the Publisher Node

怎么整一个发布者节点呢,往下看
首先要建立自己的工作空间和功能包,这部分在其他教程里有我就不讲了,百度也有详细教程,然后在功能包下创建一个src目录:mkdir -p src
src目录下将会包含这个功能包中的任何源文件
ROSwiki这里也举了一个编写发布者节点的例子:https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/talker/talker.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"#include <sstream>/*** 本教程演示了通过ROS系统发送消息的简单方法。*/
int main(int argc, char **argv)
{/*** ros::init()函数需要看到argc和argv,这样它就可以执行命令行提供的任何ros参数和名称重映射。* 对于编程式重标记,你可以使用不同版本的init(),它直接接受重标记,* 但对于大多数命令行程序,传递argc和argv是最简单的方法。init()的第三个参数是节点的名称。**在使用ros系统的任何其他部分之前,必须调用其中一个版本的ros::init()。*/ros::init(argc, argv, "talker");/*** NodeHandle是与ROS系统通信的主要接入点。* 第一个被构造的NodeHandle将完全初始化该节点,* 最后一个被破坏的NodeHandle将关闭该节点。*/ros::NodeHandle n;/*** advertise()函数是告诉ROS您想要发布给定主题名称的方法。* 这将调用对ROS主节点的调用,后者将保存谁在发布和谁在订阅的注册表。* 在这个advertise()调用完成后,主节点将通知任何试图订阅这个主题名的人,然后他们将与这个节点协商一个点对点连接。* advertise()返回一个Publisher对象,该对象允许您通过调用publish()来发布主题上的消息。* 一旦返回的Publisher对象的所有副本被销毁,主题将自动取消通告。* advertise()的第二个参数是用于发布消息的消息队列的大小。* 如果消息发布的速度比发送的速度快,这里的数字指定了在丢弃一些消息之前需要缓冲多少条消息。*/ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);ros::Rate loop_rate(10);/*** 我们已经发送了多少消息的计数。这用于为每个消息创建一个惟一的字符串。*/int count = 0;while (ros::ok()){/*** 这是一个消息对象。用数据填充它,然后发布它。*/std_msgs::String msg;std::stringstream ss;ss << "hello world " << count;msg.data = ss.str();ROS_INFO("%s", msg.data.c_str());/***publish()函数是发送消息的方式。参数是消息对象。这个对象的类型必须与作为advertise<>()调用的模板形参给出的类型一致,就像在上面的构造函数中所做的那样。*/chatter_pub.publish(msg);ros::spinOnce();loop_rate.sleep();++count;}return 0;
}

对代码来做一个分解解析:

#include "ros/ros.h"

ros/ros.h是一个方便的include,它包含了使用ros系统中最常见的公共部分所需的所有头文件。

#include "std_msgs/String.h"

这包括std_msgs/String消息,它驻留在std_msgs包中。这是从该包中的String.msg文件自动生成的头文件。有关消息定义的更多信息,请参见消息页面。

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

初始化ROS。这允许ROS通过命令行进行名称重映射——目前并不重要。这也是我们指定节点名称的地方。在运行的系统中,节点名称不能重复。
此处使用的名称必须是基本名称,即里面不能有/。

ros::NodeHandle n;

创建此进程节点的句柄。创建的第一个NodeHandle实际上将执行节点的初始化,而销毁的最后一个NodeHandle将清理该节点正在使用的所有资源。

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

告诉master我们将要发布一个std_msgs/String类型的关于主题“chatter”的消息。这让master告诉任何监听“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如果:

  • 收到一个SIGINT (Ctrl-C)
  • 我们已经被另一个同名节点踢出网络
  • ros::shutdown()已经被应用程序的另一部分调用
  • 所有的ros::NodeHandles已经被销毁

一旦ros::ok()返回false,所有的ros调用都将失败。

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

我们使用消息改编类(通常由msg文件生成)在ROS上广播消息。更复杂的数据类型是可能的,但现在我们将使用标准的String消息,它有一个成员:“data”。

chatter_pub.publish(msg);

现在,我们实际上把消息广播给任何有联系的人。

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

ROS_INFO和朋友们是我们printf/cout的替代品。有关更多信息,请参阅rosconsole文档。

ros::spinOnce();

在这里调用ros::spinOnce()对于这个简单的程序来说是不必要的,因为我们没有接收到任何回调。但是,如果您要向这个应用程序添加一个订阅,并且这里没有ros::spinOnce(),那么您的回调将永远不会被调用。所以,为了更好的衡量,添加它。

loop_rate.sleep();

现在我们使用ros::rate对象休眠一段时间,以达到10Hz的发布速率。
概括一下就是:

  • 初始化ROS系统;
  • 通知主服务器我们将发布关于chatter主题的std_msgs/String消息;
  • 在向chatter发布消息时,每秒循环10次。

Writing the Subscriber Node

依旧是一个例程:https://raw.github.com/ros/ros_tutorials/kinetic-devel/roscpp_tutorials/listener/listener.cpp

#include "ros/ros.h"
#include "std_msgs/String.h"/*** 本教程演示了通过ROS系统简单地接收消息。*/
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{ROS_INFO("I heard: [%s]", msg->data.c_str());
}int main(int argc, char **argv)
{ros::init(argc, argv, "listener");ros::NodeHandle n;/*** 使用subscribe()调用可以告诉ROS您希望接收关于给定主题的消息。* 这将调用对ROS主节点的调用,后者将保存谁在发布和谁在订阅的注册表。* 消息被传递给一个回调函数,这里称为chatterCallback。* subscribe()返回一个Subscriber对象,您必须持有该对象,直到您想取消订阅为止。* 当订阅服务器对象的所有副本超出范围时,将自动从该主题取消订阅此回调。** subscribe()函数的第二个参数是消息队列的大小。* 如果消息到达的速度比处理的速度快,这就是在开始丢弃最旧的消息之前将被缓冲的消息数。*/ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);/*** Ros::spin()将进入一个循环,泵送回调函数。* 在这个版本中,所有的回调都将在这个线程(主线程)中被调用。* ros::spin()将在按Ctrl-C时退出,或者被主节点关闭。*/ros::spin();return 0;
}

依旧是代码拆解解析,这里只讲跟前面发布者节点代码中没有重复的部分。

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);

通过主服务器订阅“chatter”话题。每当有新消息到达时,ROS将调用chatterCallback()函数。第二个参数是队列大小,以防我们无法足够快地处理消息。在本例中,如果队列达到1000条消息,当新消息到达时,我们将开始丢弃旧消息。
NodeHandle::subscribe()返回一个ros::Subscriber对象,您必须一直持有该对象,直到您想要取消订阅。当销毁Subscriber对象时,它将自动取消订阅聊天主题。
有几个版本的NodeHandle::subscribe()函数允许您指定一个类成员函数,甚至任何可以由Boost function对象调用的函数。roscpp overview包含更多信息。

ros::spin();

ros::spin()进入一个循环,尽可能快地调用消息回调。不过不要担心,如果没有什么可以让它做的,它不会占用太多的CPU。一旦ros::ok()返回false, ros::shutdown()将退出,这意味着ros::shutdown()被默认的Ctrl-C处理程序调用,master告诉我们关闭,或者被手动调用。
还有其他的方法来泵送回调,但是我们在这里不考虑这些。roscpp_tutorials包有一些演示应用程序来演示这一点。roscpp overview还包含更多信息。
概括一下就是:

  • 初始化ROS系统
  • 订阅这个话题
  • 循环,等待消息的到来
  • 当消息到达时,将调用chatterCallback()函数

Building your nodes

前面使用catkin_create_pkg创建新功能包的时候已经自动创建了一个package.xml和一个CMakelists.txt文件
前面我们创建的两个cpp文件分别为talker.cpp和listener.cpp,现在我们首先要修改CMakelists中的内容,在底部添加:

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空间的包目录中,默认位于~/catkin_ws/devel/lib/<包名>。
注意,你必须将可执行目标的依赖项添加到消息生成目标:

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:
在你的catkin工作空间下

cd ~ / catkin_ws
catkin_make

ok,到这里我们就完成了了解节点——节点的运行使用——节点的编写这样一个学习过程,下一期我们来讲讲topic话题~

ROS wiki系列|通过ROS wiki-tutorials学习节点相关推荐

  1. ROS wiki系列|通过ROS wiki-tutorials学习话题

    上一期指路:ROS wiki系列|通过ROS wiki-tutorials学习节点 这一期我们就用ROS wiki中的tutorials来学习ROS中另外一个重要的概念:topic--话题 在前面讲解 ...

  2. ROS wiki系列|通过ROS wiki-tutorials学习服务和参数

    依旧是上一期指路:ROS wiki系列|通过ROS wiki-tutorials学习话题 前面讲了节点和话题,我们接下来讲服务和参数,走你~ 同样甩上我们今天的教程页面链接:Understanding ...

  3. ROS wiki系列|Documentation-ROS部分讲解

    上一篇文章介绍了ROS wiki的大体结构,回顾戳→ROS wiki系列|ROS wiki初探 接下来的内容就是分模块介绍啦,首先是重头戏Documentation中的ROS部分,上一篇文章讲到这部分 ...

  4. ROS wiki系列|ROS wiki初探(自用)

    在进行ROS学习的过程中,我们总是需要借助一些资料来进行学习,其中,ROS wiki是每个ROS人都必不可少会使用到的工具,在ROS学习中我们也经常要使用ROS wiki来查阅一些语法的解析.功能包的 ...

  5. ROS wiki系列|ROS入门基础概念讲解

    上一期我们对ROS wiki中ROS部分进行了着重讲解,回顾戳这 这一期我们主要介绍ROS-getting started部分的一些基本概念 相关wiki页面:http://wiki.ros.org/ ...

  6. 【ROS wiki】利用ros wiki寻求问题答案

    ROS wiki系列文章简介:ROS wiki系列文章是本人ROS专栏下的子专题.该系列文章主要用来介绍:ROS初学者如何利用好ROS官方提供的ROS wiki平台,来查询ROS资料,了解ROS包的功 ...

  7. ros入门--中科院软件所ros学习笔记

    视频链接: 中科院软件所-机器人操作系统入门(ROS入门教程)_哔哩哔哩_bilibili 中科院软件所-机器人操作系统入门(ROS入门教程)_哔哩哔哩_bilibili 另外有一个不错的 学习网址: ...

  8. 古月居《ROS入门21讲》零基础学习笔记

    文章目录 前言 1.课程简介 2.Linux系统介绍及安装 3.Linux基础操作(操作集) 命令结构 常用命令 快捷操作 4.cpp&python极简基础(操作集) 简单对比 安装编译器 编 ...

  9. ROS机器人开发实践 [胡春旭] 学习笔记与资料

    资料链接: https://pan.baidu.com/s/1MRYL3asMJhOzWiAsBZKfzg 提取码: 9t3e 复制这段内容后打开百度网盘手机App,操作更方便哦 ROS常用的概念(一 ...

最新文章

  1. 从LeetCode 679. 24 Game--C++ 解法--二十四点 到穷举24点所有可能性-24点大全
  2. Web服务器性能/压力测试工具http_load、webbench、ab、Siege使用教程
  3. Global Mapper怎么能够导出.xyz文件
  4. 联想小新300加固态_就联想小新 Pro 13 固态硬盘混用一事,官方回应
  5. java打包python到exe文件
  6. 信息学奥赛一本通C++语言——1096:数字统计
  7. Office2010-2016官方镜像大全
  8. 穿透防火墙调用EJB--rmi-http在JBOSS中的应用
  9. SQLServer2K远程连接问题解决方案(转载自飞狐小屋)
  10. exclips为什么j创建局java出错_clips.BuildRule出错
  11. DevOps-2-从凤凰项目谈起
  12. 现在1分、2分、5分硬币的收藏价格如何呢?
  13. CF 949D Curfew——贪心(思路!!!)
  14. 【博弈论】Nim游戏/Nim博弈及其异或的详细易懂理解
  15. 【Musescore 】开源打谱软件 快速入门笔记
  16. 重庆APP开发价格费用如何计算?
  17. DHCP与DHCP中继
  18. Crackmes.de上borismilner的一个crackme
  19. Python-小数取整与小数四舍五入
  20. C# Buffer.BlockCopy方法详解

热门文章

  1. 江苏省普通话水平测试计算机评分细则,苏州语言文字网--[江苏省普通话水平测试评分细则(试行)]...
  2. 如何给PowerPoint每页加上总页码
  3. 星座夫妻(真的很准)
  4. com2引脚 proface_台达触摸屏rs485使用com2的那两个端子啊?
  5. 【python实现生成隐藏的一句话木马】
  6. ab753变频器参数怎么拷贝到面板_富士和三菱变频器面板参数的拷贝方法
  7. 如何在execl中制作列与列错开的表格?
  8. 流媒体流媒体ffmpeg_游戏流媒体服务将面临与流媒体电视相同的问题
  9. 计算机在教学管理中应用浅论,浅谈多媒体在计算机教学中的应用
  10. 齐鲁工业大学计算机应用技术专业,2017年齐鲁工业大学计算机应用技术研究所671C语言程序设计考研题库...