def init_cfg_path():
  global CFG_PATH
  masteruri = masteruri_from_ros()
  CFG_PATH = ''.join([get_ros_home(), os.sep, 'node_manager', os.sep])
  '''
  Creates and runs the ROS node.
  '''
  if not os.path.isdir(CFG_PATH):
    os.makedirs(CFG_PATH)
  return masteruri
Exemple #2
0
def getDefaultRPCPort(zeroconf=False):
  try:
    from common import masteruri_from_ros
    masteruri = masteruri_from_ros()
    rospy.loginfo("ROS Master URI: %s", masteruri)
    from urlparse import urlparse
    return urlparse(masteruri).port+(600 if zeroconf else 300) 
  except:
    import traceback
    print traceback.format_exc()
    return 11911 if zeroconf else 11611
 def getMasteruri(self):
     '''
 Requests the ROS master URI from the ROS master through the RPC interface and 
 returns it. The 'materuri' attribute will be set to the requested value.
 @return: ROS master URI
 @rtype: C{str} or C{None}
 '''
     if not hasattr(self, 'materuri') or self.materuri is None:
         masteruri = masteruri_from_ros()
         master = xmlrpclib.ServerProxy(masteruri)
         code, message, self.materuri = master.getUri(rospy.get_name())
     return self.materuri
def init_cfg_path():
  global CFG_PATH
  masteruri = masteruri_from_ros()
  CFG_PATH = ''.join([get_ros_home(), os.sep, 'node_manager', os.sep])
  '''
  Creates and runs the ROS node.
  '''
  if not os.path.isdir(CFG_PATH):
    os.makedirs(CFG_PATH)
  # start ROS-Master, if not currently running
  StartHandler._prepareROSMaster(masteruri)
  return masteruri
 def getMasteruri(self):
   '''
   Requests the ROS master URI from the ROS master through the RPC interface and 
   returns it. The 'materuri' attribute will be set to the requested value.
   @return: ROS master URI
   @rtype: C{str} or C{None}
   '''
   if not hasattr(self, 'materuri') or self.materuri is None:
     masteruri = masteruri_from_ros()
     master = xmlrpclib.ServerProxy(masteruri)
     code, message, self.materuri = master.getUri(rospy.get_name())
   return self.materuri
Exemple #6
0
 def reload(self):
     '''
 Loads the settings from file or sets default values if no one exists.
 '''
     self._terminal_emulator = None
     self._terminal_command_arg = 'e'
     self._masteruri = masteruri_from_ros()
     self.CFG_PATH = os.path.join(get_ros_home(), 'node_manager')
     # loads the current configuration path. If the path was changed, a redirection
     # file exists with new configuration folder
     if not os.path.isdir(self.CFG_PATH):
         os.makedirs(self.CFG_PATH)
         self._cfg_path = self.CFG_PATH
     else:
         settings = self.qsettings(
             os.path.join(self.CFG_PATH, self.CFG_REDIRECT_FILE))
         self._cfg_path = settings.value('cfg_path', self.CFG_PATH)
     # after the settings path was loaded, load other settings
     self._robots_path = self.ROBOTS_DIR
     settings = self.qsettings(self.CFG_FILE)
     self._default_user = settings.value('default_user', self.USER_DEFAULT)
     try:
         self._launch_history_length = int(
             settings.value('launch_history_length',
                            self.LAUNCH_HISTORY_LENGTH))
     except:
         self._launch_history_length = self.LAUNCH_HISTORY_LENGTH
     try:
         self._param_history_length = int(
             settings.value('param_history_length',
                            self.PARAM_HISTORY_LENGTH))
     except:
         self._param_history_length = self.PARAM_HISTORY_LENGTH
     self._current_dialog_path = self.CURRENT_DIALOG_PATH
     self._log_viewer = self.LOG_VIEWER
     self._start_remote_script = self.STARTER_SCRIPT
     self._respawn_script = self.RESPAWN_SCRIPT
     self._launch_view_file_ext = self.str2list(
         settings.value('launch_view_file_ext',
                        ', '.join(self.LAUNCH_VIEW_EXT)))
     self._store_geometry = self.str2bool(
         settings.value('store_geometry', self.STORE_GEOMETRY))
     self.SEARCH_IN_EXT = list(
         set(self.SEARCH_IN_EXT) | set(self._launch_view_file_ext))
     self._autoupdate = self.str2bool(
         settings.value('autoupdate', self.AUTOUPDATE))
