class TestRqtRosGraph(unittest.TestCase):
    """
    :author: Isaac Saito
    """

    def setUp(self):
        unittest.TestCase.setUp(self)

        self._model = QStandardItemModel()
        node1 = QStandardItem('node1')
        self._node1_1 = QStandardItem('node1_1')
        self._node1_1_1 = QStandardItem('node1_1_1')
        node1_1_2 = QStandardItem('node1_1_2')
        node1_2 = QStandardItem('node1_2')

        node1.appendRow(self._node1_1)
        self._node1_1.appendRow(self._node1_1_1)
        self._node1_1.appendRow(node1_1_2)
        node1.appendRow(node1_2)

        self._model.appendRow(node1)

        #node_list = [node1, node1_1, self._node1_1_1, node1_1_2, node1_2]
        #self._model.appendRow(node_list)

        self._grn_node1_1_1 = '/node1/node1_1/node1_1_1'
        self._len_lower_grn_node1_1 = 2

    def tearDown(self):
        unittest.TestCase.tearDown(self)
        del self._model

    def test_get_upper_grn(self):
        self.assertEqual(RqtRosGraph.get_upper_grn(self._node1_1_1.index(), ''),
                         self._grn_node1_1_1)

    def test_get_lower_grn_dfs(self):
        self.assertEqual(len(RqtRosGraph.get_lower_grn_dfs(
                                                  self._node1_1.index(),
                                                  '')),
                         self._len_lower_grn_node1_1)

    def test_get_full_grn(self):
        self.assertEqual(RqtRosGraph.get_full_grn(self._node1_1_1.index()),
                         self._grn_node1_1_1)
class TestRqtRosGraph(unittest.TestCase):
    """
    :author: Isaac Saito
    """
    def setUp(self):
        unittest.TestCase.setUp(self)

        self._model = QStandardItemModel()
        node1 = QStandardItem('node1')
        self._node1_1 = QStandardItem('node1_1')
        self._node1_1_1 = QStandardItem('node1_1_1')
        node1_1_2 = QStandardItem('node1_1_2')
        node1_2 = QStandardItem('node1_2')

        node1.appendRow(self._node1_1)
        self._node1_1.appendRow(self._node1_1_1)
        self._node1_1.appendRow(node1_1_2)
        node1.appendRow(node1_2)

        self._model.appendRow(node1)

        # node_list = [node1, node1_1, self._node1_1_1, node1_1_2, node1_2]
        # self._model.appendRow(node_list)

        self._grn_node1_1_1 = '/node1/node1_1/node1_1_1'
        self._len_lower_grn_node1_1 = 2

    def tearDown(self):
        unittest.TestCase.tearDown(self)
        del self._model

    def test_get_upper_grn(self):
        self.assertEqual(
            RqtRosGraph.get_upper_grn(self._node1_1_1.index(), ''),
            self._grn_node1_1_1)

    def test_get_lower_grn_dfs(self):
        self.assertEqual(
            len(RqtRosGraph.get_lower_grn_dfs(self._node1_1.index(), '')),
            self._len_lower_grn_node1_1)

    def test_get_full_grn(self):
        self.assertEqual(RqtRosGraph.get_full_grn(self._node1_1_1.index()),
                         self._grn_node1_1_1)
Esempio n. 3
0
    def _on_ctrl_info(self, index):
        popup = self._popup_widget

        ctrl = self._controllers[index.row()]
        popup.ctrl_name.setText(ctrl.name)
        popup.ctrl_type.setText(ctrl.type)

        res_model = QStandardItemModel()
        model_root = QStandardItem('Claimed Resources')
        res_model.appendRow(model_root)
        for hw_res in ctrl.claimed_resources:
            hw_iface_item = QStandardItem(hw_res.hardware_interface)
            model_root.appendRow(hw_iface_item)
            for res in hw_res.resources:
                res_item = QStandardItem(res)
                hw_iface_item.appendRow(res_item)

        popup.resource_tree.setModel(res_model)
        popup.resource_tree.setItemDelegate(FontDelegate(popup.resource_tree))
        popup.resource_tree.expandAll()
        popup.move(QCursor.pos())
        popup.show()
Esempio n. 4
0
    def _on_ctrl_info(self, index):
        popup = self._popup_widget

        ctrl = self._controllers[index.row()]
        popup.ctrl_name.setText(ctrl.name)
        popup.ctrl_type.setText(ctrl.type)

        res_model = QStandardItemModel()
        model_root = QStandardItem('Claimed Resources')
        res_model.appendRow(model_root)
        for hw_res in ctrl.claimed_resources:
            hw_iface_item = QStandardItem(hw_res.hardware_interface)
            model_root.appendRow(hw_iface_item)
            for res in hw_res.resources:
                res_item = QStandardItem(res)
                hw_iface_item.appendRow(res_item)

        popup.resource_tree.setModel(res_model)
        popup.resource_tree.setItemDelegate(FontDelegate(popup.resource_tree))
        popup.resource_tree.expandAll()
        popup.move(QCursor.pos())
        popup.show()
Esempio n. 5
0
class MoveitWidget(QWidget):
    """#TODO: comment
    """
    # To be connected to PluginContainerWidget
    sig_sysmsg = None
    sig_param = Signal(bool, str)  # param name emitted
    sig_node = Signal(bool, str)  # param name emitted

    _SPLITTER_H = 'splitter_horizontal'

    def __init__(self, parent, plugin_context):
        """
        @type parent: MoveitMain
        """

        self._nodes_monitored = ['/move_group']
        self._selected_topics = [('/pointcloud', 'sensor_msgs/PointCloud'),
                                 ('/pointcloud2', 'sensor_msgs/PointCloud2'),
                                 ('/image', 'sensor_msgs/Image'),
                                 ('/camera_info', 'sensor_msgs/CameraInfo')]
        self._params_monitored = [
            '/robot_description', '/robot_description_semantic'
        ]

        super(MoveitWidget, self).__init__()
        self._parent = parent
        self._plugin_context = plugin_context
        self._refresh_rate = 5  # With default value

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_moveit'),
                               'resource', 'moveit_top.ui')
        loadUi(ui_file, self, {'TopicWidget': TopicWidget})

        # Custom widget classes don't show in QSplitter when they instantiated
        # in .ui file and not explicitly added to QSplitter like this. Thus
        # this is a workaround.
        self._splitter.addWidget(self._widget_topic)

        self._spinbox_refreshrate.valueChanged.connect(
            self._update_refreshrate)
        # Show default ref rate on QSpinbox
        self._spinbox_refreshrate.setValue(self._refresh_rate)

        # Monitor node
        self._is_checking_nodes = True
        self._node_qitems = {}
        self._node_monitor_thread = self._init_monitor_nodes(
            self._nodes_monitored)
        self._node_monitor_thread.start()
        #TODO: connect sys msg for nodes.

        # topic to show
        # Delegate GUI functionality to rqt_topic.TopicWidget.
        self._widget_topic.set_selected_topics(self._selected_topics)
        self._widget_topic.set_topic_specifier(TopicWidget.SELECT_BY_MSGTYPE)
        self._widget_topic.start()
        # To connect signal in a widget to PluginContainerWidget.
        #TODO: In this way, Signal from only one instance is hooked.
        # Not a good design at all.
        self.sig_sysmsg = self._widget_topic.sig_sysmsg

        # Init monitoring parameters.
        self._is_checking_params = True
        self._param_qitems = {}
        _col_names_paramtable = ['Param name', 'Found on Parameter Server?']
        self._param_check_thread = self._init_monitor_parameters(
            self._params_monitored, _col_names_paramtable)
        self._param_check_thread.start()

    def _init_monitor_nodes(self, nodes_monitored):
        """
        @type params_monitored: str[]
        @rtype: Thread
        """
        self._node_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._node_datamodel.invisibleRootItem()
        self._view_nodes.setModel(self._node_datamodel)

        node_monitor_thread = Thread(target=self._check_nodes_alive,
                                     args=(self.sig_node,
                                           self._nodes_monitored))
        #        self._node_monitor_thread = NodeMonitorThread(self, self.sig_node,
        #                                                      nodes_monitored)
        self.sig_node.connect(self._update_output_nodes)
        return node_monitor_thread

    def _check_nodes_alive(self, signal, nodes_monitored):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the nodes whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @param signal: Signal(bool, str)
        @type nodes_monitored: str[]
        """
        while self._is_checking_nodes:
            rosnode_dynamically_loaded = __import__('rosnode')
            #from rosnode import rosnode_ping
            for nodename in nodes_monitored:
                #TODO: rosnode_ping prints when the node is not found.
                # Currently I have no idea how to capture that from here.
                try:
                    #is_node_running = rosnode_ping(nodename, 1)
                    is_node_running = rosnode_dynamically_loaded.rosnode_ping(
                        nodename, 1)
                except rosnode_dynamically_loaded.ROSNodeIOException as e:
                    #TODO: Needs to be indicated on GUI
                    #      (eg. PluginContainerWidget)
                    rospy.logerr(e.message)
                    is_node_running = False

                signal.emit(is_node_running, nodename)
                rospy.logdebug('_update_output_nodes')
            del rosnode_dynamically_loaded
            time.sleep(self._refresh_rate)

    def _init_monitor_parameters(self,
                                 params_monitored,
                                 _col_names_paramtable=None):
        """
        @type params_monitored: str[]
        """
        self._params_monitored = params_monitored

        self._param_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._param_datamodel.invisibleRootItem()
        self._view_params.setModel(self._param_datamodel)

        # Names of header on the QTableView.
        if not _col_names_paramtable:
            _col_names_paramtable = [
                'Param name', 'Found on Parameter Server?'
            ]
        self._param_datamodel.setHorizontalHeaderLabels(_col_names_paramtable)

        self.sig_param.connect(self._update_output_parameters)

        param_check_thread = Thread(target=self._check_params_alive,
                                    args=(self.sig_param,
                                          self._params_monitored))
        return param_check_thread

    def _update_output_nodes(self, is_node_running, node_name):
        """
        Slot for signals that tell nodes existence.

        @type is_node_running: bool
        @type node_name: str
        """
        #TODO: What this method does is exactly the same with
        # monitor_parameters. Unify them.

        rospy.logdebug('is_node_running={} par_name={}'.format(
            is_node_running, node_name))
        node_name = str(node_name)
        node_qitem = None
        if not node_name in self._node_qitems:
            node_qitem = QStandardItem(node_name)
            self._node_qitems[node_name] = node_qitem
            self._node_datamodel.appendRow(node_qitem)
        else:  # qsitem with the node name already exists.
            node_qitem = self._node_qitems[str(node_name)]

        qindex = self._node_datamodel.indexFromItem(node_qitem)
        _str_node_running = 'Not running'
        if is_node_running:
            _str_node_running = 'Running'
        qitem_node_status = QStandardItem(_str_node_running)
        self._node_datamodel.setItem(qindex.row(), 1, qitem_node_status)

    def _check_params_alive(self, signal, params_monitored):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the params whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @type signal: Signal(bool, str)
        @param_name signal: emitting a name of the parameter that's found.
        @type params_monitored: str[]
        """

        while self._is_checking_params:
            # self._is_checking_params only turns to false when the plugin
            # shuts down.

            has_param = False

            for param_name in params_monitored:
                is_rosmaster_running = RqtRoscommUtil.is_roscore_running()

                try:
                    if is_rosmaster_running:
                        # Only if rosmaster is running, check if the parameter
                        # exists or not.
                        has_param = rospy.has_param(param_name)
                except rospy.exceptions.ROSException as e:
                    self.sig_sysmsg.emit(
                        'Exception upon rospy.has_param {}'.format(e.message))
                signal.emit(has_param, param_name)
                rospy.loginfo('has_param {}, check_param_alive: {}'.format(
                    has_param, param_name))
            time.sleep(self._refresh_rate)

    def _update_output_parameters(self, has_param, param_name):
        """
        Slot

        @type has_param: bool
        @type param_name: str
        """
        rospy.logdebug('has_param={} par_name={}'.format(
            has_param, param_name))
        param_name = str(param_name)
        param_qitem = None
        if not param_name in self._param_qitems:
            param_qitem = QStandardItem(param_name)
            self._param_qitems[param_name] = param_qitem
            self._param_datamodel.appendRow(param_qitem)
        else:  # qsitem with the param name already exists.
            param_qitem = self._param_qitems[str(param_name)]

        qindex = self._param_datamodel.indexFromItem(param_qitem)
        _str_param_found = 'No'
        if has_param:
            _str_param_found = 'Yes'
        qitem_param_status = QStandardItem(_str_param_found)
        self._param_datamodel.setItem(qindex.row(), 1, qitem_param_status)
        self._view_params.resizeColumnsToContents()

    def _update_refreshrate(self, refresh_rate):
        """
        Slot

        @type refresh_rate: int
        """
        self._refresh_rate = refresh_rate

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(self._SPLITTER_H,
                                    self._splitter.saveState())

    def restore_settings(self, plugin_settings, instance_settings):
        if instance_settings.contains(self._SPLITTER_H):
            self._splitter.restoreState(
                instance_settings.value(self._SPLITTER_H))
        else:
            self._splitter.setSizes([100, 100, 200])
        pass

    def shutdown(self):
        """
        Overridden.

        Close threads.

        @raise RuntimeError:
        """
        try:
            #self._node_monitor_thread.join()  # No effect
            self._is_checking_nodes = False
            self._node_monitor_thread = None
            #self._param_check_thread.join()

            self._is_checking_params = False
            self._param_check_thread = None
        except RuntimeError as e:
            rospy.logerr(e)
            raise e
