コード例 #1
0
    def __init__(self, parent=None):
        super(LaunchWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('roslaunch_monitor'),
                               'resource', 'rqt_monitor_plugin.ui')
        loadUi(
            ui_file, self, {
                'ExtendedComboBox': ExtendedComboBox,
                'LaunchTreeWidget': LaunchTreeWidget
            })
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_launch_button.setIcon(QIcon.fromTheme('add'))
        self.remove_launch_button.setIcon(QIcon.fromTheme('remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.launch_tree_widget.model().item_value_changed.connect(
            self.change_launch)
        self.launch_tree_widget.remove_publisher.connect(self.remove_launch)
        #self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_launch_button.clicked.connect(
            self.launch_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_launches)
コード例 #2
0
    def __init__(self, node, parent=None):
        super(PublisherWidget, self).__init__(parent)
        self._node = node
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        package_path = get_package_path('rqt_publisher')
        ui_file = os.path.join(package_path, 'share', 'rqt_publisher',
                               'resource', 'Publisher.ui')
        loadUi(
            ui_file, self, {
                'ExtendedComboBox': ExtendedComboBox,
                'PublisherTreeWidget': PublisherTreeWidget
            })
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_publisher_button.setIcon(QIcon.fromTheme('list-add'))
        self.remove_publisher_button.setIcon(QIcon.fromTheme('list-remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.publisher_tree_widget.model().item_value_changed.connect(
            self.change_publisher)
        self.publisher_tree_widget.remove_publisher.connect(
            self.remove_publisher)
        self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_publisher_button.clicked.connect(
            self.publisher_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_publishers)
コード例 #3
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     if not self._scan_to_angle:
         self._scan_to_angle = ScanToAngle('/scan',self._laser_scan_angle_topic_name)
     if not self._motion:
         self._motion = DriftEstimation(self._laser_scan_angle_topic_name, self._gyro_scan_angle_topic_name, self._error_scan_angle_topic_name, self._cmd_vel_topic_name,self._gyro_topic_name)
         self._motion.init(self._ui.angular_speed_spinbox.value())
     rospy.sleep(0.5)
     self._plot_widget.data_plot.reset()
     self._plot_widget._start_time = rospy.get_time()
     self._plot_widget.enable_timer(True)
     try:
         self._plot_widget.remove_topic(self._error_scan_angle_topic_name+'/scan_angle')
         self._plot_widget_live.remove_topic(self._laser_scan_angle_topic_name+'/scan_angle')
         self._plot_widget_live.remove_topic(self._gyro_scan_angle_topic_name+'/scan_angle')
         self._plot_widget_live.remove_topic(self._cmd_vel_topic_name+'/angular/z')
     except KeyError:
         pass
     self._plot_widget_live.add_topic(self._cmd_vel_topic_name+'/angular/z')
     self._plot_widget_live.add_topic(self._laser_scan_angle_topic_name+'/scan_angle')
     self._plot_widget_live.add_topic(self._gyro_scan_angle_topic_name+'/scan_angle')
     self._plot_widget.add_topic(self._error_scan_angle_topic_name+'/scan_angle')
     self._motion_thread = WorkerThread(self._motion.execute, None)
     self._motion_thread.start()
コード例 #4
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._state = CliffSensorFrame.STATE_FORWARD
     self._motion_thread = WorkerThread(self._motion.execute,
                                        self._run_finished)
     self._motion_thread.start()
コード例 #5
0
 def on_start_button_clicked(self):
     self.start_button.setEnabled(False)
     self.stop_button.setEnabled(True)
     self._motion_thread = WorkerThread(self._motion.execute_speed,
                                        self._run_finished)
     self._motion_thread.start()
     #rospy.loginfo("current:"+self._config.get_cmd_topic())
     self._motion.change_topic(self._config.get_cmd_topic())
     self._config.run(False, False, False, True)
コード例 #6
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._motion = Square('/mobile_base/commands/velocity', '/odom',
                           self._gyro_topic_name)
     self._motion.init(self._ui.speed_spinbox.value(),
                       self._ui.distance_spinbox.value())
     self._motion_thread = WorkerThread(self._motion.execute,
                                        self._run_finished)
     self._motion_thread.start()
コード例 #7
0
    def create_editor(self):
        editor = FrameEditor()

        editor.observers.append(self)

        self.signal_update.connect(self.update_all)

        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        self.old_frame_list = []
        self.old_selected = ""

        return editor
コード例 #8
0
    def __init__(self, parent=None):
        super(MsgEditorWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_annotation_data'), 'resource', 'MsgEditor.ui')
        loadUi(ui_file, self, {'ExtendedComboBox': ExtendedComboBox, 'MessageTreeWidget': MessageTreeWidget})

        self.refresh_combo_boxes()

        self.message_tree_widget.model().item_value_changed.connect(self.change_message)
        self.clear_button.clicked.connect(self.clean)
コード例 #9
0
 def _run_finished(self):
     if self._state == CliffSensorFrame.STATE_STOPPED:
         return
     elif self._state == CliffSensorFrame.STATE_FORWARD:
         self._state = CliffSensorFrame.STATE_BACKWARD
         self._motion.init(-self._motion.speed, 0.2)
         self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
         self._motion_thread.start()
     else:
         self._state = CliffSensorFrame.STATE_FORWARD
         self._motion.init(-self._motion.speed, self._distance)
         self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
         self._motion_thread.start()
コード例 #10
0
 def _run_finished(self):
     if self._state == CliffSensorFrame.STATE_STOPPED:
         return
     elif self._state == CliffSensorFrame.STATE_FORWARD:
         self._state = CliffSensorFrame.STATE_BACKWARD
         self._motion.init(-self._motion.speed, 0.2)
         self._motion_thread = WorkerThread(self._motion.execute,
                                            self._run_finished)
         self._motion_thread.start()
     else:
         self._state = CliffSensorFrame.STATE_FORWARD
         self._motion.init(-self._motion.speed, self._distance)
         self._motion_thread = WorkerThread(self._motion.execute,
                                            self._run_finished)
         self._motion_thread.start()
コード例 #11
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     if not self._scan_to_angle:
         self._scan_to_angle = ScanToAngle("/scan", self._laser_scan_angle_topic_name)
     if not self._motion:
         self._motion = DriftEstimation(
             self._laser_scan_angle_topic_name,
             self._gyro_scan_angle_topic_name,
             self._error_scan_angle_topic_name,
             self._cmd_vel_topic_name,
             self._gyro_topic_name,
         )
         self._motion.init(self._ui.angular_speed_spinbox.value())
     rospy.sleep(0.5)
     self._plot_widget.data_plot.reset()
     self._plot_widget._start_time = rospy.get_time()
     self._plot_widget.enable_timer(True)
     try:
         self._plot_widget.remove_topic(self._error_scan_angle_topic_name + "/scan_angle")
         self._plot_widget_live.remove_topic(self._laser_scan_angle_topic_name + "/scan_angle")
         self._plot_widget_live.remove_topic(self._gyro_scan_angle_topic_name + "/scan_angle")
         self._plot_widget_live.remove_topic(self._cmd_vel_topic_name + "/angular/z")
     except KeyError:
         pass
     self._plot_widget_live.add_topic(self._cmd_vel_topic_name + "/angular/z")
     self._plot_widget_live.add_topic(self._laser_scan_angle_topic_name + "/scan_angle")
     self._plot_widget_live.add_topic(self._gyro_scan_angle_topic_name + "/scan_angle")
     self._plot_widget.add_topic(self._error_scan_angle_topic_name + "/scan_angle")
     self._motion_thread = WorkerThread(self._motion.execute, None)
     self._motion_thread.start()
コード例 #12
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._motion = Square('/mobile_base/commands/velocity', '/odom', self._gyro_topic_name)
     self._motion.init(self._ui.speed_spinbox.value(), self._ui.distance_spinbox.value())
     self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
     self._motion_thread.start()
コード例 #13
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     if not self._motion: 
         self._motion = Rotate(self._cmd_vel_topic_name)
         self._motion.init(self._ui.angular_speed_spinbox.value())
     if not self.robot_state_subscriber:
         self.robot_state_subscriber = rospy.Subscriber("/mobile_base/events/robot_state", RobotStateEvent, self.robot_state_callback)
     rospy.sleep(0.5)
     self._plot_widget._start_time = rospy.get_time()
     self._plot_widget.enable_timer(True)
     try:
         self._plot_widget.remove_topic(self._battery_topic_name)
     except KeyError:
         pass
     self._plot_widget.add_topic(self._battery_topic_name)
     self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
     self._motion_thread.start()
コード例 #14
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     if not self._motion: 
         self._motion = Rotate(self._cmd_vel_topic_name)
         self._motion.init(self._ui.angular_speed_spinbox.value())
     if not self.robot_state_subscriber:
         self.robot_state_subscriber = rospy.Subscriber("/mobile_base/events/robot_state", RobotStateEvent, self.robot_state_callback)
     rospy.sleep(0.5)
     self._plot_widget._start_time = rospy.get_time()
     self._plot_widget.enable_timer(True)
     try:
         self._plot_widget.remove_topic(self._battery_topic_name)
     except KeyError:
         pass
     self._plot_widget.add_topic(self._battery_topic_name)
     self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
     self._motion_thread.start()
コード例 #15
0
    def __init__(self, parent=None):
        super(PublisherWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_publisher'), 'resource', 'Publisher.ui')
        loadUi(ui_file, self, {'ExtendedComboBox': ExtendedComboBox, 'PublisherTreeWidget': PublisherTreeWidget})
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_publisher_button.setIcon(QIcon.fromTheme('list-add'))
        self.remove_publisher_button.setIcon(QIcon.fromTheme('list-remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.publisher_tree_widget.model().item_value_changed.connect(self.change_publisher)
        self.publisher_tree_widget.remove_publisher.connect(self.remove_publisher)
        self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_publisher_button.clicked.connect(self.publisher_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_publishers)
コード例 #16
0
class BatteryProfileFrame(QFrame):
    def __init__(self, parent=None):
        super(BatteryProfileFrame, self).__init__(parent)
        self._cmd_vel_topic_name = '/mobile_base/commands/velocity'
        self._battery_topic_name = "/mobile_base/sensors/core/battery"
        self._ui = Ui_battery_profile_frame()
        self._motion = None
        self.robot_state_subscriber = None
        self._motion_thread = None

    def setupUi(self, cmd_vel_topic_name):
        self._ui.setupUi(self)
        self._cmd_vel_topic_name = cmd_vel_topic_name
        self._plot_layout = QVBoxLayout(self._ui.battery_profile_group_box)
        self._plot_widget = PlotWidget()
        self._plot_widget.setWindowTitle("Battery Profile")
        self._plot_widget.topic_edit.setText(self._battery_topic_name)
        self._plot_layout.addWidget(self._plot_widget)

        self._data_plot = DataPlot(self._plot_widget)
        self._data_plot.set_autoscale(y=False)
        self._data_plot.set_ylim([0, 180])
        self._plot_widget.switch_data_plot_widget(self._data_plot)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: battery test shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################
        
    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        self._stop()
    
    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass


    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        if not self._motion: 
            self._motion = Rotate(self._cmd_vel_topic_name)
            self._motion.init(self._ui.angular_speed_spinbox.value())
        if not self.robot_state_subscriber:
            self.robot_state_subscriber = rospy.Subscriber("/mobile_base/events/robot_state", RobotStateEvent, self.robot_state_callback)
        rospy.sleep(0.5)
        self._plot_widget._start_time = rospy.get_time()
        self._plot_widget.enable_timer(True)
        try:
            self._plot_widget.remove_topic(self._battery_topic_name)
        except KeyError:
            pass
        self._plot_widget.add_topic(self._battery_topic_name)
        self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        '''
          Hardcore stoppage - straight to zero.
        '''
        self._stop()
        
    def _stop(self):
        self._plot_widget.enable_timer(False) # pause plot rendering
        if self._motion_thread:
            self._motion.stop()
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion.shutdown()
            self._motion = None
        if self.robot_state_subscriber:
            self.robot_state_subscriber.unregister()
            self.robot_state_subscriber = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # External Slot Callbacks
    ##########################################################################
    @Slot(str)
    def on_cmd_vel_topic_combo_box_currentIndexChanged(self, topic_name):
        '''
          To be connected to the configuration dock combo box (via the main testsuite frame)
        '''
        self._cmd_vel_topic_name = topic_name
        print("DudetteBattery %s" % topic_name)

    ##########################################################################
    # Ros Callbacks
    ##########################################################################

    def robot_state_callback(self, data):
        if data.state == RobotStateEvent.OFFLINE:
            self.stop()
コード例 #17
0
class PayloadFrame(QFrame):
    def __init__(self, parent=None):
        super(PayloadFrame, self).__init__(parent)
        self._gyro_topic_name = '/mobile_base/sensors/imu_data'
        self._ui = Ui_payload_frame()
        self._motion = None
        self._motion_thread = None

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: payload frame shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################
        
    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        self._stop()
    
    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        self._motion_thread = None
        self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._motion = Square('/mobile_base/commands/velocity', '/odom', self._gyro_topic_name)
        self._motion.init(self._ui.speed_spinbox.value(), self._ui.distance_spinbox.value())
        self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._stop()
        
    def _stop(self):
        if self._motion:
            self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.speed_spinbox.value(), self._ui.distance_spinbox.value())

    @pyqtSlot(float)
    def on_distance_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.speed_spinbox.value(), self._ui.distance_spinbox.value())
コード例 #18
0
class LaunchWidget(QWidget):
    add_launch = Signal(str, str, str, bool)
    change_launch = Signal(int, str, str, str, object)
    #publish_once = Signal(int)
    remove_launch = Signal(int)
    clean_up_launches = Signal()

    def __init__(self, parent=None):
        super(LaunchWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('roslaunch_monitor'),
                               'resource', 'rqt_monitor_plugin.ui')
        loadUi(
            ui_file, self, {
                'ExtendedComboBox': ExtendedComboBox,
                'LaunchTreeWidget': LaunchTreeWidget
            })
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_launch_button.setIcon(QIcon.fromTheme('add'))
        self.remove_launch_button.setIcon(QIcon.fromTheme('remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.launch_tree_widget.model().item_value_changed.connect(
            self.change_launch)
        self.launch_tree_widget.remove_publisher.connect(self.remove_launch)
        #self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_launch_button.clicked.connect(
            self.launch_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_launches)

    def shutdown_plugin(self):
        self._update_thread.kill()

    @Slot()
    def refresh_combo_boxes(self):
        self._update_thread.kill()
        self.file_combo_box.setEnabled(False)
        self.package_combo_box.setEnabled(False)
        self.file_combo_box.setEditText('updating...')
        self.package_combo_box.setEditText('updating...')
        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        # update type_combo_box
        message_type_names = []
        try:
            # this only works on fuerte and up
            packages = sorted([
                pkg_tuple[0] for pkg_tuple in rosmsg.iterate_packages(
                    self._rospack, rosmsg.MODE_MSG)
            ])
        except:
            # this works up to electric
            packages = sorted(rosmsg.list_packages())
        for package in packages:
            for base_type_str in rosmsg.list_msgs(package,
                                                  rospack=self._rospack):
                message_class = roslib.message.get_message_class(base_type_str)
                if message_class is not None:
                    message_type_names.append(base_type_str)

        # TODO: get all ROS packages and launch files here instead
        #self.type_combo_box.setItems.emit(sorted(message_type_names))
        packages = sorted([
            pkg_tuple[0]
            for pkg_tuple in RqtRoscommUtil.iterate_packages('launch')
        ])
        self.package_combo_box.setItems.emit(packages)

        # update topic_combo_box
        #_, _, topic_types = rospy.get_master().getTopicTypes()
        #self._topic_dict = dict(topic_types)
        #self.topic_combo_box.setItems.emit(sorted(self._topic_dict.keys()))

    @Slot()
    def _update_finished(self):
        self.package_combo_box.setEnabled(True)
        self.file_combo_box.setEnabled(True)

    @Slot(str)
    def on_package_combo_box_currentIndexChanged(self, package):
        #if topic_name in self._topic_dict:
        #    self.type_combo_box.setEditText(self._topic_dict[topic_name])
        #pass
        _launch_instance_list = RqtRoscommUtil.list_files(package, 'launch')
        _launchfile_instances = [
            x.split('/')[1] for x in _launch_instance_list
        ]
        self.file_combo_box.setItems.emit(_launchfile_instances)
        #self.file_combo_box.clear()
        #self.file_combo_box.addItems(_launchfile_instances)

    @Slot()
    def on_add_launch_button_clicked(self):
        package_name = str(self.package_combo_box.currentText())
        file_name = str(self.file_combo_box.currentText())
        arguments = str(self.arguments_combo_box.currentText())
        enabled = False
        self.add_launch.emit(package_name, file_name, arguments, enabled)
コード例 #19
0
class BatteryProfileFrame(QFrame):
    def __init__(self, parent=None):
        super(BatteryProfileFrame, self).__init__(parent)
        self._cmd_vel_topic_name = "/mobile_base/commands/velocity"
        self._battery_topic_name = "/mobile_base/sensors/core/battery"
        self._ui = Ui_battery_profile_frame()
        self._motion = None
        self.robot_state_subscriber = None
        self._motion_thread = None

    def setupUi(self, cmd_vel_topic_name):
        self._ui.setupUi(self)
        self._cmd_vel_topic_name = cmd_vel_topic_name
        self._plot_layout = QVBoxLayout(self._ui.battery_profile_group_box)
        self._plot_widget = PlotWidget()
        self._plot_widget.setWindowTitle("Battery Profile")
        self._plot_widget.topic_edit.setText(self._battery_topic_name)
        self._plot_layout.addWidget(self._plot_widget)
        self._plot_widget.switch_data_plot_widget(FullSizeDataPlot(self._plot_widget))
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        """
          Used to terminate the plugin
        """
        rospy.loginfo("Kobuki TestSuite: battery test shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def hibernate(self):
        """
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        """
        self._stop()

    def restore(self):
        """
          Restore the frame after a hibernate.
        """
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        if not self._motion:
            self._motion = Rotate(self._cmd_vel_topic_name)
            self._motion.init(self._ui.angular_speed_spinbox.value())
        if not self.robot_state_subscriber:
            self.robot_state_subscriber = rospy.Subscriber(
                "/mobile_base/events/robot_state", RobotStateEvent, self.robot_state_callback
            )
        rospy.sleep(0.5)
        self._plot_widget._start_time = rospy.get_time()
        self._plot_widget.enable_timer(True)
        try:
            self._plot_widget.remove_topic(self._battery_topic_name)
        except KeyError:
            pass
        self._plot_widget.add_topic(self._battery_topic_name)
        self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        """
          Hardcore stoppage - straight to zero.
        """
        self._stop()

    def _stop(self):
        self._plot_widget.enable_timer(False)  # pause plot rendering
        if self._motion_thread:
            self._motion.stop()
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion.shutdown()
            self._motion = None
        if self.robot_state_subscriber:
            self.robot_state_subscriber.unregister()
            self.robot_state_subscriber = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # External Slot Callbacks
    ##########################################################################
    @Slot(str)
    def on_cmd_vel_topic_combo_box_currentIndexChanged(self, topic_name):
        """
          To be connected to the configuration dock combo box (via the main testsuite frame)
        """
        self._cmd_vel_topic_name = topic_name
        print("DudetteBattery %s" % topic_name)

    ##########################################################################
    # Ros Callbacks
    ##########################################################################

    def robot_state_callback(self, data):
        if data.state == RobotStateEvent.OFFLINE:
            self.stop()
コード例 #20
0
class CliffSensorFrame(QFrame):
    STATE_FORWARD = "forward"
    STATE_BACKWARD = "backward"
    STATE_STOPPED = "stopped"
        
    def __init__(self, parent=None):
        super(CliffSensorFrame, self).__init__(parent)
        self._ui = Ui_cliff_sensor_frame()
        self._motion = TravelForward('/mobile_base/commands/velocity','/odom', '/mobile_base/events/cliff')
        self._motion_thread = None
        self._distance = 1.2
        self._state = CliffSensorFrame.STATE_FORWARD
        self._is_alive = False # Used to indicate whether the frame is alive or not (see hibernate/restore methods)
        

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.speed_spinbox.value(), self._distance)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: cliff sensor shutdown")
        self._motion.shutdown()

    ##########################################################################
    # Widget Management
    ##########################################################################
        
    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass
    
    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass


    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        if self._state == CliffSensorFrame.STATE_STOPPED:
            return
        elif self._state == CliffSensorFrame.STATE_FORWARD:
            self._state = CliffSensorFrame.STATE_BACKWARD
            self._motion.init(-self._motion.speed, 0.2)
            self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
            self._motion_thread.start()
        else:
            self._state = CliffSensorFrame.STATE_FORWARD
            self._motion.init(-self._motion.speed, self._distance)
            self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
            self._motion_thread.start()
        
    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._state = CliffSensorFrame.STATE_FORWARD
        self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._state = CliffSensorFrame.STATE_STOPPED
        self.stop()
        
    def stop(self):
        self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        self._motion.init(self._ui.speed_spinbox.value(), self._distance)
コード例 #21
0
class FrameEditorGUI(ProjectPlugin, Interface):

    signal_update = QtCore.Signal(int)

    def __init__(self, context):
        super(FrameEditorGUI, self).__init__(context)

        self.setObjectName('FrameEditorGUI')

        self.file_type = "YAML files(*.yaml)"

        self.editor.parse_args(context.argv())

        # Update filename display
        self.update_current_filename()

        ## Update thread ##
        ##
        self._update_thread.start()
        self.update_all(3)

    def create_editor(self):
        editor = FrameEditor()

        editor.observers.append(self)

        self.signal_update.connect(self.update_all)

        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        self.old_frame_list = []
        self.old_selected = ""

        return editor

    def create_main_widget(self):

        ## Main widget
        widget = QWidget()
        ui_file = os.path.join(rospkg.RosPack().get_path('frame_editor'),
                               'src/frame_editor', 'FrameEditorGUI.ui')
        loadUi(ui_file, widget)
        widget.setObjectName('FrameEditorGUIUi')

        #if context.serial_number() > 1:
        #    widget.setWindowTitle(widget.windowTitle() + (' (%d)' % context.serial_number()))
        widget.setWindowTitle("frame editor")

        ## Undo View
        #widget.undo_frame.layout().addWidget(QtWidgets.QUndoView(self.editor.undo_stack))

        ## Views
        self.editor.init_views()
        self.interface_style = FrameEditor_StyleWidget(self.editor)

        widget.style_frame.layout().addWidget(
            self.interface_style.get_widget())

        ## Connections ##
        ##
        widget.btn_add.clicked.connect(self.btn_add_clicked)
        widget.btn_delete.clicked.connect(self.btn_delete_clicked)
        widget.btn_duplicate.clicked.connect(self.btn_duplicate_clicked)
        widget.list_frames.currentTextChanged.connect(
            self.selected_frame_changed)
        widget.btn_refresh.clicked.connect(self.update_tf_list)

        widget.btn_set_parent_rel.clicked.connect(
            self.btn_set_parent_rel_clicked)
        widget.btn_set_parent_abs.clicked.connect(
            self.btn_set_parent_abs_clicked)
        widget.btn_set_pose.clicked.connect(self.btn_set_pose_clicked)
        widget.btn_set_position.clicked.connect(self.btn_set_position_clicked)
        widget.btn_set_orientation.clicked.connect(
            self.btn_set_orientation_clicked)
        widget.btn_set_x.clicked.connect(self.btn_set_x_clicked)
        widget.btn_set_y.clicked.connect(self.btn_set_y_clicked)
        widget.btn_set_z.clicked.connect(self.btn_set_z_clicked)
        widget.btn_set_a.clicked.connect(self.btn_set_a_clicked)
        widget.btn_set_b.clicked.connect(self.btn_set_b_clicked)
        widget.btn_set_c.clicked.connect(self.btn_set_c_clicked)

        widget.btn_reset_position_rel.clicked.connect(
            self.btn_reset_position_rel_clicked)
        widget.btn_reset_position_abs.clicked.connect(
            self.btn_reset_position_abs_clicked)
        widget.btn_reset_orientation_rel.clicked.connect(
            self.btn_reset_orientation_rel_clicked)
        widget.btn_reset_orientation_abs.clicked.connect(
            self.btn_reset_orientation_abs_clicked)

        widget.txt_x.editingFinished.connect(self.x_valueChanged)
        widget.txt_y.editingFinished.connect(self.y_valueChanged)
        widget.txt_z.editingFinished.connect(self.z_valueChanged)
        widget.txt_a.editingFinished.connect(self.a_valueChanged)
        widget.txt_b.editingFinished.connect(self.b_valueChanged)
        widget.txt_c.editingFinished.connect(self.c_valueChanged)

        widget.btn_rad.toggled.connect(self.update_fields)

        widget.combo_style.currentIndexChanged.connect(
            self.frame_style_changed)

        return widget

    def _update_thread_run(self):
        self.editor.run()

    @Slot()
    def _update_finished(self):
        print "> Shutting down"

    def update(self, editor, level, elements):
        self.signal_update.emit(level)

    @Slot(int)
    def update_all(self, level):
        ## Update list widgets
        if level & 1:
            self.update_frame_list()
            self.update_tf_list()
            self.update_current_filename()

        ## Update the currently selected frame
        if level & 2:
            self.update_active_frame()

        ## Update only text fields, spin boxes,...
        if level & 4:
            self.update_fields()

    @Slot()
    def update_tf_list(self):
        self.widget.list_tf.clear()
        self.widget.list_tf.addItems(
            sorted(self.editor.all_frame_ids(include_temp=False)))

    def update_frame_list(self):
        new_list = self.editor.frames.keys()

        ## Add missing
        items = []
        for item in new_list:
            if item not in self.old_frame_list:
                items.append(item)
        self.widget.list_frames.addItems(items)

        ## Delete removed
        for item in self.old_frame_list:
            if item not in new_list:
                if self.widget.list_frames.currentItem(
                ) and item == self.widget.list_frames.currentItem().text():
                    self.widget.list_frames.setCurrentItem(None)
                found = self.widget.list_frames.findItems(
                    item, QtCore.Qt.MatchExactly)
                self.widget.list_frames.takeItem(
                    self.widget.list_frames.row(found[0]))

        self.widget.list_frames.sortItems()

        self.old_frame_list = new_list

    def update_active_frame(self):
        if not self.editor.active_frame:
            self.old_selected = ""
            self.widget.list_frames.setCurrentItem(None)
            self.widget.box_edit.setEnabled(False)
            return  # deselect and quit

        self.widget.box_edit.setEnabled(True)

        name = self.editor.active_frame.name
        if name == self.old_selected:
            return  # no change

        ## Select item in list
        items = self.widget.list_frames.findItems(name, QtCore.Qt.MatchExactly)
        self.widget.list_frames.setCurrentItem(items[0])

        self.update_fields()

        self.old_selected = name

    @Slot()
    def update_fields(self):

        f = self.editor.active_frame
        if not f:
            return

        w = self.widget

        w.txt_name.setText(f.name)
        w.txt_parent.setText(f.parent)

        ## Relative
        w.txt_x.setValue(f.position[0])
        w.txt_y.setValue(f.position[1])
        w.txt_z.setValue(f.position[2])

        rot = tf.transformations.euler_from_quaternion(f.orientation)
        if self.widget.btn_deg.isChecked():
            rot = (180.0 * rot[0] / math.pi, 180.0 * rot[1] / math.pi,
                   180.0 * rot[2] / math.pi)

        w.txt_a.setValue(rot[0])
        w.txt_b.setValue(rot[1])
        w.txt_c.setValue(rot[2])

        txt_abs_pos = (w.txt_abs_x, w.txt_abs_y, w.txt_abs_z)
        txt_abs_rot = (w.txt_abs_a, w.txt_abs_b, w.txt_abs_c)

        ## Absolute
        try:
            position, orientation = FromTransformStamped(
                f.tf_buffer.lookup_transform('world', f.name, rospy.Time(0)))
            for txt, p in zip(txt_abs_pos, position):
                txt.setEnabled(True)
                txt.setValue(p)
            rot = tf.transformations.euler_from_quaternion(orientation)
            if self.widget.btn_deg.isChecked():
                rot = map(math.degrees, rot)
            for txt, r in zip(txt_abs_rot, rot):
                txt.setEnabled(True)
                txt.setValue(r)
        except:
            for txt in txt_abs_rot + txt_abs_pos:
                txt.setEnabled(False)

        ## Style
        self.widget.combo_style.setCurrentIndex(
            self.widget.combo_style.findText(f.style))

    @Slot(str)
    def selected_frame_changed(self, name):
        if name == "":
            return

        if not self.editor.active_frame or (self.editor.active_frame.name !=
                                            name):
            self.editor.command(
                Command_SelectElement(self.editor, self.editor.frames[name]))

    ## BUTTONS ##
    ##
    def write_file(self, file_name):
        return self.editor.save_file(file_name)

    @Slot()
    def clear_all(self):
        self.editor.command(Command_ClearAll(self.editor))

    @Slot(bool)
    def btn_add_clicked(self, checked):
        # Get a unique frame name
        existing_frames = set(self.editor.all_frame_ids())

        name, ok = QtWidgets.QInputDialog.getText(self.widget, "Add New Frame",
                                                  "Name:",
                                                  QtWidgets.QLineEdit.Normal,
                                                  "my_frame")

        while ok and name in existing_frames:
            name, ok = QtWidgets.QInputDialog.getText(
                self.widget, "Add New Frame", "Name (must be unique):",
                QtWidgets.QLineEdit.Normal, "my_frame")
        if not ok:
            return

        if not existing_frames:
            available_parents = ["world"]
        else:
            available_parents = self.editor.all_frame_ids(include_temp=False)
        parent, ok = QtWidgets.QInputDialog.getItem(self.widget,
                                                    "Add New Frame",
                                                    "Parent Name:",
                                                    sorted(available_parents))

        if not ok or parent == "":
            return

        self.editor.command(
            Command_AddElement(self.editor, Frame(name, parent=parent)))

    @Slot(bool)
    def btn_duplicate_clicked(self, checked):
        item = self.widget.list_frames.currentItem()
        if not item:
            return
        source_name = item.text()
        parent_name = self.editor.frames[source_name].parent

        # Get a unique frame name
        existing_frames = set(self.editor.all_frame_ids())

        name, ok = QtWidgets.QInputDialog.getText(self.widget,
                                                  "Duplicate Frame", "Name:",
                                                  QtWidgets.QLineEdit.Normal,
                                                  source_name)

        while ok and name in existing_frames:
            name, ok = QtWidgets.QInputDialog.getText(
                self.widget, "Duplicate Frame", "Name (must be unique):",
                QtWidgets.QLineEdit.Normal, source_name)
        if not ok:
            return

        self.editor.command(
            Command_CopyElement(self.editor, name, source_name, parent_name))

    @Slot(bool)
    def btn_delete_clicked(self, checked):
        item = self.widget.list_frames.currentItem()
        if not item:
            return
        self.editor.command(
            Command_RemoveElement(self.editor,
                                  self.editor.frames[item.text()]))

    ## PARENTING ##
    ##
    @Slot(bool)
    def btn_set_parent_rel_clicked(self, checked):
        self.set_parent(False)

    @Slot(bool)
    def btn_set_parent_abs_clicked(self, checked):
        self.set_parent(True)

    def set_parent(self, keep_absolute):
        parent = self.widget.list_tf.currentItem()
        if not parent:
            return  # none selected

        if parent.text() == self.editor.active_frame.name:
            return  # you can't be your own parent

        self.editor.command(
            Command_SetParent(self.editor, self.editor.active_frame,
                              parent.text(), keep_absolute))

    ## SET BUTTONS ##
    ##
    @Slot(bool)
    def btn_set_pose_clicked(self, checked):
        self.set_pose(["x", "y", "z", "a", "b", "c"])

    @Slot(bool)
    def btn_set_position_clicked(self, checked):
        self.set_pose(["x", "y", "z"])

    @Slot(bool)
    def btn_set_orientation_clicked(self, checked):
        self.set_pose(["a", "b", "c"])

    @Slot(bool)
    def btn_set_x_clicked(self, checked):
        self.set_pose(["x"])

    @Slot(bool)
    def btn_set_y_clicked(self, checked):
        self.set_pose(["y"])

    @Slot(bool)
    def btn_set_z_clicked(self, checked):
        self.set_pose(["z"])

    @Slot(bool)
    def btn_set_a_clicked(self, checked):
        self.set_pose(["a"])

    @Slot(bool)
    def btn_set_b_clicked(self, checked):
        self.set_pose(["b"])

    @Slot(bool)
    def btn_set_c_clicked(self, checked):
        self.set_pose(["c"])

    def set_pose(self, mode):
        source = self.widget.list_tf.currentItem()
        if not source:
            return  # none selected

        frame = self.editor.active_frame
        self.editor.command(
            Command_AlignElement(self.editor, frame, source.text(), mode))

    ## RESET BUTTONS ##
    ##
    @Slot(bool)
    def btn_reset_position_rel_clicked(self, checked):
        self.editor.command(
            Command_SetPosition(self.editor, self.editor.active_frame,
                                (0, 0, 0)))

    @Slot(bool)
    def btn_reset_position_abs_clicked(self, checked):
        position, orientation = FromTransformStamped(
            self.editor.active_frame.tf_buffer.lookup_transform(
                self.editor.active_frame.parent, "world", rospy.Time(0)))
        self.editor.command(
            Command_SetPosition(self.editor, self.editor.active_frame,
                                position))

    @Slot(bool)
    def btn_reset_orientation_rel_clicked(self, checked):
        self.editor.command(
            Command_SetOrientation(self.editor, self.editor.active_frame,
                                   (0, 0, 0, 1)))

    @Slot(bool)
    def btn_reset_orientation_abs_clicked(self, checked):
        position, orientation = FromTransformStamped(
            self.editor.active_frame.listener.lookupTransform(
                self.editor.active_frame.parent, "world", rospy.Time(0)))
        self.editor.command(
            Command_SetOrientation(self.editor, self.editor.active_frame,
                                   orientation))

    ## Spin Boxes ##
    ##
    def set_value(self, widget, symbol):
        frame = self.editor.active_frame
        value = widget.value()

        ## Deg to rad
        if self.widget.btn_deg.isChecked() and symbol in ['a', 'b', 'c']:
            value = value * math.pi / 180.0

        if frame.value(symbol) != value:
            self.editor.command(
                Command_SetValue(self.editor, self.editor.active_frame, symbol,
                                 value))

    @Slot()
    def x_valueChanged(self):
        self.set_value(self.widget.txt_x, 'x')

    @Slot()
    def y_valueChanged(self):
        self.set_value(self.widget.txt_y, 'y')

    @Slot()
    def z_valueChanged(self):
        self.set_value(self.widget.txt_z, 'z')

    @Slot()
    def a_valueChanged(self):
        self.set_value(self.widget.txt_a, 'a')

    @Slot()
    def b_valueChanged(self):
        self.set_value(self.widget.txt_b, 'b')

    @Slot()
    def c_valueChanged(self):
        self.set_value(self.widget.txt_c, 'c')

    ## FRAME STYLE ##
    ##
    @Slot(int)
    def frame_style_changed(self, id):
        style = self.widget.combo_style.currentText().lower()
        if self.editor.active_frame.style != style:
            self.editor.command(
                Command_SetStyle(self.editor, self.editor.active_frame, style))

    ## PLUGIN ##
    ##
    def shutdown_plugin(self):
        super(FrameEditorGUI, self).shutdown_plugin()
        self._update_thread.kill()
コード例 #22
0
ファイル: conman.py プロジェクト: kuka-isir/conman
    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)
        self._widget.namespace_input.currentIndexChanged.connect(
            self._handle_refresh_clicked)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.refresh_button.clicked[bool].connect(
            self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(
            self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
        #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = {}
        self.groups = {}

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()

        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0, 4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0, 4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

        self.refresh_combo_box()
コード例 #23
0
    def __init__(self, context):
        super(Smach, self).__init__(context)

        self.initialized = 0

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        # Give QObjects reasonable names
        self.setObjectName('Smach')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rqt_smach.ui')

        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)

        # Give QObjects reasonable names
        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('SmachPluginUi')

        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette ()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #Connect widgets with corresponding methods
        self._widget.namespace_input.currentIndexChanged.connect(self._handle_ns_changed)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.restrict_ns.clicked.connect(self.refresh_combo_box)
        self._widget.ud_path_input.currentIndexChanged.connect(self._handle_ud_path)
        self._widget.ud_set_initial.clicked.connect(self._handle_ud_set_path)
        self._widget.ud_text_browser.setReadOnly(1)
        self._widget.show_implicit_button.clicked.connect(self._handle_show_implicit)
        self._widget.help_button.setIcon(QIcon.fromTheme('help-contents'))
        self._widget.help_button.clicked.connect(self._handle_help)
        self._widget.tree.clicked.connect(self._handle_tree_clicked)

        #Depth and width spinners:
        self._widget.depth_input.setRange(-1, 1337)
        self._widget.depth_input.setValue(-1)
        self._widget.depth_input.valueChanged.connect(self._set_depth)

        self._widget.label_width_input.setRange(1, 1337)
        self._widget.label_width_input.setValue(40)
        self._widget.label_width_input.valueChanged.connect(self._set_width)

        self._widget.tree.setColumnCount(1)
        self._widget.tree.setHeaderLabels(["Containers"])
        self._widget.tree.show()

        self._ns = ""
        self.refresh_combo_box()

        # Bind path list
        self._widget.path_input.currentIndexChanged.connect(
                self._handle_path_changed)

        #Keep Combo Boxes sorted
        self._widget.namespace_input.setInsertPolicy(6)
        self._widget.path_input.setInsertPolicy(6)
        self._widget.ud_path_input.setInsertPolicy(6)

        #Set up mouse actions for xdot widget
        self._widget.xdot_widget.register_select_callback(self.select_cb)

        # Create graph data structures
        # Containers is a map of (container path) -> container proxy
        self._containers = {}
        self._top_containers = {}

        # smach introspection client
        self._client = smach_ros.IntrospectionClient()
        self._selected_paths = []

        # Message subscribers
        self._structure_subs = {}
        self._status_subs = {}

        # Initialize xdot display state
        self._path = '/'
        self._needs_zoom = True
        self._structure_changed = True
        self._max_depth = -1
        self._show_all_transitions = False
        self._label_wrapper = textwrap.TextWrapper(40,break_long_words=True)
        self._graph_needs_refresh = True
        self._tree_needs_refresh = True

        self._keep_running = True

        self._update_server_list()
        self._update_graph()
        self._update_tree()

        # Start a timer to update the server list
        self._server_timer = QTimer(self)
        self._server_timer.timeout.connect(self._update_server_list)
        self._server_timer.start(1000)

        # Start a timer to update the graph display
        self._graph_timer = QTimer(self)
        self._graph_timer.timeout.connect(self._update_graph)
        self._graph_timer.start(1093)

        # Start a timer to update the._widget.tree display
        self._tree_timer = QTimer(self)
        self._tree_timer.timeout.connect(self._update_tree)
        self._tree_timer.start(1217)
コード例 #24
0
ファイル: conman.py プロジェクト: RCPRG-ros-pkg/conman
class Conman(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)
        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when 
        # it's set in _widget). This is useful when you open multiple 
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette ()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)
        self._widget.namespace_input.currentIndexChanged.connect(self._handle_refresh_clicked)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.refresh_button.clicked[bool].connect(self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
                #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = { }
        self.groups = { }

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()


        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0,4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0,4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

        self.refresh_combo_box()

    def block_changed(self, item):
        row = item.row()
        name = self._blocks_model.item(row,3).text()
        block = self.blocks[name]
        checked = item.checkState() == Qt.Checked

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        self._update_thread.kill()
        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 trigger_configuration(self):
        # Comment in to signal that the plugin has a way to configure
        # This will enable a setting button (gear icon) in each dock widget title bar
        # Usually used to open a modal configuration dialog

    @Slot()
    def refresh_combo_box(self):
        self._update_thread.kill()
        self._widget.namespace_input.setEnabled(False)
        self._widget.namespace_input.setEditText('updating...')
        self._update_thread.start()

    def _update_thread_run(self):
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        keys = list(self._topic_dict.keys())
        namespaces = list()
        for i in keys:
            if i.endswith("get_blocks_action/goal"):
                namespaces.append(i[0:i.index("get_blocks_action/goal")])

        self._widget.namespace_input.setItems.emit(namespaces)

    @Slot()
    def _update_finished(self):
        self._widget.namespace_input.setEnabled(True)

    def _get_result_cb(self, status, res):
        rospy.loginfo("got result!")
        self._blocks_model.setRowCount(0)
        self._blocks_model.setRowCount(len(res.blocks))

        for (i,block) in zip(range(len(res.blocks)),res.blocks):

            # Store in dict
            self.blocks[block.name] = block

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked if block.state.value == conman_msgs.msg.TaskState.RUNNING else Qt.Unchecked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setTristate(True)

            action = QStandardItem(True)
            action.setText("")

            state = QStandardItem(True)
            state.setText(state_map[block.state.value])

            name = QStandardItem(True)
            name.setText(str(block.name))

            self._blocks_model.setItem(i,0,cb)
            self._blocks_model.setItem(i,1,action)
            self._blocks_model.setItem(i,2,state)
            self._blocks_model.setItem(i,3,name)

        for (i,group) in zip(range(len(res.groups)),res.groups):

            self.groups[group.name] = group

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setEnabled(False)

            name = QStandardItem(True)
            name.setText(str(group.name))

            self._groups_model.setItem(i,0,cb)
            self._groups_model.setItem(i,3,name)

        self._update_groups()
        self._update_blocks()

        self._widget.blocks_table.resizeColumnsToContents()
        self._widget.blocks_table.horizontalHeader().setStretchLastSection(True)
        self._widget.groups_table.resizeColumnsToContents()
        self._widget.groups_table.horizontalHeader().setStretchLastSection(True)

    def _update_blocks(self):
        
        for (name, block) in self.blocks.items():
            items = self._blocks_model.findItems(name, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue
            
            row = item.row()
            checked = self._blocks_model.item(row,0).checkState() == Qt.Checked
            if checked and block.state.value != conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row,1).setText("ENABLE")
            elif not checked and block.state.value == conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row,1).setText("DISABLE")
            else:
                self._blocks_model.item(row,1).setText("")
        self._update_groups()

    def _enable_group(self, index, enable):
        name = self._groups_model.item(index, 3).text()
        group = self.groups[name]

        for member in group.members:
            items = self._blocks_model.findItems(member, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue
            
            row = item.row()
            self._blocks_model.item(row,0).setCheckState(Qt.Checked if enable else Qt.Unchecked)

        self._update_blocks()
        
    def _update_groups(self):
        for (name, group) in self.groups.items():
            group_items = self._groups_model.findItems(name, column=3)
            if len(group_items) > 0:
                group_item = group_items[0]
            else:
                continue
            group_row = group_item.row()

            members_checked = []

            for member in group.members:
                items = self._blocks_model.findItems(member, column=3)
                if len(items) > 0:
                    item = items[0]
                else:
                    continue
                row = item.row()
                members_checked.append(self._blocks_model.item(row,0).checkState() == Qt.Checked)

            if all(members_checked):
                check = Qt.Checked
            else:
                check = Qt.Unchecked

            self._groups_model.item(group_row,0).setCheckState(check)


    def _query_blocks(self):
        if self._get_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Getting blocks...")
                goal = conman_msgs.msg.GetBlocksGoal()
                goal.publish_flow_graph = self._widget.generate_graph_checkbox.isChecked()
                self._get_blocks.send_goal(goal, done_cb=self._get_result_cb)


    def enable_widgets(self, enable):
        
        #self._widget.generate_graph_checkbox.setEnabled(enable)
        self._widget.force_enable_checkbox.setEnabled(enable)
        #self._widget.disable_unused_button.setEnabled(enable)
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.blocks_table.setEnabled(enable)
        self._widget.groups_table.setEnabled(enable)
        self._widget.regenerate_graph_button.setEnabled(enable)

    def _handle_refresh_clicked(self, checked):
        ns = self._widget.namespace_input.currentText()

        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)

                self._dotcode_sub = rospy.Subscriber(
                        ns+'/dotcode',
                        std_msgs.msg.String,
                        self._dotcode_msg_cb)

                self._get_blocks = actionlib.SimpleActionClient(
                        ns+'/get_blocks_action',
                        conman_msgs.msg.GetBlocksAction)

                self._set_blocks = actionlib.SimpleActionClient(
                        ns+'/set_blocks_action',
                        conman_msgs.msg.SetBlocksAction)

                rospy.loginfo("Creating action clients on namespace '%s'..." % ns)

                if not self._get_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." % self._get_blocks.action_client.ns)
                    return
                if not self._set_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." % self._set_blocks.action_client.ns)
                    return

                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

            self._query_blocks()


    def _handle_commit_clicked(self, checked):
        if self._set_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Setting blocks...")
                goal = conman_msgs.msg.SetBlocksGoal()
                goal.diff = True
                goal.force = True

                for i in range(self._blocks_model.rowCount()):
                    name = self._blocks_model.item(i,3).text()
                    action = self._blocks_model.item(i,1).text()

                    if action == 'DISABLE':
                        goal.disable.append(name)
                    elif action == 'ENABLE':
                        goal.enable.append(name)

                self._set_blocks.send_goal(goal, done_cb=self._get_set_result_cb)

    def _get_set_result_cb(self, status, res):

        self._query_blocks()

    @Slot(str)
    def _update_graph(self,dotcode):
        global initialized
        if initialized: 
            self._widget.xdot_widget.set_dotcode(dotcode, center=False);
        else:
            self._widget.xdot_widget.set_dotcode(dotcode, center=True);
            self._widget.xdot_widget.zoom_to_fit()
            initialized = 1

    def _dotcode_msg_cb(self, msg):
        #self.new_dotcode_data = msg.data
        self.update_graph_sig.emit(msg.data)
    
    def _update_widgets(self):
        self._update_groups()
        self._update_blocks()
コード例 #25
0
class PayloadFrame(QFrame):
    def __init__(self, parent=None):
        super(PayloadFrame, self).__init__(parent)
        self._gyro_topic_name = '/mobile_base/sensors/imu_data'
        self._ui = Ui_payload_frame()
        self._motion = None
        self._motion_thread = None

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: payload frame shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch).
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        self._stop()

    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        self._motion_thread = None
        self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._motion = Square('/mobile_base/commands/velocity', '/odom',
                              self._gyro_topic_name)
        self._motion.init(self._ui.speed_spinbox.value(),
                          self._ui.distance_spinbox.value())
        self._motion_thread = WorkerThread(self._motion.execute,
                                           self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._stop()

    def _stop(self):
        if self._motion:
            self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.speed_spinbox.value(),
                              self._ui.distance_spinbox.value())

    @pyqtSlot(float)
    def on_distance_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.speed_spinbox.value(),
                              self._ui.distance_spinbox.value())