Exemple #7
0
    def __init__(self, name, uri, discoverer_name, monitoruri, timestamp):
        '''
    Initialization method for the SyncThread. 
    @param name: the name of the ROS master synchronized with.
    @type name:  C{str}
    @param uri: the URI of the ROS master synchronized with
    @type uri:  C{str}
    @param discoverer_name: the name of the discovery node running on ROS master synchronized with.
    @type discoverer_name:  C{str}
    @param monitoruri: The URI of RPC server of the discovery node to get the ROS master state by calling a method only once.
    @type monitoruri:  C{str}
    @param timestamp: The timestamp of the current state of the ROS master info.
    @type timestamp:  C{float64}
    '''
        # init thread
        threading.Thread.__init__(self)
        self.masterInfo = MasterInfo(name, uri, discoverer_name, monitoruri,
                                     timestamp)
        self.localMasteruri = masteruri_from_ros()
        rospy.logdebug("SyncThread[%s]: create this sync thread",
                       self.masterInfo.name)
        # synchronization variables
        self.__cv = threading.Condition()
        self.__lock_info = threading.RLock()
        self.__sync_info = None  #SyncMasterInfo with currently synchronized nodes, publisher (topic, node, nodeuri), subscriber(topic, node, nodeuri) and services
        self.__stop = False
        # a list with published topics as a tuple of (topic name, node name, node URL)
        self.__publisher = []
        # a list with subscribed topics as a tuple of (topic name, node name, node URL)
        self.__subscriber = []
        # a list with services as a tuple of (service name, service URL, node name, node URL)
        self.__services = []
        self.__own_state = None

        #setup the interface
        self._loadInterface()

        # congestion avoidance: wait for minimum 1 sec. If an update request is received wait
        # for next 1 second. Force update after maximum 5 sec since first update request.
        self._ts_first_update_request = None
        self._ts_last_update_request = None

        self.start()
 def reload(self):
   '''
   Loads the settings from file or sets default values if no one exists.
   '''
   self._terminal_emulator = None
   self._terminal_command_arg = 'e'
   self._masteruri = masteruri_from_ros()
   self.CFG_PATH = os.path.join(get_ros_home(), 'node_manager')
   # loads the current configuration path. If the path was changed, a redirection
   # file exists with new configuration folder
   if not os.path.isdir(self.CFG_PATH):
     os.makedirs(self.CFG_PATH)
     self._cfg_path = self.CFG_PATH
   else:
     settings = self.qsettings(os.path.join(self.CFG_PATH, self.CFG_REDIRECT_FILE))
     self._cfg_path = settings.value('cfg_path', self.CFG_PATH)
   # after the settings path was loaded, load other settings
   self._robots_path = self.ROBOTS_DIR
   settings = self.qsettings(self.CFG_FILE)
   self._default_user = settings.value('default_user', self.USER_DEFAULT)
   settings.beginGroup('default_user_hosts')
   self._default_user_hosts = dict()
   for k in settings.childKeys():
     self._default_user_hosts[k] = settings.value(k, self._default_user)
   settings.endGroup()
   try:
     self._launch_history_length = int(settings.value('launch_history_length', self.LAUNCH_HISTORY_LENGTH))
   except:
     self._launch_history_length = self.LAUNCH_HISTORY_LENGTH
   try:
     self._param_history_length = int(settings.value('param_history_length', self.PARAM_HISTORY_LENGTH))
   except:
     self._param_history_length = self.PARAM_HISTORY_LENGTH
   self._current_dialog_path = self.CURRENT_DIALOG_PATH
   self._log_viewer = self.LOG_VIEWER
   self._start_remote_script = self.STARTER_SCRIPT
   self._respawn_script = self.RESPAWN_SCRIPT
   self._launch_view_file_ext = self.str2list(settings.value('launch_view_file_ext', ', '.join(self.LAUNCH_VIEW_EXT)))
   self._store_geometry = self.str2bool(settings.value('store_geometry', self.STORE_GEOMETRY))
   self.SEARCH_IN_EXT = list(set(self.SEARCH_IN_EXT) | set(self._launch_view_file_ext))
   self._autoupdate = self.str2bool(settings.value('autoupdate', self.AUTOUPDATE))
  def __init__(self, name, uri, discoverer_name, monitoruri, timestamp):
    '''
    Initialization method for the SyncThread. 
    @param name: the name of the ROS master synchronized with.
    @type name:  C{str}
    @param uri: the URI of the ROS master synchronized with
    @type uri:  C{str}
    @param discoverer_name: the name of the discovery node running on ROS master synchronized with.
    @type discoverer_name:  C{str}
    @param monitoruri: The URI of RPC server of the discovery node to get the ROS master state by calling a method only once.
    @type monitoruri:  C{str}
    @param timestamp: The timestamp of the current state of the ROS master info.
    @type timestamp:  C{float64}
    '''
    # init thread
    threading.Thread.__init__(self)
    self.masterInfo = MasterInfo(name, uri, discoverer_name, monitoruri, timestamp)
    self.localMasteruri = masteruri_from_ros()
    rospy.logdebug("SyncThread[%s]: create this sync thread", self.masterInfo.name)
    # synchronization variables 
    self.__cv = threading.Condition()
    self.__lock_info = threading.RLock()
    self.__sync_info = None #SyncMasterInfo with currently synchronized nodes, publisher (topic, node, nodeuri), subscriber(topic, node, nodeuri) and services
    self.__stop = False
    # a list with published topics as a tuple of (topic name, node name, node URL)
    self.__publisher = []
    # a list with subscribed topics as a tuple of (topic name, node name, node URL)
    self.__subscriber = []
    # a list with services as a tuple of (service name, service URL, node name, node URL)
    self.__services = []
    self.__own_state = None
    
    #setup the interface
    self._loadInterface()

    # congestion avoidance: wait for minimum 1 sec. If an update request is received wait 
    # for next 1 second. Force update after maximum 5 sec since first update request.
    self._ts_first_update_request = None
    self._ts_last_update_request = None

    self.start()
  def __init__(self, rpcport=11611, do_retry=True):
    '''
    Initialize method. Creates an XML-RPC server on given port and starts this
    in its own thread.
    
    :param rpcport: the port number for the XML-RPC server
    
    :type rpcport:  int
    
    :param do_retry: retry to create XML-RPC server
    
    :type do_retry: bool
    '''
    self._state_access_lock = threading.RLock()
    self._create_access_lock = threading.RLock()
    self._lock = threading.RLock()
    self.__masteruri = masteruri_from_ros()
    self.__new_master_state = None
    self.__masteruri_rpc = None
    self.__mastername = None
    self.__cached_nodes = dict()
    self.__cached_services = dict()
    self.ros_node_name = str(rospy.get_name())
    if rospy.has_param('~name'):
      self.__mastername = rospy.get_param('~name')
    self.__mastername = self.getMastername()
    rospy.set_param('/mastername', self.__mastername)

    self.__master_state = None
    '''the current state of the ROS master'''
    self.rpcport = rpcport
    '''the port number of the RPC server'''

    self._printed_errors = dict()
    self._last_clearup_ts = time.time()

    # Create an XML-RPC server
    self.ready = False
    while not self.ready and (not rospy.is_shutdown()):
      try:
        self.rpcServer = RPCThreading(('', rpcport), logRequests=False, allow_none=True)
        rospy.loginfo("Start RPC-XML Server at %s", self.rpcServer.server_address)
        self.rpcServer.register_introspection_functions()
        self.rpcServer.register_function(self.getListedMasterInfo, 'masterInfo')
        self.rpcServer.register_function(self.getListedMasterInfoFiltered, 'masterInfoFiltered')
        self.rpcServer.register_function(self.getMasterContacts, 'masterContacts')
        self._rpcThread = threading.Thread(target = self.rpcServer.serve_forever)
        self._rpcThread.setDaemon(True)
        self._rpcThread.start()
        self.ready = True
      except socket.error:
        if not do_retry:
          raise Exception(''.join(["Error while start RPC-XML server on port ", str(rpcport), ". Is a Node Manager already running?"]))
        rospy.logwarn(''.join(["Error while start RPC-XML server on port ", str(rpcport), ". Try again..."]))
        time.sleep(1)
      except:
        import traceback
        print traceback.format_exc()
        if not do_retry:
          raise

    self._master = xmlrpclib.ServerProxy(self.getMasteruri())
    # === UPDATE THE LAUNCH URIS Section ===
    # subscribe to get parameter updates
    rospy.loginfo("Subscribe to parameter `/roslaunch/uris`")
    self.__mycache_param_server = rospy.impl.paramserver.get_param_server_cache()
    # HACK: use own method to get the updates also for parameters in the subgroup 
    self.__mycache_param_server.update = self.__update_param
    # first access, make call to parameter server
    self._update_launch_uris_lock = threading.RLock()
    self.__launch_uris = {}
    code, msg, value = self._master.subscribeParam(self.ros_node_name, rospy.get_node_uri(), '/roslaunch/uris')
    # the new timer will be created in self._update_launch_uris()
    self._timer_update_launch_uris = None
    if code == 1:
      for k,v in value.items():
        self.__launch_uris[roslib.names.ns_join('/roslaunch/uris', k)] = v
    self._update_launch_uris()
    def __init__(self, rpcport=11611, do_retry=True, ipv6=False):
        '''
    Initialize method. Creates an XML-RPC server on given port and starts this
    in its own thread.
    
    :param rpcport: the port number for the XML-RPC server
    
    :type rpcport:  int
    
    :param do_retry: retry to create XML-RPC server
    
    :type do_retry: bool
    
    :param ipv6: Use ipv6
    
    :type ipv6: bool
    '''
        self._state_access_lock = threading.RLock()
        self._create_access_lock = threading.RLock()
        self._lock = threading.RLock()
        self.__masteruri = masteruri_from_ros()
        self.__new_master_state = None
        self.__masteruri_rpc = None
        self.__mastername = None
        self.__cached_nodes = dict()
        self.__cached_services = dict()
        self.ros_node_name = str(rospy.get_name())
        if rospy.has_param('~name'):
            self.__mastername = rospy.get_param('~name')
        self.__mastername = self.getMastername()
        rospy.set_param('/mastername', self.__mastername)

        self.__master_state = None
        '''the current state of the ROS master'''
        self.rpcport = rpcport
        '''the port number of the RPC server'''

        self._printed_errors = dict()
        self._last_clearup_ts = time.time()

        # Create an XML-RPC server
        self.ready = False
        while not self.ready and (not rospy.is_shutdown()):
            try:
                RPCClass = RPCThreading
                if ipv6:
                    RPCClass = RPCThreadingV6
                self.rpcServer = RPCClass(('', rpcport),
                                          logRequests=False,
                                          allow_none=True)
                rospy.loginfo("Start RPC-XML Server at %s",
                              self.rpcServer.server_address)
                self.rpcServer.register_introspection_functions()
                self.rpcServer.register_function(self.getListedMasterInfo,
                                                 'masterInfo')
                self.rpcServer.register_function(
                    self.getListedMasterInfoFiltered, 'masterInfoFiltered')
                self.rpcServer.register_function(self.getMasterContacts,
                                                 'masterContacts')
                self._rpcThread = threading.Thread(
                    target=self.rpcServer.serve_forever)
                self._rpcThread.setDaemon(True)
                self._rpcThread.start()
                self.ready = True
            except socket.error as e:
                if not do_retry:
                    raise Exception(
                        "Error while start RPC-XML server on port %d: %s\nIs a Node Manager already running?"
                        % (rpcport, e))
                rospy.logwarn(
                    "Error while start RPC-XML server on port %d: %s\nTry again..."
                    % (rpcport, e))
                time.sleep(1)
            except:
                import traceback
                print traceback.format_exc()
                if not do_retry:
                    raise

        self._master = xmlrpclib.ServerProxy(self.getMasteruri())
        # === UPDATE THE LAUNCH URIS Section ===
        # subscribe to get parameter updates
        rospy.loginfo("Subscribe to parameter `/roslaunch/uris`")
        self.__mycache_param_server = rospy.impl.paramserver.get_param_server_cache(
        )
        # HACK: use own method to get the updates also for parameters in the subgroup
        self.__mycache_param_server.update = self.__update_param
        # first access, make call to parameter server
        self._update_launch_uris_lock = threading.RLock()
        self.__launch_uris = {}
        code, msg, value = self._master.subscribeParam(self.ros_node_name,
                                                       rospy.get_node_uri(),
                                                       '/roslaunch/uris')
        # the new timer will be created in self._update_launch_uris()
        self._timer_update_launch_uris = None
        if code == 1:
            for k, v in value.items():
                self.__launch_uris[roslib.names.ns_join('/roslaunch/uris',
                                                        k)] = v
        self._update_launch_uris()
  def runNode(cls, node, launch_config, force2host=None, masteruri=None, auto_pw_request=False, user=None, pw=None, item=None):
    '''
    Start the node with given name from the given configuration.
    @param node: the name of the node (with name space)
    @type node: C{str}
    @param launch_config: the configuration containing the node
    @type launch_config: L{LaunchConfig} 
    @param force2host: start the node on given host.
    @type force2host: L{str} 
    @param masteruri: force the masteruri.
    @type masteruri: L{str} 
    @param auto_pw_request: opens question dialog directly, use True only if the method is called from the main GUI thread
    @type auto_pw_request: bool
    @raise StartException: if the screen is not available on host.
    @raise Exception: on errors while resolving host
    @see: L{node_manager_fkie.is_local()}
    '''
    #'print "RUN node", node, time.time()
    n = launch_config.getNode(node)
    if n is None:
      raise StartException(''.join(["Node '", node, "' not found!"]))

    env = list(n.env_args)
    if n.respawn:
      # set the respawn environment variables
      respawn_params = cls._get_respawn_params(rospy.names.ns_join(n.namespace, n.name), launch_config.Roscfg.params)
      if respawn_params['max'] > 0:
        env.append(('RESPAWN_MAX', '%d'%respawn_params['max']))
      if respawn_params['min_runtime'] > 0:
        env.append(('RESPAWN_MIN_RUNTIME', '%d'%respawn_params['min_runtime']))
      if respawn_params['delay'] > 0:
        env.append(('RESPAWN_DELAY', '%d'%respawn_params['delay']))
    prefix = n.launch_prefix if not n.launch_prefix is None else ''
    if prefix.lower() == 'screen' or prefix.lower().find('screen ') != -1:
      rospy.loginfo("SCREEN prefix removed before start!")
      prefix = ''
    args = [''.join(['__ns:=', n.namespace.rstrip(rospy.names.SEP)]), ''.join(['__name:=', n.name])]
    if not (n.cwd is None):
      args.append(''.join(['__cwd:=', n.cwd]))

    # add remaps
    for remap in n.remap_args:
      args.append(''.join([remap[0], ':=', remap[1]]))

    # get host of the node
    host = launch_config.hostname
    env_loader = ''
    if n.machine_name:
      machine = launch_config.Roscfg.machines[n.machine_name]
      if not machine.address in ['localhost', '127.0.0.1']:
        host = machine.address
        if masteruri is None:
          masteruri = nm.nameres().masteruri(n.machine_name)
      #TODO: env-loader support?
