Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ROS2]Added refresh rate control and made pyqtgraph improvements #72

Open
wants to merge 1 commit into
base: rolling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions resource/plot.ui
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,33 @@
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="dataPlotControls">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>5</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<property name="bottomMargin">
<number>5</number>
</property>
<item>
Expand Down Expand Up @@ -101,7 +119,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="pause_button">
<widget class="QPushButton" name="play_pause_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
Expand All @@ -118,7 +136,32 @@
</size>
</property>
<property name="checkable">
<bool>true</bool>
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="refresh_rate_spinbox">
<property name="toolTip">
<string>Data refresh rate</string>
</property>
<property name="suffix">
<string> hz</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>150.000000000000000</double>
</property>
<property name="stepType">
<enum>QAbstractSpinBox::DefaultStepType</enum>
</property>
<property name="value">
<double>50.000000000000000</double>
</property>
</widget>
</item>
Expand Down
2 changes: 2 additions & 0 deletions src/rqt_plot/data_plot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ def save_settings(self, plugin_settings, instance_settings):
ylim = [float(y) for y in ylim]
instance_settings.set_value('x_limits', pack(xlim))
instance_settings.set_value('y_limits', pack(ylim))
self._data_plot_widget.save_settings(plugin_settings, instance_settings)

def restore_settings(self, plugin_settings, instance_settings):
"""Restore the settings for this widget
Expand All @@ -259,6 +260,7 @@ def restore_settings(self, plugin_settings, instance_settings):
self.set_ylim(ylim)
except:
qWarning("Failed to restore Y limits")
self._data_plot_widget.restore_settings(plugin_settings, instance_settings)

def doSettingsDialog(self):
"""Present the user with a dialog for choosing the plot backend
Expand Down
6 changes: 6 additions & 0 deletions src/rqt_plot/data_plot/mat_data_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,9 @@ def get_xlim(self):

def get_ylim(self):
return list(self._canvas.axes.get_ybound())

def save_settings(self, plugin_settings, instance_settings):
pass

def restore_settings(self, plugin_settings, instance_settings):
pass
35 changes: 33 additions & 2 deletions src/rqt_plot/data_plot/pyqtgraph_data_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

from python_qt_binding.QtCore import Slot, Qt, qVersion, qWarning, Signal
from python_qt_binding.QtGui import QColor
from python_qt_binding.QtWidgets import QVBoxLayout, QWidget
from python_qt_binding.QtWidgets import QAction, QSpinBox, QVBoxLayout, QWidget

if qVersion().startswith('5.'):
try:
Expand Down Expand Up @@ -69,6 +69,8 @@ def __init__(self, parent=None):
self._plot_widget.getPlotItem().addLegend()
self._plot_widget.setBackground((255, 255, 255))
self._plot_widget.setXRange(0, 10, padding=0)
self._line_width = 1
self._add_line_width_menu_option()
vbox = QVBoxLayout()
vbox.addWidget(self._plot_widget)
self.setLayout(vbox)
Expand All @@ -78,7 +80,7 @@ def __init__(self, parent=None):
self._current_vline = None

def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False):
pen = mkPen(curve_color, width=1)
pen = mkPen(curve_color, width=self._line_width)
symbol = "o"
symbolPen = mkPen(QColor(Qt.black))
symbolBrush = mkBrush(curve_color)
Expand Down Expand Up @@ -106,6 +108,21 @@ def _update_legend(self):
if self._current_vline:
self._plot_widget.addItem(self._current_vline)

def _add_line_width_menu_option(self):
menu = self._plot_widget.getMenu().addMenu('Line Width')
menu.setLayout(QVBoxLayout())
self._line_width_spinbox = QSpinBox()
self._line_width_spinbox.setRange(1, 30)
self._line_width_spinbox.valueChanged.connect(self._line_width_spinbox_valueChanged)
menu.layout().addWidget(self._line_width_spinbox)

@Slot(int)
def _line_width_spinbox_valueChanged(self, val):
self._line_width = val
for curve in self._curves.values():
color = curve.opts['pen'].color()
curve.setPen(mkPen(color, width=self._line_width))

def redraw(self):
pass

Expand All @@ -132,3 +149,17 @@ def get_xlim(self):
def get_ylim(self):
_, y_range = self._plot_widget.viewRange()
return y_range

def save_settings(self, plugin_settings, instance_settings):
instance_settings.set_value('plot_widget_state', self._plot_widget.saveState())
instance_settings.set_value('qt_line_width', self._line_width)

def restore_settings(self, plugin_settings, instance_settings):
plot_widget_state = instance_settings.value('plot_widget_state')
if plot_widget_state is not None:
self._plot_widget.restoreState(plot_widget_state)

qt_line_width = instance_settings.value('qt_line_width')
if qt_line_width is not None:
self._line_width = int(qt_line_width)
self._line_width_spinbox.setValue(self._line_width)
6 changes: 6 additions & 0 deletions src/rqt_plot/data_plot/qwt_data_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ def get_xlim(self):
def get_ylim(self):
return self._y_limits

def save_settings(self, plugin_settings, instance_settings):
pass

def restore_settings(self, plugin_settings, instance_settings):
pass