コード例 #26
0
    def __init__(self, context):
        super(RosPackGraph, self).__init__(context)
        self.initialized = False
        self._current_dotcode = None
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)
        self._nodes = {}
        self._edges = {}
        self._options = {}
        self._options_serialized = ''

        self.setObjectName('RosPackGraph')

        rospack = rospkg.RosPack()
        rosstack = rospkg.RosStack()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        # generator builds rosgraph
        self.dotcode_generator = RosPackageGraphDotcodeGenerator(rospack, rosstack)
        # dot_to_qt transforms into Qt elements using dot layout
        self.dot_to_qt = DotToQtGenerator()

        self._widget = QWidget()
        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_dep'), 'resource', 'RosPackGraph.ui')
        loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('RosPackGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1)
        self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2)
        self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3)
        self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4)
        self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5)
        self._widget.depth_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0)
        self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'), 1)
        self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2)
        self._widget.directions_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        self._widget.package_type_combo_box.insertItem(0, self.tr('wet & dry'), 3)
        self._widget.package_type_combo_box.insertItem(1, self.tr('wet only'), 2)
        self._widget.package_type_combo_box.insertItem(2, self.tr('dry only'), 1)
        self._widget.package_type_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        completionmodel = StackageCompletionModel(self._widget.filter_line_edit, rospack, rosstack)
        completer = RepeatedWordCompleter(completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)

        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(self._refresh_rospackgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self._widget.filter_line_edit.selectionChanged.connect(self._clear_filter)
        
        self._widget.with_stacks_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.colorize_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.hide_transitives_check_box.clicked.connect(self._refresh_rospackgraph)

        self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(self._update_rospackgraph)

        self._widget.highlight_connections_check_box.toggled.connect(self._refresh_rospackgraph)
        self._widget.auto_fit_graph_check_box.toggled.connect(self._refresh_rospackgraph)
        self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(self._save_image)

        self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()

        context.add_widget(self._widget)
        
        # If in either of following case, this turnes True
        # - 1st filtering key is already input by user
        # - filtering key is restored
        self._filtering_started = False
コード例 #27
0
class RosPackGraph(Plugin):

    _deferred_fit_in_view = Signal()

    def __init__(self, context):
        super(RosPackGraph, self).__init__(context)
        self.initialized = False
        self._current_dotcode = None
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)
        self._nodes = {}
        self._edges = {}
        self._options = {}
        self._options_serialized = ''

        self.setObjectName('RosPackGraph')

        rospack = rospkg.RosPack()
        rosstack = rospkg.RosStack()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        # generator builds rosgraph
        self.dotcode_generator = RosPackageGraphDotcodeGenerator(rospack, rosstack)
        # dot_to_qt transforms into Qt elements using dot layout
        self.dot_to_qt = DotToQtGenerator()

        self._widget = QWidget()
        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_dep'), 'resource', 'RosPackGraph.ui')
        loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('RosPackGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1)
        self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2)
        self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3)
        self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4)
        self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5)
        self._widget.depth_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0)
        self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'), 1)
        self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2)
        self._widget.directions_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        self._widget.package_type_combo_box.insertItem(0, self.tr('wet & dry'), 3)
        self._widget.package_type_combo_box.insertItem(1, self.tr('wet only'), 2)
        self._widget.package_type_combo_box.insertItem(2, self.tr('dry only'), 1)
        self._widget.package_type_combo_box.currentIndexChanged.connect(self._refresh_rospackgraph)

        completionmodel = StackageCompletionModel(self._widget.filter_line_edit, rospack, rosstack)
        completer = RepeatedWordCompleter(completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)

        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(self._refresh_rospackgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self._widget.filter_line_edit.selectionChanged.connect(self._clear_filter)
        
        self._widget.with_stacks_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.colorize_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.hide_transitives_check_box.clicked.connect(self._refresh_rospackgraph)

        self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(self._update_rospackgraph)

        self._widget.highlight_connections_check_box.toggled.connect(self._refresh_rospackgraph)
        self._widget.auto_fit_graph_check_box.toggled.connect(self._refresh_rospackgraph)
        self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(self._save_image)

        self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()

        context.add_widget(self._widget)
        
        # If in either of following case, this turnes True
        # - 1st filtering key is already input by user
        # - filtering key is restored
        self._filtering_started = False

    def shutdown_plugin(self):
        self._update_thread.kill()

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value('depth_combo_box_index', self._widget.depth_combo_box.currentIndex())
        instance_settings.set_value('directions_combo_box_index', self._widget.directions_combo_box.currentIndex())
        instance_settings.set_value('package_type_combo_box', self._widget.package_type_combo_box.currentIndex())
        instance_settings.set_value('filter_line_edit_text', self._widget.filter_line_edit.text())
        instance_settings.set_value('with_stacks_state', self._widget.with_stacks_check_box.isChecked())
        instance_settings.set_value('hide_transitives_state', self._widget.hide_transitives_check_box.isChecked())
        instance_settings.set_value('mark_state', self._widget.mark_check_box.isChecked())
        instance_settings.set_value('colorize_state', self._widget.colorize_check_box.isChecked())
        instance_settings.set_value('auto_fit_graph_check_box_state', self._widget.auto_fit_graph_check_box.isChecked())
        instance_settings.set_value('highlight_connections_check_box_state', self._widget.highlight_connections_check_box.isChecked())

    def restore_settings(self, plugin_settings, instance_settings):
        _str_filter = instance_settings.value('filter_line_edit_text', '')
        if (_str_filter == None or _str_filter == '') and \
           not self._filtering_started:
            _str_filter = '(Separate pkgs by comma)'
        else:
            self._filtering_started = True
        
        self._widget.depth_combo_box.setCurrentIndex(int(instance_settings.value('depth_combo_box_index', 0)))
        self._widget.directions_combo_box.setCurrentIndex(int(instance_settings.value('directions_combo_box_index', 0)))
        self._widget.package_type_combo_box.setCurrentIndex(int(instance_settings.value('package_type_combo_box', 0)))
        self._widget.filter_line_edit.setText(_str_filter)
        self._widget.with_stacks_check_box.setChecked(instance_settings.value('with_stacks_state', True) in [True, 'true'])
        self._widget.mark_check_box.setChecked(instance_settings.value('mark_state', True) in [True, 'true'])
        self._widget.colorize_check_box.setChecked(instance_settings.value('colorize_state', False) in [True, 'true'])
        self._widget.hide_transitives_check_box.setChecked(instance_settings.value('hide_transitives_state', False) in [True, 'true'])
        self._widget.auto_fit_graph_check_box.setChecked(instance_settings.value('auto_fit_graph_check_box_state', True) in [True, 'true'])
        self._widget.highlight_connections_check_box.setChecked(instance_settings.value('highlight_connections_check_box_state', True) in [True, 'true'])
        self.initialized = True
        self._refresh_rospackgraph()

    def _update_rospackgraph(self):
        # re-enable controls customizing fetched ROS graph
        self._widget.depth_combo_box.setEnabled(True)
        self._widget.directions_combo_box.setEnabled(True)
        self._widget.package_type_combo_box.setEnabled(True)
        self._widget.filter_line_edit.setEnabled(True)
        self._widget.with_stacks_check_box.setEnabled(True)
        self._widget.mark_check_box.setEnabled(True)
        self._widget.colorize_check_box.setEnabled(True)
        self._widget.hide_transitives_check_box.setEnabled(True)

        self._refresh_rospackgraph(force_update=True)

    def _update_options(self):
        self._options['depth'] = self._widget.depth_combo_box.itemData(self._widget.depth_combo_box.currentIndex())
        self._options['directions'] = self._widget.directions_combo_box.itemData(self._widget.directions_combo_box.currentIndex())
        self._options['package_types'] = self._widget.package_type_combo_box.itemData(self._widget.package_type_combo_box.currentIndex())
        self._options['with_stacks'] = self._widget.with_stacks_check_box.isChecked()
        self._options['mark_selected'] = self._widget.mark_check_box.isChecked()
        self._options['hide_transitives'] = self._widget.hide_transitives_check_box.isChecked()
        # TODO: Allow different color themes
        self._options['colortheme'] = True if self._widget.colorize_check_box.isChecked() else None
        self._options['names'] = self._widget.filter_line_edit.text().split(',')
        if self._options['names'] == [u'None']:
            self._options['names'] = []
        self._options['highlight_level'] = 3 if self._widget.highlight_connections_check_box.isChecked() else 1
        self._options['auto_fit'] = self._widget.auto_fit_graph_check_box.isChecked()

    def _refresh_rospackgraph(self, force_update=False):
        if not self.initialized:
            return

        self._update_thread.kill()

        self._update_options()

        # avoid update if options did not change and force_update is not set
        new_options_serialized = pickle.dumps(self._options)
        if new_options_serialized == self._options_serialized and not force_update:
            return
        self._options_serialized = pickle.dumps(self._options)

        self._scene.setBackgroundBrush(Qt.lightGray)

        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        self._update_graph(self._generate_dotcode())

    @Slot()
    def _update_finished(self):
        self._scene.setBackgroundBrush(Qt.white)
        self._redraw_graph_scene()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _generate_dotcode(self):
        includes = []
        excludes = []
        for name in self._options['names']:
            if name.strip().startswith('-'):
                excludes.append(name.strip()[1:])
            else:
                includes.append(name.strip())
        # orientation = 'LR'
        descendants = True
        ancestors = True
        if self._options['directions'] == 1:
            descendants = False
        if self._options['directions'] == 0:
            ancestors = False
        return self.dotcode_generator.generate_dotcode(dotcode_factory=self.dotcode_factory,
                                                       selected_names=includes,
                                                       excludes=excludes,
                                                       depth=self._options['depth'],
                                                       with_stacks=self._options['with_stacks'],
                                                       descendants=descendants,
                                                       ancestors=ancestors,
                                                       mark_selected=self._options['mark_selected'],
                                                       colortheme=self._options['colortheme'],
                                                       hide_transitives=self._options['hide_transitives'],
                                                       hide_wet=self._options['package_types'] == 1,
                                                       hide_dry=self._options['package_types'] == 2)

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_graph(self, dotcode):
        self._current_dotcode = dotcode
        self._nodes, self._edges = self.dot_to_qt.dotcode_to_qt_items(self._current_dotcode, self._options['highlight_level'])

    def _generate_tool_tip(self, url):
        if url is not None and ':' in url:
            item_type, item_path = url.split(':', 1)
            if item_type == 'node':
                tool_tip = 'Node:\n  %s' % (item_path)
                service_names = rosservice.get_service_list(node=item_path)
                if service_names:
                    tool_tip += '\nServices:'
                    for service_name in service_names:
                        try:
                            service_type = rosservice.get_service_type(service_name)
                            tool_tip += '\n  %s [%s]' % (service_name, service_type)
                        except rosservice.ROSServiceIOException, e:
                            tool_tip += '\n  %s' % (e)
                return tool_tip
            elif item_type == 'topic':
                topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
                return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
        return url
コード例 #28
0
ファイル: conman.py プロジェクト: RCPRG-ros-pkg/conman
    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)
        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when 
        # it's set in _widget). This is useful when you open multiple 
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette ()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)
        self._widget.namespace_input.currentIndexChanged.connect(self._handle_refresh_clicked)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.refresh_button.clicked[bool].connect(self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
                #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = { }
        self.groups = { }

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()


        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0,4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0,4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

        self.refresh_combo_box()
コード例 #29
0
ファイル: ros_pack_graph.py プロジェクト: daju1-ros/rqt
class RosPackGraph(Plugin):

    _deferred_fit_in_view = Signal()

    def __init__(self, context):
        super(RosPackGraph, self).__init__(context)
        self.initialized = False
        self._current_dotcode = None
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        self._nodes = []
        self._edges = []
        self._options = {}
        self._options_serialized = ''

        self.setObjectName('RosPackGraph')

        rospack = rospkg.RosPack()
        rosstack = rospkg.RosStack()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        # generator builds rosgraph
        self.dotcode_generator = RosPackageGraphDotcodeGenerator(
            rospack, rosstack)
        # dot_to_qt transforms into Qt elements using dot layout
        self.dot_to_qt = DotToQtGenerator()

        self._widget = QWidget()
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'RosPackGraph.ui')
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('RosPackGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1)
        self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2)
        self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3)
        self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4)
        self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5)
        self._widget.depth_combo_box.setCurrentIndex(0)
        self._widget.depth_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0)
        self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'),
                                                     1)
        self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2)
        self._widget.directions_combo_box.setCurrentIndex(2)
        self._widget.directions_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        completionmodel = StackageCompletionModel(
            self._widget.filter_line_edit, rospack, rosstack)
        completer = RepeatedWordCompleter(completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)

        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(
            self._refresh_rospackgraph)
        self._widget.filter_line_edit.setCompleter(completer)

        self._widget.with_stacks_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.colorize_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.hide_transitives_check_box.clicked.connect(
            self._refresh_rospackgraph)

        self._widget.refresh_graph_push_button.setIcon(
            QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(
            self._update_rospackgraph)

        self._widget.highlight_connections_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.auto_fit_graph_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.fit_in_view_push_button.setIcon(
            QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(
            QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(
            QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(
            self._save_image)

        self._deferred_fit_in_view.connect(self._fit_in_view,
                                           Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()

        context.add_widget(self._widget)

    def shutdown_plugin(self):
        self._update_thread.kill()

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(
            'depth_combo_box_index',
            self._widget.depth_combo_box.currentIndex())
        instance_settings.set_value(
            'directions_combo_box_index',
            self._widget.directions_combo_box.currentIndex())
        instance_settings.set_value('filter_line_edit_text',
                                    self._widget.filter_line_edit.text())
        instance_settings.set_value(
            'with_stacks_state',
            self._widget.with_stacks_check_box.isChecked())
        instance_settings.set_value(
            'hide_transitives_state',
            self._widget.hide_transitives_check_box.isChecked())
        instance_settings.set_value('mark_state',
                                    self._widget.mark_check_box.isChecked())
        instance_settings.set_value(
            'colorize_state', self._widget.colorize_check_box.isChecked())
        instance_settings.set_value(
            'auto_fit_graph_check_box_state',
            self._widget.auto_fit_graph_check_box.isChecked())
        instance_settings.set_value(
            'highlight_connections_check_box_state',
            self._widget.highlight_connections_check_box.isChecked())

    def restore_settings(self, plugin_settings, instance_settings):
        self._widget.depth_combo_box.setCurrentIndex(
            int(instance_settings.value('depth_combo_box_index', 0)))
        self._widget.directions_combo_box.setCurrentIndex(
            int(instance_settings.value('directions_combo_box_index', 0)))
        self._widget.filter_line_edit.setText(
            instance_settings.value('filter_line_edit_text', ''))
        self._widget.with_stacks_check_box.setChecked(
            instance_settings.value('with_stacks_state', True) in
            [True, 'true'])
        self._widget.mark_check_box.setChecked(
            instance_settings.value('mark_state', True) in [True, 'true'])
        self._widget.colorize_check_box.setChecked(
            instance_settings.value('colorize_state', True) in [True, 'true'])
        self._widget.hide_transitives_check_box.setChecked(
            instance_settings.value('hide_transitives_state', True) in
            [True, 'true'])
        self._widget.auto_fit_graph_check_box.setChecked(
            instance_settings.value('auto_fit_graph_check_box_state', True) in
            [True, 'true'])
        self._widget.highlight_connections_check_box.setChecked(
            instance_settings.value('highlight_connections_check_box_state',
                                    True) in [True, 'true'])
        self.initialized = True
        self._refresh_rospackgraph()

    def _update_rospackgraph(self):
        # re-enable controls customizing fetched ROS graph
        self._widget.depth_combo_box.setEnabled(True)
        self._widget.directions_combo_box.setEnabled(True)
        self._widget.filter_line_edit.setEnabled(True)
        self._widget.with_stacks_check_box.setEnabled(True)
        self._widget.mark_check_box.setEnabled(True)
        self._widget.colorize_check_box.setEnabled(True)
        self._widget.hide_transitives_check_box.setEnabled(True)

        self._refresh_rospackgraph(force_update=True)

    def _update_options(self):
        self._options['depth'] = self._widget.depth_combo_box.itemData(
            self._widget.depth_combo_box.currentIndex())
        self._options[
            'directions'] = self._widget.directions_combo_box.itemData(
                self._widget.directions_combo_box.currentIndex())
        self._options[
            'with_stacks'] = self._widget.with_stacks_check_box.isChecked()
        self._options['mark_selected'] = self._widget.mark_check_box.isChecked(
        )
        self._options[
            'hide_transitives'] = self._widget.hide_transitives_check_box.isChecked(
            )
        # TODO: Allow different color themes
        self._options[
            'colortheme'] = True if self._widget.colorize_check_box.isChecked(
            ) else None
        self._options['names'] = self._widget.filter_line_edit.text().split(
            ',')
        if self._options['names'] == [u'None']:
            self._options['names'] = []
        self._options[
            'highlight_level'] = 3 if self._widget.highlight_connections_check_box.isChecked(
            ) else 1
        self._options[
            'auto_fit'] = self._widget.auto_fit_graph_check_box.isChecked()

    def _refresh_rospackgraph(self, force_update=False):
        if not self.initialized:
            return

        self._update_thread.kill()

        self._update_options()

        # avoid update if options did not change and force_update is not set
        new_options_serialized = pickle.dumps(self._options)
        if new_options_serialized == self._options_serialized and not force_update:
            return
        self._options_serialized = pickle.dumps(self._options)

        self._scene.setBackgroundBrush(Qt.lightGray)

        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        self._update_graph(self._generate_dotcode())

    @Slot()
    def _update_finished(self):
        self._scene.setBackgroundBrush(Qt.white)
        self._redraw_graph_scene()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _generate_dotcode(self):
        includes = []
        excludes = []
        for name in self._options['names']:
            if name.strip().startswith('-'):
                excludes.append(name.strip()[1:])
            else:
                includes.append(name.strip())
        # orientation = 'LR'
        descendants = True
        ancestors = True
        if self._options['directions'] == 1:
            descendants = False
        if self._options['directions'] == 0:
            ancestors = False
        return self.dotcode_generator.generate_dotcode(
            dotcode_factory=self.dotcode_factory,
            selected_names=includes,
            excludes=excludes,
            depth=self._options['depth'],
            with_stacks=self._options['with_stacks'],
            descendants=descendants,
            ancestors=ancestors,
            mark_selected=self._options['mark_selected'],
            colortheme=self._options['colortheme'],
            hide_transitives=self._options['hide_transitives'])

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_graph(self, dotcode):
        self._current_dotcode = dotcode
        self._nodes, self._edges = self.dot_to_qt.dotcode_to_qt_items(
            self._current_dotcode, self._options['highlight_level'])

    def _generate_tool_tip(self, url):
        if url is not None and ':' in url:
            item_type, item_path = url.split(':', 1)
            if item_type == 'node':
                tool_tip = 'Node:\n  %s' % (item_path)
                service_names = rosservice.get_service_list(node=item_path)
                if service_names:
                    tool_tip += '\nServices:'
                    for service_name in service_names:
                        try:
                            service_type = rosservice.get_service_type(
                                service_name)
                            tool_tip += '\n  %s [%s]' % (service_name,
                                                         service_type)
                        except rosservice.ROSServiceIOException, e:
                            tool_tip += '\n  %s' % (e)
                return tool_tip
            elif item_type == 'topic':
                topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
                return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
        return url
コード例 #30
0
class PublisherWidget(QWidget):
    add_publisher = Signal(str, str, float, bool)
    change_publisher = Signal(int, str, str, str, object)
    publish_once = Signal(int)
    remove_publisher = Signal(int)
    clean_up_publishers = Signal()

    def __init__(self, node, parent=None):
        super(PublisherWidget, self).__init__(parent)
        self._node = node
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        package_path = get_package_path('rqt_publisher')
        ui_file = os.path.join(package_path, 'share', 'rqt_publisher',
                               'resource', 'Publisher.ui')
        loadUi(
            ui_file, self, {
                'ExtendedComboBox': ExtendedComboBox,
                'PublisherTreeWidget': PublisherTreeWidget
            })
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_publisher_button.setIcon(QIcon.fromTheme('list-add'))
        self.remove_publisher_button.setIcon(QIcon.fromTheme('list-remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.publisher_tree_widget.model().item_value_changed.connect(
            self.change_publisher)
        self.publisher_tree_widget.remove_publisher.connect(
            self.remove_publisher)
        self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_publisher_button.clicked.connect(
            self.publisher_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_publishers)

    def shutdown_plugin(self):
        self._update_thread.kill()

    @Slot()
    def refresh_combo_boxes(self):
        self._update_thread.kill()
        self.type_combo_box.setEnabled(False)
        self.topic_combo_box.setEnabled(False)
        self.type_combo_box.setEditText('updating...')
        self.topic_combo_box.setEditText('updating...')
        self._update_thread.start()

    def _get_message_types(self, package_name):
        """
        Implementation taken from ros2cli.

        https://github.com/ros2/ros2cli/blob/master/ros2msg/ros2msg/api/__init__.py
        """
        if not has_resource('packages', package_name):
            raise LookupError('Unknown package name "{}"'.format(package_name))
        try:
            content, _ = get_resource('rosidl_interfaces', package_name)
        except LookupError:
            return []
        interface_names = content.splitlines()
        # TODO(dirk-thomas) this logic should come from a rosidl related package
        # Only return messages in msg folder
        return [
            n[4:-4] for n in interface_names
            if n.startswith('msg/') and n.endswith('.msg')
        ]

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        # update type_combo_box
        message_type_names = []
        message_types = get_all_message_types()
        for package, message_types in message_types.items():
            for message_type in message_types:
                base_type_str = package + '/msg/' + message_type
                message_class = get_message_class(base_type_str)
                if message_class is not None:
                    message_type_names.append(base_type_str)

        self.type_combo_box.setItems.emit(sorted(message_type_names))

        # update topic_combo_box
        topic_names_and_types = self._node.get_topic_names_and_types()
        self._topic_dict = dict(topic_names_and_types)
        self.topic_combo_box.setItems.emit(sorted(self._topic_dict.keys()))

    @Slot()
    def _update_finished(self):
        self.type_combo_box.setEnabled(True)
        self.topic_combo_box.setEnabled(True)

    @Slot(str)
    def on_topic_combo_box_currentIndexChanged(self, topic_name):
        # More than one topic type is possible per topic, this recommends the first one
        if topic_name in self._topic_dict and len(
                self._topic_dict[topic_name]) > 0:
            self.type_combo_box.setEditText(self._topic_dict[topic_name][0])

    @Slot()
    def on_add_publisher_button_clicked(self):
        topic_name = str(self.topic_combo_box.currentText())
        type_name = str(self.type_combo_box.currentText())
        rate = float(self.frequency_combo_box.currentText())
        enabled = False
        self.add_publisher.emit(topic_name, type_name, rate, enabled)
コード例 #31
0
class PublisherWidget(QWidget):
    add_publisher = Signal(str, str, float, bool)
    change_publisher = Signal(int, str, str, str, object)
    publish_once = Signal(int)
    remove_publisher = Signal(int)
    clean_up_publishers = Signal()

    def __init__(self, parent=None):
        super(PublisherWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_publisher'),
                               'resource', 'Publisher.ui')
        loadUi(
            ui_file, self, {
                'ExtendedComboBox': ExtendedComboBox,
                'PublisherTreeWidget': PublisherTreeWidget
            })
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_publisher_button.setIcon(QIcon.fromTheme('list-add'))
        self.remove_publisher_button.setIcon(QIcon.fromTheme('list-remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.publisher_tree_widget.model().item_value_changed.connect(
            self.change_publisher)
        self.publisher_tree_widget.remove_publisher.connect(
            self.remove_publisher)
        self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_publisher_button.clicked.connect(
            self.publisher_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_publishers)

    def shutdown_plugin(self):
        self._update_thread.kill()

    @Slot()
    def refresh_combo_boxes(self):
        self._update_thread.kill()
        self.type_combo_box.setEnabled(False)
        self.topic_combo_box.setEnabled(False)
        self.type_combo_box.setEditText('updating...')
        self.topic_combo_box.setEditText('updating...')
        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        # update type_combo_box
        message_type_names = []
        try:
            # this only works on fuerte and up
            packages = sorted([
                pkg_tuple[0] for pkg_tuple in rosmsg.iterate_packages(
                    self._rospack, rosmsg.MODE_MSG)
            ])
        except:
            # this works up to electric
            packages = sorted(rosmsg.list_packages())
        for package in packages:
            for base_type_str in rosmsg.list_msgs(package,
                                                  rospack=self._rospack):
                message_class = roslib.message.get_message_class(base_type_str)
                if message_class is not None:
                    message_type_names.append(base_type_str)

        self.type_combo_box.setItems.emit(sorted(message_type_names))

        # update topic_combo_box
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        self.topic_combo_box.setItems.emit(sorted(self._topic_dict.keys()))

    @Slot()
    def _update_finished(self):
        self.type_combo_box.setEnabled(True)
        self.topic_combo_box.setEnabled(True)

    @Slot(str)
    def on_topic_combo_box_currentIndexChanged(self, topic_name):
        if topic_name in self._topic_dict:
            self.type_combo_box.setEditText(self._topic_dict[topic_name])

    @Slot()
    def on_add_publisher_button_clicked(self):
        topic_name = str(self.topic_combo_box.currentText())
        type_name = str(self.type_combo_box.currentText())
        rate = float(self.frequency_combo_box.currentText())
        enabled = False
        self.add_publisher.emit(topic_name, type_name, rate, enabled)
コード例 #32
0
class WanderingFrame(QFrame):
    def __init__(self, parent=None):
        super(WanderingFrame, self).__init__(parent)
        self._ui = Ui_wandering_frame()
        self.bump_subscriber = rospy.Subscriber('/mobile_base/events/bumper',
                                                BumperEvent,
                                                self.bumper_event_callback)
        self._motion = SafeWandering('/mobile_base/commands/velocity', '/odom',
                                     '/mobile_base/events/bumper',
                                     '/mobile_base/events/cliff')
        self._motion_thread = None
        self._is_alive = False  # Used to indicate whether the frame is alive or not (see hibernate/restore methods)

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.speed_spinbox.value(), -0.1,
                          self._ui.angular_speed_spinbox.value())

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: wandering test shutdown")
        self._motion.shutdown()
        self.bump_subscriber.unregister()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch).
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass

    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def stop(self):
        self._motion.stop()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def _run_finished(self):
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._motion_thread = WorkerThread(self._motion.execute,
                                           self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self.stop()

    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self._ui.speed_spinbox.value(), -0.1,
                          self._ui.angular_speed_spinbox.value())

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self._ui.speed_spinbox.value(), -0.1,
                          self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # Ros Callbacks
    ##########################################################################
    def bumper_event_callback(self, msg):
        if msg.state == BumperEvent.PRESSED:
            if msg.bumper == BumperEvent.LEFT:
                self._ui.left_bump_counter_lcd.display(
                    self._ui.left_bump_counter_lcd.intValue() + 1)
            elif msg.bumper == BumperEvent.RIGHT:
                self._ui.right_bump_counter_lcd.display(
                    self._ui.right_bump_counter_lcd.intValue() + 1)
            else:
                self._ui.centre_bump_counter_lcd.display(
                    self._ui.centre_bump_counter_lcd.intValue() + 1)
コード例 #33
0
ファイル: conman.py プロジェクト: kuka-isir/conman
class Conman(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)
        self._widget.namespace_input.currentIndexChanged.connect(
            self._handle_refresh_clicked)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.refresh_button.clicked[bool].connect(
            self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(
            self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
        #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = {}
        self.groups = {}

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()

        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0, 4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0, 4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

        self.refresh_combo_box()

    def block_changed(self, item):
        row = item.row()
        name = self._blocks_model.item(row, 3).text()
        block = self.blocks[name]
        checked = item.checkState() == Qt.Checked

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        self._update_thread.kill()
        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 trigger_configuration(self):
    # Comment in to signal that the plugin has a way to configure
    # This will enable a setting button (gear icon) in each dock widget title bar
    # Usually used to open a modal configuration dialog

    @Slot()
    def refresh_combo_box(self):
        self._update_thread.kill()
        self._widget.namespace_input.setEnabled(False)
        self._widget.namespace_input.setEditText('updating...')
        self._update_thread.start()

    def _update_thread_run(self):
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        keys = list(self._topic_dict.keys())
        namespaces = list()
        for i in keys:
            if i.endswith("get_blocks_action/goal"):
                namespaces.append(i[0:i.index("get_blocks_action/goal")])

        self._widget.namespace_input.setItems.emit(namespaces)

    @Slot()
    def _update_finished(self):
        self._widget.namespace_input.setEnabled(True)

    def _get_result_cb(self, status, res):
        rospy.loginfo("got result!")
        self._blocks_model.setRowCount(0)
        self._blocks_model.setRowCount(len(res.blocks))

        for (i, block) in zip(range(len(res.blocks)), res.blocks):

            # Store in dict
            self.blocks[block.name] = block

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked if block.state.value == conman_msgs.
                             msg.TaskState.RUNNING else Qt.Unchecked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setTristate(True)

            action = QStandardItem(True)
            action.setText("")

            state = QStandardItem(True)
            state.setText(state_map[block.state.value])

            name = QStandardItem(True)
            name.setText(str(block.name))

            self._blocks_model.setItem(i, 0, cb)
            self._blocks_model.setItem(i, 1, action)
            self._blocks_model.setItem(i, 2, state)
            self._blocks_model.setItem(i, 3, name)

        for (i, group) in zip(range(len(res.groups)), res.groups):

            self.groups[group.name] = group

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setEnabled(False)

            name = QStandardItem(True)
            name.setText(str(group.name))

            self._groups_model.setItem(i, 0, cb)
            self._groups_model.setItem(i, 3, name)

        self._update_groups()
        self._update_blocks()

        self._widget.blocks_table.resizeColumnsToContents()
        self._widget.blocks_table.horizontalHeader().setStretchLastSection(
            True)
        self._widget.groups_table.resizeColumnsToContents()
        self._widget.groups_table.horizontalHeader().setStretchLastSection(
            True)

    def _update_blocks(self):

        for (name, block) in self.blocks.items():
            items = self._blocks_model.findItems(name, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue

            row = item.row()
            checked = self._blocks_model.item(row,
                                              0).checkState() == Qt.Checked
            if checked and block.state.value != conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row, 1).setText("ENABLE")
            elif not checked and block.state.value == conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row, 1).setText("DISABLE")
            else:
                self._blocks_model.item(row, 1).setText("")
        self._update_groups()

    def _enable_group(self, index, enable):
        name = self._groups_model.item(index, 3).text()
        group = self.groups[name]

        for member in group.members:
            items = self._blocks_model.findItems(member, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue

            row = item.row()
            self._blocks_model.item(
                row, 0).setCheckState(Qt.Checked if enable else Qt.Unchecked)

        self._update_blocks()

    def _update_groups(self):
        for (name, group) in self.groups.items():
            group_items = self._groups_model.findItems(name, column=3)
            if len(group_items) > 0:
                group_item = group_items[0]
            else:
                continue
            group_row = group_item.row()

            members_checked = []

            for member in group.members:
                items = self._blocks_model.findItems(member, column=3)
                if len(items) > 0:
                    item = items[0]
                else:
                    continue
                row = item.row()
                members_checked.append(
                    self._blocks_model.item(row, 0).checkState() == Qt.Checked)

            if all(members_checked):
                check = Qt.Checked
            else:
                check = Qt.Unchecked

            self._groups_model.item(group_row, 0).setCheckState(check)

    def _query_blocks(self):
        if self._get_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Getting blocks...")
                goal = conman_msgs.msg.GetBlocksGoal()
                goal.publish_flow_graph = self._widget.generate_graph_checkbox.isChecked(
                )
                self._get_blocks.send_goal(goal, done_cb=self._get_result_cb)

    def enable_widgets(self, enable):

        #self._widget.generate_graph_checkbox.setEnabled(enable)
        self._widget.force_enable_checkbox.setEnabled(enable)
        #self._widget.disable_unused_button.setEnabled(enable)
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.blocks_table.setEnabled(enable)
        self._widget.groups_table.setEnabled(enable)
        self._widget.regenerate_graph_button.setEnabled(enable)

    def _handle_refresh_clicked(self, checked):
        ns = self._widget.namespace_input.currentText()

        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)

                self._dotcode_sub = rospy.Subscriber(ns + '/dotcode',
                                                     std_msgs.msg.String,
                                                     self._dotcode_msg_cb)

                self._get_blocks = actionlib.SimpleActionClient(
                    ns + '/get_blocks_action', conman_msgs.msg.GetBlocksAction)

                self._set_blocks = actionlib.SimpleActionClient(
                    ns + '/set_blocks_action', conman_msgs.msg.SetBlocksAction)

                rospy.loginfo("Creating action clients on namespace '%s'..." %
                              ns)

                if not self._get_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." %
                                  self._get_blocks.action_client.ns)
                    return
                if not self._set_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." %
                                  self._set_blocks.action_client.ns)
                    return

                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

            self._query_blocks()

    def _handle_commit_clicked(self, checked):
        if self._set_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Setting blocks...")
                goal = conman_msgs.msg.SetBlocksGoal()
                goal.diff = True
                goal.force = True

                for i in range(self._blocks_model.rowCount()):
                    name = self._blocks_model.item(i, 3).text()
                    action = self._blocks_model.item(i, 1).text()

                    if action == 'DISABLE':
                        goal.disable.append(name)
                    elif action == 'ENABLE':
                        goal.enable.append(name)

                self._set_blocks.send_goal(goal,
                                           done_cb=self._get_set_result_cb)

    def _get_set_result_cb(self, status, res):

        self._query_blocks()

    @Slot(str)
    def _update_graph(self, dotcode):
        global initialized
        if initialized:
            self._widget.xdot_widget.set_dotcode(dotcode, center=False)
        else:
            self._widget.xdot_widget.set_dotcode(dotcode, center=True)
            self._widget.xdot_widget.zoom_to_fit()
            initialized = 1

    def _dotcode_msg_cb(self, msg):
        #self.new_dotcode_data = msg.data
        self.update_graph_sig.emit(msg.data)

    def _update_widgets(self):
        self._update_groups()
        self._update_blocks()
コード例 #34
0
class Smach(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Smach, self).__init__(context)

        self.initialized = 0

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        # Give QObjects reasonable names
        self.setObjectName('Smach')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'rqt_smach.ui')

        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)

        # Give QObjects reasonable names
        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('SmachPluginUi')

        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #Connect widgets with corresponding methods
        self._widget.namespace_input.currentIndexChanged.connect(
            self._handle_ns_changed)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.restrict_ns.clicked.connect(self.refresh_combo_box)
        self._widget.ud_path_input.currentIndexChanged.connect(
            self._handle_ud_path)
        self._widget.ud_set_initial.clicked.connect(self._handle_ud_set_path)
        self._widget.ud_text_browser.setReadOnly(1)
        self._widget.show_implicit_button.clicked.connect(
            self._handle_show_implicit)
        self._widget.help_button.setIcon(QIcon.fromTheme('help-contents'))
        self._widget.help_button.clicked.connect(self._handle_help)
        self._widget.tree.clicked.connect(self._handle_tree_clicked)

        #Depth and width spinners:
        self._widget.depth_input.setRange(-1, 1337)
        self._widget.depth_input.setValue(-1)
        self._widget.depth_input.valueChanged.connect(self._set_depth)

        self._widget.label_width_input.setRange(1, 1337)
        self._widget.label_width_input.setValue(40)
        self._widget.label_width_input.valueChanged.connect(self._set_width)

        self._widget.tree.setColumnCount(1)
        self._widget.tree.setHeaderLabels(["Containers"])
        self._widget.tree.show()

        self._ns = ""
        self.refresh_combo_box()

        # Bind path list
        self._widget.path_input.currentIndexChanged.connect(
            self._handle_path_changed)

        #Keep Combo Boxes sorted
        self._widget.namespace_input.setInsertPolicy(6)
        self._widget.path_input.setInsertPolicy(6)
        self._widget.ud_path_input.setInsertPolicy(6)

        #Set up mouse actions for xdot widget
        self._widget.xdot_widget.register_select_callback(self.select_cb)

        # Create graph data structures
        # Containers is a map of (container path) -> container proxy
        self._containers = {}
        self._top_containers = {}

        # smach introspection client
        self._client = smach_ros.IntrospectionClient()
        self._selected_paths = []

        # Message subscribers
        self._structure_subs = {}
        self._status_subs = {}

        # Initialize xdot display state
        self._path = '/'
        self._needs_zoom = True
        self._structure_changed = True
        self._max_depth = -1
        self._show_all_transitions = False
        self._label_wrapper = textwrap.TextWrapper(40, break_long_words=True)
        self._graph_needs_refresh = True
        self._tree_needs_refresh = True

        self._keep_running = True

        self._update_server_list()
        self._update_graph()
        self._update_tree()

        # Start a timer to update the server list
        self._server_timer = QTimer(self)
        self._server_timer.timeout.connect(self._update_server_list)
        self._server_timer.start(1000)

        # Start a timer to update the graph display
        self._graph_timer = QTimer(self)
        self._graph_timer.timeout.connect(self._update_graph)
        self._graph_timer.start(1093)

        # Start a timer to update the._widget.tree display
        self._tree_timer = QTimer(self)
        self._tree_timer.timeout.connect(self._update_tree)
        self._tree_timer.start(1217)

    def _handle_tree_clicked(self):
        selected = self._widget.tree.selectedItems()[0]
        path = "/" + str(selected.text(0))
        parent = selected.parent()
        while parent:
            path = "/" + str(parent.text(0)) + path
            parent = parent.parent()
        self._widget.ud_path_input.setCurrentIndex(
            self._widget.ud_path_input.findText(path))

    def _handle_help(self):
        """Event: Help button pressed"""
        helpMsg = QMessageBox()
        helpMsg.setWindowTitle("Keyboard Controls")
        helpMsg.setIcon(QMessageBox.Information)
        helpMsg.setText(
            "Pan: Arrow Keys\nZoom: PageUp / PageDown\nZoom To Fit: F\nRefresh: R"
        )
        ret = helpMsg.exec_()

    def select_cb(self, event):
        """Event: Click to select a graph node to display user data and update the graph."""
        # Only set string status
        x = event.x()
        y = event.y()
        url = self._widget.xdot_widget.get_url(x, y)

        if url is None:
            return

        item = self._widget.xdot_widget.items_by_url.get(url.url, None)

        if item:
            self._widget.status_bar.showMessage(item.url)
            # Left button-up

            if item.url not in self._containers:
                if ':' in item.url:
                    container_url = '/'.join(item.url.split(':')[:-1])
                else:
                    container_url = '/'.join(item.url.split('/')[:-1])
            else:
                container_url = item.url

            if event.button() == Qt.LeftButton:
                self._selected_paths = [item.url]
                self._widget.ud_path_input.setCurrentIndex(
                    self._widget.ud_path_input.findText(item.url))

        self._graph_needs_refresh = True

    def _handle_show_implicit(self):
        """Event: Show Implicit button checked"""
        self._show_all_transitions = not self._show_all_transitions
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def _set_depth(self):
        """Event: Depth value changed"""
        self._max_depth = self._widget.depth_input.value()
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def _set_width(self):
        """Event: Label Width value changed"""
        self._label_wrapper.width = self._widget.label_width_input.value()
        self._graph_needs_refresh = True

    def _handle_ud_set_path(self):
        """Event: Set as Initial State button pressed"""
        state_path = self._widget.ud_path_input.currentText()
        parent_path = get_parent_path(state_path)
        if len(parent_path) > 0:
            state = get_label(state_path)
            server_name = self._containers[parent_path]._server_name
            self._client.set_initial_state(server_name,
                                           parent_path, [state],
                                           timeout=rospy.Duration(60.0))
            self._structure_changed = True
            self._graph_needs_refresh = True
            if self._widget.zoom_checkbox.isChecked():
                self._needs_zoom = True

    def _handle_ud_path(self):
        """Event: User Data selection combo box changed"""
        path = self._widget.ud_path_input.currentText()
        #Check the path is non-zero length
        if len(path) > 0:
            # Get the container corresponding to this path, since userdata is
            # stored in the containers
            if path not in self._containers:
                parent_path = get_parent_path(path)
            else:
                parent_path = path

            if parent_path not in self._containers:
                parent_path = get_parent_path(parent_path)

            if parent_path in self._containers:
                # Get the container
                container = self._containers[parent_path]

                # Generate the userdata string
                ud_str = ''
                for (k, v) in container._local_data._data.iteritems():
                    ud_str += str(k) + ": "
                    vstr = str(v)
                    # Add a line break if this is a multiline value
                    if vstr.find('\n') != -1:
                        ud_str += '\n'
                    ud_str += vstr + '\n\n'
                #Display the user data
                self._widget.ud_text_browser.setPlainText(ud_str)
                self._widget.ud_text_browser.show()

    def _update_server_list(self):
        """Update the list of known SMACH introspection servers."""
        # Discover new servers
        if self._widget.restrict_ns.isChecked():
            server_names = [self._widget.namespace_input.currentText()[0:-1]]
            #self._status_subs = {}
        else:
            server_names = self._client.get_servers()

        new_server_names = [
            sn for sn in server_names if sn not in self._status_subs
        ]

        # Create subscribers for newly discovered servers
        for server_name in new_server_names:

            # Create a subscriber for the plan structure (topology) published by this server
            self._structure_subs[server_name] = rospy.Subscriber(
                server_name + smach_ros.introspection.STRUCTURE_TOPIC,
                SmachContainerStructure,
                callback=self._structure_msg_update,
                callback_args=server_name,
                queue_size=50)

            # Create a subscriber for the active states in the plan published by this server
            self._status_subs[server_name] = rospy.Subscriber(
                server_name + smach_ros.introspection.STATUS_TOPIC,
                SmachContainerStatus,
                callback=self._status_msg_update,
                queue_size=50)

    def _structure_msg_update(self, msg, server_name):
        """Update the structure of the SMACH plan (re-generate the dotcode)."""

        # Just return if we're shutting down
        if not self._keep_running:
            return

        # Get the node path
        path = msg.path
        pathsplit = path.split('/')
        parent_path = '/'.join(pathsplit[0:-1])

        rospy.logdebug("RECEIVED: " + path)
        rospy.logdebug("CONTAINERS: " + str(self._containers.keys()))

        # Initialize redraw flag
        needs_redraw = False

        # Determine if we need to update one of the proxies or create a new one
        if path in self._containers:
            rospy.logdebug("UPDATING: " + path)

            # Update the structure of this known container
            needs_redraw = self._containers[path].update_structure(msg)
        else:
            rospy.logdebug("CONSTRUCTING: " + path)

            # Create a new container
            container = ContainerNode(server_name, msg)
            self._containers[path] = container

            #Add items to ud path combo box
            if self._widget.ud_path_input.findText(path) == -1:
                self._widget.ud_path_input.addItem(path)

            for item in container._children:
                if self._widget.ud_path_input.findText(path + "/" +
                                                       item) == -1:
                    self._widget.ud_path_input.addItem(path + "/" + item)

            # Store this as a top container if it has no parent
            if parent_path == '':
                self._top_containers[path] = container

            # Append the path to the appropriate widgets
            self._append_new_path(path)

            # We need to redraw the graph if this container's parent is being viewed
            if path.find(self._widget.path_input.currentText()) == 0:
                needs_redraw = True

        if needs_redraw:
            self._structure_changed = True
            if self._widget.zoom_checkbox.isChecked():
                self._needs_zoom = True
            self._tree_needs_refresh = True
            self._graph_needs_refresh = True

    def _status_msg_update(self, msg):
        """Process status messages."""

        # Check if we're in the process of shutting down
        if not self._keep_running:
            return

        # Get the path to the updating conainer
        path = msg.path
        rospy.logdebug("STATUS MSG: " + path)

        # Check if this is a known container
        if path in self._containers:
            # Get the container and check if the status update requires regeneration
            container = self._containers[path]
            if container.update_status(msg):
                self._graph_needs_refresh = True
                self._tree_needs_refresh = True

    def _append_new_path(self, path):
        """Append a new path to the path selection widgets"""
        if ((not self._widget.restrict_ns.isChecked())
                or ((self._widget.restrict_ns.isChecked()) and
                    (self._widget.namespace_input.currentText() in path))
                or (path == self._widget.namespace_input.currentText()[0:-1])):
            self._widget.path_input.addItem(path)

    def _update_graph(self):
        """This thread continuously updates the graph when it changes.

        The graph gets updated in one of two ways:

          1: The structure of the SMACH plans has changed, or the display
          settings have been changed. In this case, the dotcode needs to be
          regenerated.

          2: The status of the SMACH plans has changed. In this case, we only
          need to change the styles of the graph.
        """
        if self._keep_running and self._graph_needs_refresh and not rospy.is_shutdown(
        ):
            # Get the containers to update
            containers_to_update = {}
            # Check if the path that's currently being viewed is in the
            # list of existing containers
            if self._path in self._containers:
                # Some non-root path
                containers_to_update = {
                    self._path: self._containers[self._path]
                }
            elif self._path == '/':
                # Root path
                containers_to_update = self._top_containers

            # Check if we need to re-generate the dotcode (if the structure changed)
            # TODO: needs_zoom is a misnomer
            if self._structure_changed or self._needs_zoom:
                dotstr = "digraph {\n\t"
                dotstr += ';'.join([
                    "compound=true",
                    "outputmode=nodesfirst",
                    "labeljust=l",
                    "nodesep=0.5",
                    "minlen=2",
                    "mclimit=5",
                    "clusterrank=local",
                    "ranksep=0.75",
                    # "remincross=true",
                    # "rank=sink",
                    "ordering=\"\"",
                ])
                dotstr += ";\n"

                # Generate the rest of the graph
                # TODO: Only re-generate dotcode for containers that have changed
                for path, container in containers_to_update.items():
                    dotstr += container.get_dotcode(self._selected_paths, [],
                                                    0, self._max_depth,
                                                    self._containers,
                                                    self._show_all_transitions,
                                                    self._label_wrapper)

                # The given path isn't available
                if len(containers_to_update) == 0:
                    dotstr += '"__empty__" [label="Path not available.", shape="plaintext"]'

                dotstr += '\n}\n'

                # Set the dotcode to the new dotcode, reset the flags
                self.set_dotcode(dotstr, zoom=False)
                self._structure_changed = False
                self._graph_needs_refresh = False

            # Update the styles for the graph if there are any updates
            for path, container in containers_to_update.items():
                container.set_styles(self._selected_paths, 0, self._max_depth,
                                     self._widget.xdot_widget.items_by_url,
                                     self._widget.xdot_widget.subgraph_shapes,
                                     self._containers)
            self._widget.xdot_widget.repaint()

    def set_dotcode(self, dotcode, zoom=True):
        """Set the xdot view's dotcode and refresh the display."""
        # Set the new dotcode
        if self._widget.xdot_widget.set_dotcode(dotcode, False):
            # Re-zoom if necessary
            if zoom or self._needs_zoom:
                self._widget.xdot_widget.zoom_to_fit()
                self._needs_zoom = False

    def _update_tree(self):
        """Update the tree view."""
        if self._keep_running and self._tree_needs_refresh and not rospy.is_shutdown(
        ):
            self._tree_nodes = {}
            self._widget.tree.clear()
            for path, tc in self._top_containers.iteritems():
                if ((not self._widget.restrict_ns.isChecked()) or
                    ((self._widget.restrict_ns.isChecked()) and
                     (self._widget.namespace_input.currentText() in path)) or
                    (path
                     == self._widget.namespace_input.currentText()[0:-1])):
                    self.add_to_tree(path, None)
            self._tree_needs_refresh = False
            self._widget.tree.sortItems(0, 0)

    def add_to_tree(self, path, parent):
        """Add a path to the tree view."""
        if parent is None:
            container = QTreeWidgetItem()
            container.setText(0, self._containers[path]._label)
            self._widget.tree.addTopLevelItem(container)
        else:
            container = QTreeWidgetItem(parent)
            container.setText(0, self._containers[path]._label)

        # Add children to_tree
        for label in self._containers[path]._children:
            child_path = '/'.join([path, label])
            if child_path in self._containers.keys():
                self.add_to_tree(child_path, container)
            else:
                child = QTreeWidgetItem(container)
                child.setText(0, label)

    def append_tree(self, container, parent=None):
        """Append an item to the tree view."""
        if not parent:
            node = QTreeWidgetItem()
            node.setText(0, container._label)
            self._widget.tree.addTopLevelItem(node)
            for child_label in container._children:
                child = QTreeWidgetItem(node)
                child.setText(0, child_label)

    def _update_thread_run(self):
        """Update the list of namespaces."""
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        keys = list(self._topic_dict.keys())
        namespaces = list()
        for i in keys:
            print i
            if i.endswith("smach/container_status"):
                namespaces.append(i[0:i.index("smach/container_status")])
        self._widget.namespace_input.setItems.emit(namespaces)

    @Slot()
    def _update_finished(self):
        """Enable namespace combo box."""
        self._widget.namespace_input.setEnabled(True)

    def _handle_ns_changed(self):
        """If namespace selection is changed then reinitialize everything."""
        ns = self._widget.namespace_input.currentText()
        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)
                rospy.loginfo("Creating action clients on namespace '%s'..." %
                              ns)
                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

                self._containers = {}
                self._top_containers = {}
                self._selected_paths = []

                self._structure_subs = {}
                self._status_subs = {}

                self._needs_zoom = True
                self._structure_changed = True
                self._max_depth = -1
                self._show_all_transitions = False
                self._graph_needs_refresh = True
                self._tree_needs_refresh = True
                #self._widget.namespace_input.clear()
                self._widget.path_input.clear()
                self._widget.ud_path_input.clear()
                self._widget.tree.clear()

    @Slot()
    def refresh_combo_box(self):
        """Refresh namespace combo box."""
        self._update_thread.kill()
        self._containers = {}
        self._top_containers = {}
        self._selected_paths = []

        self._structure_subs = {}
        self._status_subs = {}

        self._structure_changed = True
        self._tree_needs_refresh = True
        #self._graph_needs_refresh = True

        #self._widget.namespace_input.clear()
        self._widget.path_input.clear()
        self._widget.ud_path_input.clear()
        self._widget.tree.clear()
        if self._widget.restrict_ns.isChecked():
            self._widget.namespace_input.setEnabled(False)
            self._widget.namespace_input.setEditText('updating...')
            self._widget.ns_refresh_button.setEnabled(True)
            self._update_thread.start()
        else:
            self._widget.namespace_input.setEnabled(False)
            self._widget.namespace_input.setEditText('Unrestricted')
            self._widget.ns_refresh_button.setEnabled(False)
            self._graph_needs_refresh = True
            self._tree_needs_refresh = True
            self._widget.path_input.addItem('/')

    def _handle_path_changed(self, checked):
        """If the path input is changed, update graph."""
        self._path = self._widget.path_input.currentText()
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def enable_widgets(self, enable):
        """Enable all widgets."""
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.path_input.setEnabled(enable)
        self._widget.depth_input.setEnabled(enable)
        self._widget.label_width_input.setEnabled(enable)
        self._widget.ud_path_input.setEnabled(enable)
        self._widget.ud_text_browser.setEnabled(enable)
コード例 #35
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._state = CliffSensorFrame.STATE_FORWARD
     self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
     self._motion_thread.start()
コード例 #36
0
class LifeFrame(QFrame):
    STATE_STOPPED = "stopped"
    STATE_RUN = "running"
    STATE_IDLE = "idle"

    def __init__(self, parent=None):
        super(LifeFrame, self).__init__(parent)
        self._ui = Ui_life_frame()
        self._motion = Rotate('/mobile_base/commands/velocity')
        self._motion_thread = None
        self._timer = QTimer()
        #self._timer.setInterval(60000) #60s
        self._timer.setInterval(250)  #60s
        QObject.connect(self._timer, SIGNAL('timeout()'), self,
                        SLOT('update_progress_callback()'))
        self._state = LifeFrame.STATE_STOPPED
        self._is_alive = False  # Used to indicate whether the frame is alive or not (see hibernate/restore methods)

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.angular_speed_spinbox.value())

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: life frame shutdown")
        self._motion.shutdown()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass

    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def start(self):
        self._state = LifeFrame.STATE_RUN
        self._ui.run_progress.reset()
        self._ui.idle_progress.reset()
        self._motion_thread = WorkerThread(self._motion.execute, None)
        self._motion_thread.start()

    def stop(self):
        self._state = LifeFrame.STATE_STOPPED
        self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._timer.start()
        self.start()

    @Slot()
    def on_stop_button_clicked(self):
        self.stop()
        self._timer.stop()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        self._motion.init(self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # Timer Callbacks
    ##########################################################################

    @Slot()
    def update_progress_callback(self):
        if self._state == LifeFrame.STATE_RUN:
            new_value = self._ui.run_progress.value() + 1
            if new_value == self._ui.run_progress.maximum():
                print("  Switching to idle")
                self._motion.stop()
                self._state = LifeFrame.STATE_IDLE
            else:
                self._ui.run_progress.setValue(new_value)
        if self._state == LifeFrame.STATE_IDLE:
            new_value = self._ui.idle_progress.value() + 1
            if new_value == self._ui.idle_progress.maximum():
                print("  Switching to run")
                self.start()
            else:
                self._ui.idle_progress.setValue(new_value)
コード例 #37
0
class GyroDriftFrame(QFrame):
    def __init__(self, parent=None):
        super(GyroDriftFrame, self).__init__(parent)
        self._ui = Ui_gyro_drift_frame()
        self._laser_scan_angle_topic_name = "/laser_scan_angle"
        self._gyro_scan_angle_topic_name = "/gyro_scan_angle"
        self._error_scan_angle_topic_name = "/error_scan_angle"
        self._cmd_vel_topic_name = "/mobile_base/commands/velocity"
        self._gyro_topic_name = "/mobile_base/sensors/imu_data"
        self._motion = None
        self._scan_to_angle = None
        self._motion_thread = None

    def setupUi(self):
        self._ui.setupUi(self)
        self._plot_layout = QVBoxLayout(self._ui.scan_angle_group_box)
        self._plot_widget = PlotWidget()
        self._plot_widget.setWindowTitle("Error")
        self._plot_layout.addWidget(self._plot_widget)
        self._plot_widget.switch_data_plot_widget(FullSizeDataPlot(self._plot_widget))
        self._plot_widget.data_plot.dynamic_range = True
        self._plot_widget_live = PlotWidget()
        self._plot_widget_live.setWindowTitle("Live Graphs")
        self._plot_widget_live.switch_data_plot_widget(MatDataPlot(self._plot_widget_live))
        self._plot_layout.addWidget(self._plot_widget_live)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        """
          Used to terminate the plugin
        """
        rospy.loginfo("Kobuki TestSuite: gyro drift shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def _pause_plots(self):
        """
         Pause plots, more importantly, pause greedy plot rendering
        """
        self._plot_widget.enable_timer(False)
        self._plot_widget_live.enable_timer(False)

    def hibernate(self):
        """
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        """
        self._stop()

    def restore(self):
        """
          Restore the frame after a hibernate.
        """
        pass

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        if not self._scan_to_angle:
            self._scan_to_angle = ScanToAngle("/scan", self._laser_scan_angle_topic_name)
        if not self._motion:
            self._motion = DriftEstimation(
                self._laser_scan_angle_topic_name,
                self._gyro_scan_angle_topic_name,
                self._error_scan_angle_topic_name,
                self._cmd_vel_topic_name,
                self._gyro_topic_name,
            )
            self._motion.init(self._ui.angular_speed_spinbox.value())
        rospy.sleep(0.5)
        self._plot_widget.data_plot.reset()
        self._plot_widget._start_time = rospy.get_time()
        self._plot_widget.enable_timer(True)
        try:
            self._plot_widget.remove_topic(self._error_scan_angle_topic_name + "/scan_angle")
            self._plot_widget_live.remove_topic(self._laser_scan_angle_topic_name + "/scan_angle")
            self._plot_widget_live.remove_topic(self._gyro_scan_angle_topic_name + "/scan_angle")
            self._plot_widget_live.remove_topic(self._cmd_vel_topic_name + "/angular/z")
        except KeyError:
            pass
        self._plot_widget_live.add_topic(self._cmd_vel_topic_name + "/angular/z")
        self._plot_widget_live.add_topic(self._laser_scan_angle_topic_name + "/scan_angle")
        self._plot_widget_live.add_topic(self._gyro_scan_angle_topic_name + "/scan_angle")
        self._plot_widget.add_topic(self._error_scan_angle_topic_name + "/scan_angle")
        self._motion_thread = WorkerThread(self._motion.execute, None)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._stop()

    def _stop(self):
        self._pause_plots()
        if self._scan_to_angle:
            self._scan_to_angle.shutdown()
            self._scan_to_angle = None
        if self._motion:
            self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion.shutdown()
            self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.angular_speed_spinbox.value())
コード例 #38
0
class Smach(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Smach, self).__init__(context)

        self.initialized = 0

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        # Give QObjects reasonable names
        self.setObjectName('Smach')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rqt_smach.ui')

        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)

        # Give QObjects reasonable names
        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('SmachPluginUi')

        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette ()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #Connect widgets with corresponding methods
        self._widget.namespace_input.currentIndexChanged.connect(self._handle_ns_changed)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.restrict_ns.clicked.connect(self.refresh_combo_box)
        self._widget.ud_path_input.currentIndexChanged.connect(self._handle_ud_path)
        self._widget.ud_set_initial.clicked.connect(self._handle_ud_set_path)
        self._widget.ud_text_browser.setReadOnly(1)
        self._widget.show_implicit_button.clicked.connect(self._handle_show_implicit)
        self._widget.help_button.setIcon(QIcon.fromTheme('help-contents'))
        self._widget.help_button.clicked.connect(self._handle_help)
        self._widget.tree.clicked.connect(self._handle_tree_clicked)

        #Depth and width spinners:
        self._widget.depth_input.setRange(-1, 1337)
        self._widget.depth_input.setValue(-1)
        self._widget.depth_input.valueChanged.connect(self._set_depth)

        self._widget.label_width_input.setRange(1, 1337)
        self._widget.label_width_input.setValue(40)
        self._widget.label_width_input.valueChanged.connect(self._set_width)

        self._widget.tree.setColumnCount(1)
        self._widget.tree.setHeaderLabels(["Containers"])
        self._widget.tree.show()

        self._ns = ""
        self.refresh_combo_box()

        # Bind path list
        self._widget.path_input.currentIndexChanged.connect(
                self._handle_path_changed)

        #Keep Combo Boxes sorted
        self._widget.namespace_input.setInsertPolicy(6)
        self._widget.path_input.setInsertPolicy(6)
        self._widget.ud_path_input.setInsertPolicy(6)

        #Set up mouse actions for xdot widget
        self._widget.xdot_widget.register_select_callback(self.select_cb)

        # Create graph data structures
        # Containers is a map of (container path) -> container proxy
        self._containers = {}
        self._top_containers = {}

        # smach introspection client
        self._client = smach_ros.IntrospectionClient()
        self._selected_paths = []

        # Message subscribers
        self._structure_subs = {}
        self._status_subs = {}

        # Initialize xdot display state
        self._path = '/'
        self._needs_zoom = True
        self._structure_changed = True
        self._max_depth = -1
        self._show_all_transitions = False
        self._label_wrapper = textwrap.TextWrapper(40,break_long_words=True)
        self._graph_needs_refresh = True
        self._tree_needs_refresh = True

        self._keep_running = True

        self._update_server_list()
        self._update_graph()
        self._update_tree()

        # Start a timer to update the server list
        self._server_timer = QTimer(self)
        self._server_timer.timeout.connect(self._update_server_list)
        self._server_timer.start(1000)

        # Start a timer to update the graph display
        self._graph_timer = QTimer(self)
        self._graph_timer.timeout.connect(self._update_graph)
        self._graph_timer.start(1093)

        # Start a timer to update the._widget.tree display
        self._tree_timer = QTimer(self)
        self._tree_timer.timeout.connect(self._update_tree)
        self._tree_timer.start(1217)

    def _handle_tree_clicked(self):
        selected = self._widget.tree.selectedItems()[0]
        path = "/" + str(selected.text(0))
        parent = selected.parent()
        while parent:
            path = "/" + str(parent.text(0)) + path
            parent = parent.parent()
        self._widget.ud_path_input.setCurrentIndex(self._widget.ud_path_input.findText(path))

    def _handle_help(self):
        """Event: Help button pressed"""
        helpMsg = QMessageBox()
        helpMsg.setWindowTitle("Keyboard Controls")
        helpMsg.setIcon(QMessageBox.Information)
        helpMsg.setText("Pan: Arrow Keys\nZoom: PageUp / PageDown\nZoom To Fit: F\nRefresh: R")
        ret = helpMsg.exec_()

    def select_cb(self, event):
        """Event: Click to select a graph node to display user data and update the graph."""
        # Only set string status
        x = event.x()
        y = event.y()
        url = self._widget.xdot_widget.get_url(x,y)

        if url is None:
            return

        item = self._widget.xdot_widget.items_by_url.get(url.url, None)

        if item:
            self._widget.status_bar.showMessage(item.url)
            # Left button-up

            if item.url not in self._containers:
                if ':' in item.url:
                    container_url = '/'.join(item.url.split(':')[:-1])
                else:
                    container_url = '/'.join(item.url.split('/')[:-1])
            else:
                container_url = item.url

            if event.button() == Qt.LeftButton:
                self._selected_paths = [item.url]
                self._widget.ud_path_input.setCurrentIndex(self._widget.ud_path_input.findText(item.url))

        self._graph_needs_refresh = True

    def _handle_show_implicit(self):
        """Event: Show Implicit button checked"""
        self._show_all_transitions = not self._show_all_transitions
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def _set_depth(self):
        """Event: Depth value changed"""
        self._max_depth = self._widget.depth_input.value()
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def _set_width(self):
        """Event: Label Width value changed"""
        self._label_wrapper.width = self._widget.label_width_input.value()
        self._graph_needs_refresh = True

    def _handle_ud_set_path(self):
        """Event: Set as Initial State button pressed"""
        state_path = self._widget.ud_path_input.currentText()
        parent_path = get_parent_path(state_path)
        if len(parent_path) > 0:
            state = get_label(state_path)
            server_name = self._containers[parent_path]._server_name
            self._client.set_initial_state(server_name,parent_path,[state],timeout = rospy.Duration(60.0))
            self._structure_changed = True
            self._graph_needs_refresh = True
            if self._widget.zoom_checkbox.isChecked():
                self._needs_zoom = True

    def _handle_ud_path(self):
        """Event: User Data selection combo box changed"""
        path = self._widget.ud_path_input.currentText()
        #Check the path is non-zero length
        if len(path) > 0:
            # Get the container corresponding to this path, since userdata is
            # stored in the containers
            if path not in self._containers:
                parent_path = get_parent_path(path)
            else:
                parent_path = path

            if parent_path not in self._containers:
                parent_path = get_parent_path(parent_path)

            if parent_path in self._containers:
                # Get the container
                container = self._containers[parent_path]

                # Generate the userdata string
                ud_str = ''
                for (k,v) in container._local_data._data.iteritems():
                    ud_str += str(k)+": "
                    vstr = str(v)
                    # Add a line break if this is a multiline value
                    if vstr.find('\n') != -1:
                        ud_str += '\n'
                    ud_str+=vstr+'\n\n'
                #Display the user data
                self._widget.ud_text_browser.setPlainText(ud_str)
                self._widget.ud_text_browser.show()

    def _update_server_list(self):
        """Update the list of known SMACH introspection servers."""
        # Discover new servers
        if self._widget.restrict_ns.isChecked():
            server_names = [self._widget.namespace_input.currentText()[0:-1]]
            #self._status_subs = {}
        else:
            server_names = self._client.get_servers()

        new_server_names = [sn for sn in server_names if sn not in self._status_subs]

        # Create subscribers for newly discovered servers
        for server_name in new_server_names:

            # Create a subscriber for the plan structure (topology) published by this server
            self._structure_subs[server_name] = rospy.Subscriber(
                    server_name+smach_ros.introspection.STRUCTURE_TOPIC,
                    SmachContainerStructure,
                    callback = self._structure_msg_update,
                    callback_args = server_name,
                    queue_size=50)

            # Create a subscriber for the active states in the plan published by this server
            self._status_subs[server_name] = rospy.Subscriber(
                    server_name+smach_ros.introspection.STATUS_TOPIC,
                    SmachContainerStatus,
                    callback = self._status_msg_update,
                    queue_size=50)

    def _structure_msg_update(self, msg, server_name):
        """Update the structure of the SMACH plan (re-generate the dotcode)."""

        # Just return if we're shutting down
        if not self._keep_running:
            return

        # Get the node path
        path = msg.path
        pathsplit = path.split('/')
        parent_path = '/'.join(pathsplit[0:-1])

        rospy.logdebug("RECEIVED: "+path)
        rospy.logdebug("CONTAINERS: "+str(self._containers.keys()))

        # Initialize redraw flag
        needs_redraw = False

        # Determine if we need to update one of the proxies or create a new one
        if path in self._containers:
            rospy.logdebug("UPDATING: "+path)

            # Update the structure of this known container
            needs_redraw = self._containers[path].update_structure(msg)
        else:
            rospy.logdebug("CONSTRUCTING: "+path)

            # Create a new container
            container = ContainerNode(server_name, msg)
            self._containers[path] = container

            #Add items to ud path combo box
            if self._widget.ud_path_input.findText(path) == -1:
                self._widget.ud_path_input.addItem(path)

            for item in container._children:
                if self._widget.ud_path_input.findText(path+"/"+item) == -1:
                    self._widget.ud_path_input.addItem(path+"/"+item)

            # Store this as a top container if it has no parent
            if parent_path == '':
                self._top_containers[path] = container

            # Append the path to the appropriate widgets
            self._append_new_path(path)

            # We need to redraw the graph if this container's parent is being viewed
            if path.find(self._widget.path_input.currentText()) == 0:
                needs_redraw = True

        if needs_redraw:
            self._structure_changed = True
            if self._widget.zoom_checkbox.isChecked():
                self._needs_zoom = True
            self._tree_needs_refresh = True
            self._graph_needs_refresh = True

    def _status_msg_update(self, msg):
        """Process status messages."""

        # Check if we're in the process of shutting down
        if not self._keep_running:
            return

        # Get the path to the updating conainer
        path = msg.path
        rospy.logdebug("STATUS MSG: "+path)

        # Check if this is a known container
        if path in self._containers:
            # Get the container and check if the status update requires regeneration
            container = self._containers[path]
            if container.update_status(msg):
                self._graph_needs_refresh = True
                self._tree_needs_refresh = True

    def _append_new_path(self, path):
        """Append a new path to the path selection widgets"""
        if ((not self._widget.restrict_ns.isChecked()) or ((self._widget.restrict_ns.isChecked()) and (self._widget.namespace_input.currentText() in path)) or (path == self._widget.namespace_input.currentText()[0:-1])):
            self._widget.path_input.addItem(path)

    def _update_graph(self):
        """This thread continuously updates the graph when it changes.

        The graph gets updated in one of two ways:

          1: The structure of the SMACH plans has changed, or the display
          settings have been changed. In this case, the dotcode needs to be
          regenerated.

          2: The status of the SMACH plans has changed. In this case, we only
          need to change the styles of the graph.
        """
        if self._keep_running and self._graph_needs_refresh and not rospy.is_shutdown():
                # Get the containers to update
            containers_to_update = {}
            # Check if the path that's currently being viewed is in the
            # list of existing containers
            if self._path in self._containers:
                # Some non-root path
                containers_to_update = {self._path:self._containers[self._path]}
            elif self._path == '/':
                # Root path
                containers_to_update = self._top_containers

            # Check if we need to re-generate the dotcode (if the structure changed)
            # TODO: needs_zoom is a misnomer
            if self._structure_changed or self._needs_zoom:
                dotstr = "digraph {\n\t"
                dotstr += ';'.join([
                    "compound=true",
                    "outputmode=nodesfirst",
                    "labeljust=l",
                    "nodesep=0.5",
                    "minlen=2",
                    "mclimit=5",
                    "clusterrank=local",
                    "ranksep=0.75",
                    # "remincross=true",
                    # "rank=sink",
                    "ordering=\"\"",
                    ])
                dotstr += ";\n"

                # Generate the rest of the graph
                # TODO: Only re-generate dotcode for containers that have changed
                for path,container in containers_to_update.items():
                    dotstr += container.get_dotcode(
                            self._selected_paths,[],
                            0,self._max_depth,
                            self._containers,
                            self._show_all_transitions,
                            self._label_wrapper)

                # The given path isn't available
                if len(containers_to_update) == 0:
                    dotstr += '"__empty__" [label="Path not available.", shape="plaintext"]'

                dotstr += '\n}\n'

                # Set the dotcode to the new dotcode, reset the flags
                self.set_dotcode(dotstr,zoom=False)
                self._structure_changed = False
                self._graph_needs_refresh = False

            # Update the styles for the graph if there are any updates
            for path,container in containers_to_update.items():
                container.set_styles(
                        self._selected_paths,
                        0,self._max_depth,
                        self._widget.xdot_widget.items_by_url,
                        self._widget.xdot_widget.subgraph_shapes,
                        self._containers)
            self._widget.xdot_widget.repaint()

    def set_dotcode(self, dotcode, zoom=True):
        """Set the xdot view's dotcode and refresh the display."""
        # Set the new dotcode
        if self._widget.xdot_widget.set_dotcode(dotcode, False):
            # Re-zoom if necessary
            if zoom or self._needs_zoom:
                self._widget.xdot_widget.zoom_to_fit()
                self._needs_zoom = False

    def _update_tree(self):
        """Update the tree view."""
        if self._keep_running and self._tree_needs_refresh and not rospy.is_shutdown():
            self._tree_nodes = {}
            self._widget.tree.clear()
            for path,tc in self._top_containers.iteritems():
                if ((not self._widget.restrict_ns.isChecked()) or ((self._widget.restrict_ns.isChecked()) and (self._widget.namespace_input.currentText() in path)) or (path == self._widget.namespace_input.currentText()[0:-1])):
                    self.add_to_tree(path, None)
            self._tree_needs_refresh = False
            self._widget.tree.sortItems(0,0)

    def add_to_tree(self, path, parent):
        """Add a path to the tree view."""
        if parent is None:
            container = QTreeWidgetItem()
            container.setText(0, self._containers[path]._label)
            self._widget.tree.addTopLevelItem(container)
        else:
            container = QTreeWidgetItem(parent)
            container.setText(0, self._containers[path]._label)

        # Add children to_tree
        for label in self._containers[path]._children:
            child_path = '/'.join([path,label])
            if child_path in self._containers.keys():
                self.add_to_tree(child_path, container)
            else:
                child = QTreeWidgetItem(container)
                child.setText(0, label)

    def append_tree(self, container, parent = None):
        """Append an item to the tree view."""
        if not parent:
            node = QTreeWidgetItem()
            node.setText(0, container._label)
            self._widget.tree.addTopLevelItem(node)
            for child_label in container._children:
                child = QTreeWidgetItem(node)
                child.setText(0, child_label)

    def _update_thread_run(self):
        """Update the list of namespaces."""
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        keys = list(self._topic_dict.keys())
        namespaces = list()
        for i in keys:
            print i
            if i.endswith("smach/container_status"):
                namespaces.append(i[0:i.index("smach/container_status")])
        self._widget.namespace_input.setItems.emit(namespaces)

    @Slot()
    def _update_finished(self):
        """Enable namespace combo box."""
        self._widget.namespace_input.setEnabled(True)

    def _handle_ns_changed(self):
        """If namespace selection is changed then reinitialize everything."""
        ns = self._widget.namespace_input.currentText()
        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)
                rospy.loginfo("Creating action clients on namespace '%s'..." % ns)
                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

                self._containers = {}
                self._top_containers = {}
                self._selected_paths = []

                self._structure_subs = {}
                self._status_subs = {}

                self._needs_zoom = True
                self._structure_changed = True
                self._max_depth = -1
                self._show_all_transitions = False
                self._graph_needs_refresh = True
                self._tree_needs_refresh = True
                #self._widget.namespace_input.clear()
                self._widget.path_input.clear()
                self._widget.ud_path_input.clear()
                self._widget.tree.clear()

    @Slot()
    def refresh_combo_box(self):
        """Refresh namespace combo box."""
        self._update_thread.kill()
        self._containers = {}
        self._top_containers = {}
        self._selected_paths = []

        self._structure_subs = {}
        self._status_subs = {}

        self._structure_changed = True
        self._tree_needs_refresh = True
        #self._graph_needs_refresh = True

        #self._widget.namespace_input.clear()
        self._widget.path_input.clear()
        self._widget.ud_path_input.clear()
        self._widget.tree.clear()
        if self._widget.restrict_ns.isChecked():
            self._widget.namespace_input.setEnabled(False)
            self._widget.namespace_input.setEditText('updating...')
            self._widget.ns_refresh_button.setEnabled(True)
            self._update_thread.start()
        else:
            self._widget.namespace_input.setEnabled(False)
            self._widget.namespace_input.setEditText('Unrestricted')
            self._widget.ns_refresh_button.setEnabled(False)
            self._graph_needs_refresh = True
            self._tree_needs_refresh = True
            self._widget.path_input.addItem('/')

    def _handle_path_changed(self, checked):
        """If the path input is changed, update graph."""
        self._path = self._widget.path_input.currentText()
        self._graph_needs_refresh = True
        self._structure_changed = True
        if self._widget.zoom_checkbox.isChecked():
            self._needs_zoom = True

    def enable_widgets(self, enable):
        """Enable all widgets."""
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.path_input.setEnabled(enable)
        self._widget.depth_input.setEnabled(enable)
        self._widget.label_width_input.setEnabled(enable)
        self._widget.ud_path_input.setEnabled(enable)
        self._widget.ud_text_browser.setEnabled(enable)
