sr_data_visualizer_gui.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # Copyright 2020 Shadow Robot Company Ltd.
4 #
5 # This program is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation version 2 of the License.
8 #
9 # This program is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 # more details.
13 #
14 # You should have received a copy of the GNU General Public License along
15 # with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 import yaml
18 import matplotlib
19 import numpy as np
20 import os
21 import signal
22 import rospy
23 import rospkg
24 import string
25 import re
26 import time
27 import atexit
28 matplotlib.use("Qt5Agg") # noqa
29 from python_qt_binding.QtGui import *
30 from python_qt_binding.QtCore import *
31 try:
32  from python_qt_binding.QtWidgets import *
33 except ImportError:
34  pass
35 import sys
36 from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
37 from matplotlib.figure import Figure
38 from matplotlib.animation import TimedAnimation
39 from matplotlib.lines import Line2D
40 from python_qt_binding.QtGui import *
41 from python_qt_binding.QtCore import *
42 from qt_gui.plugin import Plugin
43 from python_qt_binding import loadUi
44 try:
45  from python_qt_binding.QtWidgets import *
46 except ImportError:
47  pass
48 from sensor_msgs.msg import JointState
49 from control_msgs.msg import JointControllerState
50 from diagnostic_msgs.msg import DiagnosticArray
51 from std_msgs.msg import Float64MultiArray
52 from QtGui import QIcon, QColor, QPainter, QFont
53 from QtWidgets import QMessageBox, QWidget
54 from QtCore import QRectF, QTimer
55 from sr_robot_msgs.msg import Biotac, BiotacAll
56 from sr_utilities.hand_finder import HandFinder
57 
58 
60  def __init__(self, context):
61  self.init_complete = False
62  self.first_run = True
63  super(SrDataVisualizer, self).__init__(context)
64  self.setObjectName("SrDataVisualizer")
65  self._widget = QWidget()
66  self._hand_finder = HandFinder()
67  self._hand_parameters = self._hand_finder.get_hand_parameters()
68  self._joint_prefix = self._hand_parameters.joint_prefix
69  for key in self._hand_parameters.joint_prefix:
70  self.hand_serial = key
71  self._joint_prefix = self._hand_parameters.joint_prefix[self.hand_serial]
72  ui_file = os.path.join(rospkg.RosPack().get_path('sr_data_visualization'), 'uis', 'hand-e_visualizer.ui')
73  loadUi(ui_file, self._widget)
74  if __name__ != "__main__":
75  context.add_widget(self._widget)
76  self._widget.setWindowTitle("Dexterous Hand Data Visualizer")
77 
78  # Set white background color
79  p = self._widget.palette()
80  p.setColor(self._widget.backgroundRole(), Qt.white)
81  self._widget.setPalette(p)
82  self.tab_widget_main = self._widget.findChild(QTabWidget, "tabWidget_main")
83  self.tabWidget_motor_stats = self._widget.findChild(QTabWidget, "tabWidget_motor_stats")
84 
85  # Change tabs background color
86  p = self.tab_widget_main.palette()
87  stylesheet = """
88  QTabWidget>QWidget>QWidget{background: white;}
89  """
90  p.setColor(self.tab_widget_main.backgroundRole(), Qt.white)
91  self.tab_widget_main.setStyleSheet(stylesheet)
92 
93  self.tab_widget_main.currentChanged.connect(self.tab_change)
94  self.tabWidget_motor_stats.currentChanged.connect(self.tab_change_mstat)
95 
96  motor_stat_keys_file = os.path.join(rospkg.RosPack().get_path('sr_data_visualization'), 'config',
97  'data_visualiser_motor_stat_keys.yaml')
98  if self._joint_prefix == "rh_":
99  parameters_file = os.path.join(rospkg.RosPack().get_path('sr_data_visualization'), 'config',
100  'data_visualiser_parameters_rh.yaml')
101  elif self._joint_prefix == "lh_":
102  parameters_file = os.path.join(rospkg.RosPack().get_path('sr_data_visualization'), 'config',
103  'data_visualiser_parameters_lh.yaml')
104  else:
105  rospy.logerr("Unknown hand detected")
106 
107  self.t0 = time.time()
108 
109  self.reset_tab_1 = self._widget.findChild(QPushButton, "reset_tab1")
110  self.reset_tab_2 = self._widget.findChild(QPushButton, "reset_tab2")
111  self.reset_tab_3 = self._widget.findChild(QPushButton, "reset_tab3")
112  self.reset_tab_1.clicked.connect(self.reset_1)
113  self.reset_tab_2.clicked.connect(self.reset_2)
114  self.reset_tab_3.clicked.connect(self.reset_3)
115 
116  self.font_offset = -3
117 
118  self._widget.resizeEvent = self.on_resize_main
119 
120  self.type_dict = {
121  0: "pos_vel_eff",
122  1: "control_loops",
123  2: "motor_stat"
124  }
125 
128 
129  with open(motor_stat_keys_file, 'r') as stream:
130  try:
131  self.motor_stat_keys = yaml.load(stream)
132  except yaml.YAMLError as exc:
133  print(exc)
134 
135  with open(parameters_file, 'r') as stream:
136  try:
137  data_loaded = yaml.load(stream)
138  self._initialize(data_loaded)
139  except yaml.YAMLError as exc:
140  print(exc)
141 
142  self._setup_radio_buttons()
143 
144  self.tabWidget_motor_stats.setCurrentIndex(0)
145  self.tabWidget_motor_stats.setCurrentIndex(1)
146  self.tabWidget_motor_stats.setCurrentIndex(2)
147  self.tabWidget_motor_stats.setCurrentIndex(3)
148  self.tabWidget_motor_stats.setCurrentIndex(4)
149  self.tabWidget_motor_stats.setCurrentIndex(5)
150  self.tabWidget_motor_stats.setCurrentIndex(0)
151 
152  # Update legends on motor_stat graphs
153  self._change_graphs(all=True, type=2, ncol=1)
154 
155  QTimer.singleShot(5000, self.reset_1)
156  self.init_complete = True
157 
158  def shutdown_plugin(self):
159  graph_type = [key for key, value in self.graph_names_global.items()]
160  for element in graph_type:
161  for key, graph in self.graph_dict_global[element].iteritems():
162  graph.enabled = False
163 
164  def on_resize_main(self, empty):
165  if (self._widget.width() * self._widget.height()) < 3500000:
166  self.font_offset = -3
167  else:
168  self.font_offset = 1
169 
170  def reset_1(self):
171  self._reset_graphs(0)
172  self.radio_button_all.setChecked(True)
173 
174  def reset_2(self):
175  self._reset_graphs(1)
176  self.radio_button_ctrl_all.setChecked(True)
177 
178  def reset_3(self):
179  self._reset_graphs(2)
180  self.radioButton_all_motor_stat.setChecked(True)
181 
182  def _reset_graphs(self, tab):
183  graph_type = [key for key, value in self.graph_names_global.items() if self.type_dict[tab] in key]
184  for element in graph_type:
185  for key, graph in self.graph_dict_global[element].iteritems():
186  graph.ax1.clear()
187  graph._handle_resize()
188  if tab == 2:
189  ncol = 1
190  else:
191  ncol = 3
192  self._change_graphs(all=True, type=tab, ncol=ncol)
193 
196  self.timer = QTimer(self._widget)
197  for i in range(self.number_of_biotacs):
198  tactile_gui = SrGuiBiotac(None)
199  tactile_gui._widget = self._widget
200  tactile_gui.find_children(i)
201  self.tactile_gui_list.append(tactile_gui)
202  widget = self._widget.findChild(QWidget, "widget" + "_" + str(i))
203  widget.resizeEvent = self.on_resize_tactile
204 
205  self.timer.timeout.connect(widget.update)
206  widget.paintEvent = tactile_gui.paintEvent
207  if not tactile_gui._hand_parameters.mapping:
208  rospy.logerr("No hand detected")
209 
210  self.label_list = []
211  self.lcd_list = []
212 
213  for j in range(self.number_of_biotacs):
214  lcds = []
215  labels = []
216  for i in range(1, self.electrodes_per_biotac):
217  if i < 10:
218  lcd = self._widget.findChild(QLCDNumber, "lcdE0" + str(i) + "_" + str(j))
219  label = self._widget.findChild(QLabel, "label_E0" + str(i) + "_" + str(j))
220  else:
221  lcd = self._widget.findChild(QLCDNumber, "lcdE" + str(i) + "_" + str(j))
222  label = self._widget.findChild(QLabel, "label_E" + str(i) + "_" + str(j))
223  lcds.append(lcd)
224  labels.append(label)
225  self.lcd_list.append(lcds)
226  self.label_list.append(labels)
227  self.timer.start(50)
228 
229  def on_resize_tactile(self, none):
230  for tactile_widget in self.tactile_gui_list:
231  tactile_widget.redraw_electrodes()
232 
233  if (self._widget.width() * self._widget.height()) < 3500000:
234  scale = 6
235  mheight = 18
236  else:
237  scale = 12
238  mheight = 30
239 
240  font = QFont('Sans Serif', scale)
241  font.setKerning(True)
242  for j in range(self.number_of_biotacs):
243  for i in range(self.electrodes_per_biotac - 1):
244  self.lcd_list[j][i].setMinimumHeight(2)
245  self.lcd_list[j][i].setMaximumHeight(mheight)
246  self.label_list[j][i].setFont(font)
247 
248  def tab_change_mstat(self, tab_index):
249  self._hide_and_refresh(tab_index, "motor_stat")
250 
251  def tab_change(self, tab_index):
252  self._hide_and_refresh(tab_index, "main")
253 
254  def _hide_and_refresh(self, tab_index, tab_type):
255  self._hide_tabs(tab_index, tab_type)
256 
257  def _hide_tabs(self, tab_index, tab):
258  if tab == "main":
259  if tab_index == 0:
260  graph_type = [key for key, value in self.graph_names_global.items() if "pos_vel_eff" not in key]
261  self._disable_graphs(graph_type, disable=True)
262  self._disable_graphs(["pos_vel_eff"], disable=False)
263  elif tab_index == 1:
264  graph_type = [key for key, value in self.graph_names_global.items() if "control_loops" not in key]
265  self._disable_graphs(graph_type, disable=True)
266  self._disable_graphs(["control_loops"], disable=False)
267  elif tab_index == 2:
268  graph_type = [key for key, value in self.graph_names_global.items() if "motor_stat" not in key]
269  self._disable_graphs(graph_type, disable=True)
271  elif tab_index == 3:
272  graph_type = [key for key, value in self.graph_names_global.items() if "palm_extras" not in key]
273  self._disable_graphs(graph_type, disable=True)
274  graph_type = [key for key, value in self.graph_names_global.items() if "palm_extras" in key]
275  self._disable_graphs(graph_type, disable=False)
276  elif tab_index == 4:
277  graph_type = [key for key, value in self.graph_names_global.items() if "biotacs" not in key]
278  self._disable_graphs(graph_type, disable=True)
279  self._disable_graphs(["biotacs"], disable=False)
280  elif tab_index == 5:
281  graph_type = [key for key, value in self.graph_names_global.items()]
282  self._disable_graphs(graph_type, disable=True)
283  elif tab == "motor_stat":
285 
287  tab_index = self.tabWidget_motor_stats.currentIndex()
288  tab_index_dict = {
289  0: "thj",
290  1: "ffj",
291  2: "mfj",
292  3: "rfj",
293  4: "lfj",
294  5: "wrj"
295  }
296  self._hide_all_but(tab_index_dict[tab_index])
297 
298  def _hide_all_but(self, joint_group):
299  x = [value for key, value in self.graph_dict_global["motor_stat"].items() if joint_group in key]
300  for graph in x:
301  graph.enabled = True
302  x = [value for key, value in self.graph_dict_global["motor_stat"].items() if joint_group not in key]
303  for graph in x:
304  graph.enabled = False
305 
306  def _disable_graphs(self, graph_type, disable):
307  for element in graph_type:
308  for key, graph in self.graph_dict_global[element].iteritems():
309  graph.enabled = not disable
310 
312  self.radio_button_velocity = self._widget.findChild(QRadioButton, "radioButton_velocity")
313  self.radio_button_all = self._widget.findChild(QRadioButton, "radioButton_all")
314  self.radio_button_position = self._widget.findChild(QRadioButton, "radioButton_position")
315  self.radio_button_effort = self._widget.findChild(QRadioButton, "radioButton_effort")
316 
317  self.radio_button_setpoint = self._widget.findChild(QRadioButton, "radioButton_setpoint")
318  self.radio_button_input = self._widget.findChild(QRadioButton, "radioButton_input")
319  self.radio_button_dInput = self._widget.findChild(QRadioButton, "radioButton_dInput")
320  self.radio_button_error = self._widget.findChild(QRadioButton, "radioButton_error")
321  self.radio_button_output = self._widget.findChild(QRadioButton, "radioButton_output")
322  self.radio_button_ctrl_all = self._widget.findChild(QRadioButton, "radioButton_ctrl_all")
323 
324  self.radioButton_all_motor_stat = self._widget.findChild(QRadioButton, "radioButton_all_motor_stat")
325  self.radioButton_strain_gauge_left = self._widget.findChild(QRadioButton, "radioButton_strain_gauge_left")
326  self.radioButton_strain_gauge_right = self._widget.findChild(QRadioButton, "radioButton_strain_gauge_right")
327  self.radioButton_measured_pwm = self._widget.findChild(QRadioButton, "radioButton_measured_pwm")
328  self.radioButton_measured_current = self._widget.findChild(QRadioButton, "radioButton_measured_current")
329  self.radioButton_measured_voltage = self._widget.findChild(QRadioButton, "radioButton_measured_voltage")
330  self.radioButton_measured_effort = self._widget.findChild(QRadioButton, "radioButton_measured_effort")
331  self.radioButton_temperature = self._widget.findChild(QRadioButton, "radioButton_temperature")
332  self.radioButton_unfiltered_position = self._widget.findChild(QRadioButton, "radioButton_unfiltered_position")
333  self.radioButton_unfiltered_force = self._widget.findChild(QRadioButton, "radioButton_unfiltered_force")
334  self.radioButton_last_commanded_effort = self._widget.findChild(QRadioButton,
335  "radioButton_last_commanded_effort")
336  self.radioButton_encoder_position = self._widget.findChild(QRadioButton, "radioButton_encoder_position")
337 
339  number_of_radio_button_pages = 3
340  for j in range(number_of_radio_button_pages):
341  for i in range(len(self.global_yaml["graphs"][j]["lines"])):
342  tmp = self._make_all_button_functions(i, all=False, type=j)
343  self.radio_button_list.append(tmp)
344  tmp = self._make_all_button_functions(i, all=True, type=j)
345  self.radio_button_list.append(tmp)
346 
347  self.radio_button_position.toggled.connect(lambda: self.radio_button_list[0](self.radio_button_position))
348  self.radio_button_velocity.toggled.connect(lambda: self.radio_button_list[1](self.radio_button_velocity))
349  self.radio_button_effort.toggled.connect(lambda: self.radio_button_list[2](self.radio_button_effort))
350  self.radio_button_all.toggled.connect(lambda: self.radio_button_list[3](self.radio_button_all))
351 
352  self.radio_button_setpoint.toggled.connect(lambda: self.radio_button_list[4](self.radio_button_setpoint))
353  self.radio_button_input.toggled.connect(lambda: self.radio_button_list[5](self.radio_button_input))
354  self.radio_button_dInput.toggled.connect(lambda: self.radio_button_list[6](self.radio_button_dInput))
355  self.radio_button_error.toggled.connect(lambda: self.radio_button_list[7](self.radio_button_error))
356  self.radio_button_output.toggled.connect(lambda: self.radio_button_list[8](self.radio_button_output))
357  self.radio_button_ctrl_all.toggled.connect(lambda: self.radio_button_list[9](self.radio_button_ctrl_all))
358 
359  self.radioButton_strain_gauge_left.toggled.connect(
360  lambda: self.radio_button_list[10](self.radioButton_strain_gauge_left))
361  self.radioButton_strain_gauge_right.toggled.connect(
362  lambda: self.radio_button_list[11](self.radioButton_strain_gauge_right))
363  self.radioButton_measured_pwm.toggled.connect(
364  lambda: self.radio_button_list[12](self.radioButton_measured_pwm))
365  self.radioButton_measured_current.toggled.connect(
366  lambda: self.radio_button_list[13](self.radioButton_measured_current))
367  self.radioButton_measured_voltage.toggled.connect(
368  lambda: self.radio_button_list[14](self.radioButton_measured_voltage))
369  self.radioButton_measured_effort.toggled.connect(
370  lambda: self.radio_button_list[15](self.radioButton_measured_effort))
371  self.radioButton_temperature.toggled.connect(
372  lambda: self.radio_button_list[16](self.radioButton_temperature))
373  self.radioButton_unfiltered_position.toggled.connect(
374  lambda: self.radio_button_list[17](self.radioButton_unfiltered_position))
375  self.radioButton_unfiltered_force.toggled.connect(
376  lambda: self.radio_button_list[18](self.radioButton_unfiltered_force))
377  self.radioButton_last_commanded_effort.toggled.connect(
379  self.radioButton_encoder_position.toggled.connect(
380  lambda: self.radio_button_list[20](self.radioButton_encoder_position))
381  self.radioButton_all_motor_stat.toggled.connect(
382  lambda: self.radio_button_list[21](self.radioButton_all_motor_stat))
383 
384  def _make_all_button_functions(self, i, all, type):
385  graph_type = self.type_dict[type]
386 
387  if "legend_columns" in self.global_yaml["graphs"][type]:
388  number_of_columns = self.global_yaml["graphs"][type]["legend_columns"]
389  elif all and graph_type == "pos_vel_eff":
390  number_of_columns = 3
391  elif all and graph_type == "control_loops":
392  number_of_columns = 5
393  elif all and graph_type == "motor_stat":
394  number_of_columns = 1
395 
396  if all:
397  def _button_function(b):
398  if b.text() == "All":
399  if b.isChecked():
400  self._change_graphs(all=True, type=type, ncol=number_of_columns)
401  else:
402  legend_name = self.global_yaml["graphs"][type]["lines"][i]
403  legend_name_stripped = re.sub(r"[\(\[].*?[\)\]]", "", legend_name).strip()
404 
405  def _button_function(b):
406  if legend_name_stripped in b.text():
407  if b.isChecked():
408  self._change_graphs(all=False, legend_name=[legend_name],
409  line_number=i, type=type, ncol=1)
410  return _button_function
411 
412  def _change_graphs(self, all, **kwargs):
413  index = kwargs["type"]
414  type = self.type_dict[index]
415 
416  if 'ncol' not in kwargs:
417  ncols = 3
418  else:
419  ncols = kwargs["ncol"]
420 
421  for i in range(len(self.graph_names_global[type])):
422  graph = self.graph_dict_global[type][self.graph_names_global[type][i]]
423  if all:
424  ymin, ymax = self._find_max_range(self.global_yaml["graphs"][index])
425  graph.ymin = ymin
426  graph.ymax = ymax
427  graph.plot_all = True
428  graph.ax1.yaxis.set_tick_params(which='both', labelbottom=False)
429  graph.re_init()
430  graph.ax1.legend(graph.line, self.global_yaml["graphs"][index]["lines"],
431  bbox_to_anchor=(0.0, 1.0, 1.0, 0.9), framealpha=0.8, loc=3, mode="expand",
432  borderaxespad=0.5, ncol=ncols,
433  prop={'size': 9 + self.font_offset})
434  else:
435  graph.ymin = self.global_yaml["graphs"][index]["ranges"][kwargs["line_number"]][0]
436  graph.ymax = self.global_yaml["graphs"][index]["ranges"][kwargs["line_number"]][1]
437  graph.line_to_plot = kwargs["line_number"]
438  graph.plot_all = False
439  graph.ax1.yaxis.set_tick_params(which='both', labelbottom=True, labelsize=6)
440  graph.re_init()
441  graph.ax1.legend(graph.line, kwargs["legend_name"], bbox_to_anchor=(0.0, 1.0, 1.0, 0.9),
442  framealpha=0.8, loc=3, mode="expand", borderaxespad=0.5,
443  prop={'size': 10 + self.font_offset})
444  if graph.enabled:
445  graph.update()
446  graph.draw()
447 
449  def _callback(value):
450  if graph.plot_all:
451  ymin, ymax = self._find_max_range(self.global_yaml["graphs"][1])
452  graph.addData(value.set_point * (ymax / self.global_yaml["graphs"][1]["ranges"][0][1]), 0)
453  graph.addData(value.process_value * (ymax / self.global_yaml["graphs"][1]["ranges"][1][1]), 1)
454  graph.addData(value.process_value_dot * (ymax / self.global_yaml["graphs"][1]["ranges"][2][1]), 2)
455  graph.addData(value.error * (ymax / self.global_yaml["graphs"][1]["ranges"][3][1]), 3)
456  graph.addData(value.command * (ymax / self.global_yaml["graphs"][1]["ranges"][4][1]), 4)
457  else:
458  graph.addData(value.set_point, 0)
459  graph.addData(value.process_value, 1)
460  graph.addData(value.process_value_dot, 2)
461  graph.addData(value.error, 3)
462  graph.addData(value.command, 4)
463 
464  return _callback
465 
466  def _find_max_range(self, graphs):
467  ymin = 0
468  ymax = 0
469  for i in range(len(graphs["ranges"])):
470  if graphs["ranges"][i][0] <= ymin and graphs["ranges"][i][1] >= ymax:
471  ymin = graphs["ranges"][i][0]
472  ymax = graphs["ranges"][i][1]
473  scales = [ymin, ymax]
474  return scales
475 
476  def _initialize(self, data):
477  self.global_yaml = data
478  topic_list = rospy.get_published_topics()
479  self.show_tactiles = False
480  for topic in topic_list:
481  for value in topic:
482  if "bio" in value or "Bio" in value:
484  self.show_tactiles = True
485  if self.show_tactiles is False:
486  for graphs in self.global_yaml["graphs"]:
487  if graphs["type"] == "biotacs":
488  self.global_yaml["graphs"].remove(graphs)
489  self.tab_widget_main.setTabEnabled(4, False)
490  self.tab_widget_main.setTabEnabled(5, False)
491  p = self.tab_widget_main.palette()
492  stylesheet = """
493  QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 1; border: none;}
494  QTabWidget>QWidget>QWidget{background: white;}
495  """
496  p.setColor(self.tab_widget_main.backgroundRole(), Qt.white)
497  self.tab_widget_main.setStyleSheet(stylesheet)
498 
501  self.subs = []
503  for graphs in data["graphs"]:
504  if self.show_tactiles or graphs["type"] != "biotacs":
505  ymin, ymax = self._find_max_range(graphs)
506  self.graph_names_global[graphs["type"]] = graphs["graph_names"]
507  if "legend_columns" in graphs:
508  legend_columns = graphs["legend_columns"]
509  else:
510  legend_columns = len(graphs["lines"])
511 
512  # create_graphs
513  temp_graph_dict = {}
514  for i in range(len(graphs["graph_names"])):
515  if graphs["type"] == "biotacs":
516  temp_graph_dict[graphs["graph_names"][i]] = CustomFigCanvas(num_lines=len(graphs["lines"]),
517  colour=graphs["colours"],
518  ymin=graphs["ranges"][i][0],
519  ymax=graphs["ranges"][i][1],
520  legends=graphs["lines"],
521  legend_columns=legend_columns,
522  legend_font_size=(
523  graphs["font_size"] +
524  self.font_offset),
525  num_ticks=4,
526  xaxis_tick_animation=False,
527  tail_enable=False, enabled=True)
528  else:
529  temp_graph_dict[graphs["graph_names"][i]] = CustomFigCanvas(num_lines=len(graphs["lines"]),
530  colour=graphs["colours"], ymin=ymin,
531  ymax=ymax, legends=graphs["lines"],
532  legend_columns=legend_columns,
533  legend_font_size=(
534  9 +
535  self.font_offset),
536  num_ticks=4,
537  xaxis_tick_animation=False,
538  tail_enable=False, enabled=True)
539  self.graph_dict_global[graphs["type"]] = temp_graph_dict
540 
541  # create subscribers
542  if graphs["type"] == "control_loops":
543  for i in range(len(graphs["graph_names"])):
544  sub_namespace = graphs["topic_namespace_start"] + graphs["graph_names"][i] + graphs[
545  "topic_namespace_end"]
546  tmp_callback = self._make_control_loop_callbacks(
547  self.graph_dict_global["control_loops"][graphs["graph_names"][i]])
548  self.subs.append(
549  rospy.Subscriber(sub_namespace, JointControllerState, callback=tmp_callback, queue_size=1))
550  self.control_loop_callback_dict[graphs["graph_names"][i]] = tmp_callback
551  elif graphs["type"] == "pos_vel_eff":
552  self.subs.append(
553  rospy.Subscriber(graphs["topic_namespace"], JointState, self._joint_state_cb, queue_size=1))
554  elif graphs["type"] == "motor_stat":
555  self.subs.append(
556  rospy.Subscriber(graphs["topic_namespace"], DiagnosticArray, self._diagnostic_cb,
557  queue_size=1))
558  elif graphs["type"] == "palm_extras_accelerometer":
559  self.subs.append(
560  rospy.Subscriber(graphs["topic_namespace"], Float64MultiArray, self._palm_extras_cb,
561  queue_size=1))
562  elif graphs["type"] == "biotacs":
563  self.subs.append(
564  rospy.Subscriber(graphs["topic_namespace"], BiotacAll, self._biotac_all_cb, queue_size=1))
565 
566  # init_widget_children
567  lay_dic = {}
568  for i in range(len(graphs["graph_names"])):
569  if graphs["type"] == "control_loops":
570  layout = graphs["graph_names"][i] + "_layout_ctrl"
571  elif graphs["type"] == "motor_stat":
572  layout = graphs["graph_names"][i] + "_layout_motor_stat"
573  else:
574  layout = graphs["graph_names"][i] + "_layout"
575  lay_dic[graphs["graph_names"][i]] = self._widget.findChild(QVBoxLayout, layout)
576  # attach_graphs
577  for i in range(len(graphs["graph_names"])):
578  x = lay_dic.get(graphs["graph_names"][i])
579  x.addWidget(self.graph_dict_global[graphs["type"]][graphs["graph_names"][i]])
580  # Setup palm extras graphs (as they don't need radio buttons)
581  palm_extras_graphs = [value for key, value in self.graph_dict_global.items() if 'palm_extras' in key]
582  i = 3
583  for graph in palm_extras_graphs:
584  for key, value in graph.iteritems():
585  value.plot_all = True
586  value.ax1.yaxis.set_tick_params(which='both', labelbottom=True)
587  value.ymax = self.global_yaml["graphs"][i]["ranges"][0][1]
588  value.ymin = self.global_yaml["graphs"][i]["ranges"][0][0]
589  font_size = value.ax1.legend_.prop._size
590  value.re_init()
591  value.ax1.legend(value.line, self.global_yaml["graphs"][i]["lines"],
592  bbox_to_anchor=(0.0, 1.0, 1.0, 0.9), framealpha=0.8, loc=3, mode="expand",
593  borderaxespad=0.5, ncol=len(self.global_yaml["graphs"][i]["lines"]),
594  prop={'size': font_size})
595  i += 1
596 
597  def _joint_state_cb(self, value):
598  if self.first_run:
599  # Creates map of jointstates (so we can do joint_state.values.position[joint_state_data_map["rh_FFJ1"]]
601  for i in range(len(value.name)):
602  self.joint_state_data_map[value.name[i]] = i
603  self.first_run = False
604  # Only add data to graphs once they've all been created
605  if self.init_complete:
606  # for each graph
607  for j in range(len(self.graph_names_global["pos_vel_eff"])):
608  graph = self.graph_dict_global["pos_vel_eff"][self.graph_names_global["pos_vel_eff"][j]]
609  data_index = self.joint_state_data_map[self._joint_prefix +
610  string.upper(self.graph_names_global["pos_vel_eff"][j])]
611  if graph.plot_all:
612  ymin, ymax = self._find_max_range(self.global_yaml["graphs"][0])
613  range_array = self.global_yaml["graphs"][0]["ranges"]
614  # for each line
615  graph.addData(value.position[data_index] * (ymax / range_array[0][1]), 0)
616  graph.addData(value.velocity[data_index] * (ymax / range_array[1][1]), 1)
617  graph.addData(value.effort[data_index] * (ymax / range_array[2][1]), 2)
618  else:
619  # for each line
620  graph.addData(value.position[data_index], 0)
621  graph.addData(value.velocity[data_index], 1)
622  graph.addData(value.effort[data_index], 2)
623 
624  def _diagnostic_cb(self, data):
625  # Only add data to graphs once they've all been created
626  if self.init_complete:
627  if len(data.status) > 1:
628  # for each joint_name / graph
629  # i iterate from 0 to give joint names #j iterate from 0 to give line numbers
630  for i in range(len(self.graph_names_global["motor_stat"])):
631  for j in range(len(self.motor_stat_keys[1])):
632  x = self.global_yaml["graphs"][2]["lines"][j]
633  x = re.sub(r"[\(\[].*?[\)\]]", "", x).strip()
634  ymin, ymax = self._find_max_range(self.global_yaml["graphs"][2])
635  graph = self.graph_dict_global["motor_stat"][self.graph_names_global["motor_stat"][i]]
636  data_index = self.motor_stat_keys[0][string.upper(self.graph_names_global["motor_stat"][i])]
637  data_point = data.status[data_index]
638  line_number = self.motor_stat_keys[1][x]
639  data_value = data_point.values[line_number].value
640  scale = float(ymax / self.global_yaml["graphs"][2]["ranges"][j][1])
641  if self.graph_dict_global["motor_stat"][self.graph_names_global["motor_stat"][i]].plot_all:
642  graph.addData(float(data_value) * scale, j)
643  else:
644  graph.addData(float(data_value), j)
645 
646  def _palm_extras_cb(self, data):
647  if self.init_complete:
648  palm_extras_graphs = [value for key, value in self.graph_dict_global.items() if 'palm_extras' in key]
649  for graph in palm_extras_graphs:
650  if 'palm_extras_accelerometer' in graph:
651  graph["palm_extras_accelerometer"].addData(data.data[0], 0)
652  graph["palm_extras_accelerometer"].addData(data.data[1], 1)
653  graph["palm_extras_accelerometer"].addData(data.data[2], 2)
654  if 'palm_extras_gyro' in graph:
655  graph["palm_extras_gyro"].addData(data.data[3], 0)
656  graph["palm_extras_gyro"].addData(data.data[4], 1)
657  graph["palm_extras_gyro"].addData(data.data[5], 2)
658  if 'palm_extras_adc' in graph:
659  graph["palm_extras_adc"].addData(data.data[6], 0)
660  graph["palm_extras_adc"].addData(data.data[7], 1)
661  graph["palm_extras_adc"].addData(data.data[8], 2)
662  graph["palm_extras_adc"].addData(data.data[9], 3)
663 
664  def _biotac_all_cb(self, data):
665  if self.init_complete:
666  for i in range(len(data.tactiles)):
667  self.graph_dict_global["biotacs"]["PAC0"].addData(data.tactiles[i].pac0, i)
668  self.graph_dict_global["biotacs"]["PAC1"].addData(data.tactiles[i].pac1, i)
669  self.graph_dict_global["biotacs"]["PDC"].addData(data.tactiles[i].pdc, i)
670  self.graph_dict_global["biotacs"]["TAC"].addData(data.tactiles[i].tac, i)
671  self.graph_dict_global["biotacs"]["TDC"].addData(data.tactiles[i].tdc, i)
672 
673 
675  _nb_electrodes_biotac = 19
676  _nb_electrodes_biotac_sp = 24
677 
678  def __init__(self, context):
679  super(SrGuiBiotac, self).__init__(context)
680  self.setObjectName('SrGuiBiotac')
681  self._hand_finder = HandFinder()
682  self._hand_parameters = self._hand_finder.get_hand_parameters()
683  self.load_params()
684 
685  self._widget = QWidget()
686 
687  self.latest_data = BiotacAll()
688  self.pixels = self._widget.width() * self._widget.height()
689 
690  self.define_electrodes()
693 
695 
696  def define_electrodes(self):
698  rospy.get_param(
699  "sr_gui_biotac/sensing_electrodes_x_locations",
700  [6.45, 3.65, 3.65, 6.45, 3.65, 6.45, 0.00, 1.95, -1.95,
701  0.00, -6.45, - 3.65, -3.65, -6.45, -3.65, -6.45, 0.00,
702  0.00, 0.00]) # Physical electrode locations on the sensor
704  rospy.get_param(
705  "sr_gui_biotac/sensing_electrodes_y_locations",
706  [7.58, 11.28, 14.78, 16.58, 19.08, 21.98, 4.38, 6.38, 6.38,
707  8.38, 7.58, 11.28, 14.78, 16.58, 19.08, 21.98, 11.38,
708  18.38, 22.18])
709 
711  rospy.get_param(
712  "sr_gui_biotac/excitation_electrodes_x_locations",
713  [6.45, 3.75, -3.75, -6.45])
715  rospy.get_param(
716  "sr_gui_biotac/excitation_electrodes_y_locations",
717  [12.48, 24.48, 24.48, 12.48])
718 
720  rospy.get_param(
721  "sr_gui_biotac/sensing_electrodes_x_locations",
722  [5.00, 3.65, 6.45, 4.40, 2.70, 6.45, 4.40, 1.50, 4.00, 4.50,
723  -5.00, - 3.65, -6.45, -4.40, -2.70, -6.45, -4.40, -1.50, -4.00, -4.50,
724  0.00, 1.95, -1.95, 0.00]) # Physical electrode locations on the sensor
726  rospy.get_param(
727  "sr_gui_biotac/sensing_electrodes_y_locations",
728  [4.38, 6.38, 14.78, 15.50, 18.50, 19.08, 20.00, 21.00, 23.00, 25.00,
729  4.38, 6.38, 14.78, 15.50, 18.50, 19.08, 20.00, 21.00, 23.00, 25.00,
730  7.38, 11.50, 11.50, 15.20])
731 
733  rospy.get_param(
734  "sr_gui_biotac/excitation_electrodes_x_locations",
735  [5.30, 6.00, -5.30, -6.00])
737  rospy.get_param(
738  "sr_gui_biotac/excitation_electrodes_y_locations",
739  [9.00, 22.00, 9.00, 22.00])
740 
741  def _assign_electrodes(self, nb_electrodes):
742  if nb_electrodes == self._nb_electrodes_biotac:
747  elif nb_electrodes == self._nb_electrodes_biotac_sp:
752  else:
753  rospy.logerr("Number of electrodes %d not matching known biotac models. expected: %d or %d",
754  nb_electrodes, self._nb_electrodes_biotac, self._nb_electrodes_biotac_sp)
755  return
756 
757  for n in range(len(self.sensing_electrodes_x)):
758  self.sensing_electrodes_x[n] = (
759  self.sensing_electrodes_x[n] * self.factor +
760  self.x_display_offset[0])
761  self.sensing_electrodes_y[n] = (
762  self.sensing_electrodes_y[n] * self.factor +
763  self.y_display_offset[0])
764 
765  for n in range(len(self.excitation_electrodes_x)):
766  self.excitation_electrodes_x[n] = (
767  self.excitation_electrodes_x[n] * self.factor +
768  self.x_display_offset[0])
769  self.excitation_electrodes_y[n] = (
770  self.excitation_electrodes_y[n] * self.factor +
771  self.y_display_offset[0])
772 
773  def _tactile_cb(self, msg):
774  if len(msg.tactiles[0].electrodes) != self._nb_electrodes:
775  self._nb_electrodes = len(msg.tactiles[0].electrodes)
777  self.latest_data = msg
778 
780  r = 0.0
781  g = 0.0
782  b = 255.0
783 
784  value = float(value)
785 
786  threshold = (0.0, 1000.0, 2000.0, 3000.0, 4095.0)
787 
788  if value <= threshold[0]:
789  pass
790 
791  elif value < threshold[1]:
792  r = 255
793  g = 255 * ((value - threshold[0]) / (threshold[1] - threshold[0]))
794  b = 0
795 
796  elif value < threshold[2]:
797  r = 255 * ((threshold[2] - value) / (threshold[2] - threshold[1]))
798  g = 255
799  b = 0
800 
801  elif value < threshold[3]:
802  r = 0
803  g = 255
804  b = 255 * ((value - threshold[2]) / (threshold[3] - threshold[2]))
805  elif value < threshold[4]:
806  r = 0
807  g = 255 * ((threshold[4] - value) / (threshold[4] - threshold[3]))
808  b = 255
809 
810  return QColor(r, g, b)
811 
812  def _draw_electrode(self, painter, elipse_x, elipse_y, text_x, text_y, colour, text):
813 
814  rect = QRectF(elipse_x, elipse_y, self.RECTANGLE_WIDTH,
815  self.RECTANGLE_HEIGHT)
816 
817  painter.setBrush(colour)
818  painter.drawEllipse(rect)
819 
820  rect.setX(text_x)
821  rect.setY(text_y)
822 
823  painter.drawText(rect, text)
824 
825  def paintEvent(self, paintEvent):
826  painter = QPainter(self.widget)
827  which_tactile = self.biotac_name
828 
829  painter.setFont(QFont("Arial", self.label_font_size[0]))
830 
831  if len(self.sensing_electrodes_x) == len(self.latest_data.tactiles[which_tactile].electrodes):
832  for n in range(len(self.sensing_electrodes_x)):
833  value = self.latest_data.tactiles[which_tactile].electrodes[n]
834 
835  eval("self._widget.lcdE%02d_%d.display(%d)" % (n + 1, self.biotac_name, value))
836  colour = self._get_electrode_colour_from_value(value)
837 
838  elipse_x = self.sensing_electrodes_x[n]
839  elipse_y = self.sensing_electrodes_y[n]
840 
841  if n < 9:
842  text_x = elipse_x + self.x_display_offset[1]
843  text_y = elipse_y + self.y_display_offset[1]
844 
845  else:
846  text_x = elipse_x + self.x_display_offset[2]
847  text_y = elipse_y + self.y_display_offset[2]
848 
849  self._draw_electrode(painter, elipse_x, elipse_y, text_x, text_y, colour, str(n + 1))
850 
851  painter.setFont(QFont("Arial", self.label_font_size[1]))
852 
853  for n in range(len(self.excitation_electrodes_x)):
854  elipse_x = self.excitation_electrodes_x[n]
855  elipse_y = self.excitation_electrodes_y[n]
856 
857  colour = QColor(127, 127, 127)
858 
859  text_x = elipse_x + self.x_display_offset[3]
860  text_y = elipse_y + self.y_display_offset[3]
861 
862  self._draw_electrode(painter, elipse_x, elipse_y, text_x, text_y,
863  colour, "X" + str(n + 1))
864 
865  self._widget.update()
866 
867  def _subscribe_to_topic(self, prefix):
868  if prefix:
869  rospy.Subscriber(prefix + "tactile", BiotacAll, self._tactile_cb)
870 
871  def load_params(self):
872 
873  self.RECTANGLE_WIDTH = rospy.get_param(
874  "sr_gui_biotac/electrode_display_width",
875  30) # Display sizes for electrodes in pixels
876  self.RECTANGLE_HEIGHT = rospy.get_param(
877  "sr_gui_biotac/electrode_display_height", 30)
878 
879  self.factor = 5
880  # location on the sensor in mm to display location in pixels
881  self.x_display_offset = rospy.get_param(
882  "sr_gui_biotac/x_display_offset", [125, 12.5, 4.5,
883  3.5]) # Pixel offsets for
884  # displaying electrodes. offset[0] is applied to each electrode.
885  # 1,2 and 3 are the label offsets for displaying electrode number.
886  self.y_display_offset = rospy.get_param(
887  "sr_gui_biotac/y_display_offset", [-30, 4.0, 4.0, 4.0])
888  self.label_font_size = rospy.get_param(
889  "sr_gui_biotac/electrode_label_font_sizes", [8,
890  6]) # Font sizes
891  # for labels on sensing + excitation electrodes
892 
893  if self._hand_parameters.mapping:
894  self.default_topic = (
895  self._hand_parameters.mapping.values()[0] + '/')
896  else:
897  self.default_topic = ""
898 
899  def find_children(self, biotac_name):
900  self.widget = self._widget.findChild(QWidget, "widget" + "_" + str(biotac_name))
901  self.biotac_name = biotac_name
902 
903  def redraw_electrodes(self):
904  self.pixels = self._widget.width() * self._widget.height()
905  self.define_electrodes()
906 
907  if self._nb_electrodes == self._nb_electrodes_biotac:
908  self.factor = 17.5
909  elif self._nb_electrodes == self._nb_electrodes_biotac_sp:
910  self.factor = 25.0
911  else:
912  rospy.logerr("Number of electrodes %d not matching known biotac models. expected: %d or %d",
913  self.nb_electrodes, self._nb_electrodes_biotac, self._nb_electrodes_biotac_sp)
914  return
915 
916  if self.pixels > 3500000:
917  self.factor = self.factor * 0.80
918  self.RECTANGLE_WIDTH = 40
919  self.RECTANGLE_HEIGHT = 40
920  self.x_display_offset[0] = 170
921  self.y_display_offset[0] = -30
922  self.label_font_size = [10, 9]
923  else:
924  self.factor = self.factor * 0.55
925  self.RECTANGLE_WIDTH = 25
926  self.RECTANGLE_HEIGHT = 25
927  self.x_display_offset[0] = 125
928  self.y_display_offset[0] = -30
929  self.label_font_size = [8, 8]
930 
933 
934 
935 class CustomFigCanvas(FigureCanvas, TimedAnimation):
936  def __init__(self, num_lines, colour=[], ymin=-1, ymax=1, legends=[], legend_columns='none', legend_font_size=7,
937  num_ticks=4, xaxis_tick_animation=False, tail_enable=True, enabled=True):
938  self.plot_all = True
939  self.line_to_plot = None
940  self.enabled = enabled
941  self.legends = legends
942  self.num_lines = num_lines
943  self.num_ticks = num_ticks
944  self.tail_enable = tail_enable
945  self.legend_columns = legend_columns
946  self.legend_font_size = legend_font_size
947  self.xaxis_tick_animation = xaxis_tick_animation
948  self.ymin = ymin
949  self.ymax = ymax
950  self.colour = colour
951  if legend_columns == 'none':
952  legend_columns = self.num_lines
953  self.addedDataArray = []
954  self.start_time = rospy.get_rostime()
955  for n in range(self.num_lines):
956  addedData = []
957  self.addedDataArray.append(addedData)
958 
959  # The data
960  self.xlim = 200
961  self.n = np.linspace(0, self.xlim - 1, self.xlim)
962  self.y = []
963  for n in range(self.num_lines):
964  self.y.append((self.n * 0.0) + 50)
965 
966  self.label_buffer = []
967 
968  # The window
969  self.fig = Figure(figsize=(3, 3), dpi=100, facecolor=(1.0, 1.0, 1.0, 1.0))
970  # self.fig.patch.set_alpha(0.0)
971  self.ax1 = self.fig.add_subplot(111)
972  self.x_axis = self.n
973  if not self.xaxis_tick_animation:
974  self.ax1.axes.get_xaxis().set_visible(False)
975 
976  # Shrink the font size of the x tick labels
977  for tick in self.ax1.yaxis.get_major_ticks():
978  tick.label.set_fontsize(7)
979  self.ax1.yaxis.grid(True, linestyle='-', which='major', color='lightgrey', alpha=0.5)
980  self.ax1.yaxis.set_tick_params(which='both', labelbottom=False)
981 
982  self.line = []
983  if self.tail_enable:
984  self.line_head = []
985  self.line_tail = []
986  for i in range(self.num_lines):
987  self.line.append(Line2D([], [], color=self.colour[i]))
988  if self.tail_enable:
989  self.line_tail.append(Line2D([], [], color='red', linewidth=2))
990  self.line_head.append(Line2D([], [], color='red', marker='o', markeredgecolor='r'))
991  self.ax1.add_line(self.line_tail[i])
992  self.ax1.add_line(self.line_head[i])
993  self.ax1.add_line(self.line[i])
994  self.ax1.set_xlim(0, self.xlim - 1)
995  self.ax1.set_ylim(ymin, ymax)
996 
997  self.fig.subplots_adjust(bottom=0.05, top=0.8, left=0.08, right=0.98)
998  self.ax1.legend(self.line, self.legends, bbox_to_anchor=(0.0, 1.0, 1.0, 0.9), framealpha=0.8, loc=3,
999  ncol=legend_columns, mode="expand", borderaxespad=0.5, prop={'size': legend_font_size})
1000  FigureCanvas.__init__(self, self.fig)
1001  TimedAnimation.__init__(self, self.fig, interval=50, blit=not self.xaxis_tick_animation)
1002 
1003  def re_init(self):
1004  self.line = []
1005  if self.tail_enable:
1006  self.line_head = []
1007  self.line_tail = []
1008 
1009  if self.plot_all:
1010  for i in range(self.num_lines):
1011  self.line.append(Line2D([], [], color=self.colour[i]))
1012  if self.tail_enable:
1013  self.line_tail.append(Line2D([], [], color='red', linewidth=2))
1014  self.line_head.append(Line2D([], [], color='red', marker='o', markeredgecolor='r'))
1015  self.ax1.add_line(self.line_tail[i])
1016  self.ax1.add_line(self.line_head[i])
1017  self.ax1.add_line(self.line[i])
1018  self.ax1.set_xlim(0, self.xlim - 1)
1019  self.ax1.set_ylim(self.ymin, self.ymax)
1020  else:
1021  for i in range(self.num_lines):
1022  self.line.append(Line2D([], [], color=self.colour[self.line_to_plot]))
1023  if self.tail_enable:
1024  self.line_tail.append(Line2D([], [], color='red', linewidth=2))
1025  self.line_head.append(Line2D([], [], color='red', marker='o', markeredgecolor='r'))
1026  self.ax1.add_line(self.line_tail[i])
1027  self.ax1.add_line(self.line_head[i])
1028  self.ax1.add_line(self.line[i])
1029  self.ax1.set_xlim(0, self.xlim - 1)
1030  self.ax1.set_ylim(self.ymin, self.ymax)
1031 
1032  def new_frame_seq(self):
1033  return iter(range(self.n.size))
1034 
1035  def _init_draw(self):
1036  for i in range(self.num_lines):
1037  if self.tail_enable:
1038  lines = [self.line[i], self.line_tail[i], self.line_head[i]]
1039  else:
1040  lines = [self.line[i]]
1041  for l in lines:
1042  l.set_data([], [])
1043 
1044  def addData(self, value, index):
1045  self.addedDataArray[index].append(value)
1046  if len(self.addedDataArray[index]) > (self.xlim * 2):
1047  del self.addedDataArray[index][0:self.xlim]
1048 
1049  def _step(self, *args):
1050  if self.enabled:
1051  TimedAnimation._step(self, *args)
1052 
1053  def _draw_frame(self, framedata):
1054  margin = 2
1055  for i in range(self.num_lines):
1056  while len(self.addedDataArray[i]) > 0:
1057  self.y[i] = np.roll(self.y[i], -1)
1058  self.y[i][-1] = self.addedDataArray[i][0]
1059  del (self.addedDataArray[i][0])
1060  if self.plot_all:
1061  for i in range(self.num_lines):
1062  self.line[i].set_data(self.n[0: self.n.size - margin], self.y[i][0: self.n.size - margin])
1063  if self.tail_enable:
1064  self.line_tail[i].set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]),
1065  np.append(self.y[i][-10:-1 - margin], self.y[i][-1 - margin]))
1066  self.line_head[i].set_data(self.n[-1 - margin], self.y[i][-1 - margin])
1067  self._drawn_artists = []
1068  for l in self.line:
1069  self._drawn_artists.append(l)
1070  if self.tail_enable:
1071  for l in self.line_tail:
1072  self._drawn_artists.append(l)
1073  for l in self.line_head:
1074  self._drawn_artists.append(l)
1075  else:
1076  i = self.line_to_plot
1077  self.line[i].set_data(self.n[0: self.n.size - margin], self.y[i][0: self.n.size - margin])
1078  if self.tail_enable:
1079  self.line_tail[i].set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]),
1080  np.append(self.y[i][-10:-1 - margin], self.y[i][-1 - margin]))
1081  self.line_head[i].set_data(self.n[-1 - margin], self.y[i][-1 - margin])
1082  self._drawn_artists = []
1083  for l in self.line:
1084  self._drawn_artists.append(l)
1085  if self.tail_enable:
1086  for l in self.line_tail:
1087  self._drawn_artists.append(l)
1088  for l in self.line_head:
1089  self._drawn_artists.append(l)
1090 
1091  if self.xaxis_tick_animation:
1092  time_from_start = int((rospy.get_rostime() - self.start_time).to_sec())
1093  if len(self.label_buffer) > 3:
1094  self.label_buffer = np.roll(self.label_buffer, 1)
1095  self.label_buffer[2] = time_from_start
1096  else:
1097  self.label_buffer.append(time_from_start)
1098  x = []
1099  for i in range(self.num_ticks):
1100  x.append(int(self.xlim / self.num_ticks) * i)
1101  self.ax1.set_xticks(x)
1102  self.ax1.set_xticklabels([int(i / int(self.xlim / self.num_ticks)) + time_from_start for i in x])
1103 
1104 
1105 if __name__ == "__main__":
1106  rospy.init_node("hand_e_visualizer")
1107  app = QApplication(sys.argv)
1108  data_visualiser_gui = SrDataVisualizer(None)
1109  data_visualiser_gui._widget.show()
1110  atexit.register(data_visualiser_gui.shutdown_plugin)
1111  signal.signal(signal.SIGINT, signal.SIG_DFL)
1112  sys.exit(app.exec_())
def __init__(self, num_lines, colour=[], ymin=-1, ymax=1, legends=[], legend_columns='none', legend_font_size=7, num_ticks=4, xaxis_tick_animation=False, tail_enable=True, enabled=True)
def _draw_electrode(self, painter, elipse_x, elipse_y, text_x, text_y, colour, text)


sr_data_visualization
Author(s): Tom Queen
autogenerated on Wed Oct 14 2020 03:22:43