首页 关于
树枝想去撕裂天空 / 却只戳了几个微小的窟窿 / 它透出天外的光亮 / 人们把它叫做月亮和星星
目录

ROS的Graph和Node

上一节中,我们介绍了ROS中软件组织的基本单位Package,本文我们将介绍在运行时ROS的基本单位Node。 所谓的Node,就是ROS系统中运行的一个进程。在ROS系统运行时,往往需要在各个进程或者说是Node之间传递一些数据。把信息的传递看做是图的边,进程看做是图的点,运行时的ROS系统就是一个图Graph。

在后续的介绍中我们会提到,Node通过发布和订阅Topic,提供和请求服务等形式实现信息的传递。这些都需要借助ROS客户端库(ROS Client library)来实现。 rospy和roscpp就分别是python版本和c++版本的客户端库,基本上所有的ROS程序都需要用到这两个包, 这也是为什么我们在上节中创建的package指定它们作为依赖的原因。

1. rosnode

rosnode是一个查看ROS系统中运行的各个Node信息的工具。我们仍然以初体验中提到的turtle_sim为例进行介绍。 我们通过rosnode list可以查看当前系统中正在运行的Node,但在这之前我们需要先运行roscore,否则会出现类似如下提示信息,说找不到master。

        $ rosnode list 
        ERROR: Unable to communicate with master!
master是roscore的一部分,它主要用于管理系统的各个Node,以及Node之间的通信。运行roscore之后,系统中就会有一个叫做rosout的节点,它是ros系统的log机制,用于输出和打印node节点的调试信息等。 每次运行roscore时它都是要运行的。
        $ roscore &
        $ rosnode list 
        /rosout
通过rosnode info可以查看一个Node的详细信息。
        $ rosnode info rosout
        --------------------------------------------------------------------------------
        Node [/rosout]
        Publications: 
         * /rosout_agg [rosgraph_msgs/Log]
        
        Subscriptions: 
         * /rosout [unknown type]
        
        Services: 
         * /rosout/set_logger_level
         * /rosout/get_loggers
        
        
        contacting node http://gyc:33860/ ...
        Pid: 1918