コード例 #39
0
class AngularErrorFrame(QFrame):
    def __init__(self, parent=None):
        super(AngularErrorFrame, self).__init__(parent)
        self._cmd_vel_topic_name = '/sleo_velocity_controller/cmd_vel'
        self._rospack = rospkg.RosPack()
        angular_error_file = os.path.join(
            self._rospack.get_path('sleo_testsuite'), 'resource/ui',
            'angular_error.ui')
        loadUi(angular_error_file, self)
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)
        self._config = None
        self._table_config = None
        self._motion = None
        self._motion_thread = None

    def init(self, plot_config, _table_config):
        self._config = plot_config
        self._table_config = _table_config
        self._motion = AngularError(self._config.get_cmd_topic(),
                                    self._config.get_odom_topic())
        self._motion.init(self.angular_speed_spinbox.value(),
                          self.angular_spinbox.value(),
                          self.tolerance_spinBox.value())

    ##########################################################################
    # Motion Callbacks
    ##########################################################################
    def _run_finished(self):
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)

    def stop(self):
        self._motion.stop()
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)

    ###########################################################################
    # Qt callbacks
    ###########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)
        self._motion_thread = WorkerThread(self._motion.execute,
                                           self._run_finished)
        self._motion_thread.start()
        #rospy.loginfo("current:"+self._config.get_cmd_topic())
        self._motion.change_topic(self._config.get_cmd_topic(),
                                  self._config.get_odom_topic())
        self._config.run(False, False, True, False)
        #self._table_config.table()

    @Slot()
    def on_stop_button_clicked(self):
        self.stop()

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self.angular_speed_spinbox.value(),
                          self.angular_spinbox.value(),
                          self.tolerance_spinBox.value())

    @pyqtSlot(float)
    def on_angular_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self.angular_speed_spinbox.value(),
                          self.angular_spinbox.value(),
                          self.tolerance_spinBox.value())

    @pyqtSlot(float)
    def on_tolerance_spinBox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self.angular_speed_spinbox.value(),
                          self.angular_spinbox.value(),
                          self.tolerance_spinBox.value())

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Sleo TestSuite: Angular test shutdown")
        self._motion.shutdown()
