Esempio n. 1
0
def run_node(startcfg):
    '''
    Start a node local or on specified host using a :class:`.startcfg.StartConfig`

    :param startcfg: start configuration e.g. returned by :meth:`create_start_config`
    :type startcfg: :class:`fkie_node_manager_daemon.startcfg.StartConfig`
    :raise exceptions.StartException: on errors
    :raise exceptions.BinarySelectionRequest: on multiple binaries
    :see: :meth:`fkie_node_manager.host.is_local`
    '''
    hostname = startcfg.hostname
    nodename = roslib.names.ns_join(startcfg.namespace, startcfg.name)
    if not hostname or host.is_local(hostname, wait=True):
        # run on local host
        # interpret arguments with path elements
        args = []
        for arg in startcfg.args:
            new_arg = arg
            if arg.startswith('$(find'):
                new_arg = interpret_path(arg)
                rospy.logdebug("interpret arg '%s' to '%s'" % (arg, new_arg))
            args.append(new_arg)
        # set name and namespace of the node
        if startcfg.name:
            args.append("__name:=%s" % startcfg.name)
        if startcfg.namespace:
            args.append("__ns:=%s" % startcfg.namespace)
        # add remap arguments
        for key, val in startcfg.remaps.items():
            args.append("%s:=%s" % (key, val))
        cmd_type = startcfg.binary_path
        # get binary path from package
        if not cmd_type:
            try:
                cmd = roslib.packages.find_node(startcfg.package,
                                                startcfg.binary)
            except (roslib.packages.ROSPkgException,
                    rospkg.ResourceNotFound) as e:
                # multiple nodes, invalid package
                rospy.logwarn("resource not found: %s" % utf8(e))
                raise exceptions.ResourceNotFound(
                    startcfg.package, "resource not found: %s" % utf8(e))
            if isinstance(cmd, types.StringTypes):
                cmd = [cmd]
            if cmd is None or len(cmd) == 0:
                raise exceptions.StartException(
                    '%s in package [%s] not found!' %
                    (startcfg.binary, startcfg.package))
            if len(cmd) > 1:
                # Open selection for executables
                err = 'Multiple executables with same name in package [%s]  found:' % startcfg.package
                raise exceptions.BinarySelectionRequest(cmd, err)
            else:
                cmd_type = cmd[0]
        try:
            global STARTED_BINARIES
            STARTED_BINARIES[nodename] = (cmd_type, os.path.getmtime(cmd_type))
        except Exception:
            pass
        cwd = get_cwd(startcfg.cwd, cmd_type)
        # set environment
        new_env = dict(os.environ)
        # add environment from launch
        new_env.update(startcfg.env)
        if startcfg.namespace:
            new_env['ROS_NAMESPACE'] = startcfg.namespace
        # set logging
        if startcfg.logformat:
            new_env['ROSCONSOLE_FORMAT'] = '%s' % startcfg.logformat
        if startcfg.loglevel:
            new_env['ROSCONSOLE_CONFIG_FILE'] = _rosconsole_cfg_file(
                startcfg.package, startcfg.loglevel)
        # handle respawn
        if startcfg.respawn:
            if startcfg.respawn_delay > 0:
                new_env['RESPAWN_DELAY'] = '%d' % startcfg.respawn_delay
            respawn_params = _get_respawn_params(startcfg.fullname,
                                                 startcfg.params)
            if respawn_params['max'] > 0:
                new_env['RESPAWN_MAX'] = '%d' % respawn_params['max']
            if respawn_params['min_runtime'] > 0:
                new_env['RESPAWN_MIN_RUNTIME'] = '%d' % respawn_params[
                    'min_runtime']
            cmd_type = "%s %s %s" % (settings.RESPAWN_SCRIPT, startcfg.prefix,
                                     cmd_type)
        else:
            cmd_type = "%s %s" % (startcfg.prefix, cmd_type)
        # check for masteruri
        masteruri = startcfg.masteruri
        if masteruri is None:
            masteruri = masteruri_from_ros()
        if masteruri is not None:
            if 'ROS_MASTER_URI' not in startcfg.env:
                new_env['ROS_MASTER_URI'] = masteruri
            # host in startcfg is a nmduri -> get host name
            ros_hostname = host.get_ros_hostname(masteruri, hostname)
            if ros_hostname:
                addr = socket.gethostbyname(ros_hostname)
                if addr in set(ip for _n, ip in DiscoverSocket.localifs()):
                    new_env['ROS_HOSTNAME'] = ros_hostname
            # load params to ROS master
            _load_parameters(masteruri, startcfg.params, startcfg.clear_params)
        # start
        cmd_str = utf8(
            '%s %s %s' %
            (screen.get_cmd(startcfg.fullname, new_env,
                            startcfg.env.keys()), cmd_type, ' '.join(args)))
        rospy.loginfo("%s (launch_file: '%s', masteruri: %s)" %
                      (cmd_str, startcfg.config_path, masteruri))
        rospy.logdebug("environment while run node '%s': '%s'" %
                       (cmd_str, new_env))
        SupervisedPopen(shlex.split(cmd_str),
                        cwd=cwd,
                        env=new_env,
                        object_id="run_node_%s" % startcfg.fullname,
                        description="Run [%s]%s" %
                        (utf8(startcfg.package), utf8(startcfg.binary)))
    else:
        nmduri = startcfg.nmduri
        rospy.loginfo("remote run node '%s' at '%s'" % (nodename, nmduri))
        startcfg.params.update(_params_to_package_path(startcfg.params))
        startcfg.args = _args_to_package_path(startcfg.args)
        # run on a remote machine
        channel = remote.get_insecure_channel(nmduri)
        if channel is None:
            raise exceptions.StartException(
                "Unknown launch manager url for host %s to start %s" %
                (host, startcfg.fullname))
        lm = LaunchStub(channel)
        lm.start_standalone_node(startcfg)
