欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)

程序员文章站 2022-07-14 22:09:47
...

        ROS源码量对于本菜鸟来说还是挺大的,单是roscore下就牵扯了各种类和函数调用。这篇文章仅代表我的个人见解,错误之处望各位不吝赐教。

       ROS启动时首先会要求执行roscore这条命令,在wiki里面是这样对roscore进行介绍的:

       roscore是一个节点和程序的集合,为了让ROS节点进行通信,必须运行roscore。注意:若使用的是roslaunch,如果ROS检测到roscore没有运行,ROS也将将自动启动roscore。

       roscore将启动ros master、ros参数服务器和rosout节点。

    一、roscore源码分析:

       1、如果按照前一篇博客来安装ros_comm,roscore命令的位置在~/ros_catkin_ws/install_isolated/bin/roscore。roscore首先会调用roslaunch(跟roscore相同文件夹),由roslaunch来调用roslaunch包下的其他文件,roslaunch包的位置与roslaunch文件位置不同,roslaunch包在~/ros_catkin_ws/install_isolated/lib/python2.7/dist-packages/roslaunch,同样的,这个路径不是每个人都完全一样,各位请根据自己情况自行调整。

       roslaunch首先调用的是_init_.py的main(),初始化各种参数和环境变量,如设置roslaunch的日志文件位置。然后检查已存在的日志文件大小,若已超过1GB则会提醒用户执行rosclean purge命令。

    roslaunch文件在~/.ros/log下,每次执行roscore都会生成唯一的uuid,以uuid号为日志文件夹名,该文件夹下的roslaunch-........log便是roslaunch的日志,省略号处是机器号和pid号。

     2、_init_.py各种参数配置好后就到了p.start(),p为类ROSLaunchParent,定义是在roslaunch文件夹下的parent.py。ROSLaunchParent的类函数start负责启动ROSlaunch,自然包括其下各自服务的启动:

       2.1、 _start_infrastructure():加载配置,启动XMLRPC服务器和进程监视器

       _start_infrastructure()首先调用_load_config(),加载配置变量;

        然后调用_start_pm()来启动进程监视器,进程监视器的代码部分在pemon.py实现;

       接着是_start_server(),该函数启动XMLRPC服务器,涉及到的文件主要是:server.py->rosgraph的xmlrpc.py->rosgraph的network.py;

       最后是_start_remote(),用于初始化并运行远程进程运行器,若不存在远程运行器,则不执行相关操作。

       2.2、_init_runner():初始化roslaunch运行器。

      _init_runner()初始化了在launch.py的类ROSLaunchRunner,再调用config.py的summary()将roslaunch的相关启动信息输出给用户。

       2.3、launch.py的launch()调用_setup()来设置ROS网络状态,包括参数服务器状态和核心服务,_launch_nodes()来启动声明的节点和ros master。

      2.4、pmon.py的registrations_complete()设置registrations_complete标志后,如果没有其他进程需要监控,进程监视器将退出。

      到这一步已经将各种参数初始化,完成好了准备工作,下面开始运行roslaunch执行器。

      3、_init_.py的p.spin()调用的是parent.py的spin(),运行ROSLaunch直到程序退出。

      roscore的工作大体就是这些内容,下图是我纪录的roscore函数的调用顺序,不全,给大家参考一下吧。。

ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)

      官方也给出roscore涉及到的类的继承关系及类中的数据成员和成员函数:

ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)

ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)

    二、添加开机节点

      roscore从roscore.xml读取需要启动的节点的信息,roscore.xml位于ros_catkin_ws/install_isolated/etc/ros/roscore.xml,未修改的roscore.xml是这样的:

<!-- 
  ROS Core Stack definition

  Before making any modifications to this file, please read:
  http://ros.org/wiki/roscore
  -->
<launch>
  <group ns="/">
    <param name="rosversion" command="rosversion roslaunch" />
    <param name="rosdistro" command="rosversion -d" />
    <node pkg="rosout" type="rosout" name="rosout" respawn="true"/>
  </group>
</launch>

      若要添加开机一起启动的节点,可以修改roscore.xml文件,下面我以ros官方tutorial的编写新节点的talker节点为例来进行说明。创建的talker节点在/home/haroroda/catkin_ws/src/talker/scripts/talker.py,按照tutorial里source好路径便可以进行下一步。修改如下:

<!-- 
  ROS Core Stack definition

  Before making any modifications to this file, please read:
  http://ros.org/wiki/roscore
  -->
<launch>
  <group ns="/">
    <param name="rosversion" command="rosversion roslaunch" />
    <param name="rosdistro" command="rosversion -d" />
    <node pkg="rosout" type="rosout" name="rosout" respawn="true"/>
  </group>
  <group ns="/">
    <node pkg="talker" type="talker.py" name="talker" respawn="false"/>
  </group>
</launch>

      这里ns仍是“/”,个人认为只有路径写入$ROS_PACKAGE_PATH的都可以认为是“/”,然后很明显的pkg是包名。值得注意的是type和name分别代表带扩展名的文件名和文件名,我在这卡了很久,一开始type写的是文件名,name是带扩展名的文件名,然后就报错,一层层代码查过去,最后将type和name交换就好了。虽然不懂为啥但也不想深究了(知道答案的大佬们可以留言或私心告诉我,谢谢啦)。如果是c++写的可执行文件,则type和name是一样的。respawn表示是否要在roscore生命期间重启该节点,因为有些节点执行完就结束退出了,如果respawn设为true则roslaunch会在你的节点结束时又给重新启动,直到roscore退出执行。修改好后运行roscore测试一下:

ROS源码研究(二):命令roscore执行流程及添加开机自动启动的节点(类似/rosout)

      talker.py成功启动并结束,日志文件如图最后一行所示。