class QtRappManager(Plugin):
    _update_rapps_signal = Signal()

    def __init__(self, context):
        self._context = context
        super(QtRappManager, self).__init__(context)

        self._init_ui(context)
        self._init_events()
        self._init_variables()
        self.spin()

    def _init_ui(self, context):
        self._widget = QWidget()
        self.setObjectName('QtRappManger')

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_qt_app_manager'), 'ui',
                               'qt_rapp_manager.ui')
        self._widget.setObjectName('QtRappManger')
        loadUi(ui_file, self._widget, {})

        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))
        context.add_widget(self._widget)

        # Set view mode
        self._widget.rapp_grid.setViewMode(QListView.IconMode)
        #self._widget.rapp_grid.setViewMode(QListView.ListMode)

    def _init_events(self):
        #combo box change event
        self._widget.namespace_cbox.currentIndexChanged.connect(
            self._change_namespace)

        # Rapp single click event
        self._widget.rapp_grid.clicked.connect(self._rapp_single_click)
        # Rapp double click event
        self._widget.rapp_grid.doubleClicked.connect(self._rapp_double_click)

    def _init_variables(self):
        self.initialised = False

        #init
        self._qt_rapp_manager_info = QtRappManagerInfo(self._refresh_rapps)
        self._update_rapps_signal.connect(self._update_rapp_list)

        self._rapp_view_model = QStandardItemModel()
        self._widget.rapp_grid.setModel(self._rapp_view_model)
        self._widget.rapp_grid.setWrapping(True)
        self._widget.rapp_grid.setIconSize(QSize(60, 60))
        self._widget.rapp_grid.setSpacing(10)

        self._selected_rapp = None

    def spin(self):
        self._get_appmanager_namespaces()

    def _cleanup_rapps(self):
        self._rapp_view_model.clear()
        pass

    def _get_appmanager_namespaces(self):
        namespaces = self._qt_rapp_manager_info._get_namespaces()
        for namespace in namespaces:
            ns = namespace[:namespace.find('list_rapps')]
            self._widget.namespace_cbox.addItem(ns)

    def _exit(self):
        pass

###################################################################
# Events
###################################################################

    def _change_namespace(self, event):
        self._qt_rapp_manager_info.select_rapp_manager(
            self._widget.namespace_cbox.currentText())

    def _refresh_rapps(self):
        """
        Updates from qt_app_manager_info.
        """
        self._update_rapps_signal.emit()

    def _update_rapp_list(self):
        """
        Rapp manager namespace event
        """
        self._cleanup_rapps()
        available_rapps = self._qt_rapp_manager_info.get_available_rapps()
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()

        rapp_items = []
        for r, v in available_rapps.items():
            if r in running_rapps.keys():
                item = QRappItem(v, running=True)
            else:
                item = QRappItem(v, running=False)
            self._rapp_view_model.appendRow(item)

    def _rapp_single_click(self, index):
        qrapp = self._rapp_view_model.item(index.row())
        rapp = qrapp.getRapp()
        self._create_rapp_dialog(rapp)

    def _create_rapp_dialog(self, rapp):
        is_running = self._qt_rapp_manager_info.is_running_rapp(rapp)
        self._selected_rapp = rapp
        self._dialog = QtRappDialog(self._widget, rapp,
                                    self._qt_rapp_manager_info.start_rapp,
                                    self._qt_rapp_manager_info.stop_rapp,
                                    is_running)
        self._dialog.show()

    def _rapp_double_click(self, item):
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()
        if len(running_rapps) > 0:
            names = [r['display_name'] for r in running_rapps.values()]
            show_message(self._widget, "Error",
                         "Rapp %s are already running" % names)
        else:
            self._start_rapp()

    def _start_rapp(self):
        result = self._qt_rapp_manager_info.start_rapp(
            self._selected_rapp['name'], [],
            self._selected_rapp['public_parameters'])
        show_message(self._widget, str(result.started), result.message)
        self._selected_rapp = None
        return result

    def _stop_rapp(self):
        result = self._qt_rapp_manager_info.stop_rapp()
        show_message(self._widget, str(result.stopped), result.message)
        self._selected_rapp = None
        return result

########################################
# Legacy
########################################

    def _select_rapp_tree_item(self, item):
        if not item in self.rapps.keys():
            print "HAS NO KEY"
        else:
            self.current_rapp = self.rapps[item]
        self._widget.rapp_info_text.clear()
        rapp_info = self.qt_rapp_manager_info._get_rapp_info(self.current_rapp)
        self._widget.rapp_info_text.appendHtml(rapp_info)
        self._update_rapp_parameter_layout(self.current_rapp)
        self._update_implementation_tree(self.current_rapp)

    def _update_rapp_parameter_layout(self, rapp):
        parameters_layout = self._widget.rapp_parameter_layout
        clear_layout(parameters_layout)

        for param in rapp['public_parameters']:
            one_param_layout = create_label_textedit_pair(
                param.key, param.value)
            parameters_layout.addLayout(one_param_layout)

    def _update_implementation_tree(self, rapp):
        self._widget.implementation_tree_widget.clear()
        self.selected_impl = None
        self.impls = {}
        for impl in rapp['implementations']:
            impl_item = QTreeWidgetItem(
                self._widget.implementation_tree_widget)
            impl_item.setText(0, impl)
            self.impls[impl_item] = impl

    def _select_implementation_tree_item(self, item):
        if not item in self.impls.keys():
            print "HAS NO KEY"
        else:
            self.selected_impl = self.impls[item]

    def _get_public_parameters(self):
        public_parameters = {}
        parameters_layout = self._widget.rapp_parameter_layout
        for i in reversed(range(parameters_layout.count())):
            item = parameters_layout.itemAt(i)
            key_label = item.itemAt(0).widget()
            value_textbox = item.itemAt(1).widget()
            public_parameters[key_label.text()] = str(
                value_textbox.toPlainText())
        return public_parameters
Esempio n. 7
0
class MoveitWidget(QWidget):
    """#TODO: comment
    """
    # To be connected to PluginContainerWidget
    sig_sysmsg = None
    sig_param = Signal(bool, str)  # param name emitted
    sig_node = Signal(bool, str)  # param name emitted

    _SPLITTER_H = 'splitter_horizontal'

    def __init__(self, parent, plugin_context):
        """
        @type parent: MoveitMain
        """

        self._nodes_monitored = ['/move_group']
        self._selected_topics = [('/pointcloud', 'sensor_msgs/PointCloud'),
                                 ('/pointcloud2', 'sensor_msgs/PointCloud2'),
                                 ('/image', 'sensor_msgs/Image'),
                                 ('/camera_info', 'sensor_msgs/CameraInfo')]
        self._params_monitored = ['/robot_description',
                                  '/robot_description_semantic']

        super(MoveitWidget, self).__init__()
        self._parent = parent
        self._plugin_context = plugin_context
        self._refresh_rate = 5  # With default value

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_moveit'),
                               'resource', 'moveit_top.ui')
        loadUi(ui_file, self, {'TopicWidget': TopicWidget})

        # Custom widget classes don't show in QSplitter when they instantiated
        # in .ui file and not explicitly added to QSplitter like this. Thus
        # this is a workaround.
        self._splitter.addWidget(self._widget_topic)

        self._spinbox_refreshrate.valueChanged.connect(
                                                      self._update_refreshrate)
        # Show default ref rate on QSpinbox
        self._spinbox_refreshrate.setValue(self._refresh_rate)

        # Monitor node
        self._is_checking_nodes = True
        self._node_qitems = {}
        self._node_monitor_thread = self._init_monitor_nodes(
                                                         self._nodes_monitored)
        self._node_monitor_thread.start()
        #TODO: connect sys msg for nodes.

        # topic to show
        # Delegate GUI functionality to rqt_topic.TopicWidget.
        self._widget_topic.set_selected_topics(self._selected_topics)
        self._widget_topic.set_topic_specifier(TopicWidget.SELECT_BY_MSGTYPE)
        self._widget_topic.start()
        # To connect signal in a widget to PluginContainerWidget.
        #TODO: In this way, Signal from only one instance is hooked.
        # Not a good design at all.
        self.sig_sysmsg = self._widget_topic.sig_sysmsg

        # Init monitoring parameters.
        self._is_checking_params = True
        self._param_qitems = {}
        _col_names_paramtable = ['Param name', 'Found on Parameter Server?']
        self._param_check_thread = self._init_monitor_parameters(
                                                      self._params_monitored,
                                                      _col_names_paramtable)
        self._param_check_thread.start()

    def _init_monitor_nodes(self, nodes_monitored):
        """
        @type params_monitored: str[]
        @rtype: Thread
        """
        self._node_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._node_datamodel.invisibleRootItem()
        self._view_nodes.setModel(self._node_datamodel)

        node_monitor_thread = Thread(target=self._check_nodes_alive,
                                           args=(self.sig_node,
                                                 self._nodes_monitored))