Esempio n. 2
0
def runNode(package,
            executable,
            name,
            args,
            prefix='',
            repawn=False,
            masteruri=None,
            loglevel=''):
    '''
    Runs a ROS node. Starts a roscore if needed.
    '''
    if not masteruri:
        masteruri = masteruri_from_ros()
    # start roscore, if needed
    nm.StartHandler._prepareROSMaster(masteruri)
    # start node
    try:
        cmd = roslib.packages.find_node(package, executable)
    except roslib.packages.ROSPkgException as e:
        # multiple nodes, invalid package
        raise nm.StartException(str(e))
    # handle different result types str or array of string (electric / fuerte)
    import types
    if isinstance(cmd, types.StringTypes):
        cmd = [cmd]
    if cmd is None or len(cmd) == 0:
        raise nm.StartException(' '.join([
            executable, 'in package [', package,
            '] not found!\n\nThe package was created?\nIs the binary executable?\n'
        ]))
    # create string for node parameter. Set arguments with spaces into "'".
    node_params = ' '.join(''.join(["'", a, "'"]) if a.find(' ') > -1 else a
                           for a in args[1:])
    cmd_args = [
        screen.get_cmd(name), RESPAWN_SCRIPT if repawn else '', prefix, cmd[0],
        node_params
    ]
    print('run on remote host:', ' '.join(cmd_args))
    # determine the current working path
    arg_cwd = getCwdArg('__cwd', args)
    cwd = nm.get_ros_home()
    if not (arg_cwd is None):
        if arg_cwd == 'ROS_HOME':
            cwd = nm.get_ros_home()
        elif arg_cwd == 'node':
            cwd = os.path.dirname(cmd[0])
    # set the masteruri to launch with other one master
    new_env = dict(os.environ)
    new_env['ROS_MASTER_URI'] = masteruri
    ros_hostname = nmdhost.get_ros_hostname(masteruri)
    if ros_hostname:
        addr = socket.gethostbyname(ros_hostname)
        if addr in set(ip for _n, ip in DiscoverSocket.localifs()):
            new_env['ROS_HOSTNAME'] = ros_hostname
    if loglevel:
        new_env['ROSCONSOLE_CONFIG_FILE'] = rosconsole_cfg_file(package)
    subprocess.Popen(shlex.split(str(' '.join(cmd_args))),
                     cwd=cwd,
                     env=new_env)
    if len(cmd) > 1:
        rospy.logwarn(
            'Multiple executables are found! The first one was started! Exceutables:\n%s',
            str(cmd))