예제 #1
0
    def __init__(self, parent):
        super(NodeSelection, self).__init__()
        self.parent_widget = parent
        self.selected_nodes = []
        self.setWindowTitle("Select the nodes you want to record")
        self.resize(300, 300)
        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Done", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)
        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)

        self.node_list = rosnode.get_node_names()
        self.node_list.sort()
        for node in self.node_list:
            # add planner node by choosing agent number
            if "planner" not in node:
                self.addCheckBox(node)

        self.main_widget.setLayout(self.selection_vlayout)
        self.area.setWidget(self.main_widget)

        self.show()
예제 #2
0
    def __init__(self):
        super(TopicSelection, self).__init__()
        master = rosgraph.Master('rqt_bag_recorder')
        self.setWindowTitle("Select the topics you want to record")
        self.resize(500, 700)

        self.topic_list = []
        self.selected_topics = []
        self.items_list = []

        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Record", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)

        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)
        self.item_all = QCheckBox("All", self)
        self.item_all.stateChanged.connect(self.updateList)
        self.selection_vlayout.addWidget(self.item_all)
        topic_data_list = master.getPublishedTopics('')
        topic_data_list.sort()
        for topic, datatype in topic_data_list:
            self.addCheckBox(topic)

        self.main_widget.setLayout(self.selection_vlayout)

        self.area.setWidget(self.main_widget)
        self.show()
예제 #3
0
    def __init__(self):
        super(PostProcMainWidget, self).__init__()

        # init the GUI components:
        self.bagWidget = BagWidget(self)
        self.bagFiles = self.bagWidget.getBagFiles()
        self.plotWidget = PlotWidget(self.bagFiles, self)
        self.__addPlotBtn = QPushButton("Add new Graph")
        self.__delPlotBtn = QPushButton("Delete Graph")
        self.__qualityBtn = QPushButton("Compute Data Quality")

        # connect signals to slots:
        self.__addPlotBtn.clicked.connect(self.openNewGraphDialog)
        self.__delPlotBtn.clicked.connect(self.openDelGraphDialog)
        self.__qualityBtn.clicked.connect(self.openQualityDialog)

        # setup the layout:
        layout = QGridLayout()
        # (rowIndex, rowStretch)
        layout.setRowStretch(
            0, 0)  # controls behavior when changing the window size
        # (widget, fromRow, fromColumn, rowSpan, columnSpan)
        layout.addWidget(self.bagWidget, 0, 0, 1, 3)
        layout.setRowStretch(1, 0)

        layout.addWidget(self.__addPlotBtn, 1, 0, 1, 1)
        layout.addWidget(self.__delPlotBtn, 1, 1, 1, 1)
        layout.addWidget(self.__qualityBtn, 1, 2, 1, 1)

        layout.setRowStretch(2, 1)
        layout.addWidget(self.plotWidget, 2, 0, 1, 3)

        self.setLayout(layout)
예제 #4
0
    def __init__(self):
        QWidget.__init__(self)
        self._status = "unknown"
        self._layout = QGridLayout(self)
        self._widgets = dict()

        self.__logging_cb_signal.connect(self.logging_cb)
        self.__start_logging_signal.connect(self.start_logging)
        self.__stop_logging_signal.connect(self.stop_logging)
        self._add_widget("pid_label", QLabel("PID:", self))
        self._add_widget("pid", QLineEdit(self))
        self._widgets["pid"].setMaximumWidth(50)

        self._add_widget("label_status", QLabel(self))
        self._widgets["label_status"].setText("Status: Unknown")
        self._widgets["label_status"].setTextFormat(QtCore.Qt.RichText)
        self._add_widget("button_start", QPushButton("START", self))
        self._add_widget("button_stop", QPushButton("STOP", self))
        self._widgets["button_start"].clicked.connect(
            self.__start_logging_signal.emit)
        self._widgets["button_stop"].clicked.connect(
            self.__stop_logging_signal.emit)

        self._widgets["label_warning"] = QLabel(self)
        self._layout.addWidget(self._widgets["label_warning"], 1, 0, 1, 2)
        self._widgets["label_warning"].setTextFormat(QtCore.Qt.RichText)

        rospy.Subscriber("/data_logger/status", String,
                         self.__logging_cb_signal.emit)
        self._logging_start = rospy.ServiceProxy('/data_logger/start',
                                                 DataLoggerStart)
        self._logging_stop = rospy.ServiceProxy('/data_logger/stop',
                                                DataLoggerStop)
    def __init__(self, reconf, node_name):
        """
        :type reconf: dynamic_reconfigure.client
        :type node_name: str
        """

        group_desc = reconf.get_group_descriptions()
        rospy.logdebug('DynreconfClientWidget.group_desc=%s', group_desc)
        super(DynreconfClientWidget, self).__init__(ParamUpdater(reconf),
                                                    group_desc, node_name)

        # Save and load buttons
        self.button_widget = QWidget(self)
        self.button_header = QHBoxLayout(self.button_widget)
        self.button_header.setContentsMargins(QMargins(0, 0, 0, 0))

        self.load_button = QPushButton()
        self.save_button = QPushButton()

        self.load_button.setIcon(QIcon.fromTheme('document-open'))
        self.save_button.setIcon(QIcon.fromTheme('document-save'))

        self.load_button.clicked[bool].connect(self._handle_load_clicked)
        self.save_button.clicked[bool].connect(self._handle_save_clicked)

        self.button_header.addWidget(self.save_button)
        self.button_header.addWidget(self.load_button)

        self.setMinimumWidth(150)

        self.reconf = reconf
        self.updater.start()
        self.reconf.config_callback = self.config_callback
        self._node_grn = node_name
예제 #6
0
    def __init__(self, map_topic='/map', paths=None, polygons=None):
        super(NavViewWidget, self).__init__()
        if paths is None:
            paths = [
                '/move_base/NavFn/plan',
                '/move_base/TrajectoryPlannerROS/local_plan'
            ]
        if polygons is None:
            polygons = ['/move_base/local_costmap/robot_footprint']

        self._layout = QVBoxLayout()
        self._button_layout = QHBoxLayout()

        self.setAcceptDrops(True)
        self.setWindowTitle('Navigation Viewer')

        self.paths = paths
        self.polygons = polygons
        self.map_topic = map_topic
        self._tf = tf.TransformListener()

        self._set_pose = QPushButton('Set Pose')
        self._set_goal = QPushButton('Set Goal')

        self._button_layout.addWidget(self._set_pose)
        self._button_layout.addWidget(self._set_goal)

        self._layout.addLayout(self._button_layout)

        self._nav_view = None

        self.setLayout(self._layout)