コード例 #40
0
 def start(self):
     self._state = LifeFrame.STATE_RUN
     self._ui.run_progress.reset()
     self._ui.idle_progress.reset()
     self._motion_thread = WorkerThread(self._motion.execute, None)
     self._motion_thread.start()
コード例 #41
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
     self._motion_thread.start()
コード例 #42
0
class PublisherWidget(QWidget):
    add_publisher = Signal(str, str, float, bool)
    change_publisher = Signal(int, str, str, str, object)
    publish_once = Signal(int)
    remove_publisher = Signal(int)
    clean_up_publishers = Signal()

    def __init__(self, parent=None):
        super(PublisherWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_publisher'), 'resource', 'Publisher.ui')
        loadUi(ui_file, self, {'ExtendedComboBox': ExtendedComboBox, 'PublisherTreeWidget': PublisherTreeWidget})
        self.refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self.refresh_button.clicked.connect(self.refresh_combo_boxes)
        self.add_publisher_button.setIcon(QIcon.fromTheme('list-add'))
        self.remove_publisher_button.setIcon(QIcon.fromTheme('list-remove'))
        self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))

        self.refresh_combo_boxes()

        self.publisher_tree_widget.model().item_value_changed.connect(self.change_publisher)
        self.publisher_tree_widget.remove_publisher.connect(self.remove_publisher)
        self.publisher_tree_widget.publish_once.connect(self.publish_once)
        self.remove_publisher_button.clicked.connect(self.publisher_tree_widget.remove_selected_publishers)
        self.clear_button.clicked.connect(self.clean_up_publishers)

    def shutdown_plugin(self):
        self._update_thread.kill()

    @Slot()
    def refresh_combo_boxes(self):
        self._update_thread.kill()
        self.type_combo_box.setEnabled(False)
        self.topic_combo_box.setEnabled(False)
        self.type_combo_box.setEditText('updating...')
        self.topic_combo_box.setEditText('updating...')
        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        # update type_combo_box
        message_type_names = []
        try:
            # this only works on fuerte and up
            packages = sorted([pkg_tuple[0] for pkg_tuple in rosmsg.iterate_packages(self._rospack, rosmsg.MODE_MSG)])
        except:
            # this works up to electric
            packages = sorted(rosmsg.list_packages())
        for package in packages:
            for base_type_str in rosmsg.list_msgs(package, rospack=self._rospack):
                message_class = roslib.message.get_message_class(base_type_str)
                if message_class is not None:
                    message_type_names.append(base_type_str)

        self.type_combo_box.setItems.emit(sorted(message_type_names))

        # update topic_combo_box
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        self.topic_combo_box.setItems.emit(sorted(self._topic_dict.keys()))

    @Slot()
    def _update_finished(self):
        self.type_combo_box.setEnabled(True)
        self.topic_combo_box.setEnabled(True)

    @Slot(str)
    def on_topic_combo_box_currentIndexChanged(self, topic_name):
        if topic_name in self._topic_dict:
            self.type_combo_box.setEditText(self._topic_dict[topic_name])

    @Slot()
    def on_add_publisher_button_clicked(self):
        topic_name = str(self.topic_combo_box.currentText())
        type_name = str(self.type_combo_box.currentText())
        rate = float(self.frequency_combo_box.currentText())
        enabled = False
        self.add_publisher.emit(topic_name, type_name, rate, enabled)