从打印的rosout的详细信息中,我们可以看到它对外发布着/rosout_agg的主题,订阅着/rosout主题,同时提供着/rosout/set_logger_level和/rosout/get_loggers两个服务。 关于主题和服务我们会在后续的文章中予以详细的介绍。信息的最后还列出了Node的端口号(http://gyc:33860)和进程ID(Pid: 1918)。

接下来,我们用工具rosrun打开例程turtlesim_node。它的用法如下:

        $ rosrun [package_name] [node_name]
rosrun通过指定package和node的名称运行一个节点。在官方例程turtlesim的pacakge下有四个程序或者说是node:draw_square, mimic, turtlesim_node, turtle_teleop_key。 这里我们运行turtlesim_node。
        $ rosrun turtlesim turtlesim_node
        [ INFO] [1511662070.835808200]: Starting turtlesim with node name /turtlesim
        [ INFO] [1511662070.840378400]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
它直接打印出了两行信息,其中的[ INFO]表示这两行信息的log等级,而[1511662070.835808200]则描述了时间信息。我们主要关注第一行日志,它提到运行turtlesim具有节点名称'/turtlesim'。 这与我们运行rosrun时的节点名称不是一个东西。在rosrun时,实际上是要找到一个叫做turtlesim_node的可执行文件,我们把'turtlesim_node'称为它的程序名。 而日志中提到的'/turtilesim'则是它在master中注册的名称,称为运行时名称。在ROS系统中,运行时名称唯一的标识了一个node,其它node都是通过运行时名称查找某个node并与之通信的。 我们完全可以在运行程序的时候就指定node的运行时名称,让我们再打开一个终端,执行如下的指令:
        $ rosrun turtlesim turtlesim_node __name:=turtle2
        [ INFO] [1511663400.001377120]: Starting turtlesim with node name /turtle2
        [ INFO] [1511663400.007227206]: Spawning turtle [turtle1] at x=[5.544445], y=[5.544445], theta=[0.000000]
可以看到,这次的提示信息中说运行的turtlesim的节点名称就是我们指定的名字'/turtle2'。再打开一个终端,运行rosnode list查看一下当前系统中正在运行的node, 可以看到我们刚刚运行的两个节点'turtle2'和'turtlesim'。
        $ rosnode list
        /rosout
        /turtle2
        /turtlesim

2. rostopic

现在让我们再运行一个node来控制这两个乌龟在窗口中爬行。新打开一个终端,并执行如下指令:

        $ rosrun turtlesim turtle_teleop_key 
        Reading from keyboard
        ---------------------------
        Use arrow keys to move the turtle.
终端在打印了如上所示的信息后就不再动了,此时如果我们按下键盘的四个方向键就可以在两个turtlesim的窗口中看到乌龟们以相同的节奏在窗口上摩擦摩擦,留下魔鬼的痕迹......

通过rosnode查看当前系统的node信息,可以看到新运行的node名称为'/teleop_turtle',它与'/turtlesim'和'/turtle2'之间存在一个联系:'/turtle2'和'/turtlesim'都订阅了一个叫做'/turtle1/cmd_vel'的主题, 而'/teleop_turtle'则发布了一个'/turtle1/cmd_vel'的主题。正是这个主题或者说是topic建立起了它们之间的联系。ros专门有一个图形化的工具rqt_graph可以画出这种主题发布和订阅的关系图,

        $ rosrun rqt_graph rqt_graph
运行指令就可以得到类似下图的一个窗口。在这个窗口中的箭头(专业点说是有向边)描述了它们三者之间的topic关系。因为'/turtlesim'和'/turtle2'都订阅了同一个topic,所以它们会以相同的节奏摩擦。

ros专门提供了一个rostopic的工具用于查询系统中topic的各种信息。我们可以以'-h'的参数查看各种工具的帮助。

        $ rostopic -h
        rostopic is a command-line tool for printing information about ROS Topics.
        
        Commands:
            rostopic bw display bandwidth used by topic
            rostopic delay  display delay of topic from timestamp in header
            rostopic echo   print messages to screen
            rostopic find   find topics by type
            rostopic hz display publishing rate of topic    
            rostopic info   print information about active topic
            rostopic list   list active topics
            rostopic pub    publish data to topic
            rostopic type   print topic or field type
        
        Type rostopic  -h for more detailed usage, e.g. 'rostopic echo -h'
比如说,我们可以用list指令列出当前系统中的topic,
        $ rostopic list 
        /rosout
        /rosout_agg
        /turtle1/cmd_vel
        /turtle1/color_sensor
        /turtle1/pose
也可以列出某个topic的详细信息,从中我们可以看到主题'/turtle1/cmd_vel'有一个发布者和两个订阅者。
        $ rostopic list /turtle1/cmd_vel -v
        
        Published topics:
         * /turtle1/cmd_vel [geometry_msgs/Twist] 1 publisher
        
        Subscribed topics:
         * /turtle1/cmd_vel [geometry_msgs/Twist] 2 subscribers
在ROS中各个node发布和订阅的是主题topic,而实际发出和接收到的则是一条条的消息message。就好像我们订报纸一样,订的是《人民日报》《环球时报》等报刊,实际收到的则是一张张的报纸。 每个topic都有一个类型,比如这里的'/turtle1/cmd_vel'的类型就是'geometry_msgs/Twist',不同类型的message的数据格式是不同的,这也跟《人民日报》和《环球时报》的版面和风格不一样类似。 我们可以通过rosmsg查看各种类型的message的数据格式:
        $ rosmsg show geometry_msgs/Twist
        geometry_msgs/Vector3 linear
          float64 x
          float64 y
          float64 z
        geometry_msgs/Vector3 angular
          float64 x
          float64 y
          float64 z
具体message的数据格式是什么,都有什么意义,是根据不同的应用而变化的,后续我们会创建自己的发布订阅主题,那时再详细介绍message。

3. service

服务Service是另一种用于node之间的通信机制。node会为了实现某些特殊的功能而提供对应的service,我们先把这个node称为服务器(Server)。 当我们或者其它node需要这种特殊功能的时候,就会向服务器请求(request)这一服务,把这个请求服务的node称为客户端(Client)。在服务器接到了请求之后,会相应的完成这种特殊的功能, 并最后给出响应。

比如说我们乌龟仿真就提供了一种向窗口中添加乌龟的服务'/spawn'。我们可以通过工具rosserver来查看当前系统中的各种service以及service的具体信息。下面是'/spawn'的具体信息, 它是由'/turtle2'提供的服务(至于说'/turtlesim'去哪里了,我还没整明白)。

        $ rosservice info /spawn 
        Node: /turtle2
        URI: rosrpc://gyc:39146
        Type: turtlesim/Spawn
        Args: x y theta name
最后一行中的Args列出了请求该服务时的参数,x,y分别是放入乌龟的坐标,theta是乌龟的方向,name则是乌龟的名字。比如我们添加一个叫做'wuhaha'的乌龟:
        $ rosservice call /spawn 2 2 0.2 "wuhaha"
        name: wuhaha
在'turtle2'的窗口中出现了一个新的乌龟。再查看一下'/turtle2'的节点信息,我们可以看到新增了三个topic: '/wuhaha/color_sensor', '/wuhaha/pose' 和 '/wuhaha/cmd_vel'。 也就是说我们可以通过主题'wuhaha/cmd_vel'来控制新乌龟wuhaha在窗口中摩擦。
        $ rosnode info /turtle2 
        --------------------------------------------------------------------------------
        Node [/turtle2]
        Publications: 
         * /turtle1/color_sensor [turtlesim/Color]
         * /wuhaha/color_sensor [turtlesim/Color]
         * /rosout [rosgraph_msgs/Log]
         * /wuhaha/pose [turtlesim/Pose]
         * /turtle1/pose [turtlesim/Pose]
        
        Subscriptions: 
         * /wuhaha/cmd_vel [unknown type]
         * /turtle1/cmd_vel [geometry_msgs/Twist]

        ...

4. 总结

在本文中,我们介绍了ROS运行时的基本单元Node。它实际上就是一个进程,通过发布订阅主题,请求响应服务实现与其它Node之间的通信。把通信关系看做是系统运行中的边,Node看做是节点, 整个ROS系统在运行过程中就构成了一个图Graph。




Copyright @ 高乙超. All Rights Reserved. 京ICP备16033081号-1