#      if hasattr(machine, "env_loader") and machine.env_loader:
#        env_loader = machine.env_loader
    # set the host to the given host
    if not force2host is None:
      host = force2host

    # set the ROS_MASTER_URI
    if masteruri is None:
      masteruri = masteruri_from_ros()
      env.append(('ROS_MASTER_URI', masteruri))

    abs_paths = list() # tuples of (parameter name, old value, new value)
    not_found_packages = list() # package names
    # set the global parameter
    if not masteruri is None and not masteruri in launch_config.global_param_done:
      global_node_names = cls.getGlobalParams(launch_config.Roscfg)
      rospy.loginfo("Register global parameter:\n  %s", '\n  '.join("%s%s"%(str(v)[:80],'...' if len(str(v))>80 else'') for v in global_node_names.values()))
      abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(masteruri, global_node_names, [], user, pw, auto_pw_request)
      launch_config.global_param_done.append(masteruri)

    # add params
    if not masteruri is None:
      nodens = ''.join([n.namespace, n.name, rospy.names.SEP])
      params = dict()
      for param, value in launch_config.Roscfg.params.items():
        if param.startswith(nodens):
          params[param] = value
      clear_params = []
      for cparam in launch_config.Roscfg.clear_params:
        if cparam.startswith(nodens):
          clear_params.append(cparam)
      rospy.loginfo("Delete parameter:\n  %s", '\n  '.join(clear_params))
      rospy.loginfo("Register parameter:\n  %s", '\n  '.join("%s%s"%(str(v)[:80],'...' if len(str(v))>80 else'') for v in params.values()))
      abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(masteruri, params, clear_params, user, pw, auto_pw_request)
    #'print "RUN prepared", node, time.time()

    if nm.is_local(host):
      nm.screen().testScreen()
      if item:
        cmd_type = item
      else:
        try:
          cmd = roslib.packages.find_node(n.package, n.type)
        except (Exception, roslib.packages.ROSPkgException) as e:
          # multiple nodes, invalid package
          raise StartException(''.join(["Can't find resource: ", str(e)]))
        # handle diferent result types str or array of string
        if isinstance(cmd, types.StringTypes):
          cmd = [cmd]
        cmd_type = ''
        if cmd is None or len(cmd) == 0:
          raise StartException(' '.join([n.type, 'in package [', n.package, '] not found!\n\nThe package was created?\nIs the binary executable?\n']))
        if len(cmd) > 1:
          if auto_pw_request:
            # Open selection for executables, only if the method is called from the main GUI thread
            try:
              from python_qt_binding import QtGui
              item, result = QtGui.QInputDialog.getItem(None, ' '.join(['Multiple executables', n.type, 'in', n.package]),
                                                'Select an executable',
                                                cmd, 0, False)
              if result:
                #open the selected screen
                cmd_type = item
              else:
                return
            except:
              raise StartException('Multiple executables with same name in package found!')
          else:
            err = BinarySelectionRequest(cmd, 'Multiple executables')
            raise nm.InteractionNeededError(err, 
                                            cls.runNode, (node, launch_config, force2host, masteruri, auto_pw_request, user, pw))
        else:
          cmd_type = cmd[0]
      # determine the current working path, Default: the package of the node
      cwd = get_ros_home()
      if not (n.cwd is None):
        if n.cwd == 'ROS_HOME':
          cwd = get_ros_home()
        elif n.cwd == 'node':
          cwd = os.path.dirname(cmd_type)
      cls._prepareROSMaster(masteruri)
      node_cmd = [nm.settings().respawn_script if n.respawn else '', prefix, cmd_type]
      cmd_args = [nm.screen().getSceenCmd(node)]
      cmd_args[len(cmd_args):] = node_cmd
      cmd_args.append(str(n.args))
      cmd_args[len(cmd_args):] = args
      rospy.loginfo("RUN: %s", ' '.join(cmd_args))
      new_env = dict(os.environ)
      new_env['ROS_MASTER_URI'] = masteruri
      # add the namespace environment parameter to handle some cases, e.g. rqt_cpp plugins
      if n.namespace:
        new_env['ROS_NAMESPACE'] = n.namespace
      for k, v in env:
        new_env[k] = v
      SupervisedPopen(shlex.split(str(' '.join(cmd_args))), cwd=cwd, env=new_env, id="Run node", description="Run node [%s]%s"%(str(n.package), str(n.type)))
    else:
      #'print "RUN REMOTE", node, time.time()
      # start remote
      if launch_config.PackageName is None:
        raise StartException(''.join(["Can't run remote without a valid package name!"]))
      # thus the prefix parameters while the transfer are not separated
      if prefix:
        prefix = ''.join(['"', prefix, '"'])
      # setup environment
      env_command = ''
      if env_loader:
        rospy.logwarn("env_loader in machine tag currently not supported")
        raise StartException("env_loader in machine tag currently not supported")
      if env:
        new_env = dict()
        try:
          for (k, v) in env:
            v_value, is_abs_path, found, package = cls._resolve_abs_paths(v, host, user, pw, auto_pw_request)
            new_env[k] = v_value
            if is_abs_path:
              abs_paths.append(('ENV', "%s=%s"%(k,v), "%s=%s"%(k,v_value)))
              if not found and package:
                not_found_packages.append(package)
          env_command = "env "+' '.join(["%s=%s"%(k,v) for (k, v) in new_env.items()])
        except nm.AuthenticationRequest as e:
          raise nm.InteractionNeededError(e, cls.runNode, (node, launch_config, force2host, masteruri, auto_pw_request))

      startcmd = [env_command, nm.settings().start_remote_script,
                  '--package', str(n.package),
                  '--node_type', str(n.type),
                  '--node_name', str(node),
                  '--node_respawn true' if n.respawn else '']
      if not masteruri is None:
        startcmd.append('--masteruri')
        startcmd.append(masteruri)
      if prefix:
        startcmd[len(startcmd):] = ['--prefix', prefix]

      #rename the absolute paths in the args of the node
      node_args = []
      try:
        for a in n.args.split():
          a_value, is_abs_path, found, package = cls._resolve_abs_paths(a, host, user, pw, auto_pw_request)
          node_args.append(a_value)
          if is_abs_path:
            abs_paths.append(('ARGS', a, a_value))
            if not found and package:
              not_found_packages.append(package)

        startcmd[len(startcmd):] = node_args
        startcmd[len(startcmd):] = args
        rospy.loginfo("Run remote on %s: %s", host, str(' '.join(startcmd)))
        #'print "RUN CALL", node, time.time()
        _, stdout, stderr, ok = nm.ssh().ssh_exec(host, startcmd, user, pw, auto_pw_request, close_stdin=True)
        output = stdout.read()
        error = stderr.read()
        stdout.close()
        stderr.close()
        #'print "RUN CALLOK", node, time.time()
      except nm.AuthenticationRequest as e:
        raise nm.InteractionNeededError(e, cls.runNode, (node, launch_config, force2host, masteruri, auto_pw_request))

      if ok:
        if error:
          rospy.logwarn("ERROR while start '%s': %s", node, error)
          raise StartException(str(''.join(['The host "', host, '" reports:\n', error])))
        if output:
          rospy.loginfo("STDOUT while start '%s': %s", node, output)
      # inform about absolute paths in parameter value
      if len(abs_paths) > 0:
        rospy.loginfo("Absolute paths found while start:\n%s", str('\n'.join([''.join([p, '\n  OLD: ', ov, '\n  NEW: ', nv]) for p, ov, nv in abs_paths])))

      if len(not_found_packages) > 0:
        packages = '\n'.join(not_found_packages)
        raise StartException(str('\n'.join(['Some absolute paths are not renamed because following packages are not found on remote host:', packages])))