#        self._node_monitor_thread = NodeMonitorThread(self, self.sig_node,
#                                                      nodes_monitored)
        self.sig_node.connect(self._update_output_nodes)
        return node_monitor_thread

    def _check_nodes_alive(self, signal, nodes_monitored):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the nodes whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @param signal: Signal(bool, str)
        @type nodes_monitored: str[]
        """
        while self._is_checking_nodes:
            rosnode_dynamically_loaded = __import__('rosnode')
            #from rosnode import rosnode_ping
            for nodename in nodes_monitored:
                #TODO: rosnode_ping prints when the node is not found.
                # Currently I have no idea how to capture that from here.
                try:
                    #is_node_running = rosnode_ping(nodename, 1)
                    is_node_running = rosnode_dynamically_loaded.rosnode_ping(
                                                                 nodename, 1)
                except rosnode_dynamically_loaded.ROSNodeIOException as e:
                    #TODO: Needs to be indicated on GUI
                    #      (eg. PluginContainerWidget)
                    rospy.logerr(e.message)
                    is_node_running = False

                signal.emit(is_node_running, nodename)
                rospy.logdebug('_update_output_nodes')
            del rosnode_dynamically_loaded
            time.sleep(self._refresh_rate)

    def _init_monitor_parameters(self, params_monitored,
                                 _col_names_paramtable=None):
        """
        @type params_monitored: str[]
        """
        self._params_monitored = params_monitored

        self._param_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._param_datamodel.invisibleRootItem()
        self._view_params.setModel(self._param_datamodel)

        # Names of header on the QTableView.
        if not _col_names_paramtable:
            _col_names_paramtable = ['Param name',
                                     'Found on Parameter Server?']
        self._param_datamodel.setHorizontalHeaderLabels(_col_names_paramtable)

        self.sig_param.connect(self._update_output_parameters)

        param_check_thread = Thread(target=self._check_params_alive,
                                    args=(self.sig_param,
                                          self._params_monitored))
        return param_check_thread

    def _update_output_nodes(self, is_node_running, node_name):
        """
        Slot for signals that tell nodes existence.

        @type is_node_running: bool
        @type node_name: str
        """
        #TODO: What this method does is exactly the same with
        # monitor_parameters. Unify them.

        rospy.logdebug('is_node_running={} par_name={}'.format(is_node_running,
                                                              node_name))
        node_name = str(node_name)
        node_qitem = None
        if not node_name in self._node_qitems:
            node_qitem = QStandardItem(node_name)
            self._node_qitems[node_name] = node_qitem
            self._node_datamodel.appendRow(node_qitem)
        else:  # qsitem with the node name already exists.
            node_qitem = self._node_qitems[str(node_name)]

        qindex = self._node_datamodel.indexFromItem(node_qitem)
        _str_node_running = 'Not running'
        if is_node_running:
            _str_node_running = 'Running'
        qitem_node_status = QStandardItem(_str_node_running)
        self._node_datamodel.setItem(qindex.row(), 1, qitem_node_status)

    def _check_params_alive(self, signal, params_monitored):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the params whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @type signal: Signal(bool, str)
        @param_name signal: emitting a name of the parameter that's found.
        @type params_monitored: str[]
        """

        while self._is_checking_params:
            # self._is_checking_params only turns to false when the plugin
            # shuts down.

            has_param = False

            for param_name in params_monitored:
                is_rosmaster_running = RqtRoscommUtil.is_roscore_running()

                try:
                    if is_rosmaster_running:
                        # Only if rosmaster is running, check if the parameter
                        # exists or not.
                        has_param = rospy.has_param(param_name)
                except rospy.exceptions.ROSException as e:
                    self.sig_sysmsg.emit(
                         'Exception upon rospy.has_param {}'.format(e.message))
                signal.emit(has_param, param_name)
                rospy.loginfo('has_param {}, check_param_alive: {}'.format(
                                                      has_param, param_name))
            time.sleep(self._refresh_rate)

    def _update_output_parameters(self, has_param, param_name):
        """
        Slot

        @type has_param: bool
        @type param_name: str
        """
        rospy.logdebug('has_param={} par_name={}'.format(has_param,
                                                         param_name))
        param_name = str(param_name)
        param_qitem = None
        if not param_name in self._param_qitems:
            param_qitem = QStandardItem(param_name)
            self._param_qitems[param_name] = param_qitem
            self._param_datamodel.appendRow(param_qitem)
        else:  # qsitem with the param name already exists.
            param_qitem = self._param_qitems[str(param_name)]

        qindex = self._param_datamodel.indexFromItem(param_qitem)
        _str_param_found = 'No'
        if has_param:
            _str_param_found = 'Yes'
        qitem_param_status = QStandardItem(_str_param_found)
        self._param_datamodel.setItem(qindex.row(), 1, qitem_param_status)
        self._view_params.resizeColumnsToContents()

    def _update_refreshrate(self, refresh_rate):
        """
        Slot

        @type refresh_rate: int
        """
        self._refresh_rate = refresh_rate

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(self._SPLITTER_H,
                                    self._splitter.saveState())

    def restore_settings(self, plugin_settings, instance_settings):
        if instance_settings.contains(self._SPLITTER_H):
            self._splitter.restoreState(instance_settings.value(
                                                             self._SPLITTER_H))
        else:
            self._splitter.setSizes([100, 100, 200])
        pass

    def shutdown(self):
        """
        Overridden.

        Close threads.

        @raise RuntimeError:
        """
        try:
            #self._node_monitor_thread.join()  # No effect
            self._is_checking_nodes = False
            self._node_monitor_thread = None
            #self._param_check_thread.join()

            self._is_checking_params = False
            self._param_check_thread = None
        except RuntimeError as e:
            rospy.logerr(e)
            raise e
Esempio n. 8
0
class QtRappManager(Plugin):
    _update_rapps_signal = Signal()

    def __init__(self, context):
        self._context = context
        super(QtRappManager, self).__init__(context)

        self._init_ui(context)
        self._init_events()
        self._init_variables()
        self.spin()

    def _init_ui(self, context):
        self._widget = QWidget()
        self.setObjectName('QtRappManger')

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_qt_app_manager'), 'ui',
                               'qt_rapp_manager.ui')
        self._widget.setObjectName('QtRappManger')
        loadUi(ui_file, self._widget, {})

        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))
        context.add_widget(self._widget)

        # Set view mode
        self._widget.rapp_grid.setViewMode(QListView.IconMode)
        # self._widget.rapp_grid.setViewMode(QListView.ListMode)

    def _init_events(self):
        # combo box change event
        self._widget.namespace_cbox.currentIndexChanged.connect(
            self._change_namespace)

        # Rapp single click event
        self._widget.rapp_grid.clicked.connect(self._rapp_single_click)
        # Rapp double click event
        self._widget.rapp_grid.doubleClicked.connect(self._rapp_double_click)

    def _init_variables(self):
        self.initialised = False

        # init
        self._qt_rapp_manager_info = QtRappManagerInfo(self._refresh_rapps)
        self._update_rapps_signal.connect(self._update_rapp_list)

        self._rapp_view_model = QStandardItemModel()
        self._widget.rapp_grid.setModel(self._rapp_view_model)
        self._widget.rapp_grid.setWrapping(True)
        self._widget.rapp_grid.setIconSize(QSize(60, 60))
        self._widget.rapp_grid.setSpacing(10)

        self._selected_rapp = None

    def spin(self):
        self._get_appmanager_namespaces()

    def _cleanup_rapps(self):
        self._rapp_view_model.clear()

    def _get_appmanager_namespaces(self):
        namespaces = self._qt_rapp_manager_info._get_namespaces()
        for namespace in namespaces:
            ns = namespace[:namespace.find('list_rapps')]
            self._widget.namespace_cbox.addItem(ns)

    def _exit(self):
        pass

###################################################################
# Events
###################################################################

    def _change_namespace(self, event):
        self._qt_rapp_manager_info.select_rapp_manager(
            self._widget.namespace_cbox.currentText())

    def _refresh_rapps(self):
        """
        Updates from qt_app_manager_info.
        """
        self._update_rapps_signal.emit()

    def _update_rapp_list(self):
        """
        Rapp manager namespace event
        """
        self._cleanup_rapps()
        available_rapps = self._qt_rapp_manager_info.get_available_rapps()
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()

        for r, v in available_rapps.items():
            if r in running_rapps.keys():
                item = QRappItem(v, running=True)
            else:
                item = QRappItem(v, running=False)
            self._rapp_view_model.appendRow(item)

    def _rapp_single_click(self, index):
        qrapp = self._rapp_view_model.item(index.row())
        rapp = qrapp.getRapp()
        self._create_rapp_dialog(rapp)

    def _create_rapp_dialog(self, rapp):
        is_running = self._qt_rapp_manager_info.is_running_rapp(rapp)
        self._selected_rapp = rapp
        self._dialog = QtRappDialog(self._widget, rapp,
                                    self._qt_rapp_manager_info.start_rapp,
                                    self._qt_rapp_manager_info.stop_rapp,
                                    is_running)
        self._dialog.show()

    def _rapp_double_click(self, item):
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()
        if len(running_rapps) > 0:
            names = [r['display_name'] for r in running_rapps.values()]
            show_message(self._widget, "Error",
                         "Rapp %s are already running" % names)
        else:
            self._start_rapp()

    def _start_rapp(self):
        result = self._qt_rapp_manager_info.start_rapp(
            self._selected_rapp['name'], [],
            self._selected_rapp['public_parameters'])
        show_message(self._widget, str(result.started), result.message)
        self._selected_rapp = None
        return result

    def _stop_rapp(self):
        result = self._qt_rapp_manager_info.stop_rapp()
        show_message(self._widget, str(result.stopped), result.message)
        self._selected_rapp = None
        return result