예제 #7
0
    def __init__(self, parent=None, current_values=None):
        super(BlacklistDialog, self).__init__(parent)
        self.setWindowTitle("Blacklist")
        vbox = QVBoxLayout()
        self.setLayout(vbox)

        self._blacklist = Blacklist()
        if isinstance(current_values, list):
            for val in current_values:
                self._blacklist.append(val)
        vbox.addWidget(self._blacklist)

        controls_layout = QHBoxLayout()
        add_button = QPushButton(icon=QIcon.fromTheme('list-add'))
        rem_button = QPushButton(icon=QIcon.fromTheme('list-remove'))
        ok_button = QPushButton("Ok")
        cancel_button = QPushButton("Cancel")
        add_button.clicked.connect(self._add_item)
        rem_button.clicked.connect(self._remove_item)
        ok_button.clicked.connect(self.accept)
        cancel_button.clicked.connect(self.reject)

        controls_layout.addWidget(add_button)
        controls_layout.addWidget(rem_button)
        controls_layout.addStretch(0)
        controls_layout.addWidget(ok_button)
        controls_layout.addWidget(cancel_button)
        vbox.addLayout(controls_layout)
예제 #8
0
    def __init__(self, map_topic='/map',
                 paths=['/move_base/NavFn/plan', '/move_base/TrajectoryPlannerROS/local_plan'],
                 polygons=['/move_base/local_costmap/robot_footprint']):
        super(NavViewWidget, self).__init__()
        self._layout = QVBoxLayout()
        self._button_layout = QHBoxLayout()

        self.setAcceptDrops(True)
        self.setWindowTitle('Navigation Viewer')

        self.paths = paths
        self.polygons = polygons
        self.map = map_topic
        self._tf = tf.TransformListener()

        self._nav_view = NavView(map_topic, paths, polygons, tf = self._tf, parent = self)

        self._set_pose = QPushButton('Set Pose')
        self._set_pose.clicked.connect(self._nav_view.pose_mode)
        self._set_goal = QPushButton('Set Goal')
        self._set_goal.clicked.connect(self._nav_view.goal_mode)

        self._button_layout.addWidget(self._set_pose)
        self._button_layout.addWidget(self._set_goal)

        self._layout.addLayout(self._button_layout)

        self._layout.addWidget(self._nav_view)

        self.setLayout(self._layout)
    def __init__(self, reconf, node_name):
        """
        :type reconf: dynamic_reconfigure.client
        :type node_name: str
        """
        group_desc = reconf.get_group_descriptions()
        logging.debug('ParamClientWidget.group_desc=%s', group_desc)
        super(ParamClientWidget, self).__init__(ParamUpdater(reconf),
                                                group_desc, node_name)

        # Save and load buttons
        self.button_widget = QWidget(self)
        self.button_header = QHBoxLayout(self.button_widget)
        self.button_header.setContentsMargins(QMargins(0, 0, 0, 0))

        self.load_button = QPushButton()
        self.save_button = QPushButton()

        self.load_button.setIcon(QIcon.fromTheme('document-open'))
        self.save_button.setIcon(QIcon.fromTheme('document-save'))

        self.load_button.clicked[bool].connect(self._handle_load_clicked)
        self.save_button.clicked[bool].connect(self._handle_save_clicked)

        self.button_header.addWidget(self.save_button)
        self.button_header.addWidget(self.load_button)

        self.setMinimumWidth(150)

        self.reconf = reconf
        self.updater.start()
        self.reconf.config_callback = self.config_callback
        self._node_grn = node_name
예제 #10
0
 def paintEvent(self, ev):
     QPushButton.paintEvent(self, ev)
     self.drawRect()
     self.drawCircle(self.state, QColor(0, 0, 0), False)
     self.drawCircle(self.center, QColor(0, 0, 0))
     self.drawCircle(self.current_pos, QColor(255, 0, 0))
     self.drawCrosshair(self.state)
예제 #11
0
    def __init__(self, context):
        super(SpectrogramPlugin, self).__init__(context)
        self.setObjectName('Spectrogram')

        sns.set(style="whitegrid", palette="bright", color_codes=True)

        self._widget = QWidget()
        layout = QVBoxLayout()
        self._widget.setLayout(layout)

        layout_ = QHBoxLayout()
        self.lbl_topic = QLabel('Topic:')
        layout_.addWidget(self.lbl_topic)
        self.le_topic = QLineEdit()
        layout_.addWidget(self.le_topic)
        self.apply_topic = QPushButton("Apply")
        self.apply_topic.clicked.connect(self.apply_clicked_topic)
        layout_.addWidget(self.apply_topic)
        layout.addLayout(layout_)

        layout_ = QHBoxLayout()
        self.lbl_lcf = QLabel('Low-cut Freq.[Hz]:')
        layout_.addWidget(self.lbl_lcf)
        self.spb_lcf = QSpinBox()
        self.spb_lcf.setRange(0, 50)
        self.spb_lcf.setValue(0)
        layout_.addWidget(self.spb_lcf)
        self.apply_lcf = QPushButton("Apply")
        self.apply_lcf.clicked.connect(self.apply_clicked_lcf)
        layout_.addWidget(self.apply_lcf)
        layout.addLayout(layout_)

        layout_ = QHBoxLayout()
        self.lbl_hcf = QLabel('High-cut Freq.[Hz]:')
        layout_.addWidget(self.lbl_hcf)
        self.spb_hcf = QSpinBox()
        self.spb_hcf.setRange(50, self.vib_freq / 2)
        self.spb_hcf.setValue(self.vib_freq / 2)
        layout_.addWidget(self.spb_hcf)
        self.apply_hcf = QPushButton("Apply")
        self.apply_hcf.clicked.connect(self.apply_clicked_hcf)
        layout_.addWidget(self.apply_hcf)
        layout.addLayout(layout_)

        #self.fig, self.axes = plt.subplots(2, 1, sharex=True)
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(1, 1, 1)
        self.canvas = FigureCanvas(self.fig)
        self.fig.tight_layout()
        layout.addWidget(self.canvas)

        context.add_widget(self._widget)

        self.update_signal.connect(self.update_spectrogram)
        self.subscriber_signal.connect(self.update_subscriber)
        self.subscriber_signal.emit('spectrum')
예제 #12
0
    def __init__(self, updater, config, nodename):
        self.updater = ApplyGroup.ApplyUpdater(updater, self.update_group)
        super(ApplyGroup, self).__init__(self.updater, config, nodename)

        self.button = QPushButton('Apply %s' % self.param_name)
        self.button.clicked.connect(self.updater.apply_update)

        self.button.setEnabled(False)
        self.updater.pending_updates.connect(self._pending_cb)

        self.grid.addRow(self.button)
