core调用了roslaunch.main,我们继续追踪,进到ros_comm-noet-develtoolsroslaunchsrcroslaunch文件夹中,发现有个__init__.py文件,说明这个文件夹是一个包,打开__init__.py文件找到def main(argv=sys.argv),这就是roscore调用的函数roslaunch.main的实现,如下(这里只保留主要的代码,不太重要的删掉了)。
def main(argv=sys.argv):
opons = None
logger = None
try:
from . import rlutil
paer = _get_optparse()
(options, args) = parser.parse_args(argv[1:])
args = rlutil.resolve_launch_arguments(args)
wri_d_file(options.pid_fn, options.ce, options.port)
uuid = rlutil.get_or_generate_uuid(options.run_id, options.wt_for_master)
configure_logging(uuid)
# #3088: don't check disk usage on remote machines
if not options.child_name and not options.skip_log_check:
rlutil.check_log_disk_usage()
logger = logging.getLogger('roslaunch')
logger.info("roslaunch starting with args %s"%str(argv))
logger.info("roslaunch env is %s"%os.environ)
if options.child_name:
# 这里没执行到,就不列出来了
else:
logger.info('starting in server mode')
# #1491 change terminal name
if not options.disable_title:
rlutil.change_terminal_name(args, options.core)
# Re roslaunch string from stdin when - is passed as launch filename.
roslaunch_strs = []
# This is a roslaunch parent, spin up parent server and launch processes.
# args are the roslaunch files to load
from . import parent as roslaunch_parent
# force a port binding spec if we are running a core
if options.core:
options.port = options.port or DEFAULT_MASTER_PORT
p = roslaunch_parent.ROSLaunchParent(uuid, args, roslaunch_strs=roslaunch_strs, is_core=options.core, port=options.port, local_only=options.local_only, verbose=options.verbose, force_screen=options.force_screen, force_log=options.force_log, num_workers=options.num_workers, timeout=options.timeout, master_logger_level=options.master_logger_level, show_summary=not options.no_summary, force_required=options.force_required, sigint_timeout=options.sigint_timeout, sigterm_timeout=options.sigterm_timeout)
p.start()
p.spin()
roslaunch.main开启了日志,日志记录的信息可以帮我们了解main函数执行的顺序。
我们去Ubuntu的.ros/log/路径下,打开roslaunch-ubuntu-52246.log日志文件,内容如下。
通过阅读日志我们发现,main函数首先检查日志文件夹磁盘占用情况,如果有剩余空间就继续往下运行。
然后把运行roscore的终端的标题给改了。
再调用ROSLaunchParent类中的函数,这大概就是main函数中最重要的地方了。
ROSLaunchParent类的定义是在同一路径下的parent.py文件中。为什么叫LaunchParent笔者也不清楚。
先不管它,我们再看日志,发现运行到了下面这个函数,它打算启动XMLRPC服务器端。
所以调用的顺序是:roslaunch_ init _.py文件中的main()函数调用parent.pystart()函数,start()函数调用自己类中的_start_infrastructure()函数,_start_infrastructure()函数调用自己类中的_start_server()函数,_start_server()函数再调用server.py中的start函数。
def _start_server(self):
self.logger.info("starting parent XML-RPC server")
self.server = roslaunch.server.ROSLaunchParentNode(self.config, self.pm)
self.server.start()
我们再进到server.py文件中,找到ROSLaunchNode类,里面的start函数又调用了父类XmlRpcNode中的start函数。
class ROSLaunchNode(xmlrpc.XmlRpcNode):
"""
Base XML-RPC server for roslaunch parent/child processes
"""
def start(self):
logger.info("starting roslaunch XML-RPC server")
super(ROSLaunchNode, self).start()
我们来到ros_comm-noetic-develtoolsrosgraphsrcrosgraph路径,找到xmlrpc.py文件。找到class XmlRpcNode(object)类,再进入start(self)函数,发现它调用了自己类的run函数,run函数又调用了自己类中的_run函数,_run函数又调用了自己类中的_run_init()函数,在这里才调用了真正起作用的ThrengXMLRPCServer类。
因为master节点是用python实现的,所以,需要有python版的XMLRPC库。
幸运的是,python有现成的XMLRPC库,叫pleXMLRPCServer。SimpleXMLRPCServer已经内置到python中了,无需安装。
所以,ThreadingXMLRPCServer类直接继承了SimpleXMLRPCServer,如下。
class ThreadingXMLRPCServer(socketserver.ThreadingMixIn, SimpleXMLRPCServer)