Esempio n. 9
0
class MoveitWidget(QWidget):
    """
    This Widget provides an overview about the presence of different parts of a running moveIt instance.
    """
    # To be connected to PluginContainerWidget
    sig_sysmsg = Signal(str)
    sig_param = Signal(bool, str)  # param name emitted
    sig_node = Signal(bool, str)  # node name emitted
    sig_topic = Signal(list)  # topic name emitted

    _SPLITTER_H = 'splitter_horizontal'

    def __init__(self, parent, plugin_context):
        """
        @type parent: MoveitMain
        """

        self._ros_master = xmlrpclib.ServerProxy(os.environ['ROS_MASTER_URI'])
        self._stop_event = threading.Event()

        self._nodes_monitored = ['/move_group']
        self._selected_topics = [('/pointcloud', 'sensor_msgs/PointCloud'),
                                 ('/pointcloud2', 'sensor_msgs/PointCloud2'),
                                 ('/image', 'sensor_msgs/Image'),
                                 ('/camera_info', 'sensor_msgs/CameraInfo')]
        self._params_monitored = [
            '/robot_description', '/robot_description_semantic'
        ]

        super(MoveitWidget, self).__init__()
        self._parent = parent
        self._plugin_context = plugin_context
        self._refresh_rate = 5  # With default value

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_moveit'),
                               'resource', 'moveit_top.ui')
        loadUi(ui_file, self, {'TopicWidget': TopicWidget})

        # Custom widget classes don't show in QSplitter when they instantiated
        # in .ui file and not explicitly added to QSplitter like this. Thus
        # this is a workaround.
        self._splitter.addWidget(self._widget_topic)

        self._spinbox_refreshrate.valueChanged.connect(
            self._update_refreshrate)

        # Show default ref rate on QSpinbox
        self._spinbox_refreshrate.setValue(self._refresh_rate)

        # Monitor node
        self._node_qitems = {}
        self._node_monitor_thread = self._init_monitor_nodes()
        self._node_monitor_thread.start()

        # topic to show
        self._registered_topics = None
        self._topic_monitor_thread = self._init_monitor_topics()
        self._topic_monitor_thread.start()

        # Init monitoring parameters.
        self._param_qitems = {}
        _col_names_paramtable = ['Param name', 'Found on Parameter Server?']
        self._param_check_thread = self._init_monitor_parameters(
            _col_names_paramtable)
        self._param_check_thread.start()

    def _init_monitor_nodes(self):
        """
        @rtype: Thread
        """
        self._node_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._node_datamodel.invisibleRootItem()
        self._view_nodes.setModel(self._node_datamodel)

        node_monitor_thread = threading.Thread(target=self._check_nodes_alive,
                                               args=(self.sig_node,
                                                     self._nodes_monitored,
                                                     self._stop_event))

        self.sig_node.connect(self._update_output_nodes)
        return node_monitor_thread

    def _check_nodes_alive(self, signal, nodes_monitored, stop_event):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the nodes whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @param signal: Signal(bool, str)
        @type nodes_monitored: str[]
        @type stop_event: Event()
        """
        rosnode_dynamically_loaded = __import__('rosnode')
        while True:
            for nodename in nodes_monitored:
                try:
                    registered_nodes = rosnode_dynamically_loaded.get_node_names(
                    )
                    is_node_running = nodename in registered_nodes

                except rosnode_dynamically_loaded.ROSNodeIOException as e:
                    # TODO: Needs to be indicated on GUI
                    # (eg. PluginContainerWidget)
                    rospy.logerr(e.message)
                    is_node_running = False

                signal.emit(is_node_running, nodename)
                rospy.logdebug('_update_output_nodes')
            if stop_event.wait(self._refresh_rate):
                del rosnode_dynamically_loaded
                return

    def _init_monitor_topics(self):
        """
        @rtype: Thread
        """
        topic_monitor_thread = threading.Thread(
            target=self._check_topics_alive,
            args=(self.sig_topic, self._selected_topics, self._stop_event))
        self.sig_topic.connect(self._update_output_topics)
        return topic_monitor_thread

    def _check_topics_alive(self, signal, topics_monitored, stop_event):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the topics whose names are passed exist and emits signal per
        each node.

        @param signal: Signal()
        @type topics_monitored: str[]
        @type stop_event: Event()
        """
        while True:
            code, msg, val = self._ros_master.getPublishedTopics(
                '/rqt_moveit_update_script', "")
            if code == 1:
                published_topics = dict(val)
            else:
                rospy.logerr("Communication with rosmaster failed")

            registered_topics = []
            for topic in topics_monitored:
                if topic[0] in published_topics and topic[
                        1] == published_topics.get(topic[0]):
                    registered_topics.append(
                        (topic[0], published_topics.get(topic[0])))

            signal.emit(list(registered_topics))
            rospy.logdebug('_update_output_topics')
            if stop_event.wait(self._refresh_rate):
                return

    def _init_monitor_parameters(self, _col_names_paramtable=None):
        """
        @rtype: Thread
        """

        self._param_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._param_datamodel.invisibleRootItem()
        self._view_params.setModel(self._param_datamodel)

        # Names of header on the QTableView.
        if not _col_names_paramtable:
            _col_names_paramtable = [
                'Param name', 'Found on Parameter Server?'
            ]
        self._param_datamodel.setHorizontalHeaderLabels(_col_names_paramtable)

        self.sig_param.connect(self._update_output_parameters)

        param_check_thread = threading.Thread(target=self._check_params_alive,
                                              args=(self.sig_param,
                                                    self._params_monitored,
                                                    self._stop_event))
        return param_check_thread

    def _update_output_nodes(self, is_node_running, node_name):
        """
        Slot for signals that tell nodes existence.

        @type is_node_running: bool
        @type node_name: str
        """
        # TODO: What this method does is exactly the same with
        # monitor_parameters. Unify them.

        rospy.logdebug('is_node_running={} par_name={}'.format(
            is_node_running, node_name))
        node_name = str(node_name)
        node_qitem = None
        if node_name not in self._node_qitems:
            node_qitem = QStandardItem(node_name)
            self._node_qitems[node_name] = node_qitem
            self._node_datamodel.appendRow(node_qitem)
        else:  # qsitem with the node name already exists.
            node_qitem = self._node_qitems[str(node_name)]

        qindex = self._node_datamodel.indexFromItem(node_qitem)
        _str_node_running = 'Not running'
        if is_node_running:
            _str_node_running = 'Running'
        qitem_node_status = QStandardItem(_str_node_running)
        self._node_datamodel.setItem(qindex.row(), 1, qitem_node_status)

    def _update_output_topics(self, registered_topics):
        """
        Slot for signals that tell topic's existence.

        @type registered_topics: list
        """
        # This branch will cause that once a selected topic was found the topic view will
        # never be empty again.
        if len(registered_topics) > 0:

            if self._registered_topics is None:
                self._widget_topic.set_selected_topics(registered_topics)
                self._widget_topic.set_topic_specifier(
                    TopicWidget.SELECT_BY_NAME)
                self._widget_topic.start()
            elif self._registered_topics is not None and set(
                    self._registered_topics) != set(registered_topics):
                self._widget_topic.set_selected_topics(registered_topics)

            self._registered_topics = registered_topics

    def _check_params_alive(self, signal, params_monitored, stop_event):
        """
        Working as a callback of Thread class, this method keeps looping to
        watch if the params whose names are passed exist and emits signal per
        each node.

        Notice that what MoveitWidget._check_nodes_alive &
        MoveitWidget._check_params_alive do is very similar, but since both of
        them are supposed to be passed to Thread class, there might not be
        a way to generalize these 2.

        @type signal: Signal(bool, str)
        @param_name signal: emitting a name of the parameter that's found.
        @type params_monitored: str[]
        @type stop_event: Event()
        """

        while True:
            has_param = False

            for param_name in params_monitored:
                is_rosmaster_running = RqtRoscommUtil.is_roscore_running()

                try:
                    if is_rosmaster_running:
                        # Only if rosmaster is running, check if the parameter
                        # exists or not.
                        has_param = rospy.has_param(param_name)
                except rospy.exceptions.ROSException as e:
                    rospy.logerr('Exception upon rospy.has_param {}'.format(
                        e.message))
                    self.sig_sysmsg.emit(
                        'Exception upon rospy.has_param {}'.format(e.message))
                signal.emit(has_param, param_name)
                rospy.logdebug('has_param {}, check_param_alive: {}'.format(
                    has_param, param_name))
            if stop_event.wait(self._refresh_rate):
                return

    def _update_output_parameters(self, has_param, param_name):
        """
        Slot

        @type has_param: bool
        @type param_name: str
        """
        rospy.logdebug('has_param={} par_name={}'.format(
            has_param, param_name))
        param_name = str(param_name)
        param_qitem = None
        if param_name not in self._param_qitems:
            param_qitem = QStandardItem(param_name)
            self._param_qitems[param_name] = param_qitem
            self._param_datamodel.appendRow(param_qitem)
        else:  # qsitem with the param name already exists.
            param_qitem = self._param_qitems[str(param_name)]

        qindex = self._param_datamodel.indexFromItem(param_qitem)
        _str_param_found = 'No'
        if has_param:
            _str_param_found = 'Yes'
        qitem_param_status = QStandardItem(_str_param_found)
        self._param_datamodel.setItem(qindex.row(), 1, qitem_param_status)
        self._view_params.resizeColumnsToContents()

    def _update_refreshrate(self, refresh_rate):
        """
        Slot

        @type refresh_rate: int
        """
        self._refresh_rate = refresh_rate

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(self._SPLITTER_H,
                                    self._splitter.saveState())

    def restore_settings(self, plugin_settings, instance_settings):
        if instance_settings.contains(self._SPLITTER_H):
            self._splitter.restoreState(
                instance_settings.value(self._SPLITTER_H))
        else:
            self._splitter.setSizes([100, 100, 200])
        pass

    def shutdown(self):
        """
        Overridden.

        Close threads.

        @raise RuntimeError:
        """
        try:
            self._stop_event.set()

            self._node_monitor_thread.join()
            self._param_check_thread.join()
            self._topic_monitor_thread.join()

            self._node_monitor_thread = None
            self._param_check_thread = None
            self._topic_monitor_thread = None

        except RuntimeError as e:
            rospy.logerr(e)
            raise e