예제 #13
0
파일: qt.py 프로젝트: zaxrok/py_trees_ros
    def __init__(self):
        super(Dashboard, self).__init__()

        not_latched = False
        # latched = True
        self.publishers = py_trees_ros.utilities.Publishers([
            ('scan', "~scan", std_msgs.Empty, not_latched, 1),
            ('cancel', "~cancel", std_msgs.Empty, not_latched, 1),
        ])

        self.scan_push_button = QPushButton("Scan")
        self.scan_push_button.setStyleSheet("QPushButton { font-size: 30pt; }")
        self.scan_push_button.setSizePolicy(QSizePolicy.Expanding,
                                            QSizePolicy.Expanding)
        self.scan_push_button.pressed.connect(
            functools.partial(self.publish_button_message,
                              self.publishers.scan))

        self.cancel_push_button = QPushButton("Cancel")
        self.cancel_push_button.setStyleSheet(
            "QPushButton { font-size: 30pt; }")
        self.cancel_push_button.setSizePolicy(QSizePolicy.Expanding,
                                              QSizePolicy.Expanding)
        self.cancel_push_button.pressed.connect(
            functools.partial(self.publish_button_message,
                              self.publishers.cancel))

        self.led_strip_flashing = False
        self.led_strip_on_count = 1
        self.led_strip_colour = "grey"

        self.led_strip_lock = threading.Lock()
        self.led_strip_timer = QTimer()
        self.led_strip_timer.timeout.connect(self.led_strip_timer_callback)
        self.led_strip_label = QLabel("LED Strip")
        self.led_strip_label.setAlignment(Qt.AlignCenter)
        self.led_strip_label.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Expanding)
        self.led_strip_label.setStyleSheet(
            "background-color: %s; font-size: 30pt;" % self.led_strip_colour)

        self.hbox_layout = QGridLayout(self)
        self.hbox_layout.addWidget(self.scan_push_button)
        self.hbox_layout.addWidget(self.cancel_push_button)
        self.hbox_layout.addWidget(self.led_strip_label)

        self.subscribers = py_trees_ros.utilities.Subscribers([
            ("report", "/tree/report", std_msgs.String,
             self.reality_report_callback),
            ("led_strip", "/led_strip/display", std_msgs.String,
             self.led_strip_display_callback)
        ])
        self.led_strip_timer.start(500)  # ms
예제 #14
0
 def __init__(self, parent=None):
     super(ComboBoxDialog, self).__init__()
     self.number = 0
     vbox = QVBoxLayout(self)
     self.combo_box = QComboBox(self)
     self.combo_box.activated.connect(self.onActivated)
     vbox.addWidget(self.combo_box)
     button = QPushButton()
     button.setText("Done")
     button.clicked.connect(self.buttonCallback)
     vbox.addWidget(button)
     self.setLayout(vbox)
    def setup_group_frame(self, group):
        layout = QVBoxLayout()

        # grid for buttons for named targets
        grid = QGridLayout()
        grid.setSpacing(1)

        self.button_group = QButtonGroup(self)

        row = 0
        column = 0
        named_targets = self.get_named_targets(group)
        for target in named_targets:
            button = QPushButton(target)
            self.button_group.addButton(button)
            grid.addWidget(button, row, column)
            column += 1
            if column >= self.MAX_COLUMNS:
                row += 1
                column = 0

        self.button_group.buttonClicked.connect(self._handle_button_clicked)

        # grid for show joint value and move arm buttons/text field
        joint_values_grid = QGridLayout()
        joint_values_grid.setSpacing(1)

        button_show_joint_values = QPushButton('Current Joint Values')
        button_show_joint_values.clicked[bool].connect(
            self._handle_show_joint_values_clicked)

        line_edit = QLineEdit()
        self.text_joint_values.append(line_edit)

        button_move_to = QPushButton('Move to')
        button_move_to.clicked[bool].connect(self._handle_move_to_clicked)

        joint_values_grid.addWidget(button_show_joint_values, 0, 1)
        joint_values_grid.addWidget(line_edit, 0, 2)
        joint_values_grid.addWidget(button_move_to, 0, 3)

        layout.addLayout(grid)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        layout.addWidget(line)
        layout.addLayout(joint_values_grid)

        frame = QFrame()
        frame.setLayout(layout)
        return frame
    def __init__(self, title="block_pick_and_place"):
        super(block_pick_and_place, self).__init__()

        # Initial
        self.br = tf.TransformBroadcaster()
        self.tf_listener = tf.TransformListener()
        self.ik = [0, 0, 0, 0]
        # Thread lock

        moveit_commander.roscpp_initialize(sys.argv)
        self.robot = moveit_commander.RobotCommander()
        self.scene = moveit_commander.PlanningSceneInterface()
        self.group = moveit_commander.MoveGroupCommander("arm")

        display_trajectory_publisher = rospy.Publisher(
            '/move_group/display_planned_path',
            moveit_msgs.msg.DisplayTrajectory,
            queue_size=1)
        self.gripper_cmd = rospy.Publisher('/gripper_joint/command',
                                           Float64,
                                           queue_size=1)

        # safe shutdown
        rospy.on_shutdown(self.onShutdown)

        # timer
        rospy.loginfo("[%s] Initialized " % (rospy.get_name()))
        self.group.allow_replanning(True)
        self.group.set_pose_reference_frame("base_link")

        self.group.set_goal_position_tolerance(0.005)
        self.group.set_goal_orientation_tolerance(0.05)

        self.home_pose()
        self.init_interactive_marker()

        self.arm_plan_state = False

        self.vlayout = QVBoxLayout(self)
        self.gridlayout = QGridLayout()
        self.vlayout.addLayout(self.gridlayout)

        # Buttons for randomizing and centering sliders and
        # Spinbox for on-the-fly selecting number of rows

        self.CWbutton = QPushButton('Start_to_plan', self)
        self.CWbutton.clicked.connect(self.start_event)
        self.vlayout.addWidget(self.CWbutton)
        self.SPbutton = QPushButton('Stop', self)
        self.SPbutton.clicked.connect(self.stop_event)
        self.vlayout.addWidget(self.SPbutton)
예제 #17
0
 def update(self):
     self.clean()
     if not self.request:
         rospy.logwarn('question dialog: no request, update ignored')
         return
     req = self.request
     self._text_browser.setText(req.message)
     if req.type == QuestionDialogRequest.DISPLAY:
         # All done, nothing more too see here.
         self.response = QuestionDialogResponse(
                 QuestionDialogRequest.NO_RESPONSE, "")
         self.response_ready = True
     elif req.type == QuestionDialogRequest.CHOICE_QUESTION:
         for index, options in enumerate(req.options):
             button = QPushButton(options, self._widget)
             button.clicked.connect(partial(self.handle_button, index))
             row = index / 3
             col = index % 3
             self._button_layout.addWidget(button, row, col)
             self.buttons.append(button)
     elif req.type == QuestionDialogRequest.TEXT_QUESTION:
         self.text_label = QLabel("Enter here: ", self._widget)
         self._button_layout.addWidget(self.text_label, 0, 0)
         self.text_input = QLineEdit(self._widget)
         self.text_input.editingFinished.connect(self.handle_text)
         self._button_layout.addWidget(self.text_input, 0, 1)
예제 #18
0
    def update_buttons(self):
        """ Update buttons in Qt window. """
        rospy.loginfo('level selector: update_buttons called')
        self.clean()
        for index, level in enumerate(self.levels):
            button = QPushButton(level.level_id, self._widget)
            button.clicked[bool].connect(self.handle_button)
            button.setCheckable(True)
            self._button_layout.addWidget(button)
            self.buttons.append(button)

        # Subscribe to the current level we are on.
        if self.status_subscriber is None:
            self.status_subscriber = rospy.Subscriber("level_mux/current_level",
                                                      LevelMetaData,
                                                      self.process_level_status)