コード例 #43
0
class WanderingFrame(QFrame):
    def __init__(self, parent=None):
        super(WanderingFrame, self).__init__(parent)
        self._ui = Ui_wandering_frame()
        self.bump_subscriber = rospy.Subscriber('/mobile_base/events/bumper', BumperEvent, self.bumper_event_callback)
        self._motion = SafeWandering('/mobile_base/commands/velocity','/odom', '/mobile_base/events/bumper', '/mobile_base/events/cliff')
        self._motion_thread = None
        self._is_alive = False # Used to indicate whether the frame is alive or not (see hibernate/restore methods)

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.speed_spinbox.value(), -0.1, self._ui.angular_speed_spinbox.value())

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: wandering test shutdown")
        self._motion.shutdown()
        self.bump_subscriber.unregister()

    ##########################################################################
    # Widget Management
    ##########################################################################
        
    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass
    
    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################


    def stop(self):
        self._motion.stop()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def _run_finished(self):
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._motion_thread = WorkerThread(self._motion.execute, self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self.stop()
        
    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self._ui.speed_spinbox.value(), -0.1, self._ui.angular_speed_spinbox.value())

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        # could use value, but easy to set like this
        self._motion.init(self._ui.speed_spinbox.value(), -0.1, self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # Ros Callbacks
    ##########################################################################
    def bumper_event_callback(self, msg):
        if msg.state == BumperEvent.PRESSED:
            if msg.bumper == BumperEvent.LEFT:
                self._ui.left_bump_counter_lcd.display(self._ui.left_bump_counter_lcd.intValue()+1)
            elif msg.bumper == BumperEvent.RIGHT:
                self._ui.right_bump_counter_lcd.display(self._ui.right_bump_counter_lcd.intValue()+1)
            else:
                self._ui.centre_bump_counter_lcd.display(self._ui.centre_bump_counter_lcd.intValue()+1)
コード例 #44
0
class GyroDriftFrame(QFrame):
    def __init__(self, parent=None):
        super(GyroDriftFrame, self).__init__(parent)
        self._ui = Ui_gyro_drift_frame()
        self._laser_scan_angle_topic_name = '/laser_scan_angle'
        self._gyro_scan_angle_topic_name = '/gyro_scan_angle'
        self._error_scan_angle_topic_name = '/error_scan_angle'
        self._cmd_vel_topic_name = '/mobile_base/commands/velocity'
        self._gyro_topic_name = '/mobile_base/sensors/imu_data'
        self._motion = None
        self._scan_to_angle = None
        self._motion_thread = None
        self._plot_widget = None
        self._plot_widget_live = None

    def setupUi(self):
        self._ui.setupUi(self)
        self._plot_layout = QVBoxLayout(self._ui.scan_angle_group_box)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: gyro drift shutdown")
        self._stop()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def _pause_plots(self):
        '''
         Pause plots, more importantly, pause greedy plot rendering
        '''
        if self._plot_widget:
            self._plot_widget.enable_timer(False)
        if self._plot_widget_live:
            self._plot_widget_live.enable_timer(False)

    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch).
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        self._stop()
        self._plot_layout.removeWidget(self._plot_widget)
        self._plot_layout.removeWidget(self._plot_widget_live)
        self._plot_widget = None
        self._plot_widget_live = None

    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        self._plot_widget = PlotWidget()
        self._plot_widget.setWindowTitle("Error")
        self._plot_layout.addWidget(self._plot_widget)
        self._plot_widget.switch_data_plot_widget(DataPlot(self._plot_widget))
        self._plot_widget.data_plot.dynamic_range = True
        self._plot_widget_live = PlotWidget()
        self._plot_widget_live.setWindowTitle("Live Graphs")
        self._plot_widget_live.switch_data_plot_widget(DataPlot(self._plot_widget_live))
        self._plot_layout.addWidget(self._plot_widget_live)

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        if not self._scan_to_angle:
            self._scan_to_angle = ScanToAngle('/scan',self._laser_scan_angle_topic_name)
        if not self._motion:
            self._motion = DriftEstimation(self._laser_scan_angle_topic_name, self._gyro_scan_angle_topic_name, self._error_scan_angle_topic_name, self._cmd_vel_topic_name,self._gyro_topic_name)
            self._motion.init(self._ui.angular_speed_spinbox.value())
        rospy.sleep(0.5)
        self._plot_widget._start_time = rospy.get_time()
        self._plot_widget.enable_timer(True)
        try:
            self._plot_widget.remove_topic(self._error_scan_angle_topic_name+'/scan_angle')
            self._plot_widget_live.remove_topic(self._laser_scan_angle_topic_name+'/scan_angle')
            self._plot_widget_live.remove_topic(self._gyro_scan_angle_topic_name+'/scan_angle')
            self._plot_widget_live.remove_topic(self._cmd_vel_topic_name+'/angular/z')
        except KeyError:
            pass
        self._plot_widget_live.add_topic(self._cmd_vel_topic_name+'/angular/z')
        self._plot_widget_live.add_topic(self._laser_scan_angle_topic_name+'/scan_angle')
        self._plot_widget_live.add_topic(self._gyro_scan_angle_topic_name+'/scan_angle')
        self._plot_widget.add_topic(self._error_scan_angle_topic_name+'/scan_angle')
        self._motion_thread = WorkerThread(self._motion.execute, None)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._stop()

    def _stop(self):
        self._pause_plots()
        if self._scan_to_angle:
            self._scan_to_angle.shutdown()
            self._scan_to_angle = None
        if self._motion:
            self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
            self._motion_thread = None
        if self._motion:
            self._motion.shutdown()
            self._motion = None
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        if self._motion:
            self._motion.init(self._ui.angular_speed_spinbox.value())