Esempio n. 10
0
class HandEyeCalibration(Plugin):
    PLUGIN_TITLE = ' Intel OTC Robotics: Hand-Eye Calibration'

    def __init__(self, context):
        super(HandEyeCalibration, self).__init__(context)
        self.context = context
        self.node = context.node
        self.widget = QWidget()
        self.widget.setObjectName(self.PLUGIN_TITLE)
        self.widget.setWindowTitle(self.PLUGIN_TITLE)

        # Data
        self.Tsamples = []

        # Toolbar
        _, path_pkg = get_resource('packages', 'handeye_dashboard')
        print("{}".format(path_pkg))

        self.snapshot_action = QAction(QIcon.fromTheme('camera-photo'),
                                       'Take a snapshot', self.widget)
        path = path_pkg + '/share/handeye_dashboard/images/capture.png'
        self.calibrate_action = QAction(QIcon(QPixmap.fromImage(QImage(path))),
                                        'Get the camera/robot transform',
                                        self.widget)
        self.clear_action = QAction(QIcon.fromTheme('edit-clear'),
                                    'Clear the record data.', self.widget)
        path = path_pkg + '/share/handeye_dashboard/images/UR5.png'
        self.execut_action = QAction(QIcon(QPixmap.fromImage(QImage(path))),
                                     'EStart the publishing the TF.',
                                     self.widget)
        self.toolbar = QToolBar()
        self.toolbar.addAction(self.snapshot_action)
        self.toolbar.addAction(self.calibrate_action)
        self.toolbar.addAction(self.clear_action)
        self.toolbar.addAction(self.execut_action)

        # Toolbar0
        self.l0 = QLabel(self.widget)
        self.l0.setText("Camera-Mount-Type: ")
        self.l0.setFixedWidth(150)
        self.l0.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.combobox = QComboBox(self.widget)
        self.combobox.addItem('attached on robot')
        self.combobox.addItem('fixed beside robot')
        self.toolbar0 = QToolBar()
        self.toolbar0.addWidget(self.l0)
        self.toolbar0.addWidget(self.combobox)

        # Toolbar1
        self.l1 = QLabel(self.widget)
        self.l1.setText("Camera-Frame: ")
        self.l1.setFixedWidth(150)
        self.l1.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.camera_frame = QLineEdit(self.widget)
        self.camera_frame.setText("camera_link")
        self.toolbar1 = QToolBar()
        self.toolbar1.addWidget(self.l1)
        self.toolbar1.addWidget(self.camera_frame)

        # Toolbar2
        self.l2 = QLabel(self.widget)
        self.l2.setText("Object-Frame: ")
        self.l2.setFixedWidth(150)
        self.l2.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.object_frame = QLineEdit(self.widget)
        self.object_frame.setText("calib_board")
        self.toolbar2 = QToolBar()
        self.toolbar2.addWidget(self.l2)
        self.toolbar2.addWidget(self.object_frame)

        # Toolbar3
        self.l3 = QLabel(self.widget)
        self.l3.setText("Robot-Base-Frame: ")
        self.l3.setFixedWidth(150)
        self.l3.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.base_frame = QLineEdit(self.widget)
        self.base_frame.setText("base")
        self.toolbar3 = QToolBar()
        self.toolbar3.addWidget(self.l3)
        self.toolbar3.addWidget(self.base_frame)

        # Toolbar4
        self.l4 = QLabel(self.widget)
        self.l4.setText("End-Effector-Frame: ")
        self.l4.setFixedWidth(150)
        self.l4.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.endeffector_frame = QLineEdit(self.widget)
        self.endeffector_frame.setText("tool0")
        self.toolbar4 = QToolBar()
        self.toolbar4.addWidget(self.l4)
        self.toolbar4.addWidget(self.endeffector_frame)

        # Toolbar5
        self.l5 = QLabel(self.widget)
        self.l5.setText("Sample-Number: ")
        self.l5.setFixedWidth(150)
        self.l5.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.le5 = QLineEdit(self.widget)
        self.le5.setValidator(QIntValidator())
        self.le5.setText('10')
        self.le5.setReadOnly(True)
        self.toolbar5 = QToolBar()
        self.toolbar5.addWidget(self.l5)
        self.toolbar5.addWidget(self.le5)

        # TreeView
        self.treeview = QTreeView()
        self.treeview.setAlternatingRowColors(True)
        self.model = QStandardItemModel(self.treeview)
        self.treeview.setModel(self.model)
        self.treeview.setHeaderHidden(True)

        # TextEdit
        self.textedit = QTextEdit(self.widget)
        self.textedit.setReadOnly(True)

        # Layout
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.toolbar0)
        self.layout.addWidget(self.toolbar1)
        self.layout.addWidget(self.toolbar2)
        self.layout.addWidget(self.toolbar3)
        self.layout.addWidget(self.toolbar4)
        self.layout.addWidget(self.toolbar5)
        self.layout.addWidget(self.toolbar)
        self.layoutH = QHBoxLayout()
        self.layoutH.addWidget(self.treeview)
        self.layoutH.addWidget(self.textedit)
        self.layout.addLayout(self.layoutH)
        self.widget.setLayout(self.layout)
        # Add the widget to the user interface
        if context.serial_number() > 1:
            self.widget.setWindowTitle(self.widget.windowTitle() +
                                       (' (%d)' % context.serial_number()))
        context.add_widget(self.widget)
        # Make the connections
        self.snapshot_action.triggered.connect(self.take_snapshot)
        self.calibrate_action.triggered.connect(self.calibration)
        self.clear_action.triggered.connect(self.clear)
        self.execut_action.triggered.connect(self.execution)

        # Package path
        self.path_pkg = path_pkg

        # Set up TF
        self.cli = self.node.create_client(HandeyeTF, 'handeye_tf_service')
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.node.get_logger().info(
                'service not available, waiting again...')
        self.req = HandeyeTF.Request()

    def clear(self):
        # >>> Clear the recorded samples
        self.textedit.append('Clearing the recorded data ...')
        self.textedit.clear()
        self.Tsamples = []
        self.model.clear()

    def get_tf_transform(self, frame_id, child_frame_id):
        self.req.transform.header.frame_id = frame_id
        self.req.transform.child_frame_id = child_frame_id
        self.req.publish.data = False

        future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self.node, future)

        transform = TransformStamped()

        try:
            result = future.result()
        except Exception as e:
            self.node.get_logger().info('Service call failed %r' % (e, ))
        else:
            transform = result.tf_lookup_result

        return transform

    def publish_tf_transform(self, transform_to_publish):
        self.req.publish.data = True
        self.req.transform = transform_to_publish

        future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self.node, future)

        try:
            future.result()
        except Exception as e:
            self.node.get_logger().info('Service call failed %r' % (e, ))
        else:
            self.node.get_logger().info(
                'Send the camera-robot transform :\n\tfrom `{}` to `{}`.'.
                format(self.req.transform.header.frame_id,
                       self.req.transform.child_frame_id))

    def take_snapshot(self):
        # >>> Take the snapshot
        self.textedit.append('Taking snapshot ...')

        # Get the transform from `tool0` to `base_link`
        T = self.get_tf_transform(self.base_frame.text(),
                                  self.endeffector_frame.text())
        bTe = np.zeros((4, 4))
        q = [
            T.transform.rotation.w, T.transform.rotation.x,
            T.transform.rotation.y, T.transform.rotation.z
        ]
        bTe = br.quaternion.to_transform(q)
        bTe[:3, 3] = np.array([
            T.transform.translation.x, T.transform.translation.y,
            T.transform.translation.z
        ])
        self.textedit.append('Lookup transform: from `{}` to `{}`.'.format(
            self.base_frame.text(), self.endeffector_frame.text()))
        self.node.get_logger().info(bcolors.OKGREEN + 'bTe:' + bcolors.ENDC +
                                    '\n{}'.format(bTe))

        # Get the transform from `calib_board` to `camera_link`
        T = self.get_tf_transform(self.camera_frame.text(),
                                  self.object_frame.text())
        cTo = np.zeros((4, 4))
        q = [
            T.transform.rotation.w, T.transform.rotation.x,
            T.transform.rotation.y, T.transform.rotation.z
        ]
        cTo = br.quaternion.to_transform(q)
        cTo[:3, 3] = np.array([
            T.transform.translation.x, T.transform.translation.y,
            T.transform.translation.z
        ])
        self.textedit.append('Lookup transform: from `{}` to `{}`.'.format(
            self.camera_frame.text(), self.object_frame.text()))
        self.node.get_logger().info(bcolors.OKGREEN + 'cTo:' + bcolors.ENDC +
                                    '\n{}'.format(cTo))

        parent = QStandardItem('Snapshot {}'.format(len(self.Tsamples)))
        child_1 = QStandardItem('bTe:\n{}\n{}\n{}\n{}'.format(
            bTe[0, :], bTe[1, :], bTe[2, :], bTe[3, :]))
        child_2 = QStandardItem('cTo:\n{}\n{}\n{}\n{}'.format(
            cTo[0, :], cTo[1, :], cTo[2, :], cTo[3, :]))
        parent.appendRow(child_1)
        parent.appendRow(child_2)
        self.model.appendRow(parent)
        self.Tsamples.append((bTe, cTo))
        self.le5.setText(str(len(self.Tsamples)))

    def calibration(self):
        # >>> Compute the calibration
        self.textedit.append('Making the calibration ...')
        if len(self.Tsamples) == 0:
            self.textedit.append(
                'No transform recorded, please take snapshots.')
            return
        # save samples to `dataset.json` file
        save_samples_to_file(self.Tsamples)
        import handeye
        if self.combobox.currentIndex() == 0:
            solver_cri = handeye.calibrator.HandEyeCalibrator(setup='Moving')
        if self.combobox.currentIndex() == 1:
            solver_cri = handeye.calibrator.HandEyeCalibrator(setup='Fixed')
        for sample in self.Tsamples:
            solver_cri.add_sample(sample[0], sample[1])
        try:
            bTc = solver_cri.solve(method=handeye.solver.Daniilidis1999)
            # save the calibration result to 'camera-robot.json' file
            file_output = '/tmp/' + 'camera-robot.json'
            with open(file_output, 'w') as f:
                json.dump(bTc.tolist(), f)
        except Exception:
            self.textedit.append("Failed to solve the hand-eye calibration.")

    def execution(self):
        # >>> Publish the camera-robot transform
        self.textedit.append('Publishing the camera TF ...')
        file_input = '/tmp/' + 'camera-robot.json'
        with open(file_input, 'r') as f:
            datastore = json.load(f)

        to_frame = self.camera_frame.text()
        if self.combobox.currentIndex() == 0:
            from_frame = self.endeffector_frame.text()
        if self.combobox.currentIndex() == 1:
            from_frame = self.base_frame.text()

        bTc = np.array(datastore)
        static_transformStamped = TransformStamped()
        static_transformStamped.header.stamp = ROSClock().now().to_msg()
        static_transformStamped.header.frame_id = from_frame
        static_transformStamped.child_frame_id = to_frame

        static_transformStamped.transform.translation.x = bTc[0, 3]
        static_transformStamped.transform.translation.y = bTc[1, 3]
        static_transformStamped.transform.translation.z = bTc[2, 3]

        q = br.transform.to_quaternion(bTc)
        static_transformStamped.transform.rotation.x = q[1]
        static_transformStamped.transform.rotation.y = q[2]
        static_transformStamped.transform.rotation.z = q[3]
        static_transformStamped.transform.rotation.w = q[0]

        self.publish_tf_transform(static_transformStamped)

        output_string = "camera-robot pose:\n"
        output_string += "  Translation: [{}, {}, {}]\n".format(
            bTc[0, 3], bTc[1, 3], bTc[2, 3])
        output_string += "  Rotation: in Quaternion [{}, {}, {}, {}]".format(
            q[0], q[1], q[2], q[3])
        file_path = '/tmp/' + 'camera-robot.txt'
        with open(file_path, 'w') as f:
            f.write(output_string)

    def shutdown_plugin(self):
        """
    Unregister subscribers when the plugin shutdown
    """
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # Nothing to be done here
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # Nothing to be done here
        pass
