00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 import os
00020 import rospkg
00021 import xml.etree.ElementTree as ET
00022 import time
00023 import threading
00024 import rospy
00025
00026 from qt_gui.plugin import Plugin
00027 from python_qt_binding import loadUi
00028 from PyQt4.Qt import QTimer, QLayout, QPalette, QDoubleValidator, QIntValidator
00029 from sr_robot_commander.sr_hand_commander import SrHandCommander
00030 from sr_utilities.hand_finder import HandFinder
00031
00032 from QtCore import Qt, SIGNAL, pyqtSignal
00033 from QtGui import QWidget, QFrame, QColor
00034 from QtGui import QLabel, QComboBox, QLineEdit, QPushButton, QHBoxLayout, QVBoxLayout, QGridLayout, QIcon, QFileDialog
00035
00036
00037 class Step(QWidget):
00038
00039 """
00040 A step in a sequence of steps which compose a full movement.
00041 Contains add / remove steps buttons, loop control, pause / interpolation time,
00042 grasp type.
00043 """
00044
00045 def __init__(self, parent, step_index, plugin_parent):
00046 QWidget.__init__(self, parent=parent)
00047 self.step_index = step_index
00048 self.parent = plugin_parent
00049 self.grasp = 0
00050 self.pause_time = 0
00051 self.interpolation_time = 2
00052 self.loop_to_step = -1
00053 self.number_of_loops = 0
00054 self.remaining_loops = 0
00055
00056 self.widgets = []
00057
00058 def draw(self):
00059 self.frame = QFrame(self)
00060 self.green = QColor(153, 231, 96)
00061 self.saved_palette = self.palette()
00062 green_palette = self.palette()
00063 green_palette.setBrush(QPalette.Window, self.green)
00064 self.frame.setPalette(green_palette)
00065
00066 label_grasp = QLabel(self.frame)
00067 label_grasp.setText("Grasp: ")
00068 self.widgets.append(label_grasp)
00069
00070 self.list_grasp = QComboBox(self.frame)
00071 self.refresh_list()
00072 self.frame.connect(self.list_grasp, SIGNAL(
00073 'activated(QString)'), self.grasp_choosed)
00074 self.widgets.append(self.list_grasp)
00075
00076 label_pause = QLabel(self.frame)
00077 label_pause.setText(" Pause Time:")
00078 self.widgets.append(label_pause)
00079
00080 self.pause_input = QLineEdit(self.frame)
00081 self.pause_input.setValidator(QDoubleValidator(self))
00082 self.pause_input.setText("0.0")
00083 self.pause_input.setFixedWidth(35)
00084 self.pause_input.setAlignment(Qt.AlignRight)
00085 self.frame.connect(self.pause_input, SIGNAL(
00086 'textChanged(QString)'), self.pause_changed)
00087 self.widgets.append(self.pause_input)
00088
00089 label_interp = QLabel(self.frame)
00090 label_interp.setText("s. Interpolation Time:")
00091 self.widgets.append(label_interp)
00092
00093 self.interp_input = QLineEdit(self.frame)
00094 self.interp_input.setValidator(QDoubleValidator(self))
00095 self.interp_input.setText("2.0")
00096 self.interp_input.setAlignment(Qt.AlignRight)
00097 self.interp_input.setFixedWidth(35)
00098 self.frame.connect(self.interp_input, SIGNAL(
00099 'textChanged(QString)'), self.interp_changed)
00100 self.widgets.append(self.interp_input)
00101
00102 label_looping = QLabel(self.frame)
00103 label_looping.setText("s. Loop to step:")
00104 self.widgets.append(label_looping)
00105
00106 self.loop_input = QComboBox(self.frame)
00107 for i in range(0, self.step_index + 1):
00108 if i == 0:
00109 self.loop_input.addItem("None")
00110 else:
00111 self.loop_input.addItem(str(i))
00112 self.frame.connect(self.loop_input, SIGNAL(
00113 'activated(QString)'), self.choose_looping)
00114 self.widgets.append(self.loop_input)
00115
00116 self.number_loops = QLineEdit(self.frame)
00117 self.number_loops.setValidator(QIntValidator(self))
00118 self.number_loops.setDisabled(True)
00119 self.number_loops.setText("0")
00120 self.number_loops.setAlignment(Qt.AlignRight)
00121 self.number_loops.setFixedWidth(35)
00122
00123
00124
00125 self.frame.connect(self.number_loops, SIGNAL(
00126 'textChanged(QString)'), self.number_loops_changed)
00127 self.widgets.append(self.number_loops)
00128
00129 label_times = QLabel(self.frame)
00130 label_times.setText("times. ")
00131 self.widgets.append(label_times)
00132
00133 self.new_step_button = QPushButton(self.frame)
00134 self.new_step_button.setText("+")
00135 self.new_step_button.setFixedWidth(20)
00136 self.frame.connect(
00137 self.new_step_button, SIGNAL('clicked()'), self.add_step)
00138 self.widgets.append(self.new_step_button)
00139
00140 self.remove_step_button = QPushButton(self.frame)
00141 self.remove_step_button.setText("-")
00142 self.remove_step_button.setFixedWidth(20)
00143 self.frame.connect(
00144 self.remove_step_button, SIGNAL('clicked()'), self.remove_step)
00145 self.widgets.append(self.remove_step_button)
00146
00147 self.layout = QHBoxLayout()
00148 self.layout.setAlignment(Qt.AlignCenter)
00149 self.layout.setSpacing(2)
00150 self.layout.addWidget(label_grasp)
00151 self.layout.addWidget(self.list_grasp)
00152 self.layout.addWidget(label_pause)
00153 self.layout.addWidget(self.pause_input)
00154 self.layout.addWidget(label_interp)
00155 self.layout.addWidget(self.interp_input)
00156 self.layout.addWidget(label_looping)
00157 self.layout.addWidget(self.loop_input)
00158 self.layout.addWidget(self.number_loops)
00159 self.layout.addWidget(label_times)
00160 self.layout.addWidget(self.new_step_button)
00161 self.layout.addWidget(self.remove_step_button)
00162
00163 self.frame.setLayout(self.layout)
00164
00165 layout = QVBoxLayout()
00166 layout.addWidget(self.frame)
00167 self.frame.show()
00168 self.setLayout(layout)
00169
00170 self.show()
00171
00172 def grasp_choosed(self, grasp_name):
00173 self.grasp = str(grasp_name)
00174
00175 def pause_changed(self, pause_time):
00176 self.pause_time = float(pause_time)
00177
00178 def interp_changed(self, interp_time):
00179 self.interpolation_time = float(interp_time)
00180
00181 def add_step(self):
00182 self.parent.add_step(self.step_index)
00183
00184 def number_loops_changed(self, number_loops):
00185 self.number_of_loops = int(number_loops)
00186
00187 def choose_looping(self, looping):
00188 if looping == "None":
00189 self.number_loops.setDisabled(True)
00190 self.number_loops.setText("0")
00191 self.loop_to_step = -1
00192 else:
00193 self.number_loops.setEnabled(True)
00194 self.number_loops.setText("1")
00195 self.number_of_loops = 1
00196 self.loop_to_step = int(looping) - 1
00197
00198 def remove_step(self, delete_first=False):
00199 """
00200 Make sure we don't delete the first item from the GUI
00201 """
00202 if not delete_first:
00203 if len(self.parent.steps) <= 1:
00204 return
00205 self.close()
00206 self.parent.steps.remove(self)
00207 del self
00208
00209 def set_step_id(self, index):
00210 self.step_index = index
00211
00212 def is_playing(self):
00213 self.frame.setAutoFillBackground(True)
00214 self.frame.repaint()
00215
00216 def stopped_playing(self):
00217 self.frame.setAutoFillBackground(False)
00218 self.frame.repaint()
00219
00220 def save_to_xml(self):
00221 xml_step = ET.Element("step")
00222 grasp = ET.SubElement(xml_step, "grasp")
00223 grasp.set("name", self.grasp)
00224 pause = ET.SubElement(xml_step, "pause_time")
00225 pause.text = str(self.pause_time)
00226 interpolation = ET.SubElement(xml_step, "interpolation_time")
00227 interpolation.text = str(self.interpolation_time)
00228 looping = ET.SubElement(xml_step, "loop_to_step")
00229 looping.text = str(self.loop_to_step)
00230 nb_loops = ET.SubElement(xml_step, "number_loops")
00231 nb_loops.text = str(self.number_of_loops)
00232 return xml_step
00233
00234 def load_from_xml(self, xml_element):
00235 for subelement in xml_element:
00236 if subelement.tag == "grasp":
00237 grasp_name = subelement.attrib.get("name")
00238 self.grasp_choosed(grasp_name)
00239 list_grasps = self.parent.hand_commander.get_named_targets()
00240 list_grasps.sort()
00241 for index, grasp_name_ref in zip(range(0, len(list_grasps)), list_grasps):
00242 if grasp_name == grasp_name_ref:
00243 self.list_grasp.setCurrentIndex(index)
00244 break
00245 if subelement.tag == "pause_time":
00246 self.pause_time = float(subelement.text)
00247 self.pause_input.setText(subelement.text)
00248
00249 if subelement.tag == "interpolation_time":
00250 self.interpolation_time = float(subelement.text)
00251 self.interp_input.setText(subelement.text)
00252
00253 if subelement.tag == "loop_to_step":
00254 self.loop_to_step = int(subelement.text)
00255 self.loop_input.setCurrentIndex(self.loop_to_step + 1)
00256 if self.loop_to_step == -1:
00257 self.number_loops.setDisabled(True)
00258 else:
00259 self.number_loops.setEnabled(True)
00260
00261 if subelement.tag == "number_loops":
00262 self.number_of_loops = int(subelement.text)
00263 self.number_loops.setText(subelement.text)
00264 self.grasp_slider = None
00265
00266 def refresh_list(self, value=0):
00267 self.list_grasp.clear()
00268 list_grasps = self.parent.hand_commander.get_named_targets()
00269 list_grasps.sort()
00270
00271 self.grasp = list_grasps[0]
00272
00273 for grasp_name in list_grasps:
00274 self.list_grasp.addItem(grasp_name)
00275
00276
00277 class SrGuiMovementRecorder(Plugin):
00278
00279 """
00280 A rosgui plugin for recording and replaying movements
00281 """
00282
00283 def __init__(self, context):
00284 super(SrGuiMovementRecorder, self).__init__(context)
00285 self.setObjectName('SrGuiMovementRecorder')
00286
00287 self._publisher = None
00288 self._widget = QWidget()
00289
00290 ui_file = os.path.join(rospkg.RosPack().get_path(
00291 'sr_gui_movement_recorder'), 'uis', 'SrGuiMovementRecorder.ui')
00292 loadUi(ui_file, self._widget)
00293 self._widget.setObjectName('SrGuiMovementRecorderUi')
00294 context.add_widget(self._widget)
00295
00296 self.frame = self._widget.frame
00297 self.timer = QTimer(self.frame)
00298
00299 self.layout = QVBoxLayout()
00300 self.layout.setSpacing(2)
00301
00302 self.layout.setAlignment(Qt.AlignCenter)
00303 self.layout.setSizeConstraint(QLayout.SetFixedSize)
00304
00305 self.sublayout = QGridLayout()
00306 self.command_frame = QFrame()
00307
00308
00309 hand_finder = HandFinder()
00310 self.hand_parameters = hand_finder.get_hand_parameters()
00311
00312 self.sublayout.addWidget(QLabel("Select Hand"), 0, 0)
00313 self.hand_combo_box = QComboBox()
00314
00315 for hand_serial in self.hand_parameters.mapping.keys():
00316 self.hand_combo_box.addItem(hand_serial)
00317
00318 self.sublayout.addWidget(self.hand_combo_box, 0, 1)
00319
00320 self.frame.connect(self.hand_combo_box, SIGNAL('activated(QString)'), self.hand_selected)
00321
00322 self.play_btn = QPushButton()
00323 self.play_btn.setText("Play")
00324 self.play_btn.setFixedWidth(80)
00325 self.command_frame.connect(
00326 self.play_btn, SIGNAL('clicked()'), self.button_play_clicked)
00327 self.sublayout.addWidget(self.play_btn, 0, 2)
00328
00329 self.mutex = threading.Lock()
00330 self.stopped = True
00331
00332 self.thread = None
00333
00334 self.stop_btn = QPushButton()
00335 self.stop_btn.setText("Stop")
00336 self.stop_btn.setFixedWidth(80)
00337 self.command_frame.connect(
00338 self.stop_btn, SIGNAL('clicked()'), self.stop)
00339 self.sublayout.addWidget(self.stop_btn, 0, 3)
00340
00341 self.sublayout.addWidget(QLabel(''), 0, 4)
00342
00343 self.save_btn = QPushButton()
00344 self.save_btn.setText("Save")
00345 self.save_btn.setFixedWidth(80)
00346 self.command_frame.connect(
00347 self.save_btn, SIGNAL('clicked()'), self.save)
00348 self.sublayout.addWidget(self.save_btn, 0, 5)
00349
00350 self.load_btn = QPushButton()
00351 self.load_btn.setText("Load")
00352 self.load_btn.setFixedWidth(80)
00353 self.command_frame.connect(
00354 self.load_btn, SIGNAL('clicked()'), self.load)
00355 self.sublayout.addWidget(self.load_btn, 0, 6)
00356
00357 self.command_frame.setLayout(self.sublayout)
00358 self.layout.addWidget(self.command_frame)
00359
00360 self.frame.setLayout(self.layout)
00361
00362 path_to_icons = os.path.join(
00363 rospkg.RosPack().get_path('sr_visualization_icons'), 'icons')
00364 self.load_btn.setIcon(QIcon(os.path.join(path_to_icons, 'load.png')))
00365 self.save_btn.setIcon(QIcon(os.path.join(path_to_icons, 'save.png')))
00366 self.stop_btn.setIcon(QIcon(os.path.join(path_to_icons, 'stop.png')))
00367 self.play_btn.setIcon(QIcon(os.path.join(path_to_icons, 'play.png')))
00368
00369 self.hand_commander = None
00370 self.steps = []
00371
00372 self.steps_frame = QFrame()
00373 self.steps_layout = QVBoxLayout()
00374 self.steps_frame.setLayout(self.steps_layout)
00375
00376 self.layout.addWidget(self.steps_frame)
00377
00378
00379 self.__selected_hand = None
00380 self.hand_selected(self.hand_parameters.mapping.keys()[0])
00381
00382 def hand_selected(self, serial):
00383 self.hand_commander = SrHandCommander(hand_parameters=self.hand_parameters,
00384 hand_serial=serial)
00385
00386 if self.__selected_hand == serial:
00387 return
00388
00389 self.remove_all_steps()
00390 self.add_step()
00391 self.__selected_hand = serial
00392
00393 def save(self):
00394 filename = QFileDialog.getSaveFileName(self.frame, 'Save Script', '')
00395 filename = filename[0]
00396
00397 if filename == "":
00398 return
00399
00400 root = ET.Element("movement")
00401 for step in self.steps:
00402 root.append(step.save_to_xml())
00403
00404 self.indent(root)
00405 tree = ET.ElementTree(root)
00406
00407 tree.write(filename)
00408
00409 def indent(self, elem, level=0):
00410 """
00411 print a prettier / indented xml tree
00412 """
00413 i = "\n" + level * " "
00414 if len(elem):
00415 if not elem.text or not elem.text.strip():
00416 elem.text = i + " "
00417 if not elem.tail or not elem.tail.strip():
00418 elem.tail = i
00419 for elem in elem:
00420 self.indent(elem, level + 1)
00421 if not elem.tail or not elem.tail.strip():
00422 elem.tail = i
00423 else:
00424 if level and (not elem.tail or not elem.tail.strip()):
00425 elem.tail = i
00426
00427 def load(self):
00428 """
00429 remove all the present steps
00430 and load new from xml file
00431 """
00432 filename = QFileDialog.getOpenFileName(self.frame, 'Open Script', '')
00433 filename = filename[0]
00434
00435 if filename != "":
00436 self.remove_all_steps()
00437
00438 tree = ET.parse(filename)
00439 root = tree.getroot()
00440 xml_steps = tree.findall("step")
00441
00442 for step in xml_steps:
00443 self.add_step()
00444 self.steps[-1].load_from_xml(step)
00445
00446 def remove_all_steps(self):
00447 while len(self.steps) != 0:
00448 self.steps[0].remove_step(delete_first=True)
00449
00450 def add_step(self, step_index=None):
00451 if step_index is None:
00452 step_index = len(self.steps)
00453 else:
00454 step_index += 1
00455
00456 step_tmp = Step(self.frame, step_index, self)
00457 self.steps.insert(step_index, step_tmp)
00458
00459 for index, step in enumerate(self.steps):
00460 step.set_step_id(index)
00461
00462 self.steps_layout.insertWidget(step_index, step_tmp)
00463 step_tmp.draw()
00464
00465 def button_play_clicked(self):
00466 if len(self.steps) < 1:
00467 return
00468
00469 self.play_btn.setDisabled(True)
00470 self.load_btn.setDisabled(True)
00471
00472 for step in self.steps:
00473 step.remove_step_button.setDisabled(True)
00474 step.new_step_button.setDisabled(True)
00475 step.remaining_loops = step.number_of_loops
00476
00477 self.fill_trajectory()
00478
00479 self.thread = threading.Thread(None, self.play)
00480 self.thread.start()
00481
00482 def fill_trajectory(self, step_index=None):
00483 if step_index is None:
00484 self.trajectory = []
00485 step_index = 0
00486 elif step_index >= len(self.steps):
00487 return
00488
00489 step = self.steps[step_index]
00490
00491 self.trajectory.append(
00492 {
00493 'name': step.grasp,
00494 'interpolate_time': step.interpolation_time,
00495 'pause_time': step.pause_time
00496 }
00497 )
00498
00499 if step.loop_to_step != -1 and step.remaining_loops > 0:
00500 step.remaining_loops -= 1
00501 next_step = step.loop_to_step
00502 else:
00503 next_step = step_index + 1
00504 self.fill_trajectory(next_step)
00505
00506 def play(self):
00507 self.stopped = False
00508 first_time = True
00509 index = 0
00510
00511 run = True
00512 in_progress = False
00513 while run:
00514 self.mutex.acquire()
00515 if self.stopped:
00516 self.mutex.release()
00517 return
00518 self.mutex.release()
00519
00520 if not in_progress:
00521 self.hand_commander.run_named_trajectory_unsafe(self.trajectory)
00522 in_progress = True
00523 else:
00524 rospy.sleep(0.1)
00525 run = self.hand_commander.action_is_running()
00526
00527 self.stop()
00528
00529 def stop(self):
00530 self.hand_commander.send_stop_trajectory_unsafe()
00531 for step in self.steps:
00532 step.new_step_button.setEnabled(True)
00533 step.remove_step_button.setEnabled(True)
00534 self.mutex.acquire()
00535 self.stopped = True
00536 self.mutex.release()
00537 self.play_btn.setEnabled(True)
00538 self.load_btn.setEnabled(True)
00539
00540 def _unregisterPublisher(self):
00541 if self._publisher is not None:
00542 self._publisher.unregister()
00543 self._publisher = None
00544
00545 def shutdown_plugin(self):
00546 self.remove_all_steps()
00547 self._unregisterPublisher()