Exemple #13
0
    def runNode(cls,
                node,
                launch_config,
                force2host=None,
                masteruri=None,
                auto_pw_request=False,
                user=None,
                pw=None,
                item=None):
        '''
    Start the node with given name from the given configuration.
    @param node: the name of the node (with name space)
    @type node: C{str}
    @param launch_config: the configuration containing the node
    @type launch_config: L{LaunchConfig} 
    @param force2host: start the node on given host.
    @type force2host: L{str} 
    @param masteruri: force the masteruri.
    @type masteruri: L{str} 
    @param auto_pw_request: opens question dialog directly, use True only if the method is called from the main GUI thread
    @type auto_pw_request: bool
    @raise StartException: if the screen is not available on host.
    @raise Exception: on errors while resolving host
    @see: L{node_manager_fkie.is_local()}
    '''
        #'print "RUN node", node, time.time()
        n = launch_config.getNode(node)
        if n is None:
            raise StartException(''.join(["Node '", node, "' not found!"]))

        env = list(n.env_args)
        if n.respawn:
            # set the respawn environment variables
            respawn_params = cls._get_respawn_params(
                rospy.names.ns_join(n.namespace, n.name),
                launch_config.Roscfg.params)
            if respawn_params['max'] > 0:
                env.append(('RESPAWN_MAX', '%d' % respawn_params['max']))
            if respawn_params['min_runtime'] > 0:
                env.append(('RESPAWN_MIN_RUNTIME',
                            '%d' % respawn_params['min_runtime']))
            if respawn_params['delay'] > 0:
                env.append(('RESPAWN_DELAY', '%d' % respawn_params['delay']))
        prefix = n.launch_prefix if not n.launch_prefix is None else ''
        if prefix.lower() == 'screen' or prefix.lower().find('screen ') != -1:
            rospy.loginfo("SCREEN prefix removed before start!")
            prefix = ''
        args = [
            ''.join(['__ns:=', n.namespace.rstrip(rospy.names.SEP)]),
            ''.join(['__name:=', n.name])
        ]
        if not (n.cwd is None):
            args.append(''.join(['__cwd:=', n.cwd]))

        # add remaps
        for remap in n.remap_args:
            args.append(''.join([remap[0], ':=', remap[1]]))

        # get host of the node
        host = launch_config.hostname
        env_loader = ''
        if n.machine_name:
            machine = launch_config.Roscfg.machines[n.machine_name]
            if not machine.address in ['localhost', '127.0.0.1']:
                host = machine.address
                if masteruri is None:
                    masteruri = nm.nameres().masteruri(n.machine_name)
            #TODO: env-loader support?