if __name__ == '__main__':
from python_qt_binding.QtGui import QApplication
Expand Down
9 changes: 9 additions & 0 deletions src/rqt_plot/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,20 @@ def save_settings(self, plugin_settings, instance_settings):
self._data_plot.save_settings(plugin_settings, instance_settings)
instance_settings.set_value('autoscroll', self._widget.autoscroll_checkbox.isChecked())
instance_settings.set_value('topics', pack(self._widget._rosdata.keys()))
instance_settings.set_value("refresh_rate", self._widget.refresh_rate_spinbox.value())

def restore_settings(self, plugin_settings, instance_settings):
autoscroll = instance_settings.value('autoscroll', True) in [True, 'true']
self._widget.autoscroll_checkbox.setChecked(autoscroll)
self._data_plot.autoscroll(autoscroll)

refresh_rate = instance_settings.value("refresh_rate")
if refresh_rate is not None:
try:
self._widget.refresh_rate_spinbox.setValue(float(refresh_rate))
except ValueError:
pass

self._update_title()

if len(self._widget._rosdata.keys()) == 0 and not self._args.start_empty:
Expand All @@ -164,6 +172,7 @@ def restore_settings(self, plugin_settings, instance_settings):

self._data_plot.restore_settings(plugin_settings, instance_settings)


def trigger_configuration(self):
self._data_plot.doSettingsDialog()
self._update_title()
Expand Down
56 changes: 42 additions & 14 deletions src/rqt_plot/plot_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import os
import re
import time
from typing import Optional

from ament_index_python.resources import get_resource
from python_qt_binding import loadUi
Expand Down Expand Up @@ -175,7 +176,6 @@ def is_plottable(node, topic_name):


class PlotWidget(QWidget):
_redraw_interval = 40

def __init__(self, node, initial_topics=None, start_paused=False):
super(PlotWidget, self).__init__()
Expand All @@ -189,13 +189,12 @@ def __init__(self, node, initial_topics=None, start_paused=False):
loadUi(ui_file, self)
self.subscribe_topic_button.setIcon(QIcon.fromTheme('list-add'))
self.remove_topic_button.setIcon(QIcon.fromTheme('list-remove'))
self.pause_button.setIcon(QIcon.fromTheme('media-playback-pause'))
self.play_pause_button.setIcon(QIcon.fromTheme('media-playback-pause'))
self.clear_button.setIcon(QIcon.fromTheme('edit-clear'))
self.data_plot = None

self.subscribe_topic_button.setEnabled(False)
if start_paused:
self.pause_button.setChecked(True)
self._paused = start_paused

self._topic_completer = TopicCompleter(self.topic_edit)
self._topic_completer.update_topics(node)
Expand All @@ -208,9 +207,11 @@ def __init__(self, node, initial_topics=None, start_paused=False):
# init and start update timer for plot
self._update_plot_timer = QTimer(self)
self._update_plot_timer.timeout.connect(self.update_plot)
if not self._paused:
self._set_play()

def switch_data_plot_widget(self, data_plot):
self.enable_timer(enabled=False)
self._set_pause()

self.data_plot_layout.removeWidget(self.data_plot)
if self.data_plot is not None:
Expand Down Expand Up @@ -289,8 +290,11 @@ def on_subscribe_topic_button_clicked(self):
self.add_topic(str(self.topic_edit.text()))

@Slot(bool)
def on_pause_button_clicked(self, checked):
self.enable_timer(not checked)
def on_play_pause_button_clicked(self, checked):
if self._paused:
self._set_play()
else:
self._set_pause()

@Slot(bool)
def on_autoscroll_checkbox_clicked(self, checked):
Expand All @@ -302,6 +306,13 @@ def on_autoscroll_checkbox_clicked(self, checked):
def on_clear_button_clicked(self):
self.clear_plot()

@Slot(float)
def on_refresh_rate_spinbox_valueChanged(self, val):
if not self._paused:
# If we are playing, then pause and re-play with the new interval
self._set_pause()
self._set_play(val)

def update_plot(self):
if self.data_plot is not None:
needs_redraw = False
Expand All @@ -318,9 +329,13 @@ def update_plot(self):

def _subscribed_topics_changed(self):
self._update_remove_topic_menu()
if not self.pause_button.isChecked():

if self._paused and self._rosdata:
# if pause button is not pressed, enable timer based on subscribed topics
self.enable_timer(self._rosdata)
self._set_play()
elif not self._paused and not self._rosdata:
self._set_pause()

self.data_plot.redraw()

def _update_remove_topic_menu(self):
Expand Down Expand Up @@ -378,8 +393,21 @@ def clean_up_subscribers(self):

self._subscribed_topics_changed()

def enable_timer(self, enabled=True):
if enabled:
self._update_plot_timer.start(self._redraw_interval)
else:
self._update_plot_timer.stop()
def _set_pause(self):
# pause subscriptions
self._paused = True
# Stop timer
self._update_plot_timer.stop()
# Set button to 'play'
self.play_pause_button.setIcon(QIcon.fromTheme("media-playback-start"))

def _set_play(self, refresh_rate: Optional[float] = None):
if refresh_rate is None:
refresh_rate = self.refresh_rate_spinbox.value()
# play subscriptions
self._paused = False
# Set button to 'pause'
self.play_pause_button.setIcon(QIcon.fromTheme("media-playback-pause"))
# Start timer again. Input is in milliseconds as int.
period_in_ms = 1000.0 / refresh_rate
self._update_plot_timer.start(period_in_ms)