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._noclose_str = '-hold' self._terminal_title = '--title' self._masteruri = masteruri_from_ros() self.CFG_PATH = os.path.expanduser('~/.config/ros.fkie/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 # move all stuff from old location to new try: import shutil old_cfg_path = os.path.join(get_ros_home(), 'node_manager') if os.path.exists(old_cfg_path): print("move configuration to new destination: %s" % self.CFG_PATH) for filename in os.listdir(old_cfg_path): shutil.move(os.path.join(old_cfg_path, filename), os.path.join(self.CFG_PATH, filename)) shutil.rmtree(old_cfg_path) except Exception: pass print("Configuration path: %s" % self.CFG_PATH) # after the settings path was loaded, load other settings settings = self.qsettings(self.CFG_FILE) self._data = self._load_settings(settings) # load stored usernames for hosts 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() self._current_dialog_path = self.CURRENT_DIALOG_PATH self._log_viewer = self.LOG_VIEWER self._start_remote_script = self.STARTER_SCRIPT self.SEARCH_IN_EXT = list(set(self.SEARCH_IN_EXT) | set(self.str2list(self.launch_view_file_ext))) # setup logging self._rosconsole_cfg_file = 'rosconsole.config' self.logging = LoggingConfig() self.logging.loglevel = settings.value('logging/level', LoggingConfig.LOGLEVEL) self.logging.loglevel_roscpp = settings.value('logging/level_roscpp', LoggingConfig.LOGLEVEL_ROSCPP) self.logging.loglevel_superdebug = settings.value('logging/level_superdebug', LoggingConfig.LOGLEVEL_SUPERDEBUG) self.logging.console_format = settings.value('logging/rosconsole_format', LoggingConfig.CONSOLE_FORMAT) nmd_settings.GRPC_TIMEOUT = self.timeout_grpc # setup colors settings.beginGroup('host_colors') self._host_colors = dict() for k in settings.childKeys(): self._host_colors[k] = settings.value(k, None) settings.endGroup() self.init_hosts_color_list() self._launch_history = None # list with file names self._icons_dir = os.path.join(os.path.dirname(__file__), 'icons')
def get_default_rtcp_port(zeroconf=False): try: from fkie_master_discovery.common import masteruri_from_ros masteruri = masteruri_from_ros() rospy.loginfo("ROS Master URI: %s", masteruri) return urlparse(masteruri).port + (600 if zeroconf else 300) except: import traceback print(traceback.format_exc()) return 11911 if zeroconf else 11611
def _prepareROSMaster(cls, masteruri): if masteruri is None: masteruri = masteruri_from_ros() # start roscore, if needed try: if not os.path.isdir(screen.LOG_PATH): os.makedirs(screen.LOG_PATH) socket.setdefaulttimeout(3) master = xmlrpcclient.ServerProxy(masteruri) master.getUri(rospy.get_name()) # restart ROSCORE on different masteruri?, not now... # master_uri = master.getUri(rospy.get_name()) # if masteruri != master_uri[2]: # # kill the local roscore... # raise except Exception: # run a roscore master_host = get_hostname(masteruri) if nm.is_local(master_host, True): master_port = get_port(masteruri) new_env = dict(os.environ) new_env['ROS_MASTER_URI'] = masteruri ros_hostname = nmdhost.get_ros_hostname(masteruri) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname cmd_args = '%s roscore --port %d' % (screen.get_cmd('/roscore--%d' % master_port), master_port) for n in [1, 2, 3, 4]: try: if n == 1: print("Launch ROS Master in screen ... %s" % (cmd_args)) SupervisedPopen(shlex.split(cmd_args), env=new_env, object_id="ROSCORE", description="Start roscore") elif n == 2: print("ROS Master takes too long for start, wait for next 10 sec ...") elif n == 3: print("A really slow start, wait for last 10 sec ...") # wait for roscore to avoid connection problems while init_node result = -1 count = 1 while result == -1 and count < 11: try: master = xmlrpcclient.ServerProxy(masteruri) result, _, _ = master.getUri(rospy.get_name()) # _:=uri, msg return except Exception: time.sleep(1) count += 1 if n == 4 and count >= 11: raise StartException('Cannot connect to ROS-Master: %s\n--> please run "roscore" manually!' % utf8(masteruri)) except Exception as e: raise Exception("Error while call '%s': %s" % (cmd_args, utf8(e))) else: raise Exception("ROS master '%s' is not reachable" % masteruri) finally: socket.setdefaulttimeout(None)
def _prepareROSMaster(cls, masteruri): if not masteruri: masteruri = masteruri_from_ros() # start roscore, if needed try: if not os.path.isdir(screen.LOG_PATH): os.makedirs(screen.LOG_PATH) socket.setdefaulttimeout(3) master = xmlrpcclient.ServerProxy(masteruri) master.getUri(rospy.get_name()) except Exception: # run a roscore screen.test_screen() master_host = get_hostname(masteruri) if cls.is_local(master_host, True): print("Start ROS-Master with %s ..." % masteruri) master_port = get_port(masteruri) new_env = dict(os.environ) new_env['ROS_MASTER_URI'] = masteruri ros_hostname = nmdhost.get_ros_hostname(masteruri) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname cmd_args = '%s roscore --port %d' % (screen.get_cmd( '/roscore--%d' % master_port), master_port) try: subprocess.Popen(shlex.split(cmd_args), env=new_env) # wait for roscore to avoid connection problems while init_node result = -1 count = 1 while result == -1 and count < 11: try: print(" retry connect to ROS master %d/10" % count) master = xmlrpcclient.ServerProxy(masteruri) result, _, _ = master.getUri( rospy.get_name()) # _:=uri, msg except Exception: time.sleep(1) count += 1 if count >= 11: raise StartException( 'Cannot connect to the ROS-Master: ' + str(masteruri)) except Exception as e: import sys sys.stderr.write("%s\n" % e) raise else: raise Exception("ROS master '%s' is not reachable" % masteruri) finally: socket.setdefaulttimeout(None)
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) if isstring(cmd): 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 ip in get_local_addresses()): 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))
def bc_run_node(cls, name, grpc_path='grpc://localhost:12321', masteruri='', reload_global_param=False, loglevel='', logformat='', auto_pw_request=False, user=None, pw=None): ''' Start the node with given name from the given configuration. :param runcfg: the configuration containing the start parameter :type runcfg: AdvRunCfg :raise StartException: if the screen is not available on host. :raise Exception: on errors while resolving host :see: :meth:`fkie_node_manager.is_local()` ''' startcfg = nm.nmd().launch.get_start_cfg( name, grpc_path, masteruri, reload_global_param=reload_global_param, loglevel=loglevel, logformat=logformat) new_env = dict(startcfg.env) # set logging options 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'] = launcher._rosconsole_cfg_file(startcfg.package, startcfg.loglevel) args = [] # 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)) # handle respawn if startcfg.respawn: if startcfg.respawn_delay > 0: new_env['RESPAWN_DELAY'] = '%d' % startcfg.respawn_delay respawn_params = launcher._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'] if startcfg.cwd: cwd = get_cwd(startcfg.cwd, startcfg.binary_path) if cwd: args.append('__cwd:=%s' % cwd) # check for masteruri masteruri = startcfg.masteruri on_hostname = startcfg.hostname if masteruri is None: masteruri = masteruri_from_ros() if masteruri is not None: new_env['ROS_MASTER_URI'] = masteruri if 'ROS_HOSTNAME' in os.environ: # set only ROS_HOSTNAME if node manager have also one ros_hostname = nmdhost.get_ros_hostname(masteruri, on_hostname) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname # load params to ROS master launcher._load_parameters(masteruri, startcfg.params, startcfg.clear_params) abs_paths = list() # tuples of (parameter name, old value, new value) not_found_packages = list() # package names # # set the global parameter # if runcfg.masteruri is not None and runcfg.masteruri not in runcfg.roslaunch_config.global_param_done: # global_node_names = cls.getGlobalParams(runcfg.roslaunch_config.Roscfg) # rospy.loginfo("Register global parameter:\n %s", '\n '.join("%s%s" % (utf8(v)[:80], '...' if len(utf8(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(runcfg.masteruri, global_node_names, [], runcfg.user, runcfg.pw, runcfg.auto_pw_request) # runcfg.roslaunch_config.global_param_done.append(runcfg.masteruri) # # # add params # if runcfg.masteruri is not None: # nodens = ''.join([n.namespace, n.name, rospy.names.SEP]) # params = dict() # for param, value in runcfg.roslaunch_config.Roscfg.params.items(): # if param.startswith(nodens): # params[param] = value # clear_params = [] # for cparam in runcfg.roslaunch_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" % (utf8(v)[:80], '...' if len(utf8(v)) > 80 else'') for v in params.values())) # abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(runcfg.masteruri, params, clear_params, runcfg.user, runcfg.pw, runcfg.auto_pw_request) if not nm.is_local(on_hostname, wait=True): # start remote if not startcfg.package: raise StartException( "Can't run remote without a valid package name!") # setup environment env_command = '' if new_env: try: for k, v in new_env.items(): v_value, is_abs_path, found, package = cls._bc_resolve_abs_paths( v, on_hostname, auto_pw_request, user, pw) 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.bc_run_node, { 'name': name, 'grpc_path': grpc_path, 'masteruri': masteruri, 'reload_global_param': reload_global_param, 'loglevel': loglevel, 'logformat': logformat, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw }) startcmd = [ env_command, nm.settings().start_remote_script, '--package', utf8(startcfg.package), '--node_type', utf8(startcfg.binary), '--node_name', utf8(startcfg.fullname), '--node_respawn true' if startcfg.respawn else '' ] if startcfg.masteruri is not None: startcmd.append('--masteruri') startcmd.append(startcfg.masteruri) if startcfg.prefix: startcmd[len(startcmd):] = ['--prefix', startcfg.prefix] if startcfg.loglevel: startcmd.append('--loglevel') startcmd.append(startcfg.loglevel) # rename the absolute paths in the args of the node node_args = [] error = '' output = '' try: for a in startcfg.args: a_value, is_abs_path, found, package = cls._bc_resolve_abs_paths( a, on_hostname, auto_pw_request, user, pw) 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", on_hostname, utf8(' '.join(startcmd))) _, stdout, stderr, ok = nm.ssh().ssh_exec(on_hostname, startcmd, user, pw, auto_pw_request, close_stdin=True) output = stdout.read() error = stderr.read() stdout.close() stderr.close() except nm.AuthenticationRequest as e: raise nm.InteractionNeededError( e, cls.bc_run_node, { 'name': name, 'grpc_path': grpc_path, 'masteruri': masteruri, 'reload_global_param': reload_global_param, 'loglevel': loglevel, 'logformat': logformat, 'auto_pw_request': auto_pw_request, 'user': user, 'pw': pw }) if ok: if error: rospy.logwarn("ERROR while start '%s': %s", startcfg.fullname, error) raise StartException( utf8(''.join( ['The host "', on_hostname, '" reports:\n', error]))) if output: rospy.logdebug("STDOUT while start '%s': %s", startcfg.fullname, output) # inform about absolute paths in parameter value if len(abs_paths) > 0: rospy.loginfo( "Absolute paths found while start:\n%s", utf8('\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( utf8('\n'.join([ 'Some absolute paths are not renamed because following packages are not found on remote host:', packages ])))
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 isstring(cmd): 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) # set display variable to local display if 'DISPLAY' in startcfg.env: if not startcfg.env['DISPLAY'] or startcfg.env['DISPLAY'] == 'remote': del startcfg.env['DISPLAY'] #else: # new_env['DISPLAY'] = ':0' # 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 get_local_addresses()): 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, list(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)
def __init__(self, name, uri, discoverer_name, monitoruri, timestamp, sync_on_demand=False): ''' 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} @param sync_on_demand: Synchronize topics on demand @type sync_on_demand: bool ''' self.name = name self.uri = uri self.discoverer_name = discoverer_name self.monitoruri = monitoruri self.timestamp = timestamp self.timestamp_local = 0. self.timestamp_remote = 0. self._online = True self._offline_ts = 0 self.masteruri_local = masteruri_from_ros() rospy.logdebug("SyncThread[%s]: create this sync thread", self.name) # synchronization variables self.__lock_info = threading.RLock() self.__lock_intern = threading.RLock() self._use_filtered_method = None # SyncMasterInfo with currently synchronized nodes, publisher (topic, node, nodeuri), subscriber(topic, node, nodeuri) and services self.__sync_info = None self.__unregistered = 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 = [] # the state of the own ROS master is used if `sync_on_demand` is enabled or # to determine the type of topic subscribed remote with `Empty` type self.__own_state = None # setup the filter self._filter = FilterInterface() self._filter.load(self.name, ['/rosout', rospy.get_name(), self.discoverer_name, '/node_manager', '/node_manager_daemon', '/zeroconf', '/param_sync'], [], ['/rosout', '/rosout_agg'], ['/'] if sync_on_demand else [], ['/*get_loggers', '/*set_logger_level'], [], # do not sync the bond message of the nodelets!! ['bond/Status'], [], [], []) # congestion avoidance: wait for random.random*2 sec. If an update request # is received try to cancel and restart the current timer. The timer can be # canceled for maximal MAX_UPDATE_DELAY times. self._update_timer = None self._delayed_update = 0 self.__on_update = False
def _get_package_dialog(self): muri = masteruri_from_ros() if self.init_filenames: muri = nmdurl.masteruri(self.init_filenames[0]) return PackageDialog(muri)