예제 #19
0
    def __init__(self, context, actions):
        super(ActionClientContainerWidget, self).__init__()

        grid = QGridLayout()
        grid.setSpacing(1)

        MAX_COLUMNS = 2

        self.setObjectName('ActionClientContainerWidget')

        self.clear_button = QPushButton("Clear all")
        self.clear_button.clicked[bool].connect(self._handle_clear_clicked)
        grid.addWidget(self.clear_button, 0, 0)

        self.widgets = []

        row = 1
        column = 0
        for k in sorted(actions.keys()):
            action_name = k
            widget = ActionClientWidget(context, action_name, actions[k])
            grid.addWidget(widget, row, column)
            self.widgets.append(widget)
            column += 1
            if column >= MAX_COLUMNS:
                row += 1
                column = 0

        self.setLayout(grid)
예제 #20
0
    def __init__(self):
        super(TopicSelection, self).__init__()
        master = rosgraph.Master('rqt_bag_recorder')
        self.setWindowTitle("Select the topics you want to record")
        self.resize(500, 700)

        self.topic_list = []
        self.selected_topics = []
        self.items_list = []

        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Record", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)

        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)
        self.item_all = QCheckBox("All", self)
        self.item_all.stateChanged.connect(self.updateList)
        self.selection_vlayout.addWidget(self.item_all)
        topic_data_list = master.getPublishedTopics('')
        topic_data_list.sort()
        for topic, datatype in topic_data_list:
            self.addCheckBox(topic)

        self.main_widget.setLayout(self.selection_vlayout)

        self.area.setWidget(self.main_widget)
        self.show()
예제 #21
0
    def __init__(self, context):
        '''
        Initialie the PID tuner

        Parameters:
            N/A
        Returns:
            N/A
        '''
        #Initialize with qt_gui plugin for ros
        super(PID_Tuner, self).__init__(context)

        self.layout = QVBoxLayout()
        self._widget = QWidget()
        self._widget.setLayout(self.layout)

        #Import a generic pid tunning widget for each pid controller
        self.velocity_pid_tuner_widget = PID_Tuner_Generic_Widget()
        self.steering_pid_tuner_widget = PID_Tuner_Generic_Widget()
        self.pid_tuner_widgets = [
            self.velocity_pid_tuner_widget, self.steering_pid_tuner_widget
        ]

        #Add button for sending the gains
        self.update_gains_btn = QPushButton("Update Gains")
        self.update_gains_btn.clicked.connect(self._update_gains)

        #Add the pid tuners to a layout
        for pid_tuner_widget in self.pid_tuner_widgets:
            self.layout.addWidget(pid_tuner_widget)

        self.layout.addWidget(self.update_gains_btn)

        context.add_widget(self._widget)
    def __init__(self):
        super(NodeWidgetsContainer, self).__init__()

        yaml_file = rospy.get_param("~config_file")

        stream = open(yaml_file, "r")
        nodes = yaml.load(stream)

        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('mcr_event_gui'), 'ros',
                               'resources', 'NodeWidgetsContainer.ui')
        loadUi(ui_file, self)

        grid = QGridLayout()
        grid.setSpacing(1)

        MAX_COLUMNS = 2

        self.setObjectName('NodeWidgetsContainer')

        self.clear_button = QPushButton("Clear all")
        self.clear_button.clicked[bool].connect(self._handle_clear_clicked)
        self.stop_button = QPushButton("Stop all")
        self.stop_button.clicked[bool].connect(self._handle_stop_clicked)
        grid.addWidget(self.clear_button, 0, 0)
        grid.addWidget(self.stop_button, 0, 1)

        self.widgets = []

        row = 1
        column = 0
        for k in sorted(nodes.keys()):
            node_name = k
            widget = NodeEventsWidget(node_name, nodes[k])
            width = widget.width()
            height = widget.height()
            grid.addWidget(widget, row, column)
            grid.setColumnMinimumWidth(column, width)
            grid.setRowMinimumHeight(row, height)
            self.widgets.append(widget)
            column += 1
            if column >= MAX_COLUMNS:
                row += 1
                column = 0

        self.setLayout(grid)
예제 #23
0
    def __init__(self, updater, config):
        self.updater = ApplyGroup.ApplyUpdater(updater)
        super(ApplyGroup, self).__init__(self.updater, config)

        self.button = QPushButton("Apply %s" % self.name)
        self.button.clicked.connect(self.updater.apply_update)

        rows = self.grid.rowCount()
        self.grid.addWidget(self.button, rows + 1, 1, Qt.AlignRight)
예제 #24
0
    def __init__(self, updater, config, nodename):
        """
        :param config:
        :type config: Dictionary? defined in dynamic_reconfigure.client.Client
        :type nodename: str
        """
        super(GroupWidget, self).__init__()
        self.state = config['state']
        self.param_name = config['name']
        self._toplevel_treenode_name = nodename

        # TODO: .ui file needs to be back into usage in later phase.
        #        ui_file = os.path.join(rp.get_path('rqt_reconfigure'),
        #                               'resource', 'singlenode_parameditor.ui')
        #        loadUi(ui_file, self)

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0))

        _widget_nodeheader = QWidget()
        _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader)
        _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0))

        self.nodename_qlabel = QLabel(self)
        font = QFont('Trebuchet MS, Bold')
        font.setUnderline(True)
        font.setBold(True)

        # Button to close a node.
        _icon_disable_node = QIcon.fromTheme('window-close')
        _bt_disable_node = QPushButton(_icon_disable_node, '', self)
        _bt_disable_node.setToolTip('Hide this node')
        _bt_disable_node_size = QSize(36, 24)
        _bt_disable_node.setFixedSize(_bt_disable_node_size)
        _bt_disable_node.pressed.connect(self._node_disable_bt_clicked)

        _h_layout_nodeheader.addWidget(self.nodename_qlabel)
        _h_layout_nodeheader.addWidget(_bt_disable_node)

        self.nodename_qlabel.setAlignment(Qt.AlignCenter)
        font.setPointSize(10)
        self.nodename_qlabel.setFont(font)
        grid_widget = QWidget(self)
        self.grid = QFormLayout(grid_widget)
        verticalLayout.addWidget(_widget_nodeheader)
        verticalLayout.addWidget(grid_widget, 1)
        # Again, these UI operation above needs to happen in .ui file.

        self.tab_bar = None  # Every group can have one tab bar
        self.tab_bar_shown = False

        self.updater = updater

        self.editor_widgets = []
        self._param_names = []

        self._create_node_widgets(config)

        logging.debug('Groups node name={}'.format(nodename))
        self.nodename_qlabel.setText(nodename)
예제 #25
0
 def __init__(self, parent=None):
     super(LineEditDialog, self).__init__()
     self.value = None
     vbox = QVBoxLayout(self)
     # combo box
     model = QtGui.QStandardItemModel(self)
     for elm in rospy.get_param_names():
         model.setItem(model.rowCount(), 0, QtGui.QStandardItem(elm))
     self.combo_box = QComboBox(self)
     self.line_edit = QLineEdit()
     self.combo_box.setLineEdit(self.line_edit)
     self.combo_box.setCompleter(QCompleter())
     self.combo_box.setModel(model)
     self.combo_box.completer().setModel(model)
     self.combo_box.lineEdit().setText('')
     vbox.addWidget(self.combo_box)
     # button
     button = QPushButton()
     button.setText("Done")
     button.clicked.connect(self.buttonCallback)
     vbox.addWidget(button)
     self.setLayout(vbox)
