00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 import os
00018 import time
00019 import rospy
00020 import rospkg
00021 import sys
00022
00023 from rospy import loginfo, logerr, logdebug
00024
00025 from qt_gui.plugin import Plugin
00026 from python_qt_binding import loadUi
00027
00028 import QtCore
00029 from QtCore import Qt, QEvent, QObject
00030 import QtGui
00031 from QtGui import *
00032
00033 from sr_hand.Grasp import Grasp
00034 from sr_hand.grasps_interpoler import GraspInterpoler
00035 from sr_robot_commander.sr_hand_commander import SrHandCommander
00036 from sr_utilities.hand_finder import HandFinder
00037
00038 from moveit_msgs.srv import SaveRobotStateToWarehouse as SaveState
00039 from moveit_msgs.srv import CheckIfRobotStateExistsInWarehouse as HasState
00040 from moveit_msgs.srv import DeleteRobotStateFromWarehouse as DelState
00041
00042 from moveit_msgs.msg import RobotState
00043 from control_msgs.msg import JointTrajectoryControllerState as ControllerState
00044 from threading import Lock
00045
00046
00047 class JointSelecter(QtGui.QWidget):
00048
00049 """
00050 Select which joints to save in a new grasp
00051 """
00052
00053 def __init__(self, parent, all_joints, status_topic=None):
00054 QtGui.QWidget.__init__(self, parent=parent)
00055 self.frame = QtGui.QFrame()
00056 self.layout = QtGui.QGridLayout()
00057 self.checkboxes = []
00058
00059 col = 0
00060
00061 rows = [0, 0, 0, 0, 0, 0]
00062 joint_names = all_joints.keys()
00063 joint_names.sort()
00064
00065 for joint in joint_names:
00066 if "ff" in joint.lower():
00067 col = 0
00068 elif "mf" in joint.lower():
00069 col = 1
00070 elif "rf" in joint.lower():
00071 col = 2
00072 elif "lf" in joint.lower():
00073 col = 3
00074 elif "th" in joint.lower():
00075 col = 4
00076 else:
00077 col = 5
00078
00079 row = rows[col]
00080 rows[col] = row + 1
00081 cb = QtGui.QCheckBox(str(joint), self.frame)
00082 self.checkboxes.append(cb)
00083 self.layout.addWidget(cb, row, col)
00084
00085 self.frame.setLayout(self.layout)
00086 layout = QtGui.QVBoxLayout()
00087 layout.addWidget(self.frame)
00088
00089 if status_topic is not None:
00090 self._save_target = QtGui.QCheckBox("Use joint targets instead of current positions.", self.frame)
00091 layout.addWidget(self._save_target)
00092 else:
00093 self._save_target = None
00094
00095 self.frame.show()
00096 self.setLayout(layout)
00097 self.show()
00098
00099 def use_target(self):
00100 return (self._save_target is not None) and self._save_target.isChecked()
00101
00102 def get_selected(self):
00103 """
00104 Retrieve selected joints
00105 """
00106 joints = []
00107 for cb in self.checkboxes:
00108 if cb.isChecked():
00109 joints.append(str(cb.text()))
00110
00111 return joints
00112
00113 def select_all(self):
00114 """
00115 Select all joints
00116 """
00117 for cb in self.checkboxes:
00118 cb.setChecked(True)
00119
00120 def deselect_all(self):
00121 """
00122 Unselect all joints
00123 """
00124 for cb in self.checkboxes:
00125 cb.setChecked(False)
00126
00127
00128 class GraspSaver(QtGui.QDialog):
00129
00130 """
00131 Save a new grasp from the current joints positions.
00132 """
00133
00134 def __init__(self, parent, all_joints, plugin_parent, status_topic=None):
00135 QtGui.QDialog.__init__(self, parent)
00136
00137 self._status_topic = status_topic
00138 self.plugin_parent = plugin_parent
00139 self.all_joints = all_joints
00140 self.setModal(True)
00141 self.setWindowTitle("Save Grasp")
00142
00143 self.grasp_name = ""
00144
00145 self.upper_frame = QtGui.QFrame()
00146 self.upper_layout = QtGui.QHBoxLayout()
00147 label_name = QtGui.QLabel()
00148 label_name.setText("Grasp Name: ")
00149 name_widget = QtGui.QLineEdit()
00150 self.upper_frame.connect(
00151 name_widget, QtCore.SIGNAL('textChanged(QString)'), self.name_changed)
00152
00153 self.upper_layout.addWidget(label_name)
00154 self.upper_layout.addWidget(name_widget)
00155 self.upper_frame.setLayout(self.upper_layout)
00156
00157 select_all_frame = QtGui.QFrame()
00158 select_all_layout = QtGui.QHBoxLayout()
00159 btn_select_all = QtGui.QPushButton(select_all_frame)
00160 btn_select_all.setText("Select All")
00161 select_all_layout.addWidget(btn_select_all)
00162 self.connect(
00163 btn_select_all, QtCore.SIGNAL("clicked()"), self.select_all)
00164 btn_deselect_all = QtGui.QPushButton(select_all_frame)
00165 btn_deselect_all.setText("Deselect All")
00166 select_all_layout.addWidget(btn_deselect_all)
00167 self.connect(
00168 btn_deselect_all, QtCore.SIGNAL("clicked()"), self.deselect_all)
00169 select_all_frame.setLayout(select_all_layout)
00170
00171 self.joint_selecter = JointSelecter(self, self.all_joints, status_topic)
00172
00173 btn_frame = QtGui.QFrame()
00174 self.btn_ok = QtGui.QPushButton(btn_frame)
00175 self.btn_ok.setText("OK")
00176 self.btn_ok.setDisabled(True)
00177 self.connect(self.btn_ok, QtCore.SIGNAL("clicked()"), self.accept)
00178 btn_cancel = QtGui.QPushButton(btn_frame)
00179 btn_cancel.setText("Cancel")
00180 self.connect(btn_cancel, QtCore.SIGNAL("clicked()"), self.reject)
00181
00182 btn_layout = QtGui.QHBoxLayout()
00183 btn_layout.addWidget(self.btn_ok)
00184 btn_layout.addWidget(btn_cancel)
00185 btn_frame.setLayout(btn_layout)
00186
00187 self.layout = QtGui.QVBoxLayout()
00188 self.layout.addWidget(self.upper_frame)
00189 self.layout.addWidget(select_all_frame)
00190 self.layout.addWidget(self.joint_selecter)
00191 self.layout.addWidget(btn_frame)
00192
00193 self.setLayout(self.layout)
00194 self.show()
00195
00196 try:
00197 rospy.wait_for_service("has_robot_state", 1)
00198 except rospy.ServiceException as e:
00199 QMessageBox.warning(
00200 self, "Warning", "Could not connect to warehouse services."
00201 "Please make sure they're running before saving grasps.")
00202 rospy.logerr("Tried to save, but couldn't connecto to warehouse service: %s" % str(e))
00203 self.reject()
00204
00205 self.has_state = rospy.ServiceProxy("has_robot_state",
00206 HasState)
00207 self.save_state = rospy.ServiceProxy("save_robot_state",
00208 SaveState)
00209 self.robot_name = self.plugin_parent.hand_commander.get_robot_name()
00210 rospy.logwarn("here")
00211
00212 if self._status_topic is not None:
00213 rospy.logwarn(self._status_topic)
00214 self._controller_state_subscriber = rospy.Subscriber(self._status_topic,
00215 ControllerState, self._controller_state_cb)
00216 self._position_targets = {}
00217 self._target_mutex = Lock()
00218
00219 def _controller_state_cb(self, state):
00220 self._target_mutex.acquire()
00221 self._position_targets = {name: state.desired.positions[n] for n, name in enumerate(state.joint_names)}
00222 self._target_mutex.release()
00223
00224 def select_all(self):
00225 """
00226 Select all joints
00227 """
00228 self.joint_selecter.select_all()
00229
00230 def deselect_all(self):
00231 """
00232 Unselect all joints
00233 """
00234 self.joint_selecter.deselect_all()
00235
00236 def name_changed(self, name):
00237 self.grasp_name = name
00238 if self.grasp_name != "":
00239 self.btn_ok.setEnabled(True)
00240 else:
00241 self.btn_ok.setDisabled(True)
00242
00243 def accept(self):
00244 """
00245 Save grasp for the selected joints
00246 """
00247
00248 robot_state = RobotState()
00249
00250 joint_names_to_save = self.joint_selecter.get_selected()
00251 use_target_values = self.joint_selecter.use_target()
00252
00253 if len(joint_names_to_save) == 0:
00254 joint_names_to_save = self.all_joints.keys()
00255
00256 joint_values_to_save = []
00257
00258 self._target_mutex.acquire()
00259
00260 for joint in joint_names_to_save:
00261 if use_target_values and (joint in self._position_targets):
00262 joint_values_to_save.append(self._position_targets[joint])
00263 else:
00264 joint_values_to_save.append(self.all_joints[joint])
00265
00266 self._target_mutex.release()
00267
00268 robot_state.joint_state.name = joint_names_to_save
00269 robot_state.joint_state.position = joint_values_to_save
00270
00271 if self.has_state(self.grasp_name, self.robot_name).exists:
00272 ret = QtGui.QMessageBox.question(
00273 self, "State already in warehouse!",
00274 "There is already a pose named %s in the warehouse. Overwrite?"
00275 % self.grasp_name, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
00276 QtGui.QMessageBox.No)
00277
00278 if QtGui.QMessageBox.No == ret:
00279 return
00280
00281 self.save_state(self.grasp_name, self.robot_name, robot_state)
00282
00283 try:
00284 self.plugin_parent.newPoseSavedSignal['QString'].emit(self.grasp_name)
00285 except NameError:
00286 pass
00287
00288 QtGui.QDialog.accept(self)
00289
00290
00291 class GraspChooser(QtGui.QWidget):
00292
00293 """
00294 Choose a grasp from a list of grasps.
00295 """
00296
00297 def __init__(self, parent, plugin_parent, title):
00298 QtGui.QWidget.__init__(self)
00299 self.plugin_parent = plugin_parent
00300 self.grasp = None
00301 self.title = QtGui.QLabel()
00302 self.title.setText(title)
00303
00304 def draw(self):
00305 """
00306 Draw the gui and connect signals
00307 """
00308 self.frame = QtGui.QFrame(self)
00309
00310 self.list = QtGui.QListWidget()
00311 first_item = self.refresh_list()
00312 self.connect(self.list, QtCore.SIGNAL(
00313 'itemClicked(QListWidgetItem*)'), self.grasp_selected)
00314
00315 self.connect(self.list, QtCore.SIGNAL(
00316 'itemDoubleClicked(QListWidgetItem*)'), self.double_click)
00317 self.list.setViewMode(QtGui.QListView.ListMode)
00318 self.list.setResizeMode(QtGui.QListView.Adjust)
00319 self.list.setItemSelected(first_item, True)
00320 self.grasp_selected(first_item, first_time=True)
00321
00322 self.layout = QtGui.QVBoxLayout()
00323 self.layout.addWidget(self.title)
00324 self.layout.addWidget(self.list)
00325
00326
00327
00328
00329
00330 self.plugin_parent.newPoseSavedSignal['QString'].connect(self.refresh_list)
00331
00332 self.frame.setLayout(self.layout)
00333 layout = QtGui.QVBoxLayout()
00334 layout.addWidget(self.frame)
00335 self.frame.show()
00336 self.setLayout(layout)
00337 self.show()
00338
00339 def double_click(self, item):
00340 """
00341 Sends new targets to the hand from a dictionary mapping the name of the joint to the value of its target
00342 """
00343 self.grasp_name = str(item.text())
00344 self.plugin_parent.hand_commander.move_to_named_target(self.grasp_name)
00345
00346 self.plugin_parent.set_reference_grasp()
00347
00348 def grasp_selected(self, item, first_time=False):
00349 """
00350 grasp has been selected with a single click
00351 """
00352
00353 self.grasp = Grasp()
00354 self.grasp.grasp_name = str(item.text())
00355 self.grasp.joints_and_positions = self.plugin_parent.\
00356 hand_commander.get_named_target_joint_values(item.text())
00357
00358 if not first_time:
00359 self.plugin_parent.set_reference_grasp()
00360
00361 self.plugin_parent.to_delete = self.grasp.grasp_name
00362
00363 def refresh_list(self, value=0):
00364 """
00365 refreash list of grasps
00366 """
00367 self.list.clear()
00368 first_item = None
00369 self.plugin_parent.hand_commander.refresh_named_targets()
00370 grasps = self.plugin_parent.hand_commander.get_named_targets()
00371 grasps.sort()
00372 for grasp_name in grasps:
00373 item = QtGui.QListWidgetItem(grasp_name)
00374 if first_item is None:
00375 first_item = item
00376 self.list.addItem(item)
00377 return first_item
00378
00379
00380 class GraspSlider(QtGui.QWidget):
00381
00382 """
00383 Slide from one grasp to another.
00384 """
00385
00386 def __init__(self, parent, plugin_parent):
00387 QtGui.QWidget.__init__(self, parent)
00388 self.plugin_parent = plugin_parent
00389
00390 def draw(self):
00391 """
00392 Draw the gui and connect signals
00393 """
00394 self.frame = QtGui.QFrame(self)
00395 label_frame = QtGui.QFrame(self.frame)
00396 from_label = QtGui.QLabel()
00397 from_label.setText("From")
00398 ref_label = QtGui.QLabel()
00399 ref_label.setText("Reference")
00400 to_label = QtGui.QLabel()
00401 to_label.setText("To")
00402 label_layout = QtGui.QHBoxLayout()
00403 label_layout.addWidget(from_label)
00404 label_layout.addWidget(ref_label)
00405 label_layout.addWidget(to_label)
00406
00407 label_frame.setLayout(label_layout)
00408
00409 self.slider = QtGui.QSlider()
00410 self.slider.setOrientation(QtCore.Qt.Horizontal)
00411 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00412 self.slider.setTickInterval(100)
00413 self.slider.setTickPosition(QSlider.TicksAbove)
00414 self.slider.setMinimum(-100)
00415 self.slider.setMaximum(100)
00416
00417 self.connect(self.slider, QtCore.SIGNAL(
00418 'valueChanged(int)'), self.changeValue)
00419
00420 self.layout = QtGui.QVBoxLayout()
00421 self.layout.addWidget(label_frame)
00422 self.layout.addWidget(self.slider)
00423
00424 self.frame.setLayout(self.layout)
00425 layout = QtGui.QVBoxLayout()
00426 layout.addWidget(self.frame)
00427 self.frame.show()
00428 self.setLayout(layout)
00429 self.show()
00430
00431 def changeValue(self, value):
00432 """
00433 interpolate from the current grasp to new value
00434 """
00435 self.plugin_parent.interpolate_grasps(value)
00436
00437
00438 class SrGuiGraspController(Plugin):
00439
00440 """
00441 Main GraspController plugin Dock window.
00442 """
00443
00444 newPoseSavedSignal = QtCore.pyqtSignal(str)
00445
00446 def __init__(self, context):
00447 super(SrGuiGraspController, self).__init__(context)
00448
00449 self.setObjectName('SrGuiGraspController')
00450
00451 self.icon_dir = os.path.join(
00452 rospkg.RosPack().get_path('sr_visualization_icons'), '/icons')
00453
00454 ui_file = os.path.join(rospkg.RosPack().get_path(
00455 'sr_gui_grasp_controller'), 'uis', 'SrGuiGraspController.ui')
00456 self._widget = QWidget()
00457 loadUi(ui_file, self._widget)
00458 if context is not None:
00459 context.add_widget(self._widget)
00460 self.current_grasp = Grasp()
00461
00462 self.grasp_interpoler_1 = None
00463 self.grasp_interpoler_2 = None
00464
00465 self.layout = self._widget.layout
00466
00467 subframe = QtGui.QFrame()
00468 sublayout = QtGui.QVBoxLayout()
00469
00470 self.hand_finder = HandFinder()
00471 self.hand_parameters = self.hand_finder.get_hand_parameters()
00472
00473 self.hand_commander = SrHandCommander(
00474 hand_parameters=self.hand_parameters,
00475 hand_serial=self.hand_parameters.mapping.keys()[0])
00476
00477 self.grasp_slider = GraspSlider(self._widget, self)
00478 sublayout.addWidget(self.grasp_slider)
00479
00480 btn_frame = QtGui.QFrame()
00481 btn_layout = QtGui.QHBoxLayout()
00482
00483 self.btn_save = QtGui.QPushButton()
00484 self.btn_save.setText("Save")
00485 self.btn_save.setFixedWidth(130)
00486 self.btn_save.setIcon(QtGui.QIcon(self.icon_dir + '/save.png'))
00487 btn_frame.connect(
00488 self.btn_save, QtCore.SIGNAL('clicked()'), self.save_grasp)
00489 btn_layout.addWidget(self.btn_save)
00490
00491 self.btn_del = QtGui.QPushButton()
00492 self.btn_del.setText("Delete")
00493 self.btn_del.setFixedWidth(130)
00494 btn_frame.connect(
00495 self.btn_del, QtCore.SIGNAL('clicked()'), self.delete_grasp)
00496 btn_layout.addWidget(self.btn_del)
00497
00498 btn_set_ref = QtGui.QPushButton()
00499 btn_set_ref.setText("Set Reference")
00500 btn_set_ref.setFixedWidth(130)
00501 btn_set_ref.setIcon(QtGui.QIcon(self.icon_dir + '/iconHand.png'))
00502 btn_frame.connect(btn_set_ref, QtCore.SIGNAL(
00503 'clicked()'), self.set_reference_grasp)
00504 btn_layout.addWidget(btn_set_ref)
00505
00506 btn_frame.setLayout(btn_layout)
00507 sublayout.addWidget(btn_frame)
00508 subframe.setLayout(sublayout)
00509
00510 selector_layout = QtGui.QHBoxLayout()
00511 selector_frame = QtGui.QFrame()
00512
00513 selector_layout.addWidget(QLabel("Select Hand"))
00514
00515 self.hand_combo_box = QComboBox()
00516
00517 for hand_serial in self.hand_parameters.mapping.keys():
00518 self.hand_combo_box.addItem(hand_serial)
00519
00520 selector_layout.addWidget(self.hand_combo_box)
00521
00522 selector_frame.setLayout(selector_layout)
00523 sublayout.addWidget(selector_frame)
00524
00525 selector_frame.connect(
00526 self.hand_combo_box,
00527 QtCore.SIGNAL('activated(QString)'),
00528 self.hand_selected)
00529
00530 self.grasp_from_chooser = GraspChooser(self._widget, self, "From: ")
00531 self.layout.addWidget(self.grasp_from_chooser)
00532 self.layout.addWidget(subframe)
00533
00534 self.grasp_to_chooser = GraspChooser(self._widget, self, "To: ")
00535 self.layout.addWidget(self.grasp_to_chooser)
00536
00537 self.grasp_slider.draw()
00538 self.grasp_to_chooser.draw()
00539 self.grasp_from_chooser.draw()
00540
00541 time.sleep(0.2)
00542
00543 self.set_reference_grasp()
00544
00545 self.to_delete = None
00546
00547 def hand_selected(self, serial):
00548 self.hand_commander = SrHandCommander(
00549 hand_parameters=self.hand_parameters,
00550 hand_serial=serial)
00551 self.refresh_grasp_lists()
00552
00553 def delete_grasp(self):
00554 if self.to_delete is None:
00555 QMessageBox.warning(
00556 self._widget, "No grasp selected!",
00557 "Please click a grasp name in either grasp chooser to delete.")
00558 else:
00559 ret = QtGui.QMessageBox.question(
00560 self._widget, "Delete Grasp?",
00561 "Are you sure you wish to delete grasp %s?"
00562 % self.to_delete, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
00563 QtGui.QMessageBox.No)
00564
00565 if ret == QtGui.QMessageBox.Yes:
00566 del_state = rospy.ServiceProxy("delete_robot_state", DelState)
00567 robot_name = self.hand_commander.get_robot_name()
00568 try:
00569 del_state(self.to_delete, robot_name)
00570 except rospy.ServiceException as e:
00571 QMessageBox.warning(
00572 self._widget, "Coudn't delete",
00573 "Please check warehouse services are running.")
00574 rospy.logwarn("Couldn't delete state: %s" % str(e))
00575 self.refresh_grasp_lists()
00576
00577 def refresh_grasp_lists(self):
00578 self.grasp_from_chooser.refresh_list()
00579 self.grasp_to_chooser.refresh_list()
00580
00581 def shutdown_plugin(self):
00582 self._widget.close()
00583 self._widget.deleteLater()
00584
00585 def save_settings(self, global_settings, perspective_settings):
00586 pass
00587
00588 def restore_settings(self, global_settings, perspective_settings):
00589 pass
00590
00591 def save_grasp(self):
00592 all_joints = self.hand_commander.get_current_state_bounded()
00593 GraspSaver(self._widget, all_joints, self)
00594
00595 def set_reference_grasp(self, argument=None):
00596 """
00597 Set the last commander target reference for interpolation
00598 """
00599 self.current_grasp.joints_and_positions = self.hand_commander.get_current_state()
00600 self.grasp_slider.slider.setValue(0)
00601
00602 grasp_to = self.grasp_to_chooser.grasp
00603 grasp_from = self.grasp_from_chooser.grasp
00604
00605 for g in [grasp_to, grasp_from]:
00606 for k in g.joints_and_positions.keys():
00607 if k not in self.hand_commander._move_group_commander._g.get_joints():
00608 del(g.joints_and_positions[k])
00609
00610 self.grasp_interpoler_1 = GraspInterpoler(
00611 self.grasp_from_chooser.grasp, self.current_grasp)
00612 self.grasp_interpoler_2 = GraspInterpoler(
00613 self.current_grasp, self.grasp_to_chooser.grasp)
00614
00615 def interpolate_grasps(self, value):
00616 """
00617 interpolate grasp from the current one to the one indicated by value
00618 or in the opposite direction if value < 0
00619 hand controllers must be running and reference must be set
00620 """
00621 if self.grasp_interpoler_1 is None \
00622 or self.grasp_interpoler_2 is None:
00623 QMessageBox.warning(
00624 self._widget, "Warning", "Could not read current grasp.\n"
00625 "Check that the hand controllers are running.\n"
00626 "Then click \"Set Reference\"")
00627 return
00628
00629 targets_to_send = dict()
00630 if value < 0:
00631 targets_to_send = self.grasp_interpoler_1.interpolate(100 + value)
00632 else:
00633 targets_to_send = self.grasp_interpoler_2.interpolate(value)
00634
00635 self.hand_commander.move_to_joint_value_target_unsafe(targets_to_send)
00636
00637
00638 if __name__ == "__main__":
00639 rospy.init_node("grasp_controller")
00640 app = QApplication(sys.argv)
00641 ctrl = SrGuiGraspController(None)
00642 ctrl._widget.show()
00643 app.exec_()