rqt_dyn_tune.py
Go to the documentation of this file.
1 import sys
2 import os
3 import rospy
4 import rospkg
5 
6 from qt_gui.plugin import Plugin
7 from python_qt_binding import loadUi
8 from python_qt_binding.QtWidgets import QWidget, QTreeWidgetItem, QFileDialog, QHBoxLayout
9 
10 from python_qt_binding.QtCore import Qt, QTimer, Signal, Slot, QRegExp, pyqtSignal, QSize
11 
12 from python_qt_binding.QtGui import QIcon, QFont, QFontMetrics, QPalette, QBrush
13 from python_qt_binding.QtGui import QIcon, QFont, QFontMetrics, QTextDocument, QTextOption, QPen, QPainter, QColor, QTextCursor
14 
15 import syntax
16 
17 from dyn_tune.msg import Experiment
18 from dyn_tune.srv import *
19 
20 from rqt_bag.bag_widget import BagWidget
21 from .func_widget import StyledLabel
22 
23 import json
24 
25 import argparse
26 
27 from rqt_bag.player import Player
28 from rosgraph_msgs.msg import Log
29 
30 from dyn_tune import function
31 
32 python_pkg_path = os.path.join(rospkg.RosPack().get_path('dyn_tune'), 'src', 'dyn_tune')
33 
34 if python_pkg_path not in sys.path:
35  sys.path.insert(0, python_pkg_path)
36 
37 
38 
39 class MyPlayer(Player):
40  def create_publisher(self, topic, msg, prefix = "/GROUND_TRUTH"):
41  try:
42  try:
43  self._publishers[topic] = rospy.Publisher(prefix + topic, type(msg), queue_size=100)
44  except TypeError:
45  self._publishers[topic] = rospy.Publisher(prefix + topic, type(msg))
46  return True
47  except Exception as ex:
48  # Any errors, stop listening/publishing to this topic
49  rospy.logerr('Error creating publisher on topic %s for type %s. \nError text: %s' % (prefix + topic, str(type(msg)), str(ex)))
50  if topic != CLOCK_TOPIC:
51  self.stop_publishing(topic)
52  return False
53 
54 class MyBagWidget(BagWidget):
55  def __init__(self, context, publish_clock = ""):
56  print type(context)
57  args = self._parse_args(context.argv())
58  super(MyBagWidget, self).__init__(context, args.clock)
59 
60  self._timeline._player = MyPlayer(self._timeline)
62  self.graphics_view.setBackgroundBrush(QBrush(QColor(127,127,127)))
63 
64  slabel = StyledLabel(self)
65  layout = self.horizontalLayout
66  self.horizontalLayout.takeAt(0)
67  last = self.horizontalLayout.count() - 1
68  self.horizontalLayout.takeAt(last)
69  self.horizontalLayout.insertWidget(-1, slabel, 1)
70 
71  self.filename = ''
72 
73 
74  def sizeHint(self):
75  TOPIC_HEIGHT = 27
76  PADDING = 60 + 75
77  height = TOPIC_HEIGHT * len(self._timeline._get_topics()) + PADDING
78  return QSize(0, height)
79 
80  def _parse_args(self, argv):
81  parser = argparse.ArgumentParser(prog='rqt_bag', add_help=False)
82  MyBagWidget.add_arguments(parser)
83  return parser.parse_args(argv)
84 
85  @staticmethod
86  def _isfile(parser, arg):
87  if os.path.isfile(arg):
88  return arg
89  else:
90  parser.error("Bag file %s does not exist" % ( arg ))
91 
92  @staticmethod
93  def add_arguments(parser):
94  group = parser.add_argument_group('Options for rqt_bag plugin')
95  group.add_argument('--clock', action='store_true', help='publish the clock time')
96  group.add_argument('bagfiles', type=lambda x: MyBagWidget._isfile(parser, x),
97  nargs='*', default=[], help='Bagfiles to load')
98 
100  filename = QFileDialog.getOpenFileName(self, self.tr('Load from File'), '.', self.tr('Bag files {.bag} (*.bag)'))
101 
102  if filename[0] != '':
103  self.filename = filename[0]
104  self.load_bag(filename[0])
105  self._timeline.set_publishing_state(True)
106 
107 
109  self = _self._timeline._timeline_frame
110 
111  # Background Rendering
112  self._bag_end_color = QColor(76,76,76) # QColor(0, 0, 0, 25) # color of background of timeline before first message and after last
113  self._history_background_color_alternate = QColor(179, 179, 179, 90)
114  self._history_background_color = QColor(204, 204, 204, 102)
115 
116  # Timeline Division Rendering
117  # Possible time intervals used between divisions
118  # 1ms, 5ms, 10ms, 50ms, 100ms, 500ms
119  # 1s, 5s, 15s, 30s
120  # 1m, 2m, 5m, 10m, 15m, 30m
121  # 1h, 2h, 3h, 6h, 12h
122  # 1d, 7d
123  self._sec_divisions = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5,
124  1, 5, 15, 30,
125  1 * 60, 2 * 60, 5 * 60, 10 * 60, 15 * 60, 30 * 60,
126  1 * 60 * 60, 2 * 60 * 60, 3 * 60 * 60, 6 * 60 * 60, 12 * 60 * 60,
127  1 * 60 * 60 * 24, 7 * 60 * 60 * 24]
128  self._minor_spacing = 15
129  self._major_spacing = 50
130  self._major_divisions_label_indent = 3 # padding in px between line and label
131  self._major_division_pen = QPen(QBrush(QColor(76,76,76)), 0, Qt.DashLine)
132  self._minor_division_pen = QPen(QBrush(QColor(76, 76, 76, 75)), 0, Qt.DashLine)
133  self._minor_division_tick_pen = QPen(QBrush(QColor(128, 128, 128, 128)), 0)
134 
135  # Topic Rendering
136  self.topics = []
138  self._topic_font_height = None
139  self._topic_name_sizes = None
140  self._topic_name_spacing = 30 # minimum pixels between end of topic name and start of history
142  self._topic_font = QFont("courier new")
143  self._topic_font.setPointSize(self._topic_font_size)
144  self._topic_font.setBold(False)
146  self._topic_name_max_percent = 25.0 # percentage of the horiz space that can be used for topic display
147 
148  # Time Rendering
150  self._time_font_height = None
151  self._time_font_size = 10.0
152  self._time_font = QFont("courier new")
153  self._time_font.setPointSize(self._time_font_size)
154  self._time_font.setBold(False)
155 
156  # Defaults
157  self._default_brush = QBrush(Qt.black, Qt.SolidPattern)
158  self._default_pen = QPen(QColor(240, 240, 240))
159  self._default_datatype_color = QColor(255, 180, 125, 75) # QColor(0, 0, 102, 204)
161  'sensor_msgs/CameraInfo': QColor(0, 0, 77, 204),
162  'sensor_msgs/Image': QColor(0, 77, 77, 204),
163  'sensor_msgs/LaserScan': QColor(153, 0, 0, 204),
164  'pr2_msgs/LaserScannerSignal': QColor(153, 0, 0, 204),
165  'pr2_mechanism_msgs/MechanismState': QColor(0, 153, 0, 204),
166  'tf/tfMessage': QColor(0, 153, 0, 204),
167  }
168  self._default_msg_combine_px = 1.0 # minimum number of pixels allowed between two bag messages before they are combined
170 
171  # Selected Region Rendering
172  self._selected_region_color = QColor(0, 179, 0, 42)
173  self._selected_region_outline_top_color = QColor(0.0, 77, 0.0, 102)
174  self._selected_region_outline_ends_color = QColor(0.0, 77, 0.0, 204)
175  self._selected_left = None
176  self._selected_right = None
178 
179  # Playhead Rendering
180  self._playhead = None # timestamp of the playhead
181  self._paused = False
184  self._playhead_color = QColor(255, 255, 255, 191)
185 
186  # Zoom
187  self._zoom_sensitivity = 0.005
188  self._min_zoom_speed = 0.5
189  self._max_zoom_speed = 2.0
190  self._min_zoom = 0.0001 # max zoom out (in px/s)
191  self._max_zoom = 50000.0 # max zoom in (in px/s)
192 
193  # Timeline boundries
194  self._start_stamp = None # earliest of all stamps
195  self._end_stamp = None # latest of all stamps
196  self._stamp_left = None # earliest currently visible timestamp on the timeline
197  self._stamp_right = None # latest currently visible timestamp on the timeline
198  self._history_top = 30
199  self._history_left = 0
200  self._history_width = 0
202  self._history_bounds = {}
203  self._margin_left = 30
204  self._margin_right = 20
205  self._margin_bottom = 20
206 
207 
209 
210  loggerUpdate = Signal(str, name='loggerUpdate')
211 
212  def __init__(self, context):
213  super(DynTuneUI, self).__init__(context)
214 
215  # Give QObjects reasonable names
216  self.setObjectName('dyn_tune_plugin')
217 
218  # Process standalone plugin command-line arguments
219  from argparse import ArgumentParser
220  parser = ArgumentParser()
221  # Add argument(s) to the parser.
222  parser.add_argument("-q", "--quiet", action="store_true",
223  dest="quiet",
224  help="Put plugin in silent mode")
225  args, unknowns = parser.parse_known_args(context.argv())
226  if not args.quiet:
227  print 'arguments: ', args
228  print 'unknowns: ', unknowns
229 
230  # Create QWidget
231  self._widget = QWidget()
232  self._bag_widget = MyBagWidget(context)
233 
234  # Get path to UI file which should be in the "resource" folder of this package
235  ui_file = os.path.join(rospkg.RosPack().get_path('rqt_dyn_tune'), 'resource', 'DynTune.ui')
236  # Extend the widget with all attributes and children from UI file
237  loadUi(ui_file, self._widget)
238  # Give QObjects reasonable names
239  self._widget.setObjectName('DynTuneUI')
240 
241  self._widget.vLayout.insertWidget(1, self._bag_widget, 0)
242  self._widget.vLayout.setStretchFactor(self._widget.hLayout, 1)
243  self._widget.vLayout.setStretchFactor(self._widget._widget_func, 1)
244 
245  # Show _widget.windowTitle on left-top of each plugin (when
246  # it's set in _widget). This is useful when you open multiple
247  # plugins at once. Also if you open multiple instances of your
248  # plugin at once, these lines add number to make it easy to
249  # tell from pane to pane.
250  # if context.serial_number() > 1:
251  # self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))
252  # Add widget to the user interface
253  context.add_widget(self._widget)
254 
255  index = self._widget._widget_values._column_names.index("checkbox")
256  self._widget._widget_values.topics_tree_widget.hideColumn(index)
257  self._widget._widget_values.topics_tree_widget.model().setHeaderData(0, Qt.Horizontal,"value");
258 
259  self._widget._widget_func.start()
260  self._widget._widget_values.start()
261  self._widget._widget_param.start()
262 
263  rospy.Subscriber("/rosout", Log, self.logger_update)
264  self.loggerUpdate.connect(self.logger_update_slot)
265 
266 
267  css_file = os.path.join(rospkg.RosPack().get_path('rqt_dyn_tune'), 'src', 'rqt_dyn_tune', 'css', 'selector.css')
268  with open(css_file, "r") as fh:
269  csstext = fh.read()
270  self._widget._widget_func.setStyleSheet(csstext)
271  self._widget._widget_values.setStyleSheet(csstext)
272  self._widget._widget_param.setStyleSheet(csstext)
273 
274 
275  css_file = os.path.join(rospkg.RosPack().get_path('rqt_dyn_tune'), 'src', 'rqt_dyn_tune', 'css', 'bag.css')
276  with open(css_file, "r") as fh:
277  csstext = fh.read()
278  self._bag_widget.setStyleSheet(csstext)
279 
280 
281  css_file = os.path.join(rospkg.RosPack().get_path('rqt_dyn_tune'), 'src', 'rqt_dyn_tune', 'css', 'plugin.css')
282  with open(css_file, "r") as fh:
283  csstext = fh.read()
284  self._widget.setStyleSheet(csstext)
285 
286 
287 
288  self._widget.tune_btn.clicked.connect(self.tune_clicked)
289 
290  @Slot()
291  def topics_refreshed():
292  topic_widget = self._widget._widget_values
293  values = topic_widget.get_selected_values()
294  self._widget._widget_func.topics_refreshed(values)
295 
296 
297  self._widget._widget_values.topicsRefreshed.connect(topics_refreshed)
298 
299 
300  def logger_update(self, msg):
301  if msg.name == "/dyn_tune_backbone":
302  self.loggerUpdate.emit(msg.msg)
303 
304  @Slot(str)
305  def logger_update_slot(self, msg):
306  self._widget.logger.append(msg)
307 
308  def tune_clicked(self):
309  srv = self.creat_optimize_srv()
310  print srv
311  self.optimize = rospy.ServiceProxy('/optimize', Optimize)
312  result = self.optimize(srv)
313  print result
314  pass
315 
316 
317  def create_experiment_msg(self, name = "experiment_0"):
318  exp = Experiment()
319  params_dict = self._widget._widget_param.get_selected()
320  exp.parameters = json.dumps(params_dict)
321  exp.objective = self._widget._widget_func.create_function_msg()
322 
323  return exp
324 
326  opt = OptimizeRequest()
327 
328  opt.observation_values = self._widget._widget_values.get_selected()
329  opt.start_signals = "{}"
330  opt.end_signals = "{}"
331  opt.src_bag = self._bag_widget.filename
332  opt.dst_bag = "_simulation.bag"
333 
334  opt.src_topic = "/.*"
335  opt.dst_topic = ""
336 
337  exp = self.create_experiment_msg()
338  opt.experiments.append(exp)
339 
340  return opt
341 
342 
343  # opt.src.
344 
345 
346  def shutdown_plugin(self):
347  # TODO unregister all publishers here
348  pass
349 
350  def save_settings(self, plugin_settings, instance_settings):
351  # TODO save intrinsic configuration, usually using:
352  # instance_settings.set_value(k, v)
353  pass
354 
355  def restore_settings(self, plugin_settings, instance_settings):
356  # TODO restore intrinsic configuration, usually using:
357  # v = instance_settings.value(k)
358  pass
359 
360  # def trigger_configuration(self):
361  # Comment in to signal that the plugin has a way to configure
362  # This will enable a setting button (gear icon) in each dock widget title bar
363  # Usually used to open a modal configuration dialog
def save_settings(self, plugin_settings, instance_settings)
def __init__(self, context, publish_clock="")
Definition: rqt_dyn_tune.py:55
def create_publisher(self, topic, msg, prefix="/GROUND_TRUTH")
Definition: rqt_dyn_tune.py:40
def restore_settings(self, plugin_settings, instance_settings)
def create_experiment_msg(self, name="experiment_0")


rqt_dyn_tune
Author(s):
autogenerated on Mon Jun 10 2019 14:52:08