WUT Velma robot API
velma_control_panel_widget.py
Go to the documentation of this file.
1 # Copyright (c) 2014, Robot Control and Pattern Recognition Group, Warsaw University of Technology
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
11 # * Neither the name of the Warsaw University of Technology nor the
12 # names of its contributors may be used to endorse or promote products
13 # derived from this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL <COPYright HOLDER> BE LIABLE FOR ANY
19 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 #
26 # Author: Dawid Seredynski
27 
28 from __future__ import division
29 import os
30 import subprocess
31 import tempfile
32 import threading
33 import math
34 import time
35 
36 from python_qt_binding import loadUi
37 from python_qt_binding.QtCore import Qt, QTimer, Signal, Slot, QRectF, QPointF
38 from python_qt_binding.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QHBoxLayout,\
39  QScrollArea, QGraphicsScene
40 from python_qt_binding.QtGui import QPixmap, QStandardItemModel, QStandardItem, QPolygonF
41 
42 import roslib
43 import rospkg
44 import rospy
45 from rospy.exceptions import ROSException
46 
47 from velma_common import VelmaInterface, symmetricalConfiguration
48 
50  def __init__(self):
51  self.__velma = VelmaInterface()
52  self.__is_initialized = False
53  self.__is_cancelled = False
54  self.__lock = threading.Lock()
55  self.__thread = None
56 
57  def start(self):
58  assert self.__thread is None
59  self.__thread = threading.Thread(target=self.__threadFunction)
60  self.__thread.start()
61 
62  def __threadFunction(self):
63  while (not self.isCanceled() and not rospy.is_shutdown()):
64  if self.__velma.waitForInit(timeout_s=10.0):
66  break
67  else:
68  # Reset the interface
69  del self.__velma
70  self.__velma = VelmaInterface()
71 
72  def cancelAndWait(self):
73  self.__lock.acquire()
74  self.__is_cancelled = True
75  self.__lock.release()
76  self.__thread.join()
77 
78  def __setInitializedSuccessful(self):
79  self.__lock.acquire()
80  self.__is_initialized = True
81  self.__lock.release()
82 
83  def isInitialized(self):
84  self.__lock.acquire()
85  result = self.__is_initialized
86  self.__lock.release()
87  return result
88 
89  def isCanceled(self):
90  self.__lock.acquire()
91  result = self.__is_cancelled
92  self.__lock.release()
93  return result
94 
95  def getVelmaInterface(self):
96  if not self.isInitialized():
97  raise Exception("Tried to get VelmaInterface, but it is not ready")
98  self.__thread.join()
99  return self.__velma
100 
102  def __init__(self, velma):
103  self.__lock = threading.Lock()
104  self.__thread = None
105  self.__velma = velma
106  self.__queue = []
107  self.__errors = []
108  self.__is_active = False
109  self.__is_cancelled = False
110 
111  def start(self):
112  assert self.__thread is None
113  self.__thread = threading.Thread(target=self.__threadFunction)
114  self.__thread.start()
115 
116  def __isCanceled(self):
117  self.__lock.acquire()
118  result = self.__is_cancelled
119  self.__lock.release()
120  return result
121 
122  def cancelAndWait(self):
123  self.__lock.acquire()
124  self.__is_cancelled = True
125  self.__lock.release()
126  self.__thread.join()
127 
128  def __threadFunction(self):
129  self.setActive( True )
130  while (not self.__isCanceled() and not rospy.is_shutdown()):
131  time.sleep(0.1)
132  cmd = self.__getNextCommand()
133  if cmd is None:
134  continue
135  cmd_name = cmd[0]
136  if cmd_name == 'runHoming':
137  self.__velma.startHomingHP()
138  if self.__velma.waitForHP() != 0:
139  self.__setMessage('ERROR: Could not run homing for HP motor')
140  break
141  else:
142  self.__setMessage('INFO: Homing of HP motor successful')
143  self.__velma.startHomingHT()
144  if self.__velma.waitForHT() != 0:
145  self.__setMessage('ERROR: Could not run homing for HT motor')
146  break
147  else:
148  self.__setMessage('INFO: Homing of HT motor successful')
149 
150  elif cmd_name == 'enableMotors':
151  if self.__velma.enableMotors() != 0:
152  self.__setMessage('ERROR: Could not enable motors')
153  break
154  else:
155  self.__setMessage('INFO: Enabled motors')
156 
157  elif cmd_name == 'switchToJntImp':
158  self.__velma.moveJointImpToCurrentPos(start_time=0.5)
159  error = self.__velma.waitForJoint()
160  if error != 0:
161  self.__setMessage('ERROR: Could not switchToJntImp - error code: {}'.format(error))
162  else:
163  self.__setMessage('INFO: switched to jnt_imp')
164 
165  elif cmd_name == 'switchToCartImp':
166  self.__velma.moveCartImpRightCurrentPos(start_time=0.5)
167  error = self.__velma.waitForEffectorRight()
168  if error != 0:
169  self.__setMessage('ERROR: Could not switchToCartImp - error code: {}'.format(error))
170  else:
171  self.__setMessage('INFO: switched to cart_imp')
172 
173  elif cmd_name == 'switchToRelax':
174  self.__velma.switchToRelaxBehavior()
175  self.__setMessage('INFO: switch to relax')
176  time.sleep(0.5)
177 
178  elif cmd_name == 'moveToInitialConfiguration':
179  q_map_initial = symmetricalConfiguration( {'torso_0_joint':0,
180  'right_arm_0_joint':-0.3, 'right_arm_1_joint':-1.8, 'right_arm_2_joint':1.25,
181  'right_arm_3_joint':0.85, 'right_arm_4_joint':0, 'right_arm_5_joint':-0.5,
182  'right_arm_6_joint':0} )
183 
184  self.__velma.moveJoint(q_map_initial, None, max_vel=15.0/180.0*math.pi,
185  start_time=0.5, position_tol=15.0/180.0*math.pi)
186  time.sleep(0.5)
187  error = self.__velma.waitForJoint()
188  if error != 0:
189  self.__setMessage('ERROR: Could not move - error code: {}'.format(error))
190  else:
191  self.__setMessage('INFO: moved to the initial configuration')
192 
193  elif cmd_name == 'moveHeadTo0':
194  self.__velma.moveHead([0.0, 0.0], None, max_vel=15.0/180.0*math.pi,
195  start_time=0.2, position_tol=5.0/180.0*math.pi)
196  time.sleep(0.5)
197  error = self.__velma.waitForHead()
198  if error != 0:
199  self.__setMessage('ERROR: Could not move head - error code: {}'.format(error))
200  else:
201  self.__setMessage('INFO: moved head to the initial configuration')
202 
203  elif cmd_name == 'gripperCmd':
204  side = cmd[1]
205  gr_cmd = cmd[2]
206  if gr_cmd == 'open':
207  q = [0, 0, 0, 0]
208  self.__velma.moveHand(side, q, [1, 1, 1, 1], [4000,4000,4000,4000], 1000, hold=False)
209  elif gr_cmd == 'close':
210  q = [math.radians(110), math.radians(110), math.radians(110), 0]
211  self.__velma.moveHand(side, q, [1, 1, 1, 1], [4000,4000,4000,4000], 1000, hold=False)
212  elif gr_cmd == 'reset':
213  self.__velma.resetHand(side)
214  else:
215  raise Exception('Unknown gripper command: "{}"'.format(gr_cmd))
216  if self.__velma.waitForHand(side) != 0:
217  exitError(6)
218  else:
219  raise Exception('Unknown command: {}'.format(cmd_name))
220 
221  self.setActive( False )
222 
223  def __getNextCommand(self):
224  self.__lock.acquire()
225  if len(self.__queue) > 1:
226  cmd = self.__queue[0]
227  self.__queue = self.__queue[1:]
228  elif len(self.__queue) == 1:
229  cmd = self.__queue[0]
230  self.__queue = []
231  else:
232  cmd = None
233  self.__lock.release()
234  return cmd
235 
236  def __setMessage(self, msg):
237  self.__lock.acquire()
238  now = rospy.get_rostime()
239  ms = int(now.nsecs/1000000)
240  self.__errors.append( '{}.{:03d} {}'.format(now.secs, ms, msg) )
241  self.__lock.release()
242 
243  def getNextMessage(self):
244  self.__lock.acquire()
245  if len(self.__errors) > 1:
246  result = self.__errors[0]
247  self.__errors = self.__errors[1:]
248  elif len(self.__errors) == 1:
249  result = self.__errors[0]
250  self.__errors = []
251  else:
252  result = None
253  self.__lock.release()
254  return result
255 
256  def setActive(self, active):
257  self.__lock.acquire()
258  self.__is_active = active
259  self.__lock.release()
260 
261  def isActive(self):
262  self.__lock.acquire()
263  result = self.__is_active
264  self.__lock.release()
265  return result
266 
267  def __addCommand(self, cmd):
268  self.__lock.acquire()
269  self.__queue.append( cmd )
270  self.__lock.release()
271 
272  def __addCommands(self, list_cmd):
273  self.__lock.acquire()
274  for cmd in list_cmd:
275  self.__queue.append( cmd )
276  self.__lock.release()
277 
278  def initializeRobot(self):
279  self.__addCommands( [('enableMotors',), ('runHoming',)] )
280 
281  def enableMotors(self):
282  self.__addCommand( ('enableMotors',) )
283 
284  def switchToJntImp(self):
285  self.__addCommand( ('switchToJntImp',) )
286 
287  def switchToCartImp(self):
288  self.__addCommand( ('switchToCartImp',) )
289 
290  def switchToRelax(self):
291  self.__addCommand( ('switchToRelax',) )
292 
294  self.__addCommand( ('moveToInitialConfiguration',) )
295 
296  def moveHeadTo0(self):
297  self.__addCommand( ('moveHeadTo0',) )
298 
299  def gripperCmd(self, side, cmd):
300  self.__addCommand( ('gripperCmd', side, cmd) )
301 
302 from python_qt_binding.QtCore import Qt, Signal, Slot, QRectF, QPointF, QSize, QRect, QPoint
303 from python_qt_binding.QtWidgets import QDialog, QGraphicsView, QGraphicsScene, QGraphicsPathItem, QGraphicsPolygonItem, QSizePolicy
304 from python_qt_binding.QtGui import QColor, QPen, QBrush, QPainterPath, QPolygonF, QTransform, QPainter
305 
306 class JointVis(QGraphicsView):
307  def __init__(self, parent=None):
308  super (JointVis, self).__init__ (parent)
309 
310  self.__lim = None
311  self.__pos_rect = None
312  self.__pos = None
313 
314  self.__good_brush = QBrush(QColor(0,255,0))
315  self.__soft_brush = QBrush(QColor(255,200,0))
316  self.__hard_brush = QBrush(QColor(255,100,0))
317  self.__singularity_soft_brush = QBrush(QColor(0,200,255))
318  self.__singularity_hard_brush = QBrush(QColor(0,100,255))
319 
320  self.__scene = QGraphicsScene(QRectF(0, 0, 1, 1))
321  self.setScene(self.__scene)
322  self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
323  self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
324  self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,
325  QSizePolicy.Fixed))
326  self.setMaximumHeight(10)
327  self.setStyleSheet("border: 0px")
328 
329  def paintEvent(self, event):
330  if not self.__pos is None and not self.__pos_rect is None:
331  limit_range = self.__lim[-1] - self.__lim[0]
332  self.__pos_rect.setRect( (self.__pos - self.__lim[0]) / limit_range, 0, 2.0/(self.width()-2), 1)
333  self.fitInView(self.__scene.sceneRect(), Qt.IgnoreAspectRatio);
334  super(JointVis, self).paintEvent(event)
335 
336  def setLimits(self, lim):
337  if self.__lim is None:
338  self.__lim = lim
339  soft_lim = 0.26
340  limit_range = self.__lim[-1] - self.__lim[0]
341  soft_size = soft_lim/limit_range
342  self.__scene.addRect(0, 0, soft_size, 1, QPen(Qt.NoPen), self.__soft_brush)
343  self.__scene.addRect(1.0-soft_size, 0, soft_size, 1, QPen(Qt.NoPen), self.__soft_brush)
344 
345  self.__scene.addRect(soft_size, 0, (self.__lim[1]-self.__lim[0])/limit_range-2*soft_size, 1, QPen(Qt.NoPen), self.__good_brush)
346 
347  if len(self.__lim) == 4:
348  self.__scene.addRect((self.__lim[1]-self.__lim[0])/limit_range-soft_size, 0, soft_size, 1, QPen(Qt.NoPen), self.__singularity_soft_brush)
349  self.__scene.addRect((self.__lim[2]-self.__lim[0])/limit_range, 0, soft_size, 1, QPen(Qt.NoPen), self.__singularity_soft_brush)
350 
351  self.__scene.addRect((self.__lim[1]-self.__lim[0])/limit_range, 0, (self.__lim[2]-self.__lim[1])/limit_range, 1, QPen(Qt.NoPen), self.__singularity_hard_brush)
352 
353  self.__scene.addRect((self.__lim[2]-self.__lim[0])/limit_range+soft_size, 0, (self.__lim[3]-self.__lim[2])/limit_range-2*soft_size, 1, QPen(Qt.NoPen), self.__good_brush)
354 
355  self.__pos_rect = self.__scene.addRect(0, 0, 0.05, 1, QPen(Qt.NoPen), Qt.black)
356 
357  def setPosition(self, pos):
358  self.__pos = pos
359  limit_range = self.__lim[-1] - self.__lim[0]
360  self.__pos_rect.setRect( (self.__pos - self.__lim[0]) / limit_range, 0, 2.0/(self.width()-2), 1)
361  self.setToolTip('range: ({:.2f}, {:.2f}), pos: {:.2f}'.format(self.__lim[0], self.__lim[-1], pos))
362 
363 class Joint2Vis(QGraphicsView):
364  def __init__(self, parent=None):
365  super (Joint2Vis, self).__init__ (parent)
366 
367  self.__min_x = None
368  self.__max_x = None
369  self.__min_y = None
370  self.__max_y = None
371  self.__pos_rect = None
372  self.__pos1 = None
373  self.__pos2 = None
374 
375  self.__brush_bad = QBrush(QColor(150,0,0))
376  self.__brush_good = QBrush(QColor(0,150,0))
377  self.__singularity_soft_brush = QBrush(QColor(0,200,255,128))
378  self.__singularity_hard_brush = QBrush(QColor(0,100,255,128))
379 
380  self.__scene = QGraphicsScene(QRectF(0, 0, 1, 1))
381  self.__scene.setBackgroundBrush( self.__brush_bad );
382  self.setScene(self.__scene)
383  self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
384  self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
385  self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,
386  QSizePolicy.Expanding))
387  #self.setMaximumHeight(10)
388  self.setStyleSheet("border: 0px")
389 
390  def __confToScene(self, x, y):
391  return (x - self.__min_x) / (self.__max_x - self.__min_x),\
392  (y - self.__min_y) / (self.__max_y - self.__min_y)
393 
394  def paintEvent(self, event):
395  if not self.__pos1 is None and not self.__pos_rect is None:
396  self.__drawPos()
397  self.fitInView(self.__scene.sceneRect(), Qt.KeepAspectRatio);
398  super(Joint2Vis, self).paintEvent(event)
399 
400  def setLimits(self, poly, joint_5_limits):
401  if self.__min_x is None:
402  self.__poly = poly
403  min_x = float('inf')
404  max_x = float('-inf')
405  min_y = float('inf')
406  max_y = float('-inf')
407  for idx in range(0, len(self.__poly), 2):
408  x = float(self.__poly[idx])
409  y = float(self.__poly[idx+1])
410  min_x = min(min_x, x)
411  max_x = max(max_x, x)
412  min_y = min(min_y, y)
413  max_y = max(max_y, y)
414  self.__min_x = min_x
415  self.__max_x = max_x
416  self.__min_y = min_y
417  self.__max_y = max_y
418  limit1_range = self.__max_x - self.__min_x
419  limit2_range = self.__max_y - self.__min_y
420 
421  self.__qt_poly = QPolygonF()
422 
423  for idx in range(0, len(self.__poly), 2):
424  idx2 = (idx+2) % len(self.__poly)
425  x1, y1 = self.__confToScene( float(self.__poly[idx]), float(self.__poly[idx+1]) )
426  x2, y2 = self.__confToScene( float(self.__poly[idx2]), float(self.__poly[idx2+1]) )
427  self.__qt_poly.append(QPointF(x1, y1))
428  self.__scene.addPolygon(self.__qt_poly, QPen(QColor(255, 0, 0), 0.01, Qt.SolidLine, Qt.RoundCap), self.__brush_good)
429 
430  limit_range = joint_5_limits[-1] - joint_5_limits[0]
431  soft_lim = 0.26
432  soft_size = soft_lim/limit_range
433  self.__scene.addRect((joint_5_limits[1]-joint_5_limits[0])/limit_range-soft_size, 0, soft_size, 1, QPen(Qt.NoPen), self.__singularity_soft_brush)
434  self.__scene.addRect((joint_5_limits[2]-joint_5_limits[0])/limit_range, 0, soft_size, 1, QPen(Qt.NoPen), self.__singularity_soft_brush)
435  self.__scene.addRect((joint_5_limits[1]-joint_5_limits[0])/limit_range, 0, (joint_5_limits[2]-joint_5_limits[1])/limit_range, 1, QPen(Qt.NoPen), self.__singularity_hard_brush)
436 
437  self.__pos_point = None
438 
439  def setPosition(self, pos1, pos2):
440  self.__pos1 = pos1
441  self.__pos2 = pos2
442  self.__drawPos()
443 
444  def __drawPos(self):
445  x, y = self.__confToScene( self.__pos1, self.__pos2 )
446  if self.__pos_point is None:
447  self.__pos_point = (self.__scene.addLine(x-0.03, y-0.03, x+0.03, y+0.03,
448  QPen(QColor(255, 255, 255), 0.01, Qt.SolidLine, Qt.RoundCap)),
449  self.__scene.addLine(x-0.03, y+0.03, x+0.03, y-0.03,
450  QPen(QColor(255, 255, 255), 0.01, Qt.SolidLine, Qt.RoundCap)))
451  else:
452  self.__pos_point[0].setLine(x-0.03, y-0.03, x+0.03, y+0.03)
453  self.__pos_point[1].setLine(x-0.03, y+0.03, x+0.03, y-0.03)
454 
455  def resizeScene(self):
456  self.fitInView(self.__scene.sceneRect(), Qt.KeepAspectRatio)
457 
458  def resizeEvent(self, event):
459  # call fitInView each time the widget is resized
460  self.resizeScene()
461 
462  def showEvent(self, event):
463  # call fitInView each time the widget is shown
464  self.resizeScene()
465 
466 
467 class VelmaControlPanelWidget(QWidget):
468  """
469  main class inherits from the ui window class.
470 
471  You can specify the topics that the topic pane.
472 
473  VelmaControlPanelWidget.start must be called in order to update topic pane.
474  """
475 
476  _column_names = ['topic', 'type', 'bandwidth', 'rate', 'value']
477 
478  def __init__(self, plugin=None):
479  """
480  """
481  super(VelmaControlPanelWidget, self).__init__()
482 
483  rp = rospkg.RosPack()
484  ui_file = os.path.join(rp.get_path('rqt_velma'), 'resource', 'VelmaControlPanelWidget.ui')
485  loadUi(ui_file, self)
486 
487  self._plugin = plugin
488 
489  self.__list_model = QStandardItemModel()
490  self.list_messages.setModel(self.__list_model)
491 
492  #self.button_initialize_robot.clicked.connect(
493  # lambda: self.__velma_cmd.initializeRobot() if not self.__velma_cmd is None)
494  self.button_initialize_robot.clicked.connect( self.clicked_initialize_robot )
495  self.button_enable_motors.clicked.connect( self.clicked_enable_motors )
496  self.button_switch_to_relax.clicked.connect( self.clicked_switch_to_relax )
497  self.button_switch_to_cart_imp.clicked.connect( self.clicked_switch_to_cart_imp )
498  self.button_switch_to_jnt_imp.clicked.connect( self.clicked_switch_to_jnt_imp )
499  self.button_clear_messages.clicked.connect( self.clicked_clear_messages )
500  self.button_move_to_initial_configuration.clicked.connect( self.clicked_move_to_initial_configuration )
501  self.button_move_head_to_0.clicked.connect( self.clicked_move_head_to_0 )
502 
503  self.button_right_gripper_open.clicked.connect( lambda: self.gripper_cmd('right', 'open') )
504  self.button_right_gripper_close.clicked.connect( lambda: self.gripper_cmd('right', 'close') )
505  self.button_right_gripper_reset.clicked.connect( lambda: self.gripper_cmd('right', 'reset') )
506  self.button_left_gripper_open.clicked.connect( lambda: self.gripper_cmd('left', 'open') )
507  self.button_left_gripper_close.clicked.connect( lambda: self.gripper_cmd('left', 'close') )
508  self.button_left_gripper_reset.clicked.connect( lambda: self.gripper_cmd('left', 'reset') )
509 
511  self.__velma_init.start()
512  self.__velma_cmd = None
513  self.__velma = None
514 
515  # init and start update timer
516  self._timer_refresh_topics = QTimer(self)
517  self._timer_refresh_topics.timeout.connect(self.refresh_topics)
518 
519  self.__joint_vis_map = None
520 
522  if not self.__velma_cmd is None:
523  self.__velma_cmd.initializeRobot()
524 
526  if not self.__velma_cmd is None:
527  self.__velma_cmd.enableMotors()
528 
530  if not self.__velma_cmd is None:
531  self.__velma_cmd.switchToJntImp()
532 
534  if not self.__velma_cmd is None:
535  self.__velma_cmd.switchToCartImp()
536 
538  if not self.__velma_cmd is None:
539  self.__velma_cmd.switchToRelax()
540 
542  if not self.__velma_cmd is None:
543  self.__velma_cmd.moveToInitialConfiguration()
544 
546  if not self.__velma_cmd is None:
547  self.__velma_cmd.moveHeadTo0()
548 
550  #self.list_messages
551  #self.button_clear_messages.
552  pass
553 
554  def gripper_cmd(self, side, cmd):
555  if not self.__velma_cmd is None:
556  self.__velma_cmd.gripperCmd(side, cmd)
557 
558  def start(self):
559  """
560  This method needs to be called to start updating topic pane.
561  """
562  self._timer_refresh_topics.start(100)
563 
564  def layout_widgets(self, layout):
565  return (layout.itemAt(i) for i in range(layout.count()))
566 
567  @Slot()
568  def refresh_topics(self):
569  if self.__velma is None:
570  if self.__velma_init.isInitialized():
571  self.__velma = self.__velma_init.getVelmaInterface()
573  self.__velma_cmd.start()
574  self.__joint_vis_map = {}
575  self.__other_widgets = []
576  for idx in range(7):
577  left_name = 'left_arm_{}_joint'.format(idx)
578 
579  self.__joint_vis_map[left_name] = JointVis()
580  #self.verticalLayout_4.insertWidget(idx+1, self.__joint_vis_map[left_name])
581 
582  h_layout = QHBoxLayout()
583  label = QLabel()
584  label.setText('{}'.format(idx))
585  h_layout.addWidget( label )
586  h_layout.addWidget( self.__joint_vis_map[left_name] )
587  self.__other_widgets.append(h_layout)
588  self.__other_widgets.append(label)
589  self.verticalLayout_4.insertLayout(idx+1, h_layout)
590 
591  right_name = 'right_arm_{}_joint'.format(idx)
592  self.__joint_vis_map[right_name] = JointVis()
593 # self.verticalLayout_5.insertWidget(idx+1, self.__joint_vis_map[right_name])
594  h_layout = QHBoxLayout()
595  label = QLabel()
596  label.setText('{}'.format(idx))
597  h_layout.addWidget( label )
598  h_layout.addWidget( self.__joint_vis_map[right_name] )
599  self.__other_widgets.append(h_layout)
600  self.__other_widgets.append(label)
601  self.verticalLayout_5.insertLayout(idx+1, h_layout)
602 
603  left_name = 'left_arm_double_joint'
604 
605  self.__joint_vis_map[left_name] = Joint2Vis()
606  self.verticalLayout_4.insertWidget(9, self.__joint_vis_map[left_name])
607 
608  right_name = 'right_arm_double_joint'
609  self.__joint_vis_map[right_name] = Joint2Vis()
610  self.verticalLayout_5.insertWidget(9, self.__joint_vis_map[right_name])
611 
612 
613 
614  self.__joint_vis_map['torso_0_joint'] = JointVis()
615  self.gridLayout_2.addWidget(self.__joint_vis_map['torso_0_joint'], 0, 1)
616 
617  self.__joint_vis_map['head_pan_joint'] = JointVis()
618  self.gridLayout_2.addWidget(self.__joint_vis_map['head_pan_joint'], 1, 1)
619 
620  self.__joint_vis_map['head_tilt_joint'] = JointVis()
621  self.gridLayout_2.addWidget(self.__joint_vis_map['head_tilt_joint'], 2, 1)
622 
623  self.__jnt_lim_cart = self.__velma.getCartImpJointLimits()
624  self.__head_limits = self.__velma.getHeadJointLimits()
625  for joint_name in self.__joint_vis_map:
626  if joint_name in self.__jnt_lim_cart:
627  self.__joint_vis_map[joint_name].setLimits( self.__jnt_lim_cart[joint_name] )
628  elif joint_name in self.__head_limits:
629  self.__joint_vis_map[joint_name].setLimits( self.__head_limits[joint_name] )
630  elif joint_name == 'left_arm_double_joint':
631  self.__joint_vis_map[joint_name].setLimits( self.__velma.getLeftWccPolygon(), self.__jnt_lim_cart['left_arm_5_joint'] )
632  elif joint_name == 'right_arm_double_joint':
633  self.__joint_vis_map[joint_name].setLimits( self.__velma.getRightWccPolygon(), self.__jnt_lim_cart['right_arm_5_joint'] )
634  else:
635  print('WARNING: could not get limits for joint "{}"'.format(joint_name))
636 
637  self.label_panel_state.setText('Waiting for initialization of Velma Interface')
638  self.label_current_state_core_cs.setText( 'unknown' )
639  self.label_motors_ready.setText('motors state is unknown')
640  self.label_current_state_core_ve_body.setText( 'unknown' )
641  else:
642  self.label_panel_state.setText('Velma Interface is initialized')
643 
644  diag_cs = self.__velma.getCoreCsDiag(timeout_s=1.0)
645  self.label_current_state_core_cs.setText( diag_cs.getCurrentStateName() )
646  if diag_cs.motorsReady():
647  self.label_motors_ready.setText('motors are ready')
648  else:
649  self.label_motors_ready.setText('motors are not ready')
650 
651  diag_ve_body = self.__velma.getCoreVeDiag(timeout_s=1.0)
652  self.label_current_state_core_ve_body.setText( diag_ve_body.getCurrentStateModeName() )
653 
654  while True:
655  msg = self.__velma_cmd.getNextMessage()
656  if msg is None:
657  break
658  item = QStandardItem(msg)
659  self.__list_model.appendRow(item)
660  self.list_messages.scrollToBottom()
661 
662 
663  js = self.__velma.getLastJointState()
664  if not js is None:
665  js = js[1]
666  for joint_name in self.__joint_vis_map:
667  if joint_name in js:
668  self.__joint_vis_map[joint_name].setPosition( js[joint_name] )
669 
670  self.__joint_vis_map['left_arm_double_joint'].setPosition( js['left_arm_5_joint'], js['left_arm_6_joint'] )
671  self.__joint_vis_map['right_arm_double_joint'].setPosition( js['right_arm_5_joint'], js['right_arm_6_joint'] )
672 
673  def shutdown_plugin(self):
674  if not self.__velma_init is None:
675  self.__velma_init.cancelAndWait()
676  if not self.__velma_cmd is None:
677  self.__velma_cmd.cancelAndWait()
678  self._timer_refresh_topics.stop()
679 
680  # TODO(Enhancement) Save/Restore tree expansion state
681  def save_settings(self, plugin_settings, instance_settings):
682  header_state = self.topics_tree_widget.header().saveState()
683  instance_settings.set_value('tree_widget_header_state', header_state)
684 
685  def restore_settings(self, pluggin_settings, instance_settings):
686  if instance_settings.contains('tree_widget_header_state'):
687  header_state = instance_settings.value('tree_widget_header_state')
688  if not self.topics_tree_widget.header().restoreState(header_state):
689  rospy.logwarn("rqt_topic: Failed to restore header state.")
def restore_settings(self, pluggin_settings, instance_settings)
def symmetricalConfiguration(q_map)
Get configuration based on the input configuration such that all joint positions are symmetrical...