Esempio n. 11
0
class OutputDialog(QDialog):
    def __init__(self,
                 mode,
                 dotgraph,
                 dotcode_factory,
                 dotparser,
                 param_manager,
                 models_desc_file_path,
                 nodename='',
                 parent=None):
        super(OutputDialog, self).__init__(parent)

        if mode not in ['add', 'edit']:
            raise Exception('Wrong mode for Ouput Dialog')

        self.setWindowTitle("Add a output pipe")
        self.setGeometry(300, 300, 450, 250)

        # self._widget = QDialog()

        ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'),
                               'resource', 'add_output_dialog.ui')
        loadUi(ui_file, self)

        self.dotgraph = dotgraph
        self.dotparser = dotparser
        self.dotcode_factory = dotcode_factory

        self.available_infers_list = param_manager.parse_inferlist_file(
            models_desc_file_path)

        self.connect_from_listmodel = QStandardItemModel()
        self.output_type_combobox.currentTextChanged.connect(
            self._update_display)
        self.update_output_types()

        if mode == 'add':
            self.buttonBox.accepted.connect(self._create_node_in_graph)
        elif mode == 'edit':
            self.nodename = nodename
            self.buttonBox.accepted.connect(self._edit_node_in_graph)

    def update_output_types(self, outputlist_file=None):
        self.output_type_combobox.clear()
        self.output_type_combobox.addItem('ImageWindow')
        self.output_type_combobox.addItem('Rviz')
        self.output_type_combobox.addItem('Rostopic')

    def get_infer_desc(self, infer_name):
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                return infer

    def _update_display(self, output_name):

        self.output_name_display_lineEdit.setText(output_name)
        self.update_connect_to_list(output_name)

    def update_connect_to_list(self, output_name):

        self.connect_from_listmodel.clear()

        for node in self.dotgraph.get_node_list():
            if node.get('nodetype') == 'input':
                pass
            elif node.get('nodetype') == 'output':
                pass
            elif node.get('nodetype') == 'infer':
                if output_name in self.get_infer_desc(
                        node.get_name())['connect_to']:

                    pipeline_item = QStandardItem()
                    pipeline_item.setText(node.get_name())
                    pipeline_item.setCheckable(True)
                    pipeline_item.setCheckState(False)

                    self.connect_from_listmodel.appendRow(pipeline_item)

        self.connect_from_listview.setModel(self.connect_from_listmodel)

    def _create_node_in_graph(self):

        output_node_name = str(self.output_type_combobox.currentText())

        #Create Node
        self.dotparser.parse_dotgraph_from_outputs(self.dotcode_factory,
                                                   self.dotgraph,
                                                   [output_node_name])

        #Create connection from input node to infer node
        for i in range(self.connect_from_listview.model().rowCount()):
            node_name = self.connect_from_listmodel.item(i).text()
            check_state = self.connect_from_listmodel.item(i).checkState()
            if check_state:
                connects = {node_name: [output_node_name]}
                self.dotparser.parse_dotgraph_from_connects(
                    self.dotcode_factory, self.dotgraph, connects)

    def _edit_node_in_graph(self):

        self.dotcode_factory.del_node_from_graph(self.dotgraph, self.nodename)
        self._create_node_in_graph()
Esempio n. 12
0
class MoveitWidget(QWidget):
    """#TODO: comment
    """

    # To be connected to PluginContainerWidget
    sig_sysmsg = None
    sig_param = Signal(bool, str)  # param name emitted
    sig_node = Signal(bool, str)  # param name emitted

    def __init__(self, parent, plugin_context):
        """
        @type parent: MoveitMain
        """

        self._nodes_monitored = ['/move_group']
        self._selected_topics = [('/pointcloud', 'sensor_msgs/PointCloud'),
                                 ('/pointcloud2', 'sensor_msgs/PointCloud2'),
                                 ('/image', 'sensor_msgs/Image'),
                                 ('/camera_info', 'sensor_msgs/CameraInfo')]
        _params_monitored = ['/robot_description',
                             '/robot_description_semantic']

        super(MoveitWidget, self).__init__()
        self._parent = parent
        self._plugin_context = plugin_context

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_moveit'),
                               'resource', 'moveit_top.ui')
        loadUi(ui_file, self, {'TopicWidget': TopicWidget})

        # Monitor node
        self._node_qitems = {}
        self._init_monitor_nodes(self._nodes_monitored)
        #TODO: connect sys msg for nodes.

        # topic to show
        # Delegate GUI functionality to rqt_topic.TopicWidget.
        self._widget_topic.set_selected_topics(self._selected_topics)
        self._widget_topic.set_topic_specifier(TopicWidget.SELECT_BY_MSGTYPE)
        self._widget_topic.start()
        # To connect signal in a widget to PluginContainerWidget.
        #TODO: In this way, Signal from only one instance is hooked.
        # Not a good design at all.
        self.sig_sysmsg = self._widget_topic.sig_sysmsg

        # Init monitoring parameters.
        self._param_qitems = {}
        self._init_monitor_parameters(_params_monitored)

    def _init_monitor_nodes(self, nodes_monitored):
        """
        @type params_monitored: str[]
        """
        self._node_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._node_datamodel.invisibleRootItem()
        self._view_nodes.setModel(self._node_datamodel)

        self._node_monitor_thread = NodeMonitorThread(self, self.sig_node,
                                                      nodes_monitored)
        self.sig_node.connect(self._monitor_nodes)
        self._node_monitor_thread.start()

    def _init_monitor_parameters(self, params_monitored):
        """
        @type params_monitored: str[]
        """
        self._param_datamodel = QStandardItemModel(0, 2)
        self._root_qitem = self._param_datamodel.invisibleRootItem()
        self._view_reconf.setModel(self._param_datamodel)

        self._param_check_thread = ParamCheckThread(self, self.sig_param,
                                                    params_monitored)
        self.sig_param.connect(self._monitor_parameters)
        self._param_check_thread.start()

    def _monitor_nodes(self, is_node_running, node_name):
        """
        Slot

        @type is_node_running: bool
        @type node_name: str
        """
        #TODO: What this method does is exactly the same with
        # monitor_parameters. Unify them.

        rospy.logdebug('is_node_running={} par_name={}'.format(is_node_running,
                                                              node_name))
        node_name = str(node_name)
        node_qitem = None
        if not node_name in self._node_qitems:
            node_qitem = QStandardItem(node_name)
            self._node_qitems[node_name] = node_qitem
            self._node_datamodel.appendRow(node_qitem)
        else:  # qsitem with the node name already exists.
            node_qitem = self._node_qitems[str(node_name)]

        qindex = self._node_datamodel.indexFromItem(node_qitem)
        _str_node_running = 'Not running'
        if is_node_running:
            _str_node_running = 'Running'
        qitem_node_status = QStandardItem(_str_node_running)
        self._node_datamodel.setItem(qindex.row(), 1, qitem_node_status)

    def _monitor_parameters(self, has_param, param_name):
        """
        Slot

        @type has_param: bool
        @type param_name: str
        """
        rospy.logdebug('has_param={} par_name={}'.format(has_param, param_name))
        param_name = str(param_name)
        param_qitem = None
        if not param_name in self._param_qitems:
            param_qitem = QStandardItem(param_name)
            self._param_qitems[param_name] = param_qitem
            self._param_datamodel.appendRow(param_qitem)
        else:  # qsitem with the param name already exists.
            param_qitem = self._param_qitems[str(param_name)]

        qindex = self._param_datamodel.indexFromItem(param_qitem)
        _str_param_found = 'Not found on Parameter Server'
        if has_param:
            _str_param_found = 'Found on Parameter Server'
        qitem_param_status = QStandardItem(_str_param_found)
        self._param_datamodel.setItem(qindex.row(), 1, qitem_param_status)
        #.insertColumn([qitem_param_status])

    def save_settings(self, plugin_settings, instance_settings):
        # instance_settings.set_value('splitter', self._splitter.saveState())
        pass

    def restore_settings(self, plugin_settings, instance_settings):
#        if instance_settings.contains('splitter'):
#            self._splitter.restoreState(instance_settings.value('splitter'))
#        else:
#            self._splitter.setSizes([100, 100, 200])
        pass

    def shutdown(self):
        # TODO: impl
        pass
