ROS wiki系列|通过ROS wiki-tutorials学习节点

本文深入浅出地介绍了ROS(Robot Operating System)中的节点概念及其使用方法,包括如何利用roscore、rosnode和rosrun命令行工具操作节点,以及如何用C++编写简单的发布者和订阅者节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面几期我们讲的都是一些入门相关的内容——
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(机器人操作系统,Robot Operating System),是专为机器人软件开发所设计出来的一套电脑操作系统架构。它是一个开源的元级操作系统(后操作系统),提供类似于操作系统的服务,包括硬件抽象描述、底层驱动程序管理、共用功能的执行、程序间消息传递、程序发行包管理,它也提供一些工具和库用于获取、建立、编写和执行多机融合的程序。 ROS的运行架构是一种使用ROS通信模块实现模块间P2P的松耦合的网络连接的处理架构,它执行若干种类型的通讯,包括基于服务的同步RPC(远程过程调用)通讯、基于Topic的异步数据流通讯,还有参数服务器上的数据存储。 1 发展目标 2 ROS的概念 2.1 ROS 的 Filesystem Level 2.2 ROS 的 Computation Graph Level 3 参考文献 4 外部链接 发展目标 ROS的首要设计目标是在机器人研发领域提高代码复用率。ROS是一种分布式处理框架(又名Nodes)。这使可执行文件能被单独设计,并且在运行时松散耦合。这些过程可以封装到数据包(Packages)和堆栈(Stacks)中,以便于共享和分发。ROS还支持代码库的联合系统。使得协作亦能被分发。这种从文件系统级别到社区一级的设计让独立地决定发展和实施工作成为可能。上述所有功能都能由ROS的基础工具实现。 为了实现“共享与协作”这一首要目标,人们制订了ROS架构中的其他支援性目标: “轻便”:ROS是设计得尽可能方便简易。您不必替换主框架与系统,因为ROS编写的代码可以用于其他机器人软件框架中。毫无疑问的,ROS更易于集成与其他机器人软件框架。事实上ROS已完成与OpenRAVE、Orocos和Player的整合。 ROS-agnostic库:【agnostic:不可知论】建议的开发模型是使用clear的函数接口书写ROS-agnostic库。 语言独立性:ROS框架很容易在任何编程语言中执行。我们已经能在Python和C++中顺利运行,同时添加有Lisp、Octave和Java语言库。 测试简单:ROS有一个内建的单元/组合集测试框架,称为“rostest”。这使得集成调试和分解调试很容易。 扩展性:ROS适合于大型实时系统与大型的系统开发项目。 ROS的概念 ROS有三个层次的概念:分别为Filesystem level,Computation graph level, 以及Communication level。 以下内容具体的总结了这些层次及概念。除了这三个层次的概念, ROS也定义了两种名称-- Package资源名称和Graph资源名称。同样会在以下内容中提及。 ROS 的 Filesystem Level 文件系统层概念就是你在碟片里面遇到的资源,例如: Packages:ROS的基本组织,可以包含任意格式文件。一个Package 可以包含ROS执行时处理的文件(nodes),一个ROS的依赖库,一个数据集合,配置文件或一些有用的文件在一起。 Manifests:Manifests (manifest.xml) 提供关于Package元数据,包括它的许可信息和Package之间依赖关系,以及语言特性信息像编译旗帜(编译优化参数)。 Stacks: Stacks 是Packages的集合,它提供一个完整的功能,像“navigation stack” Stack与版本号关联,同时也是如何发行ROS软件方式的关键。 Manifest Stack Manifests: Stack manifests (stack.xml) 提供关于Stack元数据,包括它的许可信息和Stack之间依赖关系。 Message (msg) types: 信息描述, 位置在路径:my_package/msg/MyMessageType.msg, 定义数据类型在ROS的 messages ROS里面。 Service (srv) types: 服务描述,位置在路径:my_package/srv/MyServiceType.srv, 定义这个请求和相应的数据结构 在ROS services 里面。 ROS 的 Computation Graph Level Computation Graph Level(计算图)就是用ROS的P2P(peer-to-peer网络传输协议)网络集中处理所有的数据。基本的Computation Graph的概念包括Node, Master, Parameter Sever,messages, services, topics, 和bags, 以上所有的这些都以不同的方式给Graph传输数据。 Nodes: Nodes(节点)是一系列运行中的程序。ROS被设计成在一定颗粒度下的模块化系统。一个机器人控制系统通常包含许多Nodes。比如一个Node控制激光雷达,一个Node控制车轮马达,一个Node处理定位,一个Node执行路径规划,另外一个提供图形化界面等等。一个ROS节点是由Libraries ROS client library写成的, 例如 roscpp 和 rospy. Master: ROS Master 提供了登记列表和对其他计算图的查找。没有Master,节点将无法找到其他节点,交换消息或调用服务。 Server Parameter Server: 参数服务器使数据按照钥匙的方式存储。目前,参数服务器是主持的组成部分。 Messages:节点之间通过messages来传递消息。一个message是一个简单的数据结构,包含一些归类定义的区。支持标准的原始数据类型(整数、浮点数、布尔数,等)和原始数组类型。message可以包含任意的嵌套结构和数组(很类似于C语言的结构structs) Topics: Messages以一种发布/订阅的方式传递。一个node可以在一个给定的topic中发布消息。Topic是一个name被用于描述消息内容。一个node针对某个topic关注与订阅特定类型的数据。可能同时有多个node发布或者订阅同一个topic的消息;也可能有一个topic同时发布或订阅多个topic。总体上,发布者和订阅者不了解彼此的存在。主要的概念在于将信息的发布者和需求者解耦、分离。逻辑上,topic可以看作是一个严格规范化的消息bus。每个bus有一个名字,每个node都可以连接到bus发送和接受符合标准类型的消息。 Services:发布/订阅模型是很灵活的通讯模式,但是多对多,单向传输对于分布式系统中经常需要的“请求/回应”式的交互来说并不合适。因此,“请求/回应” 是通过services来实现的。这种通讯的定义是一种成对的消息:一个用于请求,一个用于回应。假设一个节点提供了一个服务提供下一个name和客户使用服务发送请求消息并等待答复。ROS的客户库通常以一种远程调用的方式提供这样的交互。 Bags: Bags是一种格式,用于存储和播放ROS消息。对于储存数据来说Bags是一种很重要的机制。例如传感器数据很难收集但却是开发与测试中必须的。 在ROS的计算图中,ROS的Master以一个name service的方式工作。它给ROS节点存储了topics和service的注册信息。Nodes 与Master通信从而报告它们的注册信息。当这些节点与master通信的时候,它们可以接收关于其他以注册节点的信息并且建立与其它以注册节点之间的联系。当这些注册信息改变时Master也会回馈这些节点,同时允许节点动态创建与新节点之间的连接。 节点之间的连接是直接的; Master仅仅提供了查询信息,就像一个DNS服务器。节点订阅一个topic将会要求建立一个与发布该topics的节点的连接,并且将会在同意连接协议的基础上建立该连接。ROS里面使用最广的连接协议是TCPROS,这个协议使用标准的TCP/IP 接口。 这样的架构允许脱钩工作(decoupled operation),通过这种方式大型或是更为复杂的系统得以建立,其中names方式是一种行之有效的手段。names方式在ROS系统中扮演极为重要的角色: topics, services, and parameters 都有各自的names。每一个ROS客户端库都支持重命名,这等同于,每一个编译成功的程序能够以另一种形似【名字】运行。 例如,为了控制一个北阳激光测距仪(Hokuyo laser range-finder),我们可以启动这个hokuyo_node 驱动,这个驱动可以给与激光仪进行对话并且在"扫描"topic下可以发布sensor_msgs/LaserScan 的信息。为了处理数据,我们也许会写一个使用laser_filters的node来订阅"扫描"topic的信息。订阅之后,我们的过滤器将会自动开始接收激光仪的信息。 注意两边是如何脱钩工作的。 所有的hokuyo_node的节点都会完成发布"扫描",不需要知道是否有节点被订阅了。所有的过滤器都会完成"扫描"的订阅,不论知道还是不知道是否有节点在发布"扫描"。 在不引发任何错误的情况下,这两个nodes可以任何的顺序启动,终止,或者重启。 以后我们也许会给我们的机器人加入另外一个激光器,这会导致我们重新设置我们的系统。我们所需要做的就是重新映射已经使用过的names。当我们开始我们的第一个hokuyo_node时,我们可以说它用base_scan代替了映射扫描,并且和我们的过滤器节点做相同的事。现在,这些节点将会用base_scan的topic来通信从而代替,并且将不再监听"扫描"topic的信息。然后我们就可以为我们的新激光测距仪启动另外一个hokuyo_node。 参考文献 http://www.ros.org/wiki/ros http://bbs.axnzero.com/index.php http://blog.sina.com.cn/digital2image2processing
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值