예제 #26
0
    def add_buttons(self, colors):
        vbx = QVBoxLayout()
        i = 1
        for color in colors:

            but = QPushButton('Color {} ({})'.format(color, i))
            but.clicked.connect(self.clicked(color))

            but_short = QShortcut(QKeySequence("Ctrl+" + str(i)), self)
            but_short.activated.connect(self.clicked(color))
            i += 1
            vbx.addWidget(but)

        vbx.addStretch(1)
        self.color_buttons.setLayout(vbx)
예제 #27
0
class NodeSelection(QWidget):
    def __init__(self, parent):
        super(NodeSelection, self).__init__()
        self.parent_widget = parent
        self.selected_nodes = []
        self.setWindowTitle("Select the nodes you want to record")
        self.resize(500, 700)
        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Done", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)
        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)

        self.node_list = rosnode.get_node_names()
        self.node_list.sort()
        for node in self.node_list:
            self.addCheckBox(node)
        self.main_widget.setLayout(self.selection_vlayout)
        self.show()

    def addCheckBox(self, node):
        item = QCheckBox(node, self)
        item.stateChanged.connect(lambda x: self.updateNode(x, node))
        self.selection_vlayout.addWidget(item)

    def updateNode(self, state, node):
        if state == Qt.Checked:
            self.selected_nodes.append(node)
        else:
            self.selected_nodes.remove(node)
        if len(self.selected_nodes) > 0:
            self.ok_button.setEnabled(True)
        else:
            self.ok_button.setEnabled(False)

    def onButtonClicked(self):
        master = rosgraph.Master('rqt_bag_recorder')
        state = master.getSystemState()
        subs = [
            t for t, l in state[1] if len([
                node_name
                for node_name in self.selected_nodes if node_name in l
            ]) > 0
        ]
        # print subs
        # print len(subs)
        for topic in subs:
            self.parent_widget.changeTopicCheckState(topic, Qt.Checked)
            self.parent_widget.updateList(Qt.Checked, topic, topic)
        self.close()
예제 #28
0
    def __init__(self, parent, name, timeline):
        """
        :param name: Name of inspecting diagnostic status
        :param timeline: Timeline object from which a status is fetched
        """
        #TODO(Isaac) UI construction that currently is done in this method,
        #            needs to be done in .ui file.
        super(InspectorWindow, self).__init__(parent=parent)
        self.setWindowTitle(name)
        self._name = name

        self.layout_vertical = QVBoxLayout(self)

        self.disp = StatusSnapshot(parent=self)

        self.layout_vertical.addWidget(self.disp, 1)

        self._message_updated_processing = False
        self._queue_updated_processing = False

        self.timeline = timeline
        self.timeline.message_updated.connect(
            self.message_updated, Qt.DirectConnection)
        self.timeline.queue_updated.connect(
            self.queue_updated, Qt.DirectConnection)
        self._message_updated.connect(
            self._signal_message_updated, Qt.QueuedConnection)
        self._queue_updated.connect(
            self._signal_queue_updated, Qt.QueuedConnection)

        self.timeline_pane = TimelinePane(self, self.timeline.paused)
        self.timeline_pane.pause_changed.connect(self.timeline.set_paused)
        self.timeline_pane.position_changed.connect(self.timeline.set_position)
        self.timeline.pause_changed.connect(self.timeline_pane.set_paused)
        self.timeline.position_changed.connect(self.timeline_pane.set_position)
        self.layout_vertical.addWidget(self.timeline_pane, 0)

        self.snapshot = QPushButton("Snapshot")
        self.snapshot.clicked.connect(self._take_snapshot)
        self.layout_vertical.addWidget(self.snapshot)

        self.snaps = []

        self.setLayout(self.layout_vertical)
        # TODO better to be configurable where to appear.
        self.resize(400, 600)
예제 #29
0
    def __init__(self, btnText):
        super(BagSelector, self).__init__()

        # init the elements
        self.bagEdit = QLineEdit()
        self.bagBtn = QPushButton(btnText)

        # connect the signals to the slots
        self.bagEdit.textChanged.connect(self.pathChanged)
        self.bagBtn.clicked.connect(self.btnClicked)

        self.fileName = ""

        # layout
        layout = QHBoxLayout()
        layout.addWidget(self.bagEdit)
        layout.addWidget(self.bagBtn)
        self.setLayout(layout)
예제 #30
0
    def __init__(self, status, close_callback):
        """
        :type status: DiagnosticStatus
        :param close_callback: When the instance of this class
                               (InspectorWindow) terminates, this callback gets
                               called.
        """
        #TODO(Isaac) UI construction that currently is done in this method,
        #            needs to be done in .ui file.

        super(InspectorWindow, self).__init__()
        self.status = status
        self._close_callback = close_callback
        self.setWindowTitle(status.name)
        self.paused = False

        self.layout_vertical = QVBoxLayout(self)

        self.disp = QTextEdit(self)
        self.snapshot = QPushButton("StatusSnapshot")

        self.timeline_pane = TimelinePane(self)
        self.timeline_pane.set_timeline_data(Util.SECONDS_TIMELINE,
                                             self.get_color_for_value,
                                             self.on_pause)

        self.layout_vertical.addWidget(self.disp, 1)
        self.layout_vertical.addWidget(self.timeline_pane, 0)
        self.layout_vertical.addWidget(self.snapshot)

        self.snaps = []
        self.snapshot.clicked.connect(self._take_snapshot)

        self._sig_write.connect(self._write_key_val)
        self._sig_newline.connect(lambda: self.disp.insertPlainText('\n'))
        self._sig_clear.connect(lambda: self.disp.clear())
        self._sig_close_window.connect(self._close_callback)

        self.setLayout(self.layout_vertical)
        # TODO better to be configurable where to appear.
        self.setGeometry(0, 0, 400, 600)
        self.show()
        self.update_status_display(status)
예제 #31
0
class NodeSelection(QWidget):
    def __init__(self, parent):
        super(NodeSelection, self).__init__()
        self.parent_widget = parent
        self.selected_nodes = []
        self.setWindowTitle("Select the nodes you want to record")
        self.resize(500, 700)
        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Done", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)
        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)

        self.node_list = rosnode.get_node_names()
        self.node_list.sort()
        for node in self.node_list:
            self.addCheckBox(node)
        self.main_widget.setLayout(self.selection_vlayout)
        self.show()

    def addCheckBox(self, node):
        item = QCheckBox(node, self)
        item.stateChanged.connect(lambda x: self.updateNode(x, node))
        self.selection_vlayout.addWidget(item)

    def updateNode(self, state, node):
        if state == Qt.Checked:
            self.selected_nodes.append(node)
        else:
            self.selected_nodes.remove(node)
        if len(self.selected_nodes) > 0:
            self.ok_button.setEnabled(True)
        else:
            self.ok_button.setEnabled(False)

    def onButtonClicked(self):
        master = rosgraph.Master('rqt_bag_recorder')
        state = master.getSystemState()
        subs = [t for t, l in state[1]
                if len([node_name for node_name in self.selected_nodes if node_name in l]) > 0]
        for topic in subs:
            self.parent_widget.changeTopicCheckState(topic, Qt.Checked)
            self.parent_widget.updateList(Qt.Checked, topic)
        self.close()