コード例 #45
0
ファイル: ros_pack_graph.py プロジェクト: bponsler/rqt_dep
class RosPackGraph(Plugin):

    _deferred_fit_in_view = Signal()

    def __init__(self, context):
        super(RosPackGraph, self).__init__(context)
        self.initialized = False
        self._current_dotcode = None
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        self._nodes = {}
        self._edges = {}
        self._options = {}
        self._options_serialized = ''

        self.setObjectName('RosPackGraph')

        rospack = rospkg.RosPack()
        rosstack = rospkg.RosStack()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        # generator builds rosgraph
        self.dotcode_generator = RosPackageGraphDotcodeGenerator(
            rospack, rosstack)
        # dot_to_qt transforms into Qt elements using dot layout
        self.dot_to_qt = DotToQtGenerator()

        self._widget = QWidget()
        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_dep'), 'resource',
                               'RosPackGraph.ui')
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('RosPackGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1)
        self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2)
        self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3)
        self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4)
        self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5)
        self._widget.depth_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0)
        self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'),
                                                     1)
        self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2)
        self._widget.directions_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        self._widget.package_type_combo_box.insertItem(0, self.tr('wet & dry'),
                                                       3)
        self._widget.package_type_combo_box.insertItem(1, self.tr('wet only'),
                                                       2)
        self._widget.package_type_combo_box.insertItem(2, self.tr('dry only'),
                                                       1)
        self._widget.package_type_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        completionmodel = StackageCompletionModel(
            self._widget.filter_line_edit, rospack, rosstack)
        completer = RepeatedWordCompleter(completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)

        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(
            self._refresh_rospackgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self._widget.filter_line_edit.selectionChanged.connect(
            self._clear_filter)

        self._widget.with_stacks_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.colorize_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.hide_transitives_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.show_system_check_box.clicked.connect(
            self._refresh_rospackgraph)

        self._widget.refresh_graph_push_button.setIcon(
            QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(
            self._update_rospackgraph)

        self._widget.highlight_connections_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.auto_fit_graph_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.fit_in_view_push_button.setIcon(
            QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(
            QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(
            QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(
            self._save_image)

        self._deferred_fit_in_view.connect(self._fit_in_view,
                                           Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()

        context.add_widget(self._widget)

        # If in either of following case, this turnes True
        # - 1st filtering key is already input by user
        # - filtering key is restored
        self._filtering_started = False

    def shutdown_plugin(self):
        self._update_thread.kill()

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(
            'depth_combo_box_index',
            self._widget.depth_combo_box.currentIndex())
        instance_settings.set_value(
            'directions_combo_box_index',
            self._widget.directions_combo_box.currentIndex())
        instance_settings.set_value(
            'package_type_combo_box',
            self._widget.package_type_combo_box.currentIndex())
        instance_settings.set_value('filter_line_edit_text',
                                    self._widget.filter_line_edit.text())
        instance_settings.set_value(
            'with_stacks_state',
            self._widget.with_stacks_check_box.isChecked())
        instance_settings.set_value(
            'hide_transitives_state',
            self._widget.hide_transitives_check_box.isChecked())
        instance_settings.set_value(
            'show_system_state',
            self._widget.show_system_check_box.isChecked())
        instance_settings.set_value('mark_state',
                                    self._widget.mark_check_box.isChecked())
        instance_settings.set_value(
            'colorize_state', self._widget.colorize_check_box.isChecked())
        instance_settings.set_value(
            'auto_fit_graph_check_box_state',
            self._widget.auto_fit_graph_check_box.isChecked())
        instance_settings.set_value(
            'highlight_connections_check_box_state',
            self._widget.highlight_connections_check_box.isChecked())

    def restore_settings(self, plugin_settings, instance_settings):
        _str_filter = instance_settings.value('filter_line_edit_text', '')
        if (_str_filter == None or _str_filter == '') and \
           not self._filtering_started:
            _str_filter = '(Separate pkgs by comma)'
        else:
            self._filtering_started = True

        self._widget.depth_combo_box.setCurrentIndex(
            int(instance_settings.value('depth_combo_box_index', 0)))
        self._widget.directions_combo_box.setCurrentIndex(
            int(instance_settings.value('directions_combo_box_index', 0)))
        self._widget.package_type_combo_box.setCurrentIndex(
            int(instance_settings.value('package_type_combo_box', 0)))
        self._widget.filter_line_edit.setText(_str_filter)
        self._widget.with_stacks_check_box.setChecked(
            instance_settings.value('with_stacks_state', True) in
            [True, 'true'])
        self._widget.mark_check_box.setChecked(
            instance_settings.value('mark_state', True) in [True, 'true'])
        self._widget.colorize_check_box.setChecked(
            instance_settings.value('colorize_state', False) in [True, 'true'])
        self._widget.hide_transitives_check_box.setChecked(
            instance_settings.value('hide_transitives_state', False) in
            [True, 'true'])
        self._widget.show_system_check_box.setChecked(
            instance_settings.value('show_system_state', False) in
            [True, 'true'])
        self._widget.auto_fit_graph_check_box.setChecked(
            instance_settings.value('auto_fit_graph_check_box_state', True) in
            [True, 'true'])
        self._widget.highlight_connections_check_box.setChecked(
            instance_settings.value('highlight_connections_check_box_state',
                                    True) in [True, 'true'])
        self.initialized = True
        self._refresh_rospackgraph()

    def _update_rospackgraph(self):
        # re-enable controls customizing fetched ROS graph
        self._widget.depth_combo_box.setEnabled(True)
        self._widget.directions_combo_box.setEnabled(True)
        self._widget.package_type_combo_box.setEnabled(True)
        self._widget.filter_line_edit.setEnabled(True)
        self._widget.with_stacks_check_box.setEnabled(True)
        self._widget.mark_check_box.setEnabled(True)
        self._widget.colorize_check_box.setEnabled(True)
        self._widget.hide_transitives_check_box.setEnabled(True)
        self._widget.show_system_check_box.setEnabled(True)

        self._refresh_rospackgraph(force_update=True)

    def _update_options(self):
        self._options['depth'] = self._widget.depth_combo_box.itemData(
            self._widget.depth_combo_box.currentIndex())
        self._options[
            'directions'] = self._widget.directions_combo_box.itemData(
                self._widget.directions_combo_box.currentIndex())
        self._options[
            'package_types'] = self._widget.package_type_combo_box.itemData(
                self._widget.package_type_combo_box.currentIndex())
        self._options[
            'with_stacks'] = self._widget.with_stacks_check_box.isChecked()
        self._options['mark_selected'] = self._widget.mark_check_box.isChecked(
        )
        self._options[
            'hide_transitives'] = self._widget.hide_transitives_check_box.isChecked(
            )
        self._options[
            'show_system'] = self._widget.show_system_check_box.isChecked()
        # TODO: Allow different color themes
        self._options[
            'colortheme'] = True if self._widget.colorize_check_box.isChecked(
            ) else None
        self._options['names'] = self._widget.filter_line_edit.text().split(
            ',')
        if self._options['names'] == [u'None']:
            self._options['names'] = []
        self._options[
            'highlight_level'] = 3 if self._widget.highlight_connections_check_box.isChecked(
            ) else 1
        self._options[
            'auto_fit'] = self._widget.auto_fit_graph_check_box.isChecked()

    def _refresh_rospackgraph(self, force_update=False):
        if not self.initialized:
            return

        self._update_thread.kill()

        self._update_options()

        # avoid update if options did not change and force_update is not set
        new_options_serialized = pickle.dumps(self._options)
        if new_options_serialized == self._options_serialized and not force_update:
            return
        self._options_serialized = pickle.dumps(self._options)

        self._scene.setBackgroundBrush(Qt.lightGray)

        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        self._update_graph(self._generate_dotcode())

    @Slot()
    def _update_finished(self):
        self._scene.setBackgroundBrush(Qt.white)
        self._redraw_graph_scene()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _generate_dotcode(self):
        includes = []
        excludes = []
        for name in self._options['names']:
            if name.strip().startswith('-'):
                excludes.append(name.strip()[1:])
            else:
                includes.append(name.strip())
        # orientation = 'LR'
        descendants = True
        ancestors = True
        if self._options['directions'] == 1:
            descendants = False
        if self._options['directions'] == 0:
            ancestors = False
        return self.dotcode_generator.generate_dotcode(
            dotcode_factory=self.dotcode_factory,
            selected_names=includes,
            excludes=excludes,
            depth=self._options['depth'],
            with_stacks=self._options['with_stacks'],
            descendants=descendants,
            ancestors=ancestors,
            mark_selected=self._options['mark_selected'],
            colortheme=self._options['colortheme'],
            hide_transitives=self._options['hide_transitives'],
            show_system=self._options['show_system'],
            hide_wet=self._options['package_types'] == 1,
            hide_dry=self._options['package_types'] == 2)

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_graph(self, dotcode):
        self._current_dotcode = dotcode
        self._nodes, self._edges = self.dot_to_qt.dotcode_to_qt_items(
            self._current_dotcode, self._options['highlight_level'])

    def _generate_tool_tip(self, url):
        if url is not None and ':' in url:
            item_type, item_path = url.split(':', 1)
            if item_type == 'node':
                tool_tip = 'Node:\n  %s' % (item_path)
                service_names = rosservice.get_service_list(node=item_path)
                if service_names:
                    tool_tip += '\nServices:'
                    for service_name in service_names:
                        try:
                            service_type = rosservice.get_service_type(
                                service_name)
                            tool_tip += '\n  %s [%s]' % (service_name,
                                                         service_type)
                        except rosservice.ROSServiceIOException as e:
                            tool_tip += '\n  %s' % (e)
                return tool_tip
            elif item_type == 'topic':
                topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
                return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
        return url

    def _redraw_graph_scene(self):
        # remove items in order to not garbage nodes which will be continued to be used
        for item in self._scene.items():
            self._scene.removeItem(item)
        self._scene.clear()
        for node_item in self._nodes.values():
            self._scene.addItem(node_item)
        for edge_items in self._edges.values():
            for edge_item in edge_items:
                edge_item.add_to_scene(self._scene)

        self._scene.setSceneRect(self._scene.itemsBoundingRect())
        if self._options['auto_fit']:
            self._fit_in_view()

    def _load_dot(self, file_name=None):
        if file_name is None:
            file_name, _ = QFileDialog.getOpenFileName(
                self._widget, self.tr('Open graph from file'), None,
                self.tr('DOT graph (*.dot)'))
            if file_name is None or file_name == '':
                return

        try:
            fh = open(file_name, 'rb')
            dotcode = fh.read()
            fh.close()
        except IOError:
            return

        # disable controls customizing fetched ROS graph
        self._widget.depth_combo_box.setEnabled(False)
        self._widget.directions_combo_box.setEnabled(False)
        self._widget.package_type_combo_box.setEnabled(False)
        self._widget.filter_line_edit.setEnabled(False)
        self._widget.with_stacks_check_box.setEnabled(False)
        self._widget.mark_check_box.setEnabled(False)
        self._widget.colorize_check_box.setEnabled(False)
        self._widget.hide_transitives_check_box.setEnabled(False)
        self._widget.show_system_check_box.setEnabled(False)

        self._update_graph(dotcode)
        self._redraw_graph_scene()

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

    def _save_dot(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as DOT'), 'rospackgraph.dot',
            self.tr('DOT graph (*.dot)'))
        if file_name is None or file_name == '':
            return

        handle = QFile(file_name)
        if not handle.open(QIODevice.WriteOnly | QIODevice.Text):
            return

        handle.write(self._current_dotcode)
        handle.close()

    def _save_svg(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as SVG'), 'rospackgraph.svg',
            self.tr('Scalable Vector Graphic (*.svg)'))
        if file_name is None or file_name == '':
            return

        generator = QSvgGenerator()
        generator.setFileName(file_name)
        generator.setSize((self._scene.sceneRect().size() * 2.0).toSize())

        painter = QPainter(generator)
        painter.setRenderHint(QPainter.Antialiasing)
        self._scene.render(painter)
        painter.end()

    def _save_image(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as image'), 'rospackgraph.png',
            self.tr('Image (*.bmp *.jpg *.png *.tiff)'))
        if file_name is None or file_name == '':
            return

        img = QImage((self._scene.sceneRect().size() * 2.0).toSize(),
                     QImage.Format_ARGB32_Premultiplied)
        painter = QPainter(img)
        painter.setRenderHint(QPainter.Antialiasing)
        self._scene.render(painter)
        painter.end()
        img.save(file_name)

    def _clear_filter(self):
        if not self._filtering_started:
            self._widget.filter_line_edit.setText('')
            self._filtering_started = True
コード例 #46
0
class CliffSensorFrame(QFrame):
    STATE_FORWARD = "forward"
    STATE_BACKWARD = "backward"
    STATE_STOPPED = "stopped"

    def __init__(self, parent=None):
        super(CliffSensorFrame, self).__init__(parent)
        self._ui = Ui_cliff_sensor_frame()
        self._motion = TravelForward('/mobile_base/commands/velocity', '/odom',
                                     '/mobile_base/events/cliff')
        self._motion_thread = None
        self._distance = 1.2
        self._state = CliffSensorFrame.STATE_FORWARD
        self._is_alive = False  # Used to indicate whether the frame is alive or not (see hibernate/restore methods)

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.speed_spinbox.value(), self._distance)

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: cliff sensor shutdown")
        self._motion.shutdown()

    ##########################################################################
    # Widget Management
    ##########################################################################

    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass

    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass

    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def _run_finished(self):
        if self._state == CliffSensorFrame.STATE_STOPPED:
            return
        elif self._state == CliffSensorFrame.STATE_FORWARD:
            self._state = CliffSensorFrame.STATE_BACKWARD
            self._motion.init(-self._motion.speed, 0.2)
            self._motion_thread = WorkerThread(self._motion.execute,
                                               self._run_finished)
            self._motion_thread.start()
        else:
            self._state = CliffSensorFrame.STATE_FORWARD
            self._motion.init(-self._motion.speed, self._distance)
            self._motion_thread = WorkerThread(self._motion.execute,
                                               self._run_finished)
            self._motion_thread.start()

    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._state = CliffSensorFrame.STATE_FORWARD
        self._motion_thread = WorkerThread(self._motion.execute,
                                           self._run_finished)
        self._motion_thread.start()

    @Slot()
    def on_stop_button_clicked(self):
        self._state = CliffSensorFrame.STATE_STOPPED
        self.stop()

    def stop(self):
        self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)

    @pyqtSlot(float)
    def on_speed_spinbox_valueChanged(self, value):
        self._motion.init(self._ui.speed_spinbox.value(), self._distance)
コード例 #47
0
 def on_start_button_clicked(self):
     self._ui.start_button.setEnabled(False)
     self._ui.stop_button.setEnabled(True)
     self._motion_thread = WorkerThread(self._motion.execute,
                                        self._run_finished)
     self._motion_thread.start()
コード例 #48
0
ファイル: ros_pack_graph.py プロジェクト: bponsler/rqt_dep
    def __init__(self, context):
        super(RosPackGraph, self).__init__(context)
        self.initialized = False
        self._current_dotcode = None
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        self._nodes = {}
        self._edges = {}
        self._options = {}
        self._options_serialized = ''

        self.setObjectName('RosPackGraph')

        rospack = rospkg.RosPack()
        rosstack = rospkg.RosStack()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        # generator builds rosgraph
        self.dotcode_generator = RosPackageGraphDotcodeGenerator(
            rospack, rosstack)
        # dot_to_qt transforms into Qt elements using dot layout
        self.dot_to_qt = DotToQtGenerator()

        self._widget = QWidget()
        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_dep'), 'resource',
                               'RosPackGraph.ui')
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('RosPackGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1)
        self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2)
        self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3)
        self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4)
        self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5)
        self._widget.depth_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0)
        self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'),
                                                     1)
        self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2)
        self._widget.directions_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        self._widget.package_type_combo_box.insertItem(0, self.tr('wet & dry'),
                                                       3)
        self._widget.package_type_combo_box.insertItem(1, self.tr('wet only'),
                                                       2)
        self._widget.package_type_combo_box.insertItem(2, self.tr('dry only'),
                                                       1)
        self._widget.package_type_combo_box.currentIndexChanged.connect(
            self._refresh_rospackgraph)

        completionmodel = StackageCompletionModel(
            self._widget.filter_line_edit, rospack, rosstack)
        completer = RepeatedWordCompleter(completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)

        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(
            self._refresh_rospackgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self._widget.filter_line_edit.selectionChanged.connect(
            self._clear_filter)

        self._widget.with_stacks_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph)
        self._widget.colorize_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.hide_transitives_check_box.clicked.connect(
            self._refresh_rospackgraph)
        self._widget.show_system_check_box.clicked.connect(
            self._refresh_rospackgraph)

        self._widget.refresh_graph_push_button.setIcon(
            QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(
            self._update_rospackgraph)

        self._widget.highlight_connections_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.auto_fit_graph_check_box.toggled.connect(
            self._refresh_rospackgraph)
        self._widget.fit_in_view_push_button.setIcon(
            QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(
            QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(
            QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(
            self._save_image)

        self._deferred_fit_in_view.connect(self._fit_in_view,
                                           Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()

        context.add_widget(self._widget)

        # If in either of following case, this turnes True
        # - 1st filtering key is already input by user
        # - filtering key is restored
        self._filtering_started = False
コード例 #49
0
    def __init__(self, context):
        super(Smach, self).__init__(context)

        self.initialized = 0

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)

        # Give QObjects reasonable names
        self.setObjectName('Smach')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'rqt_smach.ui')

        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)

        # Give QObjects reasonable names
        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('SmachPluginUi')

        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #Connect widgets with corresponding methods
        self._widget.namespace_input.currentIndexChanged.connect(
            self._handle_ns_changed)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.restrict_ns.clicked.connect(self.refresh_combo_box)
        self._widget.ud_path_input.currentIndexChanged.connect(
            self._handle_ud_path)
        self._widget.ud_set_initial.clicked.connect(self._handle_ud_set_path)
        self._widget.ud_text_browser.setReadOnly(1)
        self._widget.show_implicit_button.clicked.connect(
            self._handle_show_implicit)
        self._widget.help_button.setIcon(QIcon.fromTheme('help-contents'))
        self._widget.help_button.clicked.connect(self._handle_help)
        self._widget.tree.clicked.connect(self._handle_tree_clicked)

        #Depth and width spinners:
        self._widget.depth_input.setRange(-1, 1337)
        self._widget.depth_input.setValue(-1)
        self._widget.depth_input.valueChanged.connect(self._set_depth)

        self._widget.label_width_input.setRange(1, 1337)
        self._widget.label_width_input.setValue(40)
        self._widget.label_width_input.valueChanged.connect(self._set_width)

        self._widget.tree.setColumnCount(1)
        self._widget.tree.setHeaderLabels(["Containers"])
        self._widget.tree.show()

        self._ns = ""
        self.refresh_combo_box()

        # Bind path list
        self._widget.path_input.currentIndexChanged.connect(
            self._handle_path_changed)

        #Keep Combo Boxes sorted
        self._widget.namespace_input.setInsertPolicy(6)
        self._widget.path_input.setInsertPolicy(6)
        self._widget.ud_path_input.setInsertPolicy(6)

        #Set up mouse actions for xdot widget
        self._widget.xdot_widget.register_select_callback(self.select_cb)

        # Create graph data structures
        # Containers is a map of (container path) -> container proxy
        self._containers = {}
        self._top_containers = {}

        # smach introspection client
        self._client = smach_ros.IntrospectionClient()
        self._selected_paths = []

        # Message subscribers
        self._structure_subs = {}
        self._status_subs = {}

        # Initialize xdot display state
        self._path = '/'
        self._needs_zoom = True
        self._structure_changed = True
        self._max_depth = -1
        self._show_all_transitions = False
        self._label_wrapper = textwrap.TextWrapper(40, break_long_words=True)
        self._graph_needs_refresh = True
        self._tree_needs_refresh = True

        self._keep_running = True

        self._update_server_list()
        self._update_graph()
        self._update_tree()

        # Start a timer to update the server list
        self._server_timer = QTimer(self)
        self._server_timer.timeout.connect(self._update_server_list)
        self._server_timer.start(1000)

        # Start a timer to update the graph display
        self._graph_timer = QTimer(self)
        self._graph_timer.timeout.connect(self._update_graph)
        self._graph_timer.start(1093)

        # Start a timer to update the._widget.tree display
        self._tree_timer = QTimer(self)
        self._tree_timer.timeout.connect(self._update_tree)
        self._tree_timer.start(1217)
コード例 #50
0
class LifeFrame(QFrame):
    STATE_STOPPED = "stopped"
    STATE_RUN = "running"
    STATE_IDLE = "idle"
    
    def __init__(self, parent=None):
        super(LifeFrame, self).__init__(parent)
        self._ui = Ui_life_frame()
        self._motion = Rotate('/mobile_base/commands/velocity')
        self._motion_thread = None
        self._timer = QTimer()
        #self._timer.setInterval(60000) #60s
        self._timer.setInterval(250) #60s
        QObject.connect(self._timer, SIGNAL('timeout()'), self, SLOT('update_progress_callback()'))
        self._state = LifeFrame.STATE_STOPPED
        self._is_alive = False # Used to indicate whether the frame is alive or not (see hibernate/restore methods)

    def setupUi(self):
        self._ui.setupUi(self)
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        self._motion.init(self._ui.angular_speed_spinbox.value())

    def shutdown(self):
        '''
          Used to terminate the plugin
        '''
        rospy.loginfo("Kobuki TestSuite: life frame shutdown")
        self._motion.shutdown()

    ##########################################################################
    # Widget Management
    ##########################################################################
        
    def hibernate(self):
        '''
          This gets called when the frame goes out of focus (tab switch). 
          Disable everything to avoid running N tabs in parallel when in
          reality we are only running one.
        '''
        pass
    
    def restore(self):
        '''
          Restore the frame after a hibernate.
        '''
        pass


    ##########################################################################
    # Motion Callbacks
    ##########################################################################

    def start(self):
        self._state = LifeFrame.STATE_RUN
        self._ui.run_progress.reset()
        self._ui.idle_progress.reset()
        self._motion_thread = WorkerThread(self._motion.execute, None)
        self._motion_thread.start()

    def stop(self):
        self._state = LifeFrame.STATE_STOPPED
        self._motion.stop()
        if self._motion_thread:
            self._motion_thread.wait()
        
    ##########################################################################
    # Qt Callbacks
    ##########################################################################
    @Slot()
    def on_start_button_clicked(self):
        self._ui.start_button.setEnabled(False)
        self._ui.stop_button.setEnabled(True)
        self._timer.start()
        self.start()
        
    @Slot()
    def on_stop_button_clicked(self):
        self.stop()
        self._timer.stop()
        self._ui.start_button.setEnabled(True)
        self._ui.stop_button.setEnabled(False)
        
    @pyqtSlot(float)
    def on_angular_speed_spinbox_valueChanged(self, value):
        self._motion.init(self._ui.angular_speed_spinbox.value())

    ##########################################################################
    # Timer Callbacks
    ##########################################################################

    @Slot()
    def update_progress_callback(self):
        if self._state == LifeFrame.STATE_RUN:
            new_value = self._ui.run_progress.value()+1
            if new_value == self._ui.run_progress.maximum():
                print("  Switching to idle")
                self._motion.stop()
                self._state = LifeFrame.STATE_IDLE
            else:
                self._ui.run_progress.setValue(new_value)
        if self._state == LifeFrame.STATE_IDLE:
            new_value = self._ui.idle_progress.value()+1
            if new_value == self._ui.idle_progress.maximum():
                print("  Switching to run")
                self.start()
            else:
                self._ui.idle_progress.setValue(new_value)
コード例 #51
0
 def start(self):
     self._state = LifeFrame.STATE_RUN
     self._ui.run_progress.reset()
     self._ui.idle_progress.reset()
     self._motion_thread = WorkerThread(self._motion.execute, None)
     self._motion_thread.start()
コード例 #52
0
class MsgEditorWidget(QWidget):
    msg_type_changed = Signal(str)
    change_message = Signal(int, str, str, str, object)
    clean  = Signal()
    accept = Signal()
    cancel = Signal()

    def __init__(self, parent=None):
        super(MsgEditorWidget, self).__init__(parent)
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run, self._update_finished)

        self._rospack = rospkg.RosPack()
        ui_file = os.path.join(self._rospack.get_path('rqt_annotation_data'), 'resource', 'MsgEditor.ui')
        loadUi(ui_file, self, {'ExtendedComboBox': ExtendedComboBox, 'MessageTreeWidget': MessageTreeWidget})

        self.refresh_combo_boxes()

        self.message_tree_widget.model().item_value_changed.connect(self.change_message)
        self.clear_button.clicked.connect(self.clean)

    def shutdown_plugin(self):
        self._update_thread.kill()

    @Slot()
    def refresh_combo_boxes(self):
        self._update_thread.kill()
        self.msg_type_combo_box.setEnabled(False)
        self.msg_type_combo_box.setEditText('updating...')
        self._update_thread.start()

    # this runs in a non-gui thread, so don't access widgets here directly
    def _update_thread_run(self):
        # update msg_type_combo_box
        message_type_names = []
        try:
            # this only works on fuerte and up
            packages = sorted([pkg_tuple[0] for pkg_tuple in rosmsg.iterate_packages(self._rospack, rosmsg.MODE_MSG)])
        except:
            # this works up to electric
            packages = sorted(rosmsg.list_packages())
        for package in packages:
            for base_type_str in rosmsg.list_msgs(package, rospack=self._rospack):
                message_class = roslib.message.get_message_class(base_type_str)
                if message_class is not None:
                    message_type_names.append(base_type_str)

        if hasattr(self, 'prev_type_name'):
            del self.prev_type_name
        message_type_names.append('') # null message type at first
        self.msg_type_combo_box.setItems.emit(sorted(message_type_names))

        # update topic_combo_box
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)

    @Slot()
    def _update_finished(self):
        self.msg_type_combo_box.setEnabled(True)

    @Slot(str)
    def on_msg_type_combo_box_currentIndexChanged(self, type_name):
        self.msg_type_changed.emit(type_name)
        self.prev_type_name = str(self.msg_type_combo_box.currentText())

    @Slot()
    def on_accept_button_clicked(self):
        self.accept.emit()

    def on_cancel_button_clicked(self):
        self.cancel.emit()