#      if hasattr(machine, "env_loader") and machine.env_loader:
#        env_loader = machine.env_loader
# set the host to the given host
        if not force2host is None:
            host = force2host

        # set the ROS_MASTER_URI
        if masteruri is None:
            masteruri = masteruri_from_ros()
            env.append(('ROS_MASTER_URI', masteruri))

        abs_paths = list()  # tuples of (parameter name, old value, new value)
        not_found_packages = list()  # package names
        # set the global parameter
        if not masteruri is None and not masteruri in launch_config.global_param_done:
            global_node_names = cls.getGlobalParams(launch_config.Roscfg)
            rospy.loginfo(
                "Register global parameter:\n  %s", '\n  '.join(
                    "%s%s" % (str(v)[:80], '...' if len(str(v)) > 80 else '')
                    for v in global_node_names.values()))
            abs_paths[len(abs_paths):], not_found_packages[
                len(not_found_packages):] = cls._load_parameters(
                    masteruri, global_node_names, [], user, pw,
                    auto_pw_request)
            launch_config.global_param_done.append(masteruri)

        # add params
        if not masteruri is None:
            nodens = ''.join([n.namespace, n.name, rospy.names.SEP])
            params = dict()
            for param, value in launch_config.Roscfg.params.items():
                if param.startswith(nodens):
                    params[param] = value
            clear_params = []
            for cparam in launch_config.Roscfg.clear_params:
                if cparam.startswith(nodens):
                    clear_params.append(cparam)
            rospy.loginfo("Delete parameter:\n  %s", '\n  '.join(clear_params))
            rospy.loginfo(
                "Register parameter:\n  %s", '\n  '.join(
                    "%s%s" % (str(v)[:80], '...' if len(str(v)) > 80 else '')
                    for v in params.values()))
            abs_paths[len(abs_paths):], not_found_packages[
                len(not_found_packages):] = cls._load_parameters(
                    masteruri, params, clear_params, user, pw, auto_pw_request)
        #'print "RUN prepared", node, time.time()

        if nm.is_local(host):
            nm.screen().testScreen()
            if item:
                cmd_type = item
            else:
                try:
                    cmd = roslib.packages.find_node(n.package, n.type)
                except (Exception, roslib.packages.ROSPkgException) as e:
                    # multiple nodes, invalid package
                    raise StartException(''.join(
                        ["Can't find resource: ",
                         str(e)]))
                # handle diferent result types str or array of string
                if isinstance(cmd, types.StringTypes):
                    cmd = [cmd]
                cmd_type = ''
                if cmd is None or len(cmd) == 0:
                    raise StartException(' '.join([
                        n.type, 'in package [', n.package,
                        '] not found!\n\nThe package was created?\nIs the binary executable?\n'
                    ]))
                if len(cmd) > 1:
                    if auto_pw_request:
                        # Open selection for executables, only if the method is called from the main GUI thread
                        try:
                            from python_qt_binding import QtGui
                            item, result = QtGui.QInputDialog.getItem(
                                None, ' '.join([
                                    'Multiple executables', n.type, 'in',
                                    n.package
                                ]), 'Select an executable', cmd, 0, False)
                            if result:
                                #open the selected screen
                                cmd_type = item
                            else:
                                return
                        except:
                            raise StartException(
                                'Multiple executables with same name in package found!'
                            )
                    else:
                        err = BinarySelectionRequest(cmd,
                                                     'Multiple executables')
                        raise nm.InteractionNeededError(
                            err, cls.runNode,
                            (node, launch_config, force2host, masteruri,
                             auto_pw_request, user, pw))
                else:
                    cmd_type = cmd[0]
            # determine the current working path, Default: the package of the node
            cwd = get_ros_home()
            if not (n.cwd is None):
                if n.cwd == 'ROS_HOME':
                    cwd = get_ros_home()
                elif n.cwd == 'node':
                    cwd = os.path.dirname(cmd_type)
            cls._prepareROSMaster(masteruri)
            node_cmd = [
                nm.settings().respawn_script if n.respawn else '', prefix,
                cmd_type
            ]
            cmd_args = [nm.screen().getSceenCmd(node)]
            cmd_args[len(cmd_args):] = node_cmd
            cmd_args.append(str(n.args))
            cmd_args[len(cmd_args):] = args
            rospy.loginfo("RUN: %s", ' '.join(cmd_args))
            new_env = dict(os.environ)
            new_env['ROS_MASTER_URI'] = masteruri
            # add the namespace environment parameter to handle some cases, e.g. rqt_cpp plugins
            if n.namespace:
                new_env['ROS_NAMESPACE'] = n.namespace
            for k, v in env:
                new_env[k] = v
            SupervisedPopen(shlex.split(str(' '.join(cmd_args))),
                            cwd=cwd,
                            env=new_env,
                            id="Run node",
                            description="Run node [%s]%s" %
                            (str(n.package), str(n.type)))
        else:
            #'print "RUN REMOTE", node, time.time()
            # start remote
            if launch_config.PackageName is None:
                raise StartException(''.join(
                    ["Can't run remote without a valid package name!"]))
            # thus the prefix parameters while the transfer are not separated
            if prefix:
                prefix = ''.join(['"', prefix, '"'])
            # setup environment
            env_command = ''
            if env_loader:
                rospy.logwarn(
                    "env_loader in machine tag currently not supported")
                raise StartException(
                    "env_loader in machine tag currently not supported")
            if env:
                new_env = dict()
                try:
                    for (k, v) in env:
                        v_value, is_abs_path, found, package = cls._resolve_abs_paths(
                            v, host, user, pw, auto_pw_request)
                        new_env[k] = v_value
                        if is_abs_path:
                            abs_paths.append(('ENV', "%s=%s" % (k, v),
                                              "%s=%s" % (k, v_value)))
                            if not found and package:
                                not_found_packages.append(package)
                    env_command = "env " + ' '.join(
                        ["%s=%s" % (k, v) for (k, v) in new_env.items()])
                except nm.AuthenticationRequest as e:
                    raise nm.InteractionNeededError(
                        e, cls.runNode, (node, launch_config, force2host,
                                         masteruri, auto_pw_request))

            startcmd = [
                env_command,
                nm.settings().start_remote_script, '--package',
                str(n.package), '--node_type',
                str(n.type), '--node_name',
                str(node), '--node_respawn true' if n.respawn else ''
            ]
            if not masteruri is None:
                startcmd.append('--masteruri')
                startcmd.append(masteruri)
            if prefix:
                startcmd[len(startcmd):] = ['--prefix', prefix]

            #rename the absolute paths in the args of the node
            node_args = []
            try:
                for a in n.args.split():
                    a_value, is_abs_path, found, package = cls._resolve_abs_paths(
                        a, host, user, pw, auto_pw_request)
                    node_args.append(a_value)
                    if is_abs_path:
                        abs_paths.append(('ARGS', a, a_value))
                        if not found and package:
                            not_found_packages.append(package)

                startcmd[len(startcmd):] = node_args
                startcmd[len(startcmd):] = args
                rospy.loginfo("Run remote on %s: %s", host,
                              str(' '.join(startcmd)))
                #'print "RUN CALL", node, time.time()
                _, stdout, stderr, ok = nm.ssh().ssh_exec(host,
                                                          startcmd,
                                                          user,
                                                          pw,
                                                          auto_pw_request,
                                                          close_stdin=True)
                output = stdout.read()
                error = stderr.read()
                stdout.close()
                stderr.close()
                #'print "RUN CALLOK", node, time.time()
            except nm.AuthenticationRequest as e:
                raise nm.InteractionNeededError(
                    e, cls.runNode, (node, launch_config, force2host,
                                     masteruri, auto_pw_request))

            if ok:
                if error:
                    rospy.logwarn("ERROR while start '%s': %s", node, error)
                    raise StartException(
                        str(''.join(
                            ['The host "', host, '" reports:\n', error])))
                if output:
                    rospy.loginfo("STDOUT while start '%s': %s", node, output)
            # inform about absolute paths in parameter value
            if len(abs_paths) > 0:
                rospy.loginfo(
                    "Absolute paths found while start:\n%s",
                    str('\n'.join([
                        ''.join([p, '\n  OLD: ', ov, '\n  NEW: ', nv])
                        for p, ov, nv in abs_paths
                    ])))

            if len(not_found_packages) > 0:
                packages = '\n'.join(not_found_packages)
                raise StartException(
                    str('\n'.join([
                        'Some absolute paths are not renamed because following packages are not found on remote host:',
                        packages
                    ])))