예제 #32
0
    def __init__(self, linesList, parent=None):
        super(DelPlotDialog, self).__init__()
        self.linesList = linesList  # list of the axes
        self.parent = parent

        # init the components:
        self.setWindowTitle("Delete Graph")
        self.resize(300, 200)
        self.linesListWidget = QListWidget(self)
        self.refreshList(self.linesList)
        self.__btn = QPushButton("Delete")

        # connect signals
        self.__btn.clicked.connect(self.btnPressed)

        # layout:
        layout = QVBoxLayout()
        layout.addWidget(self.linesListWidget)
        layout.addWidget(self.__btn)
        self.setLayout(layout)
예제 #33
0
    def __init__(self, params, id_radio):
        super(inputDialog, self).__init__()

        self.id_radio = id_radio
        self.center()
        layout = QFormLayout()

        self.label_items = []
        self.label_comment = dict()
        self.client_answers_items = []
        self.greather_conditions = []
        self.button_clicked = False
        # print params
        for item in params:
            param = item[0]
            label = item[1]
            cond = item[2]
            if not label == "":
                label = " (%s)" % label
            self.greather_conditions.append((param, cond))
            label_item = QLabel(param + label, self)
            # self.label_items[param] = QLabel(param + label, self)
            label_item.setAlignment(Qt.AlignCenter)
            self.label_items.append(param)
            client_answers = QLineEdit()
            self.client_answers_items.append(client_answers)
            # self.label_comment[label] = QLabel(label, self)
            # self.label_comment[label].setAlignment(Qt.AlignCenter)
            # layout.addWidget(self.label_comment[label])
            layout.addRow(label_item, client_answers)

        self.ok_button = QPushButton("ok", self)
        self.ok_button.clicked.connect(self.onButtonClicked)

        layout.addWidget(self.ok_button)

        self.setLayout(layout)
        self.setWindowTitle("Update Parameters")

        self.show()
예제 #34
0
    def __init__(self, parent):
        super(NodeSelection, self).__init__()
        self.parent_widget = parent
        self.selected_nodes = []
        self.setWindowTitle("Select the nodes you want to record")
        self.resize(500, 700)
        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Done", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)
        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)

        self.node_list = rosnode.get_node_names()
        self.node_list.sort()
        for node in self.node_list:
            self.addCheckBox(node)
        self.main_widget.setLayout(self.selection_vlayout)
        self.show()
예제 #35
0
    def __init__(self, updater, config, nodename):
        '''
        :param config:
        :type config: Dictionary? defined in dynamic_reconfigure.client.Client
        :type nodename: str
        '''

        super(GroupWidget, self).__init__()
        self.state = config['state']
        self.param_name = config['name']
        self._toplevel_treenode_name = nodename

        # TODO: .ui file needs to be back into usage in later phase.
#        ui_file = os.path.join(rp.get_path('rqt_reconfigure'),
#                               'resource', 'singlenode_parameditor.ui')
#        loadUi(ui_file, self)

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0))

        _widget_nodeheader = QWidget()
        _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader)
        _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0))

        self.nodename_qlabel = QLabel(self)
        font = QFont('Trebuchet MS, Bold')
        font.setUnderline(True)
        font.setBold(True)

        # Button to close a node.
        _icon_disable_node = QIcon.fromTheme('window-close')
        _bt_disable_node = QPushButton(_icon_disable_node, '', self)
        _bt_disable_node.setToolTip('Hide this node')
        _bt_disable_node_size = QSize(36, 24)
        _bt_disable_node.setFixedSize(_bt_disable_node_size)
        _bt_disable_node.pressed.connect(self._node_disable_bt_clicked)

        _h_layout_nodeheader.addWidget(self.nodename_qlabel)
        _h_layout_nodeheader.addWidget(_bt_disable_node)

        self.nodename_qlabel.setAlignment(Qt.AlignCenter)
        font.setPointSize(10)
        self.nodename_qlabel.setFont(font)
        grid_widget = QWidget(self)
        self.grid = QFormLayout(grid_widget)
        verticalLayout.addWidget(_widget_nodeheader)
        verticalLayout.addWidget(grid_widget, 1)
        # Again, these UI operation above needs to happen in .ui file.

        self.tab_bar = None  # Every group can have one tab bar
        self.tab_bar_shown = False

        self.updater = updater

        self.editor_widgets = []
        self._param_names = []

        self._create_node_widgets(config)

        rospy.logdebug('Groups node name={}'.format(nodename))
        self.nodename_qlabel.setText(nodename)
예제 #36
0
class TopicSelection(QWidget):

    recordSettingsSelected = Signal(bool, list)

    def __init__(self):
        super(TopicSelection, self).__init__()
        master = rosgraph.Master('rqt_bag_recorder')
        self.setWindowTitle("Select the topics you want to record")
        self.resize(500, 700)

        self.topic_list = []
        self.selected_topics = []
        self.items_list = []

        self.area = QScrollArea(self)
        self.main_widget = QWidget(self.area)
        self.ok_button = QPushButton("Record", self)
        self.ok_button.clicked.connect(self.onButtonClicked)
        self.ok_button.setEnabled(False)

        self.main_vlayout = QVBoxLayout(self)
        self.main_vlayout.addWidget(self.area)
        self.main_vlayout.addWidget(self.ok_button)
        self.setLayout(self.main_vlayout)

        self.selection_vlayout = QVBoxLayout(self)
        self.item_all = QCheckBox("All", self)
        self.item_all.stateChanged.connect(self.updateList)
        self.selection_vlayout.addWidget(self.item_all)
        topic_data_list = master.getPublishedTopics('')
        topic_data_list.sort()
        for topic, datatype in topic_data_list:
            self.addCheckBox(topic)

        self.main_widget.setLayout(self.selection_vlayout)

        self.area.setWidget(self.main_widget)
        self.show()

    def addCheckBox(self, topic):
        self.topic_list.append(topic)
        item = QCheckBox(topic, self)
        item.stateChanged.connect(lambda x: self.updateList(x,topic))
        self.items_list.append(item)
        self.selection_vlayout.addWidget(item)


    def updateList(self, state, topic = None):
        if topic is None: # The "All" checkbox was checked / unchecked
            if state == Qt.Checked:
                self.item_all.setTristate(False)
                for item in self.items_list:
                    if item.checkState() == Qt.Unchecked:
                        item.setCheckState(Qt.Checked)
            elif state == Qt.Unchecked:
                self.item_all.setTristate(False)
                for item in self.items_list:
                    if item.checkState() == Qt.Checked:
                        item.setCheckState(Qt.Unchecked)
        else:
            if state == Qt.Checked:
                self.selected_topics.append(topic)
            else:
                self.selected_topics.remove(topic)
                if self.item_all.checkState()==Qt.Checked:
                    self.item_all.setCheckState(Qt.PartiallyChecked)

        if self.selected_topics == []:
            self.ok_button.setEnabled(False)
        else:
            self.ok_button.setEnabled(True)

    def onButtonClicked(self):
        self.close()
        self.recordSettingsSelected.emit((self.item_all.checkState() == Qt.Checked), self.selected_topics)
