def updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: L{master_discovery_fkie.msg.ROSMaster} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) break # update or add a the item root = self.invisibleRootItem() doAddItem = True for i in range(root.rowCount()): masterItem = root.child(i) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): root.insertRow(i, MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri))))) doAddItem = False break if doAddItem: root.appendRow(MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri)))))
def hostNameFrom(cls, masteruri, address): ''' Returns the name generated from masteruri and address @param masteruri: URI of the ROS master assigned to the host @type masteruri: C{str} @param address: the address of the host @type address: C{str} ''' name = nm.nameres().mastername(masteruri, address) if not name: name = address return '@'.join([name, nm.nameres().hostname(address)])
def run(self): index = 0 while (not rospy.is_shutdown()) and self._running: msg = None address = None status_text = ''.join(['listen on network: ', str(index), ' (', str(self._networks_count), ')']) self.status_text_signal.emit(status_text) with self.mutex: while True: try: (msg, address) = self.sockets[index].recvfrom(1024) hostname = None force_update = False if not address is None: try: hostname = self._hosts[address[0]] except: hostname = nm.nameres().hostname(str(address[0])) if hostname is None or hostname == str(address[0]): self.status_text_signal.emit(''.join(['resolve: ', str(address[0])])) try: (hostname, aliaslist, ipaddrlist) = socket.gethostbyaddr(str(address[0])) nm.nameres().addInfo(None, hostname, hostname) nm.nameres().addInfo(None, address[0], hostname) except: import traceback print traceback.format_exc() pass self._hosts[address[0]] = hostname if not msg is None: try: (version, msg_tuple) = Discoverer.msg2masterState(msg, address) if not self._discovered.has_key(index): self._discovered[index] = dict() force_update = True self._discovered[index][address] = (hostname, time.time()) except Exception, e: import traceback print traceback.format_exc() pass if force_update: self._updateDisplay() except socket.timeout: # rospy.logwarn("TIMOUT ignored") break except socket.error: import traceback rospy.logwarn("socket error: %s", traceback.format_exc()) break except:
def updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: L{master_discovery_fkie.msg.ROSMaster} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) try: del self.pyqt_workaround[masterItem.master.name] except: pass break # update or add a the item root = self.invisibleRootItem() doAddItem = True for i in range(root.rowCount()): masterItem = root.child(i, self.COL_NAME) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): mitem = MasterItem.getItemList( master, (nm.is_local(nm.nameres().getHostname(master.uri)))) self.pyqt_workaround[ master. name] = mitem # workaround for using with PyQt: store the python object to keep the defined attributes in the MasterItem subclass root.insertRow(i, mitem) mitem[self.COL_NAME].parent_item = root doAddItem = False break if doAddItem: mitem = MasterItem.getItemList( master, (nm.is_local(nm.nameres().getHostname(master.uri)))) self.pyqt_workaround[ master. name] = mitem # workaround for using with PyQt: store the python object to keep the defined attributes in the MasterItem subclass root.appendRow(mitem) mitem[self.COL_NAME].parent_item = root
def load(self, argv): ''' @param argv: the list with argv parameter needed to load the launch file. The name and value are separated by C{:=} @type argv: C{[str]} @return True, if the launch file was loaded @rtype boolean @raise LaunchConfigException: on load errors ''' try: roscfg = roslaunch.ROSLaunchConfig() loader = roslaunch.XmlLoader() self.argv = self.resolveArgs(argv) loader.load(self.Filename, roscfg, verbose=False, argv=self.argv) self.__roscfg = roscfg nm.file_watcher().add_launch(self.__masteruri, self.__launchFile, self.__launch_id, self.getIncludedFiles(self.Filename)) if not nm.is_local(nm.nameres().getHostname(self.__masteruri)): files = self.getIncludedFiles(self.Filename, regexp_list=[QRegExp("\\bdefault\\b"), QRegExp("\\bvalue=.*pkg:\/\/\\b"), QRegExp("\\bvalue=.*package:\/\/\\b"), QRegExp("\\bvalue=.*\$\(find\\b")]) nm.file_watcher_param().add_launch(self.__masteruri, self.__launchFile, self.__launch_id, files) except roslaunch.XmlParseException, e: test = list(re.finditer(r"environment variable '\w+' is not set", str(e))) message = str(e) if test: message = ''.join([message, '\n', 'environment substitution is not supported, use "arg" instead!']) raise LaunchConfigException(message)
def __init__(self, launch_file, package=None, masteruri=None, argv=[]): ''' Creates the LaunchConfig object. The launch file will be not loaded on creation, first on request of Roscfg value. @param launch_file: The absolute or relative path with the launch file. By using relative path a package must be valid for remote launches. @type launch_file: C{str} @param package: the package containing the launch file. If None the launch_file will be used to determine the launch file. No remote launches a possible without a valid package. @type package: C{str} or C{None} @param masteruri: The URL of the ROS master. @type masteruri: C{str} or C{None} @param argv: the list the arguments needed for loading the given launch file @type argv: C{[str]} @raise roslaunch.XmlParseException: if the launch file can't be found. ''' QObject.__init__(self) self.__launchFile = launch_file self.__package = package_name(os.path.dirname(self.__launchFile))[0] if package is None else package self.__masteruri = masteruri if masteruri is not None else 'localhost' self.__roscfg = None self.argv = argv self.__reqTested = False self.__argv_values = dict() self.global_param_done = [] # masteruri's where the global parameters are registered self.hostname = nm.nameres().getHostname(self.__masteruri) self.__launch_id = '%.9f' % time.time() nm.file_watcher().add_launch(self.__masteruri, self.__launchFile, self.__launch_id, [self.__launchFile])
def on_heartbeat_received(self, msg, address, is_multicast): force_update = False with self.mutex: try: hostname = self._hosts[address[0]] except: self.status_text_signal.emit("resolve %s" % address[0]) hostname = nm.nameres().hostname(utf8(address[0]), resolve=True) self._hosts[address[0]] = hostname try: (_version, _msg_tuple) = Discoverer.msg2masterState(msg, address) index = address[1] - self.default_port if index not in self._discovered: self._discovered[index] = dict() self._discovered[index][address] = (hostname, time.time()) if hostname not in self._msg_counts: self._msg_counts[hostname] = 0 self._msg_counts[hostname] += 1 self._received_msgs += 1 force_update = True except: print traceback.format_exc(1) if force_update: self._updateDisplay()
def updateTypeView(cls, service, item): ''' Updates the representation of the column contains the type of the service. @param service: the service data @type service: L{master_discovery_fkie.ServiceInfo} @param item: corresponding item in the model @type item: L{ServiceItem} ''' try: if service.isLocal and service.type: service_class = service.get_service_class(nm.is_local(nm.nameres().getHostname(service.uri))) item.setText(service_class._type) elif service.type: item.setText(service.type) else: item.setText('unknown type') # removed tooltip for clarity !!! # tooltip = '' # tooltip = ''.join([tooltip, '<h4>', service_class._type, '</h4>']) # tooltip = ''.join([tooltip, '<b><u>', 'Request', ':</u></b>']) # tooltip = ''.join([tooltip, '<dl><dt>', str(service_class._request_class.__slots__), '</dt></dl>']) # # tooltip = ''.join([tooltip, '<b><u>', 'Response', ':</u></b>']) # tooltip = ''.join([tooltip, '<dl><dt>', str(service_class._response_class.__slots__), '</dt></dl>']) # # item.setToolTip(''.join(['<div>', tooltip, '</div>'])) item.setToolTip('') except: if not service.isLocal: tooltip = ''.join(['<h4>', 'Service type is not available due to he running on another host.', '</h4>']) item.setToolTip(''.join(['<div>', tooltip, '</div>']))
def updateModelData(self, nodes): ''' Updates the model data. @param nodes: a dictionary with name and info objects of the nodes. @type nodes: C{dict(str:L{NodeInfo}, ...)} ''' # separate into different hosts hosts = dict() for (name, node) in nodes.items(): host = (node.masteruri, nm.nameres().getHostname(node.uri if not node.uri is None else node.masteruri)) if not hosts.has_key(host): hosts[host] = dict() hosts[host][name] = node # update nodes for each host for ((masteruri, host), nodes_filtered) in hosts.items(): hostItem = self.getHostItem(masteruri, host) # rename the host item if needed if not hostItem is None: # host_name = nm.nameres().getName(host=host) # if host_name and not (hostItem.name == host_name): # hostItem.name = host_name hostItem.updateRunningNodeState(nodes_filtered) # update nodes of the hosts, which are not more exists for i in reversed(range(self.invisibleRootItem().rowCount())): host = self.invisibleRootItem().child(i) if not hosts.has_key(host.id): host.updateRunningNodeState({}) self.removeEmptyHosts()
def updateCapabilities(self, masteruri, cfg_name, description): ''' Updates the capabilities view. @param masteruri: the ROS master URI of updated ROS master. @type masteruri: C{str} @param cfg_name: The name of the node provided the capabilities description. @type cfg_name: C{str} @param description: The capabilities description object. @type description: U{multimaster_msgs_fkie.srv.ListDescription<http://docs.ros.org/api/multimaster_msgs_fkie/html/srv/ListDescription.html>} Response ''' # if it is a new masteruri add a new column robot_index = self._robotHeader.index(masteruri) robot_name = description.robot_name if description.robot_name else nm.nameres().mastername(masteruri) # append a new robot new_robot = False if robot_index == -1: robot_index = self._robotHeader.insertSortedItem(masteruri, robot_name) self.insertColumn(robot_index) # robot_index = self.columnCount()-1 # self._robotHeader.insertItem(robot_index) self._robotHeader.setDescription(robot_index, cfg_name, masteruri, robot_name, description.robot_type, description.robot_descr.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), description.robot_images) item = QTableWidgetItem() item.setSizeHint(QSize(96, 96)) self.setHorizontalHeaderItem(robot_index, item) self.horizontalHeaderItem(robot_index).setText(robot_name) new_robot = True else: # update self._robotHeader.setDescription(robot_index, cfg_name, masteruri, robot_name, description.robot_type, description.robot_descr.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), description.robot_images) # set the capabilities for c in description.capabilities: cap_index = self._capabilityHeader.index(c.name.decode(sys.getfilesystemencoding())) if cap_index == -1 or new_robot: if cap_index == -1: # append a new capability cap_index = self._capabilityHeader.insertSortedItem(c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding())) self.insertRow(cap_index) self.setRowHeight(cap_index, 96) self._capabilityHeader.setDescription(cap_index, cfg_name, c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding()), c.type, c.description.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), c.images) item = QTableWidgetItem() item.setSizeHint(QSize(96, 96)) self.setVerticalHeaderItem(cap_index, item) self.verticalHeaderItem(cap_index).setText(c.name.decode(sys.getfilesystemencoding())) else: self._capabilityHeader.setDescription(cap_index, cfg_name, c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding()), c.type, c.description.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), c.images) # add the capability control widget controlWidget = CapabilityControlWidget(masteruri, cfg_name, c.namespace, c.nodes) controlWidget.start_nodes_signal.connect(self._start_nodes) controlWidget.stop_nodes_signal.connect(self._stop_nodes) self.setCellWidget(cap_index, robot_index, controlWidget) self._capabilityHeader.controlWidget.insert(cap_index, controlWidget) else: self._capabilityHeader.updateDescription(cap_index, cfg_name, c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding()), c.type, c.description.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), c.images) try: self.cellWidget(cap_index, robot_index).updateNodes(cfg_name, c.namespace, c.nodes) except: import traceback print traceback.format_exc()
def updateDispayedName(self, item, show_ros_names): ''' Updates the name representation of the given QStandardItem @param item: item which represent the URI @type item: L{PySide.QtGui.QStandardItem} @param show_ros_names: show the as ROS names or as their description. @type show_ros_names: C{bool} ''' if self.descr_name and not show_ros_names: item.setText(self.descr_name) else: item.setText(NodeItem.toHTML(self.name)) tooltip = ''.join(['<html><body><h4>', self.name, '</h4><dl>']) tooltip = ''.join([tooltip, '<dt>PID: ', str(self.pid), '</dt></dl>']) uri = nm.nameres().getUri(host=nm.nameres().getHostname(self.uri)) master_discovered = (not uri is None) local = (nm.nameres().getHostname(self.uri) == nm.nameres().getHostname(self.masteruri)) if not self.pid is None: item.setIcon(QtGui.QIcon(':/icons/state_run.png')) elif not local and not master_discovered and not self.uri is None: item.setIcon(QtGui.QIcon(':/icons/state_run.png')) tooltip = ''.join([tooltip, '<dl><dt>(Remote nodes will not be ping, so they are always marked running)</dt></dl>']) # elif not master_discovered and not self.uri is None: # item.setIcon(QtGui.QIcon(':/icons/state_run.png')) elif not self.uri is None: item.setIcon(QtGui.QIcon(':/icons/crystal_clear_warning.png')) if not local and master_discovered: tooltip = ''.join(['<h4>', self.name, ' is not local, however the ROS master on this host is discovered, but no information about this node received!', '</h4>']) else: item.setIcon(QtGui.QIcon()) if self.descr_type or self.descr_name or self.descr: tooltip = ''.join([tooltip, '<b><u>Detailed description:</u></b>']) if self.descr_type: tooltip = ''.join([tooltip, '<dl><dt><b>Sensor type:</b> ', self.descr_type, '</dt>']) if self.descr_name: tooltip = ''.join([tooltip, '<dt><b>Sensor name:</b> ', self.descr_name, '</dt></dl>']) if self.descr: try: from docutils import examples tooltip = ''.join([tooltip, examples.html_body(self.descr, input_encoding='utf8')]) except: import traceback rospy.logwarn("Error while generate description for a node: %s", str(traceback.format_exc())) tooltip = ''.join([tooltip, '</dl></body></html>']) item.setToolTip(tooltip)
def updateModelData(self, nodes_extended, onhost): ''' Updates the model data. @param nodes_extended: a dictionary with name and extended info of the nodes. @type nodes_extended: C{dict(node name : L{ExtendedNodeInfo}, ...)} @param onhost: the displayed host @type onhost: C{str} ''' #remove old nodes from the list nodes = nodes_extended.keys() for i in reversed(range(self.invisibleRootItem().rowCount())): host = self.invisibleRootItem().child(i) if not host is None: # should not occur for j in reversed(range(host.rowCount())): nodeItem = host.child(j) if not nodeItem.node.name in nodes: nodeItem.node.updateRunState( ExtendedNodeInfo(nodeItem.node.name, None, None, None, None)) if self.canBeremoved(nodeItem.node): host.removeRow(j) else: nodeItem.updateNodeView(host, self.show_rosnames) elif nodes_extended[ nodeItem.node. name].uri != nodeItem.node.uri and not nodeItem.node.cfgs and not nodeItem.node.default_cfgs: # if the node was started on the other host, remove the current existing host.removeRow(j) else: return if host.rowCount() == 0: self.invisibleRootItem().removeRow(i) for (name, node) in nodes_extended.items(): # create parent items for different hosts host = nm.nameres().getHostname( node.uri if not node.uri is None else node.masteruri) if not host is None: hostItem = self.getHostItem(host, node.masteruri, onhost) doAddItem = True for i in range(hostItem.rowCount()): nodeItem = hostItem.child(i) if (nodeItem == node.name): # update item nodeItem.node.updateRunState(node) nodeItem.updateNodeView(hostItem, self.show_rosnames) doAddItem = False break elif (hostItem.child(i) > node.name): hostItem.insertRow( i, NodeItem.getItemList(node, self.show_rosnames)) doAddItem = False break if doAddItem: hostItem.appendRow( NodeItem.getItemList(node, self.show_rosnames)) else: # should not happen! print "node IGNORED", name, " - no host detected, uri:", node.uri, ", masteruri:", node.masteruri
def updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: L{master_discovery_fkie.msg.ROSMaster} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) try: del self.pyqt_workaround[masterItem.master.name] except: pass break # update or add a the item root = self.invisibleRootItem() doAddItem = True for i in range(root.rowCount()): masterItem = root.child(i, self.COL_NAME) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): mitem = MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri)))) self.pyqt_workaround[master.name] = mitem # workaround for using with PyQt: store the python object to keep the defined attributes in the MasterItem subclass root.insertRow(i, mitem) mitem[self.COL_NAME].parent_item = root doAddItem = False break if doAddItem: mitem = MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri)))) self.pyqt_workaround[master.name] = mitem # workaround for using with PyQt: store the python object to keep the defined attributes in the MasterItem subclass root.appendRow(mitem) mitem[self.COL_NAME].parent_item = root
def hostNameFrom(cls, masteruri, address): ''' Returns the name generated from masteruri and address @param masteruri: URI of the ROS master assigned to the host @type masteruri: C{str} @param address: the address of the host @type address: C{str} ''' #'print "hostNameFrom - mastername" name = nm.nameres().mastername(masteruri, address) if not name: name = address #'print "hostNameFrom - hostname" hostname = nm.nameres().hostname(address) if hostname is None: hostname = str(address) result = '@'.join([name, hostname]) if nm.nameres().getHostname(masteruri) != hostname: result = ''.join([result, '[', masteruri,']']) #'print "- hostNameFrom" return result
def updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: L{master_discovery_fkie.msg.ROSMaster} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) break # update or add a the item root = self.invisibleRootItem() doAddItem = True for i in range(root.rowCount()): masterItem = root.child(i) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): mitem = MasterItem.getItemList( master, (nm.is_local(nm.nameres().getHostname(master.uri)))) root.insertRow(i, mitem) mitem[0].parent_item = root doAddItem = False break if doAddItem: mitem = MasterItem.getItemList( master, (nm.is_local(nm.nameres().getHostname(master.uri)))) root.appendRow(mitem) mitem[0].parent_item = root
def _load_parameters(cls, masteruri, params, clear_params, user, pw, auto_pw_request): """ Load parameters onto the parameter server """ import roslaunch import roslaunch.launch param_server = xmlrpclib.ServerProxy(masteruri) p = None abs_paths = list() # tuples of (parameter name, old value, new value) not_found_packages = list() # packages names try: socket.setdefaulttimeout(6 + len(clear_params)) # multi-call style xmlrpc param_server_multi = xmlrpclib.MultiCall(param_server) # clear specified parameter namespaces # #2468 unify clear params to prevent error for p in clear_params: param_server_multi.deleteParam(rospy.get_name(), p) r = param_server_multi() for code, msg, _ in r: if code != 1 and not msg.find("is not set"): rospy.logwarn("Failed to clear parameter: %s", msg) # raise StartException("Failed to clear parameter: %s"%(msg)) # multi-call objects are not reusable socket.setdefaulttimeout(6 + len(params)) param_server_multi = xmlrpclib.MultiCall(param_server) for p in params.itervalues(): # suppressing this as it causes too much spam value, is_abs_path, found, package = cls._resolve_abs_paths( p.value, nm.nameres().address(masteruri), user, pw, auto_pw_request) if is_abs_path: abs_paths.append((p.key, p.value, value)) if not found and package: not_found_packages.append(package) if p.value is None: rospy.logwarn("The parameter '%s' is invalid: '%s'" % (p.key, p.value)) #raise StartException("The parameter '%s' is invalid: '%s'"%(p.key, p.value)) else: param_server_multi.setParam( rospy.get_name(), p.key, value if is_abs_path else p.value) r = param_server_multi() for code, msg, _ in r: if code != 1: raise StartException("Failed to set parameter: %s" % (msg)) except roslaunch.core.RLException, e: raise StartException(e)
def updateDispayedName(self): ''' Updates the name representation of the Item ''' tooltip = ''.join(['<h4>', self.node_info.name, '</h4><dl>']) tooltip = ''.join([tooltip, '<dt><b>URI:</b> ', str(self.node_info.uri), '</dt>']) tooltip = ''.join([tooltip, '<dt><b>PID:</b> ', str(self.node_info.pid), '</dt></dl>']) master_discovered = nm.nameres().hasMaster(self.node_info.masteruri) local = False if not self.node_info.uri is None and not self.node_info.masteruri is None: local = (nm.nameres().getHostname(self.node_info.uri) == nm.nameres().getHostname(self.node_info.masteruri)) if not self.node_info.pid is None: self._state = NodeItem.STATE_RUN self.setIcon(QtGui.QIcon(':/icons/state_run.png')) self.setToolTip('') elif not local and not master_discovered and not self.node_info.uri is None: self._state = NodeItem.STATE_RUN self.setIcon(QtGui.QIcon(':/icons/state_run.png')) tooltip = ''.join([tooltip, '<dl><dt>(Remote nodes will not be ping, so they are always marked running)</dt></dl>']) tooltip = ''.join([tooltip, '</dl>']) self.setToolTip(''.join(['<div>', tooltip, '</div>'])) elif not self.node_info.uri is None: self._state = NodeItem.STATE_WARNING self.setIcon(QtGui.QIcon(':/icons/crystal_clear_warning.png')) if not local and master_discovered: tooltip = ''.join(['<h4>', self.node_info.name, ' is not local, however the ROS master on this host is discovered, but no information about this node received!', '</h4>']) tooltip = ''.join([tooltip, '</dl>']) self.setToolTip(''.join(['<div>', tooltip, '</div>'])) elif self.has_running: self._state = NodeItem.STATE_DUPLICATE self.setIcon(QtGui.QIcon(':/icons/imacadam_stop.png')) tooltip = ''.join(['<h4>Where are nodes with the same name on remote hosts running. These will be terminated, if you run this node! (Only if master_sync is running or will be started somewhere!)</h4>']) tooltip = ''.join([tooltip, '</dl>']) self.setToolTip(''.join(['<div>', tooltip, '</div>'])) else: self._state = NodeItem.STATE_OFF self.setIcon(QtGui.QIcon(':/icons/state_off.png')) self.setToolTip('')
def updateCapabilities(self, masteruri, cfg_name, description): ''' Updates the capabilities view. @param masteruri: the ROS master URI of updated ROS master. @type masteruri: C{str} @param cfg_name: The name of the node provided the capabilities description. @type cfg_name: C{str} @param description: The capabilities description object. @type description: L{default_cfg_fkie.Description} ''' # if it is a new masteruri add a new column robot_index = self._robotHeader.index(masteruri) robot_name = description.robot_name if description.robot_name else nm.nameres().mastername(masteruri) if robot_index == -1: # append a new robot robot_index = self._robotHeader.insertSortedItem(masteruri, robot_name) self.insertColumn(robot_index) # robot_index = self.columnCount()-1 # self._robotHeader.insertItem(robot_index) self._robotHeader.setDescription(robot_index, cfg_name, masteruri, robot_name, description.robot_type, description.robot_descr.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), description.robot_images) item = QtGui.QTableWidgetItem() item.setSizeHint(QtCore.QSize(96,96)) self.setHorizontalHeaderItem(robot_index, item) self.horizontalHeaderItem(robot_index).setText(robot_name) else: #update self._robotHeader.setDescription(robot_index, cfg_name, masteruri, robot_name, description.robot_type, description.robot_descr.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), description.robot_images) #set the capabilities for c in description.capabilities: cap_index = self._capabilityHeader.index(c.name.decode(sys.getfilesystemencoding())) if cap_index == -1: # append a new capability cap_index = self._capabilityHeader.insertSortedItem(c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding())) self.insertRow(cap_index) self.setRowHeight(cap_index, 96) self._capabilityHeader.setDescription(cap_index, cfg_name, c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding()), c.type, c.description.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), c.images) item = QtGui.QTableWidgetItem() item.setSizeHint(QtCore.QSize(96,96)) self.setVerticalHeaderItem(cap_index, item) self.verticalHeaderItem(cap_index).setText(c.name.decode(sys.getfilesystemencoding())) # add the capability control widget controlWidget = CapabilityControlWidget(masteruri, cfg_name, c.namespace, c.nodes) controlWidget.start_nodes_signal.connect(self._start_nodes) controlWidget.stop_nodes_signal.connect(self._stop_nodes) self.setCellWidget(cap_index, robot_index, controlWidget) self._capabilityHeader.controlWidget.insert(cap_index, controlWidget) else: self._capabilityHeader.updateDescription(cap_index, cfg_name, c.name.decode(sys.getfilesystemencoding()), c.name.decode(sys.getfilesystemencoding()), c.type, c.description.replace("\\n ", "\n").decode(sys.getfilesystemencoding()), c.images) self._capabilityHeader.controlWidget[cap_index].updateNodes(cfg_name, c.namespace, c.nodes)
def updateModelData(self, nodes_extended, onhost): ''' Updates the model data. @param nodes_extended: a dictionary with name and extended info of the nodes. @type nodes_extended: C{dict(node name : L{ExtendedNodeInfo}, ...)} @param onhost: the displayed host @type onhost: C{str} ''' #remove old nodes from the list nodes = nodes_extended.keys() for i in reversed(range(self.invisibleRootItem().rowCount())): host = self.invisibleRootItem().child(i) if not host is None: # should not occur for j in reversed(range(host.rowCount())): nodeItem = host.child(j) if not nodeItem.node.name in nodes: nodeItem.node.updateRunState(ExtendedNodeInfo(nodeItem.node.name, None, None, None, None)) if self.canBeremoved(nodeItem.node): host.removeRow(j) else: nodeItem.updateNodeView(host, self.show_rosnames) elif nodes_extended[nodeItem.node.name].uri != nodeItem.node.uri and not nodeItem.node.cfgs and not nodeItem.node.default_cfgs: # if the node was started on the other host, remove the current existing host.removeRow(j) else: return if host.rowCount() == 0: self.invisibleRootItem().removeRow(i) for (name, node) in nodes_extended.items(): # create parent items for different hosts host = nm.nameres().getHostname(node.uri if not node.uri is None else node.masteruri) if not host is None: hostItem = self.getHostItem(host, node.masteruri, onhost) doAddItem = True for i in range(hostItem.rowCount()): nodeItem = hostItem.child(i) if (nodeItem == node.name): # update item nodeItem.node.updateRunState(node) nodeItem.updateNodeView(hostItem, self.show_rosnames) doAddItem = False break elif (hostItem.child(i) > node.name): hostItem.insertRow(i, NodeItem.getItemList(node, self.show_rosnames)) doAddItem = False break if doAddItem: hostItem.appendRow(NodeItem.getItemList(node, self.show_rosnames)) else: # should not happen! print "node IGNORED", name, " - no host detected, uri:", node.uri, ", masteruri:", node.masteruri
def _load_parameters(cls, masteruri, params, clear_params, user, pw, auto_pw_request): """ Load parameters onto the parameter server """ import roslaunch import roslaunch.launch param_server = xmlrpclib.ServerProxy(masteruri) p = None abs_paths = list() # tuples of (parameter name, old value, new value) not_found_packages = list() # packages names param_errors = [] try: socket.setdefaulttimeout(6 + len(clear_params)) # multi-call style xmlrpc param_server_multi = xmlrpclib.MultiCall(param_server) # clear specified parameter namespaces # #2468 unify clear params to prevent error for p in clear_params: param_server_multi.deleteParam(rospy.get_name(), p) r = param_server_multi() for code, msg, _ in r: if code != 1 and not msg.find("is not set"): rospy.logwarn("Failed to clear parameter: %s", msg) # raise StartException("Failed to clear parameter: %s"%(msg)) # multi-call objects are not reusable socket.setdefaulttimeout(6 + len(params)) param_server_multi = xmlrpclib.MultiCall(param_server) address = nm.nameres().address(masteruri) for p in params.itervalues(): # suppressing this as it causes too much spam value, is_abs_path, found, package = cls._resolve_abs_paths(p.value, address, user, pw, auto_pw_request) if is_abs_path: abs_paths.append((p.key, p.value, value)) if not found and package: not_found_packages.append(package) # if p.value is None: # rospy.logwarn("The parameter '%s' is invalid: '%s'"%(p.key, p.value)) # raise StartException("The parameter '%s' is invalid: '%s'"%(p.key, p.value)) param_server_multi.setParam(rospy.get_name(), p.key, value if is_abs_path else p.value) test_ret = cls._test_value(p.key, value if is_abs_path else p.value) if test_ret: param_errors.extend(test_ret) r = param_server_multi() for code, msg, _ in r: if code != 1: raise StartException("Failed to set parameter: %s" % (msg)) except roslaunch.core.RLException, e: raise StartException(e)
def on_heartbeat_received(self, msg, address, is_multicast): force_update = False with self.mutex: try: hostname = self._hosts[address[0]] except: self.status_text_signal.emit("resolve %s" % address[0]) hostname = nm.nameres().hostname(str(address[0]), resolve=True) self._hosts[address[0]] = hostname try: (_version, _msg_tuple) = Discoverer.msg2masterState(msg, address) index = address[1] - self.default_port if index not in self._discovered: self._discovered[index] = dict() self._discovered[index][address] = (hostname, time.time()) self._received_msgs += 1 force_update = True except: print traceback.format_exc(1) if force_update: self._updateDisplay()
def on_heartbeat_received(self, msg, address): force_update = False with self.mutex: try: hostname = self._hosts[address[0]] except: self.status_text_signal.emit("resolve %s" % address[0]) hostname = nm.nameres().hostname(str(address[0]), resolve=True) self._hosts[address[0]] = hostname try: (version, msg_tuple) = Discoverer.msg2masterState(msg, address) index = address[1] - self.default_port if not self._discovered.has_key(index): self._discovered[index] = dict() self._discovered[index][address] = (hostname, time.time()) self._received_msgs += 1 force_update = True except: print traceback.format_exc(1) if force_update: self._updateDisplay()
def updateMaster(self, master): ''' Updates the information of the ros master. If the ROS master not exists, it will be added. @param master: the ROS master to update @type master: L{master_discovery_fkie.msg.ROSMaster} ''' # remove master, if his name was changed but not the ROS master URI root = self.invisibleRootItem() for i in reversed(range(root.rowCount())): masterItem = root.child(i) if masterItem.master.uri == master.uri and masterItem.master.name != master.name: root.removeRow(i) try: del self.pyqt_workaround[masterItem.master.name] except: pass break # update or add a the item root = self.invisibleRootItem() doAddItem = True is_local = nm.is_local(nm.nameres().getHostname(master.uri)) for index in range(root.rowCount()): masterItem = root.child(index, self.COL_NAME) if (masterItem == master.name): # update item masterItem.master = master masterItem.updateMasterView(root) doAddItem = False break elif (masterItem > master.name): self.addRow(master, is_local, root, index) doAddItem = False break if doAddItem: self.addRow(master, is_local, root, -1)
def updateDispayedName(self, item, show_ros_names): ''' Updates the name representation of the given QStandardItem @param item: item which represent the URI @type item: L{PySide.QtGui.QStandardItem} @param show_ros_names: show the as ROS names or as their description. @type show_ros_names: C{bool} ''' if self.descr_name and not show_ros_names: item.setText(self.descr_name) else: item.setText(NodeItem.toHTML(self.name)) tooltip = ''.join(['<html><body><h4>', self.name, '</h4><dl>']) tooltip = ''.join([tooltip, '<dt>PID: ', str(self.pid), '</dt></dl>']) uri = nm.nameres().getUri(host=nm.nameres().getHostname(self.uri)) master_discovered = (not uri is None) local = (nm.nameres().getHostname( self.uri) == nm.nameres().getHostname(self.masteruri)) if not self.pid is None: item.setIcon(QtGui.QIcon(':/icons/state_run.png')) elif not local and not master_discovered and not self.uri is None: item.setIcon(QtGui.QIcon(':/icons/state_run.png')) tooltip = ''.join([ tooltip, '<dl><dt>(Remote nodes will not be ping, so they are always marked running)</dt></dl>' ]) # elif not master_discovered and not self.uri is None: # item.setIcon(QtGui.QIcon(':/icons/state_run.png')) elif not self.uri is None: item.setIcon(QtGui.QIcon(':/icons/crystal_clear_warning.png')) if not local and master_discovered: tooltip = ''.join([ '<h4>', self.name, ' is not local, however the ROS master on this host is discovered, but no information about this node received!', '</h4>' ]) else: item.setIcon(QtGui.QIcon()) if self.descr_type or self.descr_name or self.descr: tooltip = ''.join([tooltip, '<b><u>Detailed description:</u></b>']) if self.descr_type: tooltip = ''.join([ tooltip, '<dl><dt><b>Sensor type:</b> ', self.descr_type, '</dt>' ]) if self.descr_name: tooltip = ''.join([ tooltip, '<dt><b>Sensor name:</b> ', self.descr_name, '</dt></dl>' ]) if self.descr: try: from docutils import examples tooltip = ''.join([ tooltip, examples.html_body(self.descr, input_encoding='utf8') ]) except: import traceback rospy.logwarn( "Error while generate description for a node: %s", str(traceback.format_exc())) tooltip = ''.join([tooltip, '</dl></body></html>']) item.setToolTip(tooltip)
def on_save_profile(self, masteruri='', path=None): ''' Saves the current environment to a node manager profile. :param path: the pach the file to save :type path: str :param masteruri: If not empty, save the profile only for given master :type masteruri: str ''' try: if path is None: path = self.get_profile_file() if path is None: return rospy.loginfo("Save profile %s" % path) import yaml content = {} for muri, master in self._main_window.masters.items(): if not masteruri or masteruri == muri: running_nodes = master.getRunningNodesIfLocal() configs = {} md_param = {} ms_param = {} zc_param = {} smuri = muri addr = nm.nameres().address(smuri) hostname = get_hostname(smuri) mastername = '' if nm.is_local(addr): smuri = smuri.replace(hostname, '$LOCAL$') addr = '$LOCAL$' else: mastername = nm.nameres().mastername(smuri, nm.nameres().address(smuri)) for node_name in running_nodes.keys(): node_items = master.getNode(node_name) for node in node_items: if node.is_running() and node.launched_cfg is not None: # node.has_launch_cfgs(node.cfgs): cfg = node.launched_cfg if isinstance(node.launched_cfg, (str, unicode)): # it is default config cfg = node.launched_cfg.replace("/%s" % hostname, '/$LOCAL$').rstrip('/run') else: # it is a loaded launch file, get the filename cfg = to_url(node.launched_cfg.Filename) if cfg not in configs: configs[cfg] = {'nodes': []} configs[cfg]['nodes'].append(node_name) elif node_name.endswith('master_discovery'): md_param = get_rosparam('master_discovery', muri) elif node_name.endswith('master_sync'): ms_param = get_rosparam('master_sync', muri) elif node_name.endswith('zeroconf'): zc_param = get_rosparam('zeroconf', muri) elif node_name.endswith('default_cfg'): # store parameter for default configuration nn = node_name.replace("/%s" % hostname, '/$LOCAL$') if nn not in configs: configs[nn] = {'nodes': []} configs[nn]['params'] = get_rosparam(node_name, muri) configs[nn]['default'] = True # store arguments for launchfiles for a, b in master.launchfiles.items(): resolved_a = to_url(a) if resolved_a not in configs: if resolved_a.endswith('default_cfg/run'): pass else: configs[resolved_a] = {} configs[resolved_a]['default'] = False configs[resolved_a]['argv'] = b.argv # fill the configuration content for yaml as dictionary content[smuri] = {'mastername': mastername, 'address': addr, 'configs': configs} if md_param: content[smuri]['master_discovery'] = md_param if ms_param: content[smuri]['master_sync'] = ms_param if zc_param: content[smuri]['zeroconf'] = zc_param text = yaml.dump(content, default_flow_style=False) with open(path, 'w+') as f: f.write(text) except Exception as e: import traceback print utf8(traceback.format_exc(3)) MessageBox.warning(self, "Save profile Error", 'Error while save profile', utf8(e))
def runNode(cls, node, launch_config): ''' 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} @raise StartException: if the screen is not available on host. @raise Exception: on errors while resolving host @see: L{node_manager_fkie.is_local()} ''' n = launch_config.getNode(node) if n is None: raise StartException(''.join(["Node '", node, "' not found!"])) env = list(n.env_args) prefix = n.launch_prefix if not n.launch_prefix is None else '' # thus the parameters while the transfer are not separated if prefix: prefix = ''.join(['"', prefix, '"']) args = [''.join(['__ns:=', n.namespace]), ''.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] host = machine.address #TODO: env-loader support? # if hasattr(machine, "env_loader") and machine.env_loader: # env_loader = machine.env_loader masteruri = nm.nameres().getUri(host=host) # set the ROS_MASTER_URI if masteruri is None: env.append(('ROS_MASTER_URI', nm.masteruri_from_ros())) # 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(global_node_names)) cls._load_parameters(masteruri, global_node_names, []) launch_config.global_param_done.append(masteruri) # add params if not masteruri is None: nodens = ''.join([n.namespace, n.name, '/']) 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(param) rospy.loginfo("Register parameter:\n%s", '\n'.join(params)) cls._load_parameters(masteruri, params, clear_params) if nm.is_local(host): nm.screen().testScreen() 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 import types if isinstance(cmd, types.StringTypes): cmd = [cmd] cmd_type = '' if cmd is None or len(cmd) == 0: raise nm.StartException(' '.join([n.type, 'in package [', n.package, '] not found!\n\nThe package was created?\nIs the binary executable?\n'])) if len(cmd) > 1: # Open selection for executables try: from PySide 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 nm.StartException('Multiple executables with same name in package found!') else: cmd_type = cmd[0] node_cmd = [prefix, cmd_type] cmd_args = [nm.screen().getSceenCmd(node)] cmd_args[len(cmd_args):] = node_cmd cmd_args.append(n.args) cmd_args[len(cmd_args):] = args rospy.loginfo("RUN: %s", ' '.join(cmd_args)) subprocess.Popen(shlex.split(str(' '.join(cmd_args)))) else: # start remote if launch_config.PackageName is None: raise StartException(''.join(["Can't run remote without a valid package name!"])) # setup environment env_command = '' if env_loader: rospy.logwarn("env_loader in machine tag currently not supported") raise nm.StartException("env_loader in machine tag currently not supported") if env: env_command = "env "+' '.join(["%s=%s"%(k,v) for (k, v) in env]) startcmd = [env_command, nm.STARTER_SCRIPT, '--package', str(n.package), '--node_type', str(n.type), '--node_name', str(node)] if prefix: startcmd[len(startcmd):] = ['--prefix', prefix] startcmd[len(startcmd):] = n.args startcmd[len(startcmd):] = args rospy.loginfo("Run remote: %s", ' '.join(startcmd)) (stdin, stdout, stderr), ok = nm.ssh().ssh_exec(host, startcmd) if ok: stdin.close() # stderr.close() # stdout.close() error = stderr.read() if error: rospy.logwarn("ERROR while start '%s': %s", node, error) raise nm.StartException(str(''.join(['The host "', host, '" reports:\n', error]))) output = stdout.read() if output: rospy.logdebug("STDOUT while start '%s': %s", node, output)
def runNode(cls, node, launch_config, force2host=None, masteruri=None, auto_pw_request=False, user=None, pw=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} @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) 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]), ''.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] host = machine.address #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 if masteruri is None: masteruri = nm.nameres().masteruri(n.machine_name) # set the ROS_MASTER_URI if masteruri is None: masteruri = nm.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(global_node_names)) abs_paths[len(abs_paths):], not_found_packages[ len(not_found_packages):] = cls._load_parameters( masteruri, global_node_names, []) launch_config.global_param_done.append(masteruri) # add params if not masteruri is None: nodens = ''.join([n.namespace, n.name, '/']) 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(param) rospy.loginfo("Register parameter:\n%s", '\n'.join(params)) abs_paths[len(abs_paths):], not_found_packages[ len(not_found_packages):] = cls._load_parameters( masteruri, params, clear_params) #'print "RUN prepared", node, time.time() if nm.is_local(host): nm.screen().testScreen() 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 import types 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: # Open selection for executables try: from PySide 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: cmd_type = cmd[0] # determine the current working path, Default: the package of the node cwd = nm.get_ros_home() if not (n.cwd is None): if n.cwd == 'ROS_HOME': cwd = nm.get_ros_home() elif n.cwd == 'node': cwd = os.path.dirname(cmd_type) # else: # cwd = LaunchConfig.packageName(os.path.dirname(cmd_type)) cls._prepareROSMaster(masteruri) node_cmd = [ nm.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)) if not masteruri is None: new_env = dict(os.environ) new_env['ROS_MASTER_URI'] = masteruri ps = subprocess.Popen(shlex.split(str(' '.join(cmd_args))), cwd=cwd, env=new_env) else: ps = subprocess.Popen(shlex.split(str(' '.join(cmd_args))), cwd=cwd) # wait for process to avoid 'defunct' processes thread = threading.Thread(target=ps.wait) thread.setDaemon(True) thread.start() 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: env_command = "env " + ' '.join( ["%s=%s" % (k, v) for (k, v) in env]) startcmd = [ env_command, nm.STARTER_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) 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() output, error, ok = nm.ssh().ssh_exec(host, startcmd, user, pw, auto_pw_request) #'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 ])))
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 ])))
def runNode(cls, node, launch_config): ''' 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} @raise StartException: if the screen is not available on host. @raise Exception: on errors while resolving host @see: L{node_manager_fkie.is_local()} ''' n = launch_config.getNode(node) if n is None: raise StartException(''.join(["Node '", node, "' not found!"])) env = list(n.env_args) prefix = n.launch_prefix if not n.launch_prefix is None else '' # thus the parameters while the transfer are not separated if prefix: prefix = ''.join(['"', prefix, '"']) args = [ ''.join(['__ns:=', n.namespace]), ''.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] host = machine.address #TODO: env-loader support? # if hasattr(machine, "env_loader") and machine.env_loader: # env_loader = machine.env_loader masteruri = nm.nameres().getUri(host=host) # set the ROS_MASTER_URI if masteruri is None: env.append(('ROS_MASTER_URI', nm.masteruri_from_ros())) # 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(global_node_names)) cls._load_parameters(masteruri, global_node_names, []) launch_config.global_param_done.append(masteruri) # add params if not masteruri is None: nodens = ''.join([n.namespace, n.name, '/']) 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(param) rospy.loginfo("Register parameter:\n%s", '\n'.join(params)) cls._load_parameters(masteruri, params, clear_params) if nm.is_local(host): nm.screen().testScreen() 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 import types if isinstance(cmd, types.StringTypes): cmd = [cmd] cmd_type = '' if cmd is None or len(cmd) == 0: raise nm.StartException(' '.join([ n.type, 'in package [', n.package, '] not found!\n\nThe package was created?\nIs the binary executable?\n' ])) if len(cmd) > 1: # Open selection for executables try: from PySide 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 nm.StartException( 'Multiple executables with same name in package found!' ) else: cmd_type = cmd[0] node_cmd = [prefix, cmd_type] cmd_args = [nm.screen().getSceenCmd(node)] cmd_args[len(cmd_args):] = node_cmd cmd_args.append(n.args) cmd_args[len(cmd_args):] = args rospy.loginfo("RUN: %s", ' '.join(cmd_args)) subprocess.Popen(shlex.split(str(' '.join(cmd_args)))) else: # start remote if launch_config.PackageName is None: raise StartException(''.join( ["Can't run remote without a valid package name!"])) # setup environment env_command = '' if env_loader: rospy.logwarn( "env_loader in machine tag currently not supported") raise nm.StartException( "env_loader in machine tag currently not supported") if env: env_command = "env " + ' '.join( ["%s=%s" % (k, v) for (k, v) in env]) startcmd = [ env_command, nm.STARTER_SCRIPT, '--package', str(n.package), '--node_type', str(n.type), '--node_name', str(node) ] if prefix: startcmd[len(startcmd):] = ['--prefix', prefix] startcmd[len(startcmd):] = n.args startcmd[len(startcmd):] = args rospy.loginfo("Run remote: %s", ' '.join(startcmd)) (stdin, stdout, stderr), ok = nm.ssh().ssh_exec(host, startcmd) if ok: stdin.close() # stderr.close() # stdout.close() error = stderr.read() if error: rospy.logwarn("ERROR while start '%s': %s", node, error) raise nm.StartException( str(''.join( ['The host "', host, '" reports:\n', error]))) output = stdout.read() if output: rospy.logdebug("STDOUT while start '%s': %s", node, output)
def runNode(cls, node, launch_config, force2host=None, masteruri=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} @raise StartException: if the screen is not available on host. @raise Exception: on errors while resolving host @see: L{node_manager_fkie.is_local()} ''' n = launch_config.getNode(node) if n is None: raise StartException(''.join(["Node '", node, "' not found!"])) env = list(n.env_args) 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]), ''.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] host = machine.address #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 if masteruri is None: masteruri = nm.nameres().masteruri(n.machine_name) # set the ROS_MASTER_URI if masteruri is None: masteruri = nm.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(global_node_names)) abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(masteruri, global_node_names, []) launch_config.global_param_done.append(masteruri) # add params if not masteruri is None: nodens = ''.join([n.namespace, n.name, '/']) 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(param) rospy.loginfo("Register parameter:\n%s", '\n'.join(params)) abs_paths[len(abs_paths):], not_found_packages[len(not_found_packages):] = cls._load_parameters(masteruri, params, clear_params) if nm.is_local(host): nm.screen().testScreen() 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 import types if isinstance(cmd, types.StringTypes): cmd = [cmd] cmd_type = '' if cmd is None or len(cmd) == 0: raise nm.StartException(' '.join([n.type, 'in package [', n.package, '] not found!\n\nThe package was created?\nIs the binary executable?\n'])) if len(cmd) > 1: # Open selection for executables try: from PySide 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 nm.StartException('Multiple executables with same name in package found!') else: cmd_type = cmd[0] # determine the current working path, Default: the package of the node cwd = nm.get_ros_home() if not (n.cwd is None): if n.cwd == 'ROS_HOME': cwd = nm.get_ros_home() elif n.cwd == 'node': cwd = os.path.dirname(cmd_type) # else: # cwd = LaunchConfig.packageName(os.path.dirname(cmd_type)) cls._prepareROSMaster(masteruri) node_cmd = [nm.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)) if not masteruri is None: new_env=dict(os.environ) new_env['ROS_MASTER_URI'] = masteruri ps = subprocess.Popen(shlex.split(str(' '.join(cmd_args))), cwd=cwd, env=new_env) else: ps = subprocess.Popen(shlex.split(str(' '.join(cmd_args))), cwd=cwd) # wait for process to avoid 'defunct' processes thread = threading.Thread(target=ps.wait) thread.setDaemon(True) thread.start() else: # 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 nm.StartException("env_loader in machine tag currently not supported") if env: env_command = "env "+' '.join(["%s=%s"%(k,v) for (k, v) in env]) startcmd = [env_command, nm.STARTER_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 = [] for a in n.args.split(): a_value, is_abs_path, found, package = cls._resolve_abs_paths(a, host) 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))) (stdin, stdout, stderr), ok = nm.ssh().ssh_exec(host, startcmd) if ok: stdin.close() # stderr.close() # stdout.close() error = stderr.read() if error: rospy.logwarn("ERROR while start '%s': %s", node, error) raise nm.StartException(str(''.join(['The host "', host, '" reports:\n', error]))) output = stdout.read() 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 nm.StartException(str('\n'.join(['Some absolute paths are not renamed because following packages are not found on remote host:', packages])))
def on_save_profile(self, masteruri='', path=None): ''' Saves the current environment to a node manager profile. :param path: the pach the file to save :type path: str :param masteruri: If not empty, save the profile only for given master :type masteruri: str ''' try: if path is None: path = self.get_profile_file() if path is None: return rospy.loginfo("Save profile %s" % path) import yaml content = {} for muri, master in self._main_window.masters.items(): if not masteruri or masteruri == muri: running_nodes = master.getRunningNodesIfLocal() configs = {} md_param = {} ms_param = {} zc_param = {} smuri = muri addr = nm.nameres().address(smuri) hostname = get_hostname(smuri) mastername = '' if nm.is_local(addr): smuri = smuri.replace(hostname, '$LOCAL$') addr = '$LOCAL$' else: mastername = nm.nameres().mastername( smuri, nm.nameres().address(smuri)) for node_name in running_nodes.keys(): node_items = master.getNode(node_name) for node in node_items: if node.is_running( ) and node.launched_cfg is not None: # node.has_launch_cfgs(node.cfgs): cfg = node.launched_cfg if isinstance(node.launched_cfg, (str, unicode)): # it is default config cfg = node.launched_cfg.replace( "/%s" % hostname, '/$LOCAL$').rstrip('/run') else: # it is a loaded launch file, get the filename cfg = to_url(node.launched_cfg.Filename) if cfg not in configs: configs[cfg] = {'nodes': []} configs[cfg]['nodes'].append(node_name) elif node_name.endswith('master_discovery'): md_param = get_rosparam( 'master_discovery', muri) elif node_name.endswith('master_sync'): ms_param = get_rosparam('master_sync', muri) elif node_name.endswith('zeroconf'): zc_param = get_rosparam('zeroconf', muri) elif node_name.endswith('default_cfg'): # store parameter for default configuration nn = node_name.replace("/%s" % hostname, '/$LOCAL$') if nn not in configs: configs[nn] = {'nodes': []} configs[nn]['params'] = get_rosparam( node_name, muri) configs[nn]['default'] = True # store arguments for launchfiles for a, b in master.launchfiles.items(): resolved_a = to_url(a) if resolved_a not in configs: if resolved_a.endswith('default_cfg/run'): pass else: configs[resolved_a] = {} configs[resolved_a]['default'] = False configs[resolved_a]['argv'] = b.argv # fill the configuration content for yaml as dictionary content[smuri] = { 'mastername': mastername, 'address': addr, 'configs': configs } if md_param: content[smuri]['master_discovery'] = md_param if ms_param: content[smuri]['master_sync'] = ms_param if zc_param: content[smuri]['zeroconf'] = zc_param text = yaml.dump(content, default_flow_style=False) with open(path, 'w+') as f: f.write(text) except Exception as e: import traceback print traceback.format_exc(3) WarningMessageBox(QMessageBox.Warning, "Save profile Error", 'Error while save profile', str(e)).exec_()
def on_load_profile_file(self, path): ''' Load the profile file. :param path: the path of the profile file. :type path: str ''' rospy.loginfo("Load profile %s" % path) self.progressBar.setValue(0) self.setVisible(True) self.setWindowTitle("%s profile started" % os.path.basename(path).rstrip('.nmprofile')) hasstart = False if path: try: import yaml with open(path, 'r') as f: # print yaml.load(f.read()) content = yaml.load(f.read()) if not isinstance(content, dict): raise Exception("Mailformed profile: %s" % os.path.basename(path)) for muri, master_dict in content.items(): local_hostname = get_hostname( self._main_window.getMasteruri()) rmuri = muri.replace('$LOCAL$', local_hostname) master = self._main_window.getMaster(rmuri) running_nodes = master.getRunningNodesIfLocal() usr = None self._current_profile[rmuri] = set() if 'user' in master_dict: usr = master_dict['user'] if master_dict['mastername'] and master_dict[ 'mastername']: nm.nameres().add_master_entry( master.masteruri, master_dict['mastername'], master_dict['address']) hostname = master_dict['address'].replace( '$LOCAL$', local_hostname) if 'master_discovery' in master_dict: self._start_node_from_profile( master, hostname, 'master_discovery_fkie', 'master_discovery', usr, cfg=master_dict['master_discovery']) self._current_profile[rmuri].add( '/master_discovery') if 'master_sync' in master_dict: self._start_node_from_profile( master, hostname, 'master_sync_fkie', 'master_sync', usr, cfg=master_dict['master_sync']) self._current_profile[rmuri].add('/master_sync') if 'zeroconf' in master_dict: self._start_node_from_profile( master, hostname, 'master_discovery_fkie', 'zeroconf', usr, cfg=master_dict['zeroconf']) self._current_profile[rmuri].add('/zeroconf') try: do_start = [] do_not_stop = { '/rosout', rospy.get_name(), '/node_manager', '/master_discovery', '/master_sync', '*default_cfg', '/zeroconf' } configs = master_dict['configs'] conf_set = set() for cfg_name, cmdict in configs.items(): cfg_name = cfg_name.replace( '$LOCAL$', local_hostname) if cfg_name.startswith("pkg://"): cfg_name = os.path.abspath( resolve_url(cfg_name)) conf_set.add(cfg_name) reload_launch = True argv = [] is_default = False if 'default' in cmdict: if cmdict['default']: # it is a default configuration, test for load or not is_default = True if 'argv_used' in cmdict['params']: argv = cmdict['params'][ 'argv_used'] if cfg_name in master.default_cfgs: reload_launch = False if argv: params = get_rosparam( cfg_name, rmuri) if 'argv_used' in params: reload_launch = set( params['argv_used'] ) != set(argv) if reload_launch: self._main_window.on_load_launch_as_default_bypkg( cmdict['params']['package'], cmdict['params'] ['launch_file'], master, argv, local_hostname) else: do_not_stop.add(cfg_name) elif 'argv' in cmdict: if 'argv' in cmdict: argv = cmdict['argv'] # do we need to load to load/reload launch file if cfg_name in master.launchfiles: reload_launch = set( master.launchfiles[cfg_name].argv ) != set(argv) if reload_launch: self._main_window.launch_dock.load_file( cfg_name, argv, master.masteruri) if 'nodes' in cmdict: self._current_profile[rmuri].update( cmdict['nodes']) force_start = True cfg = cfg_name if not is_default else roslib.names.ns_join( cfg_name, 'run') if not reload_launch: force_start = False do_not_stop.update(set( cmdict['nodes'])) do_start.append( (reload_launch, cfg, cmdict['nodes'], force_start)) else: do_start.append( (reload_launch, cfg, cmdict['nodes'], force_start)) # close unused configurations for lfile in set( master.launchfiles.keys()) - conf_set: master._close_cfg(lfile) master.stop_nodes_by_name(running_nodes.keys(), True, do_not_stop) for reload_launch, cfg, nodes, force_start in do_start: if nodes: hasstart = True if reload_launch: master.start_nodes_after_load_cfg( cfg.rstrip('/run'), list(nodes), force_start) else: master.start_nodes_by_name( list(nodes), cfg, force_start) except Exception as ml: import traceback print traceback.format_exc(1) rospy.logwarn( "Can not load launch file for %s: %s" % (muri, ml)) except Exception as e: import traceback print traceback.format_exc(1) WarningMessageBox(QMessageBox.Warning, "Load profile error", 'Error while load profile', str(e)).exec_() if not hasstart: self.update_progress() else: QTimer.singleShot(1000, self.update_progress)
def on_load_profile_file(self, path): ''' Load the profile file. :param path: the path of the profile file. :type path: str ''' rospy.loginfo("Load profile %s" % path) self.progressBar.setValue(0) self.setVisible(True) self.setWindowTitle("%s profile started" % os.path.basename(path).rstrip('.nmprofile')) hasstart = False if path: try: import yaml with open(path, 'r') as f: # print yaml.load(f.read()) content = yaml.load(f.read()) if not isinstance(content, dict): raise Exception("Mailformed profile: %s" % os.path.basename(path)) for muri, master_dict in content.items(): local_hostname = get_hostname(self._main_window.getMasteruri()) rmuri = muri.replace('$LOCAL$', local_hostname) master = self._main_window.getMaster(rmuri) running_nodes = master.getRunningNodesIfLocal() usr = None self._current_profile[rmuri] = set() if 'user' in master_dict: usr = master_dict['user'] if master_dict['mastername'] and master_dict['mastername']: nm.nameres().add_master_entry(master.masteruri, master_dict['mastername'], master_dict['address']) hostname = master_dict['address'].replace('$LOCAL$', local_hostname) if 'master_discovery' in master_dict: self._start_node_from_profile(master, hostname, 'master_discovery_fkie', 'master_discovery', usr, cfg=master_dict['master_discovery']) self._current_profile[rmuri].add('/master_discovery') if 'master_sync' in master_dict: self._start_node_from_profile(master, hostname, 'master_sync_fkie', 'master_sync', usr, cfg=master_dict['master_sync']) self._current_profile[rmuri].add('/master_sync') if 'zeroconf' in master_dict: self._start_node_from_profile(master, hostname, 'master_discovery_fkie', 'zeroconf', usr, cfg=master_dict['zeroconf']) self._current_profile[rmuri].add('/zeroconf') try: do_start = [] do_not_stop = {'/rosout', rospy.get_name(), '/node_manager', '/master_discovery', '/master_sync', '*default_cfg', '/zeroconf'} configs = master_dict['configs'] conf_set = set() for cfg_name, cmdict in configs.items(): cfg_name = cfg_name.replace('$LOCAL$', local_hostname) if cfg_name.startswith("pkg://"): cfg_name = os.path.abspath(resolve_url(cfg_name)) conf_set.add(cfg_name) reload_launch = True argv = [] is_default = False if 'default' in cmdict: if cmdict['default']: # it is a default configuration, test for load or not is_default = True if 'argv_used' in cmdict['params']: argv = cmdict['params']['argv_used'] if cfg_name in master.default_cfgs: reload_launch = False if argv: params = get_rosparam(cfg_name, rmuri) if 'argv_used' in params: reload_launch = set(params['argv_used']) != set(argv) if reload_launch: self._main_window.on_load_launch_as_default_bypkg(cmdict['params']['package'], cmdict['params']['launch_file'], master, argv, local_hostname) else: do_not_stop.add(cfg_name) elif 'argv' in cmdict: if 'argv' in cmdict: argv = cmdict['argv'] # do we need to load to load/reload launch file if cfg_name in master.launchfiles: reload_launch = set(master.launchfiles[cfg_name].argv) != set(argv) if reload_launch: self._main_window.launch_dock.load_file(cfg_name, argv, master.masteruri) if 'nodes' in cmdict: self._current_profile[rmuri].update(cmdict['nodes']) force_start = True cfg = cfg_name if not is_default else roslib.names.ns_join(cfg_name, 'run') if not reload_launch: force_start = False do_not_stop.update(set(cmdict['nodes'])) do_start.append((reload_launch, cfg, cmdict['nodes'], force_start)) else: do_start.append((reload_launch, cfg, cmdict['nodes'], force_start)) # close unused configurations for lfile in set(master.launchfiles.keys()) - conf_set: master._close_cfg(lfile) master.stop_nodes_by_name(running_nodes.keys(), True, do_not_stop) for reload_launch, cfg, nodes, force_start in do_start: if nodes: hasstart = True if reload_launch: master.start_nodes_after_load_cfg(cfg.rstrip('/run'), list(nodes), force_start) else: master.start_nodes_by_name(list(nodes), cfg, force_start) except Exception as ml: import traceback print utf8(traceback.format_exc(1)) rospy.logwarn("Can not load launch file for %s: %s" % (muri, utf8(ml))) except Exception as e: import traceback print traceback.format_exc(1) MessageBox.warning(self, "Load profile error", 'Error while load profile', utf8(e)) if not hasstart: self.update_progress() else: QTimer.singleShot(1000, self.update_progress)
def runNode(cls, runcfg): ''' 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: L{node_manager_fkie.is_local()} ''' # 'print "RUN node", node, time.time() n = runcfg.roslaunch_config.getNode(runcfg.node) if n is None: raise StartException(''.join(["Node '", runcfg.node, "' not found!"])) env = list(n.env_args) # set logging options if runcfg.logging is not None: if not runcfg.logging.is_default('console_format'): env.append(('ROSCONSOLE_FORMAT', '%s' % runcfg.logging.console_format)) if n.respawn: # set the respawn environment variables respawn_params = cls._get_respawn_params(rospy.names.ns_join(n.namespace, n.name), runcfg.roslaunch_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 n.launch_prefix is not None else '' if prefix.lower() == 'screen' or prefix.lower().find('screen ') != -1: rospy.loginfo("SCREEN prefix removed before start!") prefix = '' args = ['__ns:=%s' % n.namespace.rstrip(rospy.names.SEP), '__name:=%s' % n.name] if n.cwd is not None: args.append('__cwd:=%s' % n.cwd) # add remaps for remap in n.remap_args: args.append(''.join([remap[0], ':=', remap[1]])) # get host of the node host = runcfg.roslaunch_config.hostname env_loader = '' if n.machine_name: machine = runcfg.roslaunch_config.Roscfg.machines[n.machine_name] if machine.address not in ['localhost', '127.0.0.1']: host = machine.address if runcfg.masteruri is None: runcfg.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 runcfg.force2host is not None: host = runcfg.force2host # set the ROS_MASTER_URI if runcfg.masteruri is None: runcfg.masteruri = masteruri_from_ros() env.append(('ROS_MASTER_URI', runcfg.masteruri)) ros_hostname = NameResolution.get_ros_hostname(runcfg.masteruri) if ros_hostname: env.append(('ROS_HOSTNAME', ros_hostname)) 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) # 'print "RUN prepared", node, time.time() if nm.is_local(host, wait=True): nm.screen().testScreen() if runcfg.executable: cmd_type = runcfg.executable else: try: cmd = roslib.packages.find_node(n.package, n.type) except (Exception, roslib.packages.ROSPkgException) as starterr: # multiple nodes, invalid package raise StartException("Can't find resource: %s" % starterr) # 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("%s in package [%s] not found!\n\nThe package " "was created?\nIs the binary executable?\n" % (n.type, n.package)) if len(cmd) > 1: if runcfg.auto_pw_request: # Open selection for executables, only if the method is called from the main GUI thread try: try: from python_qt_binding.QtGui import QInputDialog except: from python_qt_binding.QtWidgets import QInputDialog item, result = QInputDialog.getItem(None, 'Multiple executables %s in %s' % (n.type, 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, (runcfg,)) 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(runcfg.masteruri) node_cmd = [nm.settings().respawn_script if n.respawn else '', prefix, cmd_type] cmd_args = [nm.screen().getSceenCmd(runcfg.node)] cmd_args[len(cmd_args):] = node_cmd cmd_args.append(utf8(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'] = runcfg.masteruri ros_hostname = NameResolution.get_ros_hostname(runcfg.masteruri) if ros_hostname: new_env['ROS_HOSTNAME'] = ros_hostname # add the namespace environment parameter to handle some cases, # e.g. rqt_cpp plugins if n.namespace: new_env['ROS_NAMESPACE'] = n.namespace # set logging options if runcfg.logging is not None: if not runcfg.logging.is_default('loglevel'): env.append(('ROSCONSOLE_CONFIG_FILE', nm.settings().rosconsole_cfg_file(n.package))) for key, value in env: new_env[key] = value SupervisedPopen(shlex.split(utf8(' '.join(cmd_args))), cwd=cwd, env=new_env, object_id="Run node", description="Run node " "[%s]%s" % (utf8(n.package), utf8(n.type))) nm.filewatcher().add_binary(cmd_type, runcfg.node, runcfg.masteruri, runcfg.roslaunch_config.Filename) else: # 'print "RUN REMOTE", node, time.time() # start remote if runcfg.roslaunch_config.PackageName is None: raise StartException("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, runcfg.user, runcfg.pw, runcfg.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, (runcfg,)) startcmd = [env_command, nm.settings().start_remote_script, '--package', utf8(n.package), '--node_type', utf8(n.type), '--node_name', utf8(runcfg.node), '--node_respawn true' if n.respawn else ''] if runcfg.masteruri is not None: startcmd.append('--masteruri') startcmd.append(runcfg.masteruri) if prefix: startcmd[len(startcmd):] = ['--prefix', prefix] if runcfg.logging is not None: if not runcfg.logging.is_default('loglevel'): startcmd.append('--loglevel') startcmd.append(nm.settings().logging.loglevel) # 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, runcfg.user, runcfg.pw, runcfg.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, utf8(' '.join(startcmd))) # 'print "RUN CALL", node, time.time() _, stdout, stderr, ok = nm.ssh().ssh_exec(host, startcmd, runcfg.user, runcfg.pw, runcfg.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, (runcfg,)) if ok: if error: rospy.logwarn("ERROR while start '%s': %s", runcfg.node, error) raise StartException(utf8(''.join(['The host "', host, '" reports:\n', error]))) if output: rospy.loginfo("STDOUT while start '%s': %s", runcfg.node, 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])))