Esempio n. 13
0
class VinoGraph(Plugin):
    def __init__(self, context):
        super(VinoGraph, self).__init__(context)
        # Give QObjects reasonable names
        self.setObjectName('VinoGraph')

        # Process standalone plugin command-line arguments
        from argparse import ArgumentParser
        parser = ArgumentParser()
        # Add argument(s) to the parser.
        parser.add_argument("-q",
                            "--quiet",
                            action="store_true",
                            dest="quiet",
                            help="Put plugin in silent mode")
        args, unknowns = parser.parse_known_args(context.argv())
        if not args.quiet:
            print 'arguments: ', args
            print 'unknowns: ', unknowns

        # Create QWidget
        self._widget = QWidget()
        # Get path to UI file which should be in the "resource" folder of this package
        ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'),
                               'resource', 'rqt_vino_plugin.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        # Give QObjects reasonable names
        self._widget.setObjectName('VinoGraphUi')
        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple  QListView
        # plugins at once. Also if you open multiple instances of your
        # plugin at once, these lines add number to make it easy to
        # tell from pane to pane.
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        #A dict which stores pipeline name and dotgraph pair
        self._dotgraphs = dict()
        #which dotgraph currently drawing on the scence
        self._current_dotcode = None
        self._current_pipeline_name = ''
        #Pydot
        self.dotcode_factory = VinoPydotFactory()
        self.dot_to_qt = DotToQtGenerator()
        self.param_manager = ParamManagerWrapper()

        #Binding scene canvas
        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)
        self._widget.graphics_view.setClickNodeCallback(self._edit_node)

        #QListview of pipelines
        self._listmodel = QStandardItemModel()
        self._widget.pipeline_name_listview.clicked.connect(
            self._display_choosed_pipeline)
        #self._widget.pipeline_name_listview.itemRenamed.connect(self._rename_pipeline)
        #Load pipelines from yaml file
        self._widget.load_pipeline_push_button.clicked.connect(
            self._load_pipeline)
        #Create a pipeline
        self._widget.create_pipeline_push_button.clicked.connect(
            self._create_pipeline)
        #Add input to pipeline graph
        self._widget.add_input_push_button.clicked.connect(self._add_input)
        #Add infer
        self._widget.add_inference_push_button.clicked.connect(self._add_infer)
        self._widget.add_output_push_button.clicked.connect(self._add_output)

        self._widget.save_pipeline_push_button.clicked.connect(
            self._save_pipeline)

        self.models_desc_file_path = os.path.join(
            rospkg.RosPack().get_path('vino_param_lib'), 'param',
            'models.yaml')

        # Add widget to the user interface
        context.add_widget(self._widget)

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # TODO save intrinsic configuration, usually using:
        # instance_settings.set_value(k, v)
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # TODO restore intrinsic configuration, usually using:
        # v = instance_settings.value(k)
        pass

    def _refresh_rosgraph(self):

        self._widget.pipeline_name_listview.setModel(self._listmodel)
        self._widget.pipeline_name_listview.show()

        self._redraw_graph_view()

        # if not self.initialized:
        #     return
        # self._update_graph_view(self._generate_dotcode())

    def _rename_pipeline(self, item, col):

        pass

    def _display_choosed_pipeline(self, index):

        pipeline_name = self._listmodel.data(index)
        if pipeline_name in self._dotgraphs.iterkeys():
            self._current_pipeline_name = pipeline_name

        self._refresh_rosgraph()

    def _load_pipeline(self):
        self._dotgraphs.clear()
        self._listmodel.clear()

        file_path, _ = QFileDialog.getOpenFileName(
            self._widget, "QFileDialog.getOpenFileName()", "", "*.yaml")

        self._dotgraphs = generate_dotcode_from_yaml_file(
            self.dotcode_factory, self.param_manager, str(file_path))

        for pipeline_name, pipeline_dotgraph in self._dotgraphs.items():

            pipeline_item = QStandardItem()
            pipeline_item.setText(pipeline_name)
            self._listmodel.appendRow(pipeline_item)

        self._current_pipeline_name = self._dotgraphs.iterkeys().next()

        self._refresh_rosgraph()
        #self._display_choosed_pipeline(pipeline_item)

    def _redraw_graph_view(self):

        self._scene.clear()

        if self._dotgraphs == None:
            return

        self._current_dotcode = self.dotcode_factory.create_dot(
            self._dotgraphs[self._current_pipeline_name])

        highlight_level = 2

        (nodes, edges) = self.dot_to_qt.dotcode_to_qt_items(
            self._current_dotcode,
            highlight_level=highlight_level,
            same_label_siblings=False,
            scene=self._scene)

        self._scene.setSceneRect(self._scene.itemsBoundingRect())
        #if self._widget.auto_fit_graph_check_box.isChecked():

        self._fit_in_view()

    def _add_input(self):

        dlg = InputDialog('add',
                          self._dotgraphs[self._current_pipeline_name],
                          self.dotcode_factory,
                          dotparser,
                          self.param_manager,
                          parent=self._widget)

        dlg.exec_()

        self._refresh_rosgraph()

    def _add_infer(self):
        if self._current_pipeline_name == '':
            return
        dlg = InferenceDialog('add',
                              self._dotgraphs[self._current_pipeline_name],
                              self.dotcode_factory,
                              dotparser,
                              self.param_manager,
                              self.models_desc_file_path,
                              parent=self._widget)
        dlg.exec_()

        self._refresh_rosgraph()

    def _edit_node(self, nodename=''):
        if self._current_pipeline_name == '':
            return
        selected_node = self._dotgraphs[self._current_pipeline_name].get_node(
            nodename.encode('utf-8'))[0]

        selected_node_type = selected_node.get('nodetype')

        if selected_node_type == 'input':
            self._edit_input(nodename)
        elif selected_node_type == 'infer':
            self._edit_infer(nodename)
        elif selected_node_type == 'output':
            self._edit_output(nodename)

    def _edit_infer(self, nodename=''):

        dlg = InferenceDialog('edit',
                              self._dotgraphs[self._current_pipeline_name],
                              self.dotcode_factory,
                              dotparser,
                              self.param_manager,
                              self.models_desc_file_path,
                              nodename=nodename,
                              parent=self._widget)
        dlg.exec_()

        self._refresh_rosgraph()

    def _edit_input(self, nodename=''):

        dlg = InputDialog('edit',
                          self._dotgraphs[self._current_pipeline_name],
                          self.dotcode_factory,
                          dotparser,
                          self.param_manager,
                          nodename=nodename,
                          parent=self._widget)
        dlg.exec_()
        self._refresh_rosgraph()

    def _edit_output(self, nodename=''):
        dlg = OutputDialog('edit',
                           self._dotgraphs[self._current_pipeline_name],
                           self.dotcode_factory,
                           dotparser,
                           self.param_manager,
                           models_desc_file_path=self.models_desc_file_path,
                           nodename=nodename,
                           parent=self._widget)
        dlg.exec_()

        self._refresh_rosgraph()

    def _add_output(self):
        dlg = OutputDialog('add',
                           self._dotgraphs[self._current_pipeline_name],
                           self.dotcode_factory,
                           dotparser,
                           self.param_manager,
                           models_desc_file_path=self.models_desc_file_path,
                           parent=self._widget)
        dlg.exec_()

        self._refresh_rosgraph()

    def _fit_in_view(self):
        self._widget.graphics_view.fitInView(self._scene.itemsBoundingRect(),
                                             Qt.KeepAspectRatio)

    def _create_pipeline(self):

        pipeline_name, okPressed = QInputDialog.getText(
            self._widget, "Create a new pipeline", "new pipeline name:",
            QLineEdit.Normal, "")

        if okPressed != True or pipeline_name == '':
            #Empty name
            return

        pipeline_item = QStandardItem()
        pipeline_item.setText(pipeline_name)
        self._listmodel.appendRow(pipeline_item)

        new_dotgraph = dotparser.generate_dotcode_from_empty(
            self.dotcode_factory, pipeline_name)
        self._dotgraphs.update(new_dotgraph)
        self._current_pipeline_name = pipeline_name
        self._refresh_rosgraph()

    def _save_pipeline(self):
        # print(self._dotgraphs )
        self.dotcode_factory.parse_nodes(
            self._dotgraphs[self._current_pipeline_name])
Esempio n. 14
0
class InferenceDialog(QDialog):
    def __init__(self, mode, dotgraph , dotcode_factory, dotparser , param_manager, models_desc_file_path, nodename='', parent = None):
        super(InferenceDialog, self).__init__(parent)



        if mode not in ['add','edit']:
            raise Exception('wrong mode for InferenceDialog')
        
    
        self.nodename = nodename

        self.setWindowTitle("Dialog")
        self.setGeometry(300,300,450,250)

        # self._widget = QDialog()

        ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'), 'resource', 'add_inference_dialog.ui')
        loadUi(ui_file, self)
        

        self.dotgraph = dotgraph
        self.dotparser = dotparser
        self.dotcode_factory = dotcode_factory
 
 
        self.available_infers_list = param_manager.parse_inferlist_file(models_desc_file_path)
        


        # self.node_name_lineedit.textEdited.connect(self._edit_infer_name)
        #self.node_infer_name_combobox.activated.connect(self.update_infer_names)
        self.node_infer_combobox.currentTextChanged.connect(self._select_infer_type)

        self.connect_from_listmodel = QStandardItemModel()#(self.connect_from_listview)
        self.connect_to_listmodel = QStandardItemModel()#(self.connect_to_listview)

        # self.connect_from_listmodel.itemChanged.connect(self._connect_from_changed)
        
        #self.connect_to_listview.setModel(self.connect_to_listmodel)

      
        self.update_infer_names()
        self.update_connect_from_list()

        if mode == 'add':
            self.buttonBox.accepted.connect(self._create_node_in_graph)
        elif mode == 'edit':
            self.buttonBox.accepted.connect(self._edit_node_in_graph)
        

    def update_infer_names(self):
        self.node_infer_combobox.clear()
        for infer in self.available_infers_list:
            self.node_infer_combobox.addItem(infer['infer_name'])

    def get_infer_desc(self,infer_name):
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                return infer
    def get_model_desc(self,infer_name,model_type):
        for model_desc in self.get_infer_desc(infer_name)['available_models']:
            if model_desc['name'] == model_type:
                return model_desc
    def update_connect_to_list(self, infer_name):
        self.connect_from_listmodel.clear()
        self.connect_to_listmodel.clear()

        for node in self.dotgraph.get_node_list():
            
            pipeline_item = QStandardItem()
            pipeline_item.setText(node.get_name())
            pipeline_item.setCheckable(True)
            pipeline_item.setCheckState(False)

            if node.get_name() == infer_name.encode('utf-8'):
                continue
            if node.get('nodetype') == 'input':

                self.connect_from_listmodel.appendRow(pipeline_item)

                # self.connect_from_listview.addItem(node.get_name())
            elif node.get('nodetype') == 'output':
                self.connect_to_listmodel.appendRow(pipeline_item)
                # self.connect_to_listview.addItem(node.get_name())
            elif node.get('nodetype') == 'infer':
                if  infer_name in self.get_infer_desc(infer_name)['connect_from']:
                    self.connect_from_listmodel.appendRow(pipeline_item)
                elif  infer_name in self.get_infer_desc(infer_name)['connect_to']:
                    self.connect_to_listmodel.appendRow(pipeline_item)

            
        self.connect_from_listview.setModel(self.connect_from_listmodel)
        self.connect_to_listview.setModel(self.connect_to_listmodel)
   

    def update_connect_from_list(self):
        pass

    def update_model_type(self,infer_name):
        self.node_model_combobox.clear()
        # infer = self.get_infer_desc(infer_name)
        for model in self.get_infer_desc(infer_name)['available_models']:
            self.node_model_combobox.addItem(model['name'])
        # self.node_model_combobox.addItem("MobileNetSSD")
        # self.node_model_combobox.addItem("YoloV2")
    def _select_infer_type(self,infer_name):
        self.node_engine_combobox.clear()
        infer_name = str(infer_name)
        
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                for engine in infer['available_engine']:
                    self.node_engine_combobox.addItem(engine)

        self.update_model_type(infer_name)
        self.update_connect_to_list(infer_name)

    def _edit_infer_name(self,infer_name):
        self.node_name_display_lineEdit.setText(infer_name)

    
    def _create_node_in_graph(self):

        infer_node_name =  str(self.node_infer_combobox.currentText()) 
        print('ava_list',self.available_infers_list)

        infer_node_engine = self.node_engine_combobox.currentText()
        print(self.get_infer_desc(infer_node_name))
        infer_node_model_type = self.node_model_combobox.currentText()
        infer_node_label = self.get_model_desc(infer_node_name, infer_node_model_type)['label']
        infer_node_model = self.get_model_desc(infer_node_name, infer_node_model_type)['model']
        #Create Node 
        self.dotparser.parse_dotgraph_from_infers(self.dotcode_factory,self.dotgraph, [{'name': infer_node_name,
                                                                                        'engine':infer_node_engine,
                                                                                        'model':infer_node_model,
                                                                                        'label':infer_node_label,
                                                                                        'batch':1}])
                                                                                     #To-do Implement batch configure

        #Create connection from input node to infer node
        for i in range(self.connect_from_listview.model().rowCount()):
            node_name = self.connect_from_listmodel.item(i).text()
            check_state = self.connect_from_listmodel.item(i).checkState()
            if check_state:
                connects = { node_name: [infer_node_name] }
                self.dotparser.parse_dotgraph_from_connects(self.dotcode_factory,self.dotgraph,connects)
        
        #Create connection from infer node to output node
        for i in range(self.connect_to_listview.model().rowCount()):
            node_name = self.connect_to_listmodel.item(i).text()
            check_state = self.connect_to_listmodel.item(i).checkState()
            if check_state:
                connects = { infer_node_name :[node_name] }
                self.dotparser.parse_dotgraph_from_connects(self.dotcode_factory,self.dotgraph,connects)

                
    def _edit_node_in_graph(self):
       
        self.dotcode_factory.del_node_from_graph(self.dotgraph,self.nodename)
        self._create_node_in_graph()