예제 #37
0
class PlotWidget(QWidget):

    def __init__(self, timeline, parent, topic):
        super(PlotWidget, self).__init__(parent)
        self.setObjectName('PlotWidget')

        self.timeline = timeline
        msg_type = self.timeline.get_datatype(topic)
        self.msgtopic = topic
        self.start_stamp = self.timeline._get_start_stamp()
        self.end_stamp = self.timeline._get_end_stamp()

        # the current region-of-interest for our bag file
        # all resampling and plotting is done with these limits
        self.limits = [0,(self.end_stamp-self.start_stamp).to_sec()]

        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_bag_plugins'), 'resource', 'plot.ui')
        loadUi(ui_file, self)
        self.message_tree = MessageTree(msg_type, self)
        self.data_tree_layout.addWidget(self.message_tree)
        # TODO: make this a dropdown with choices for "Auto", "Full" and
        #       "Custom"
        #       I continue to want a "Full" option here
        self.auto_res.stateChanged.connect(self.autoChanged)

        self.resolution.editingFinished.connect(self.settingsChanged)
        self.resolution.setValidator(QDoubleValidator(0.0,1000.0,6,self.resolution))


        self.timeline.selected_region_changed.connect(self.region_changed)

        self.recompute_timestep()

        self.plot = DataPlot(self)
        self.plot.set_autoscale(x=False)
        self.plot.set_autoscale(y=DataPlot.SCALE_VISIBLE)
        self.plot.autoscroll(False)
        self.plot.set_xlim(self.limits)
        self.data_plot_layout.addWidget(self.plot)

        self._home_button = QPushButton()
        self._home_button.setToolTip("Reset View")
        self._home_button.setIcon(QIcon.fromTheme('go-home'))
        self._home_button.clicked.connect(self.home)
        self.plot_toolbar_layout.addWidget(self._home_button)

        self._config_button = QPushButton("Configure Plot")
        self._config_button.clicked.connect(self.plot.doSettingsDialog)
        self.plot_toolbar_layout.addWidget(self._config_button)

        self.set_cursor(0)

        self.paths_on = set()
        self._lines = None

        # get bag from timeline
        bag = None
        start_time = self.start_stamp
        while bag is None:
            bag,entry = self.timeline.get_entry(start_time, topic)
            if bag is None:
                start_time = self.timeline.get_entry_after(start_time)[1].time

        self.bag = bag
        # get first message from bag
        msg = bag._read_message(entry.position)
        self.message_tree.set_message(msg[1])

        # state used by threaded resampling
        self.resampling_active = False
        self.resample_thread = None
        self.resample_fields = set()

    def set_cursor(self, position):
        self.plot.vline(position, color=DataPlot.RED)
        self.plot.redraw()

    def add_plot(self, path):
        self.resample_data([path])

    def update_plot(self):
        if len(self.paths_on)>0:
            self.resample_data(self.paths_on)

    def remove_plot(self, path):
        self.plot.remove_curve(path)
        self.paths_on.remove(path)
        self.plot.redraw()

    def load_data(self):
        """get a generator for the specified time range on our bag"""
        return self.bag.read_messages(self.msgtopic,
                self.start_stamp+rospy.Duration.from_sec(self.limits[0]),
                self.start_stamp+rospy.Duration.from_sec(self.limits[1]))

    def resample_data(self, fields):
        if self.resample_thread:
            # cancel existing thread and join
            self.resampling_active = False
            self.resample_thread.join()

        for f in fields:
            self.resample_fields.add(f)

        # start resampling thread
        self.resampling_active = True
        self.resample_thread = threading.Thread(target=self._resample_thread)
        # explicitly mark our resampling thread as a daemon, because we don't
        # want to block program exit on a long resampling operation
        self.resample_thread.setDaemon(True)
        self.resample_thread.start()

    def _resample_thread(self):
        # TODO:
        # * look into doing partial display updates for long resampling 
        #   operations
        # * add a progress bar for resampling operations
        x = {}
        y = {}
        for path in self.resample_fields:
            x[path] = []
            y[path] = []

        msgdata = self.load_data()

        for entry in msgdata:
            # detect if we're cancelled and return early
            if not self.resampling_active:
                return

            for path in self.resample_fields:
                # this resampling method is very unstable, because it picks
                # representative points rather than explicitly representing
                # the minimum and maximum values present within a sample
                # If the data has spikes, this is particularly bad because they
                # will be missed entirely at some resolutions and offsets
                if x[path]==[] or (entry[2]-self.start_stamp).to_sec()-x[path][-1] >= self.timestep:
                    y_value = entry[1]
                    for field in path.split('.'):
                        index = None
                        if field.endswith(']'):
                            field = field[:-1]
                            field, _, index = field.rpartition('[')
                        y_value = getattr(y_value, field)
                        if index:
                            index = int(index)
                            y_value = y_value[index]
                    y[path].append(y_value)
                    x[path].append((entry[2]-self.start_stamp).to_sec())

            # TODO: incremental plot updates would go here...
            #       we should probably do incremental updates based on time;
            #       that is, push new data to the plot maybe every .5 or .1
            #       seconds
            #       time is a more useful metric than, say, messages loaded or
            #       percentage, because it will give a reasonable refresh rate
            #       without overloading the computer
            # if we had a progress bar, we could emit a signal to update it here

        # update the plot with final resampled data
        for path in self.resample_fields:
            if len(x[path]) < 1:
                qWarning("Resampling resulted in 0 data points for %s" % path)
            else:
                if path in self.paths_on:
                    self.plot.clear_values(path)
                    self.plot.update_values(path, x[path], y[path])
                else:
                    self.plot.add_curve(path, path, x[path], y[path])
                    self.paths_on.add(path)

        self.plot.redraw()

        self.resample_fields.clear()
        self.resampling_active = False

    def recompute_timestep(self):
        # this is only called if we think the timestep has changed; either
        # by changing the limits or by editing the resolution
        limits = self.limits
        if self.auto_res.isChecked():
            timestep = round((limits[1]-limits[0])/200.0,5)
        else:
            timestep = float(self.resolution.text())
        self.resolution.setText(str(timestep))
        self.timestep = timestep

    def region_changed(self, start, end):
        # this is the only place where self.limits is set
        limits = [ (start - self.start_stamp).to_sec(),
                   (end - self.start_stamp).to_sec() ]

        # cap the limits to the start and end of our bag file
        if limits[0]<0:
            limits = [0.0,limits[1]]
        if limits[1]>(self.end_stamp-self.start_stamp).to_sec():
            limits = [limits[0],(self.end_stamp-self.start_stamp).to_sec()]

        self.limits = limits

        self.recompute_timestep()
        self.plot.set_xlim(limits)
        self.plot.redraw()
        self.update_plot()

    def settingsChanged(self):
        # resolution changed. recompute the timestep and resample
        self.recompute_timestep()
        self.update_plot()

    def autoChanged(self, state):
        if state==2:
            # auto mode enabled. recompute the timestep and resample
            self.resolution.setDisabled(True) 
            self.recompute_timestep()
            self.update_plot()   
        else:
            # auto mode disabled. enable the resolution text box
            # no change to resolution yet, so no need to redraw
            self.resolution.setDisabled(False)

    def home(self):
        # TODO: re-add the button for this. It's useful for restoring the
        #       X and Y limits so that we can see all of the data
        #       effectively a "zoom all" button

        # reset the plot to our current limits
        self.plot.set_xlim(self.limits)
        # redraw the plot; this forces a Y autoscaling
        self.plot.redraw()
예제 #38
0
    def __init__(self, timeline, parent, topic):
        super(PlotWidget, self).__init__(parent)
        self.setObjectName('PlotWidget')

        self.timeline = timeline
        msg_type = self.timeline.get_datatype(topic)
        self.msgtopic = topic
        self.start_stamp = self.timeline._get_start_stamp()
        self.end_stamp = self.timeline._get_end_stamp()

        # the current region-of-interest for our bag file
        # all resampling and plotting is done with these limits
        self.limits = [0,(self.end_stamp-self.start_stamp).to_sec()]

        rp = rospkg.RosPack()
        ui_file = os.path.join(rp.get_path('rqt_bag_plugins'), 'resource', 'plot.ui')
        loadUi(ui_file, self)
        self.message_tree = MessageTree(msg_type, self)
        self.data_tree_layout.addWidget(self.message_tree)
        # TODO: make this a dropdown with choices for "Auto", "Full" and
        #       "Custom"
        #       I continue to want a "Full" option here
        self.auto_res.stateChanged.connect(self.autoChanged)

        self.resolution.editingFinished.connect(self.settingsChanged)
        self.resolution.setValidator(QDoubleValidator(0.0,1000.0,6,self.resolution))


        self.timeline.selected_region_changed.connect(self.region_changed)

        self.recompute_timestep()

        self.plot = DataPlot(self)
        self.plot.set_autoscale(x=False)
        self.plot.set_autoscale(y=DataPlot.SCALE_VISIBLE)
        self.plot.autoscroll(False)
        self.plot.set_xlim(self.limits)
        self.data_plot_layout.addWidget(self.plot)

        self._home_button = QPushButton()
        self._home_button.setToolTip("Reset View")
        self._home_button.setIcon(QIcon.fromTheme('go-home'))
        self._home_button.clicked.connect(self.home)
        self.plot_toolbar_layout.addWidget(self._home_button)

        self._config_button = QPushButton("Configure Plot")
        self._config_button.clicked.connect(self.plot.doSettingsDialog)
        self.plot_toolbar_layout.addWidget(self._config_button)

        self.set_cursor(0)

        self.paths_on = set()
        self._lines = None

        # get bag from timeline
        bag = None
        start_time = self.start_stamp
        while bag is None:
            bag,entry = self.timeline.get_entry(start_time, topic)
            if bag is None:
                start_time = self.timeline.get_entry_after(start_time)[1].time

        self.bag = bag
        # get first message from bag
        msg = bag._read_message(entry.position)
        self.message_tree.set_message(msg[1])

        # state used by threaded resampling
        self.resampling_active = False
        self.resample_thread = None
        self.resample_fields = set()
class DynreconfClientWidget(GroupWidget):
    """
    A wrapper of dynamic_reconfigure.client instance.
    Represents a widget where users can view and modify ROS params.
    """

    def __init__(self, reconf, node_name):
        """
        :type reconf: dynamic_reconfigure.client
        :type node_name: str
        """

        group_desc = reconf.get_group_descriptions()
        rospy.logdebug('DynreconfClientWidget.group_desc=%s', group_desc)
        super(DynreconfClientWidget, self).__init__(ParamUpdater(reconf),
                                                    group_desc, node_name)

        # Save and load buttons
        self.button_widget = QWidget(self)
        self.button_header = QHBoxLayout(self.button_widget)
        self.button_header.setContentsMargins(QMargins(0, 0, 0, 0))

        self.load_button = QPushButton()
        self.save_button = QPushButton()

        self.load_button.setIcon(QIcon.fromTheme('document-open'))
        self.save_button.setIcon(QIcon.fromTheme('document-save'))

        self.load_button.clicked[bool].connect(self._handle_load_clicked)
        self.save_button.clicked[bool].connect(self._handle_save_clicked)

        self.button_header.addWidget(self.save_button)
        self.button_header.addWidget(self.load_button)

        self.setMinimumWidth(150)

        self.reconf = reconf
        self.updater.start()
        self.reconf.config_callback = self.config_callback
        self._node_grn = node_name

    def get_node_grn(self):

        return self._node_grn

    def config_callback(self, config):

        #TODO: Think about replacing callback architecture with signals.

        if config:
            # TODO: should use config.keys but this method doesnt exist

            names = [name for name, v in config.items()]
            # v isn't used but necessary to get key and put it into dict.
            rospy.logdebug('config_callback name={} v={}'.format(name, v))

            for widget in self.editor_widgets:
                if isinstance(widget, EditorWidget):
                    if widget.param_name in names:
                        rospy.logdebug('EDITOR widget.param_name=%s',
                                       widget.param_name)
                        widget.update_value(config[widget.param_name])
                elif isinstance(widget, GroupWidget):
                    cfg = find_cfg(config, widget.param_name)
                    rospy.logdebug('GROUP widget.param_name=%s',
                                   widget.param_name)
                    widget.update_group(cfg)

    def _handle_load_clicked(self):
        filename = QFileDialog.getOpenFileName(
                self, self.tr('Load from File'), '.',
                self.tr('YAML file {.yaml} (*.yaml)'))
        if filename[0] != '':
            self.load_param(filename[0])

    def _handle_save_clicked(self):
        filename = QFileDialog.getSaveFileName(
                self, self.tr('Save parameters to file...'), '.',
                self.tr('YAML files {.yaml} (*.yaml)'))
        if filename[0] != '':
            self.save_param(filename[0])

    def save_param(self, filename):
        configuration = self.reconf.get_configuration()
        if configuration is not None:
            with file(filename, 'w') as f:
                yaml.dump(configuration, f)

    def load_param(self, filename):
        with file(filename, 'r') as f:
            configuration = {}
            for doc in yaml.load_all(f.read()):
                configuration.update(doc)
        self.reconf.update_configuration(configuration)

    def close(self):
        self.reconf.close()
        self.updater.stop()

        for w in self.editor_widgets:
            w.close()

        self.deleteLater()

    def filter_param(self, filter_key):
        #TODO impl
        pass