Esempio n. 15
0
class InteractionsChooserUI():
    def __init__(self,
                 rocon_master_uri='localhost',
                 host_name='localhost',
                 with_rqt=False):
        self.with_rqt = with_rqt
        self.widget = QWidget()
        self.pairings_view_model = QStandardItemModel()
        self.interactions_view_model = QStandardItemModel()
        self.interactions_remocon = InteractionsRemocon(
            rocon_master_uri, host_name)
        self.interactions_remocon.connect(
            [self.update_group_combobox, self.refresh_grids])
        self.interactions_remocon.connect(
            [self.update_pairings_group_combobox, self.refresh_grids])
        self.default_group = "All"

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_remocon'), 'ui',
                               'interactions_chooser.ui')
        loadUi(ui_file, self.widget, {})

        # create a few directories for caching icons and ...
        utils.setup_home_dirs()
        self._init_ui()
        self._init_events()

    def shutdown(self):
        self.interactions_remocon.shutdown()

    @Slot()
    def update_group_combobox(self):
        """
        The underyling ros part of the remocon might get fresh data about the group list.
        Connect to this slot to update the combobox in the ui.
        """
        new_groups = copy.copy(
            self.interactions_remocon.interactions_table.groups())
        new_groups = [g for g in new_groups if g != "Hidden"]

        # did the underlying groups change - if so, update the combobox
        current_group = self.widget.interactions_group_combobox.currentText()
        current_size = self.widget.interactions_group_combobox.count()
        target_group = current_group if current_size != 1 else self.default_group
        current_group_list = [
            self.widget.interactions_group_combobox.itemText(i)
            for i in range(self.widget.interactions_group_combobox.count())
        ]
        if set(current_group_list) != set(['All'] + new_groups):
            self.widget.interactions_group_combobox.clear()
            self.widget.interactions_group_combobox.addItems(['All'] +
                                                             new_groups)
            index = self.widget.interactions_group_combobox.findText(
                target_group)
            if index != -1:
                self.widget.interactions_group_combobox.setCurrentIndex(index)
            self.refresh_grids()

    @Slot()
    def update_pairings_group_combobox(self):
        """
        The underyling ros part of the remocon might get fresh data about the group list.
        Connect to this slot to update the combobox in the ui.
        """
        new_groups = copy.copy(
            self.interactions_remocon.pairings_table.groups())

        # did the underlying groups change - if so, update the combobox
        current_group = self.widget.pairings_group_combobox.currentText()
        current_size = self.widget.pairings_group_combobox.count()
        target_group = current_group if current_size != 1 else self.default_pairings_group
        current_group_list = [
            self.widget.pairings_group_combobox.itemText(i)
            for i in range(self.widget.pairings_group_combobox.count())
        ]
        if set(current_group_list) != set(['All'] + new_groups):
            self.widget.pairings_group_combobox.clear()
            self.widget.pairings_group_combobox.addItems(['All'] + new_groups)
            index = self.widget.pairings_group_combobox.findText(target_group)
            if index != -1:
                self.widget.pairings_group_combobox.setCurrentIndex(index)
            self.refresh_grids()

    @Slot()
    def refresh_grids(self):
        """
        This just does a complete redraw of the interactions with the
        currently selected role. It's a bit brute force doing this
        every time the interactions' 'state' changes, but this suffices for now.
        """
        self.pairings_view_model.clear()
        self.interactions_view_model.clear()

        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        group = self.widget.pairings_group_combobox.currentText()
        for p in self.interactions_remocon.pairings_table.sorted():
            if group != "All" and p.group != group:
                continue
            is_running = False
            enabled = False
            if active_pairing is not None and p.name == active_pairing.name:
                is_running = True
                enabled = True
            elif active_pairing is None:
                enabled = True
                # enabled = not p.requires_interaction
            item = icon.QModelIconItem(p, enabled=enabled, running=is_running)
            self.pairings_view_model.appendRow(item)

        group = self.widget.interactions_group_combobox.currentText()
        for i in self.interactions_remocon.interactions_table.sorted():
            if group != "All" and i.group != group:
                continue
            if i.hidden:
                continue
            extra_tooltip_info = ""
            if i.required_pairings:
                extra_tooltip_info += " Requires "
                for required_pairing in i.required_pairings:
                    extra_tooltip_info += "'" + required_pairing + "', "
                extra_tooltip_info = extra_tooltip_info.rstrip(', ')
                if not i.bringup_pairing:
                    extra_tooltip_info += " to be running"
                extra_tooltip_info += "."
            item = icon.QModelIconItem(
                i,
                enabled=self._is_interaction_enabled(i),
                running=self._is_interaction_running(i),
                extended_tooltip_info=extra_tooltip_info)
            self.interactions_view_model.appendRow(item)

    def _init_ui(self):
        self.widget.pairings_grid.setViewMode(QListView.IconMode)
        self.widget.pairings_grid.setModel(self.pairings_view_model)
        self.widget.pairings_grid.setWordWrap(True)
        self.widget.pairings_grid.setWrapping(True)
        # really need to get away from listview, or subclass it if we want to control better how many lines of text show up
        # self.widget.pairings_grid.setTextElideMode(Qt.ElideNone)
        self.widget.pairings_grid.setIconSize(QSize(60, 60))
        self.widget.pairings_grid.setSpacing(10)
        self.widget.interactions_grid.setViewMode(QListView.IconMode)
        self.widget.interactions_grid.setModel(self.interactions_view_model)
        self.widget.interactions_grid.setWordWrap(True)
        self.widget.interactions_grid.setWrapping(True)
        self.widget.interactions_grid.setIconSize(QSize(60, 60))
        self.widget.interactions_grid.setSpacing(10)
        for ns in self.interactions_remocon.namespaces:
            self.widget.namespace_checkbox.addItem(ns)
        self.refresh_grids()
        self.widget.pairings_group_combobox.addItems(
            ['All'] + self.interactions_remocon.pairings_table.groups())
        self.widget.interactions_group_combobox.addItems(
            ['All'] + self.interactions_remocon.interactions_table.groups())
        # TODO namespace checkbox to self.interactions_remocon.active_namespace

    ##############################################################################
    # Private
    ##############################################################################

    def _init_events(self):
        self.widget.namespace_checkbox.currentIndexChanged.connect(
            self._event_change_namespace)
        self.widget.pairings_grid.clicked.connect(self._pairing_single_click)
        self.widget.interactions_grid.clicked.connect(
            self._interaction_single_click)
        self.widget.button_stop_all_interactions.clicked.connect(
            self.interactions_remocon.stop_all_interactions)
        self.widget.pairings_group_combobox.currentIndexChanged.connect(
            self.refresh_grids)
        self.widget.interactions_group_combobox.currentIndexChanged.connect(
            self.refresh_grids)

    def _event_change_namespace(self):
        rospy.logwarn(
            "Remocon : changing interaction managers is currently not supported."
        )

    def _pairing_single_click(self, index):
        pairing_item = self.pairings_view_model.item(index.row())
        pairing = pairing_item.implementation
        self._create_pairing_dialog(pairing)

    def _create_pairing_dialog(self, pairing):
        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        if active_pairing is not None:
            is_running = (active_pairing.name == pairing.name)
            is_enabled = is_running
        else:
            is_enabled = True  # not pairing.requires_interaction
            is_running = False
        self.selected_pairing = pairing
        self.dialog = PairingDialog(self.widget, pairing,
                                    self.interactions_remocon.start_pairing,
                                    self.interactions_remocon.stop_pairing,
                                    is_enabled, is_running)
        self.dialog.show()

    def _interaction_single_click(self, index):
        interaction_item = self.interactions_view_model.item(index.row())
        interaction = interaction_item.implementation
        self._create_interaction_dialog(interaction)

    def _create_interaction_dialog(self, interaction):
        self.selected_interaction = interaction
        self.dialog = InteractionDialog(
            self.widget, interaction,
            self.interactions_remocon.start_interaction,
            self.interactions_remocon.stop_interaction,
            self._is_interaction_enabled(interaction),
            self._is_interaction_running(interaction),
            self._is_interaction_permitted_new_launches(interaction))
        self.dialog.show()

    def _is_interaction_permitted_new_launches(self, interaction):
        current_number_of_launches = len(
            self.interactions_remocon.launched_interactions.get_launch_details(
                interaction.hash))
        if interaction.max == -1 or current_number_of_launches < interaction.max:
            return True
        else:
            return False

    def _is_interaction_enabled(self, interaction):
        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        enabled = True
        if interaction.required_pairings:
            if active_pairing and active_pairing.name not in interaction.required_pairings:
                enabled = False
            elif active_pairing is None:
                if not interaction.bringup_pairing:
                    enabled = False
                else:
                    available_required_pairings = [
                        name for name in interaction.required_pairings
                        if self.interactions_remocon.pairings_table.find(name)
                        is not None
                    ]
                    if not available_required_pairings:
                        enabled = False
        return enabled

    def _is_interaction_running(self, interaction):
        return True if self.interactions_remocon.launched_interactions.get_launch_details(
            interaction.hash) else False