00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 import os, time, rospy, rospkg
00017
00018 from rospy import loginfo, logerr, logdebug
00019
00020 from qt_gui.plugin import Plugin
00021 from python_qt_binding import loadUi
00022
00023 import QtCore
00024 from QtCore import Qt, QEvent, QObject
00025 import QtGui
00026 from QtGui import *
00027
00028 from sr_hand.Grasp import Grasp
00029 from sr_hand.grasps_interpoler import GraspInterpoler
00030 from sr_hand.grasps_parser import GraspParser
00031
00032 from sr_hand.shadowhand_ros import ShadowHand_ROS
00033
00034 class JointSelecter(QtGui.QWidget):
00035 """
00036 Select which joints to save in a new grasp
00037 """
00038 def __init__(self, parent, all_joints):
00039 QtGui.QWidget.__init__(self, parent=parent)
00040 self.frame = QtGui.QFrame()
00041 self.layout = QtGui.QGridLayout()
00042 self.checkboxes = []
00043
00044 col = 0
00045
00046 rows = [0, 0, 0, 0, 0, 0]
00047 joint_names = all_joints.keys()
00048 joint_names.sort()
00049 for joint in joint_names:
00050 if "fj1" in joint.lower():
00051 continue
00052 if "fj2" in joint.lower():
00053 continue
00054 if "ff" in joint.lower():
00055 col = 0
00056 elif "mf" in joint.lower():
00057 col = 1
00058 elif "rf" in joint.lower():
00059 col = 2
00060 elif "lf" in joint.lower():
00061 col = 3
00062 elif "th" in joint.lower():
00063 col = 4
00064 else:
00065 col = 5
00066
00067 row = rows[col]
00068 rows[col] = row + 1
00069 cb = QtGui.QCheckBox(str(joint), self.frame)
00070 self.checkboxes.append(cb)
00071 self.layout.addWidget(cb, row, col)
00072
00073 self.frame.setLayout(self.layout)
00074 layout = QtGui.QVBoxLayout()
00075 layout.addWidget(self.frame)
00076 self.frame.show()
00077 self.setLayout(layout)
00078 self.show()
00079
00080 def get_selected(self):
00081 """
00082 Retrieve selected joints
00083 """
00084 joints = []
00085 for cb in self.checkboxes:
00086 if cb.isChecked():
00087 joints.append(str(cb.text()))
00088
00089 return joints
00090
00091 def select_all(self):
00092 """
00093 Select all joints
00094 """
00095 for cb in self.checkboxes:
00096 cb.setChecked(True)
00097
00098 def deselect_all(self):
00099 """
00100 Unselect all joints
00101 """
00102 for cb in self.checkboxes:
00103 cb.setChecked(False)
00104
00105 class GraspSaver(QtGui.QDialog):
00106 """
00107 Save a new grasp from the current joints positions.
00108 """
00109 def __init__(self, parent, all_joints, plugin_parent):
00110 QtGui.QDialog.__init__(self, parent)
00111 self.plugin_parent = plugin_parent
00112 self.all_joints = all_joints
00113 self.setModal(True)
00114 self.setWindowTitle("Save Grasp")
00115
00116 self.grasp_name = ""
00117
00118 self.upper_frame = QtGui.QFrame()
00119 self.upper_layout = QtGui.QHBoxLayout()
00120 label_name = QtGui.QLabel()
00121 label_name.setText("Grasp Name: ")
00122 name_widget = QtGui.QLineEdit()
00123 self.upper_frame.connect(name_widget, QtCore.SIGNAL('textChanged(QString)'), self.name_changed)
00124
00125 self.upper_layout.addWidget(label_name)
00126 self.upper_layout.addWidget(name_widget)
00127 self.upper_frame.setLayout(self.upper_layout)
00128
00129 select_all_frame = QtGui.QFrame()
00130 select_all_layout = QtGui.QHBoxLayout()
00131 btn_select_all = QtGui.QPushButton(select_all_frame)
00132 btn_select_all.setText("Select All")
00133 select_all_layout.addWidget(btn_select_all)
00134 self.connect(btn_select_all, QtCore.SIGNAL("clicked()"), self.select_all)
00135 btn_deselect_all = QtGui.QPushButton(select_all_frame)
00136 btn_deselect_all.setText("Deselect All")
00137 select_all_layout.addWidget(btn_deselect_all)
00138 self.connect(btn_deselect_all, QtCore.SIGNAL("clicked()"), self.deselect_all)
00139 select_all_frame.setLayout(select_all_layout)
00140
00141 self.joint_selecter = JointSelecter(self, self.all_joints)
00142
00143 btn_frame = QtGui.QFrame()
00144 self.btn_ok = QtGui.QPushButton(btn_frame)
00145 self.btn_ok.setText("OK")
00146 self.btn_ok.setDisabled(True)
00147 self.connect(self.btn_ok, QtCore.SIGNAL("clicked()"), self.accept)
00148 btn_cancel = QtGui.QPushButton(btn_frame)
00149 btn_cancel.setText("Cancel")
00150 self.connect(btn_cancel, QtCore.SIGNAL("clicked()"), self.reject)
00151
00152 btn_layout = QtGui.QHBoxLayout()
00153 btn_layout.addWidget(self.btn_ok)
00154 btn_layout.addWidget(btn_cancel)
00155 btn_frame.setLayout(btn_layout)
00156
00157 self.layout = QtGui.QVBoxLayout()
00158 self.layout.addWidget(self.upper_frame)
00159 self.layout.addWidget(select_all_frame)
00160 self.layout.addWidget(self.joint_selecter)
00161 self.layout.addWidget(btn_frame)
00162
00163 self.setLayout(self.layout)
00164 self.show()
00165
00166 def select_all(self):
00167 """
00168 Select all joints
00169 """
00170 self.joint_selecter.select_all()
00171
00172 def deselect_all(self):
00173 """
00174 Unselect all joints
00175 """
00176 self.joint_selecter.deselect_all()
00177
00178 def name_changed(self, name):
00179 self.grasp_name = name
00180 if self.grasp_name != "":
00181 self.btn_ok.setEnabled(True)
00182 else:
00183 self.btn_ok.setDisabled(True)
00184
00185 def accept(self):
00186 """
00187 Save grasp for the selected joints
00188 """
00189 grasp = Grasp()
00190 grasp.grasp_name = self.grasp_name
00191
00192 joints_to_save = self.joint_selecter.get_selected()
00193 if len(joints_to_save) == 0:
00194 joints_to_save = self.all_joints.keys()
00195 for joint_to_save in joints_to_save:
00196 grasp.joints_and_positions[joint_to_save] = self.all_joints[joint_to_save]
00197
00198 self.plugin_parent.sr_lib.grasp_parser.write_grasp_to_file(grasp)
00199 self.plugin_parent.sr_lib.grasp_parser.refresh()
00200
00201 self.plugin_parent.reloadGraspSig['int'].emit(1)
00202
00203 QtGui.QDialog.accept(self)
00204
00205 class GraspChooser(QtGui.QWidget):
00206 """
00207 Choose a grasp from a list of grasps.
00208 """
00209 def __init__(self, parent, plugin_parent, title):
00210 QtGui.QWidget.__init__(self)
00211 self.plugin_parent = plugin_parent
00212 self.grasp = None
00213 self.title = QtGui.QLabel()
00214 self.title.setText(title)
00215
00216 def draw(self):
00217 """
00218 Draw the gui and connect signals
00219 """
00220 self.frame = QtGui.QFrame(self)
00221
00222 self.list = QtGui.QListWidget()
00223 first_item = self.refresh_list()
00224 self.connect(self.list, QtCore.SIGNAL('itemClicked(QListWidgetItem*)'), self.grasp_selected)
00225
00226 self.connect(self.list, QtCore.SIGNAL('itemDoubleClicked(QListWidgetItem*)'), self.double_click)
00227 self.list.setViewMode(QtGui.QListView.ListMode)
00228 self.list.setResizeMode(QtGui.QListView.Adjust)
00229 self.list.setItemSelected(first_item, True)
00230 self.grasp_selected(first_item, first_time=True)
00231
00232 self.layout = QtGui.QVBoxLayout()
00233 self.layout.addWidget(self.title)
00234 self.layout.addWidget(self.list)
00235
00236
00237
00238
00239 self.plugin_parent.reloadGraspSig['int'].connect(self.refresh_list)
00240
00241 self.frame.setLayout(self.layout)
00242 layout = QtGui.QVBoxLayout()
00243 layout.addWidget(self.frame)
00244 self.frame.show()
00245 self.setLayout(layout)
00246 self.show()
00247
00248 def double_click(self, item):
00249 """
00250 Sends new targets to the hand from a dictionary mapping the name of the joint to the value of its target
00251 """
00252 self.grasp = self.plugin_parent.sr_lib.grasp_parser.grasps[str(item.text())]
00253 self.plugin_parent.sr_lib.sendupdate_from_dict(self.grasp.joints_and_positions)
00254 self.plugin_parent.set_reference_grasp()
00255
00256 def grasp_selected(self, item, first_time=False):
00257 """
00258 grasp has been selected with a single click
00259 """
00260 self.grasp = self.plugin_parent.sr_lib.grasp_parser.grasps[str(item.text())]
00261 if not first_time:
00262 self.plugin_parent.grasp_changed()
00263 self.plugin_parent.set_reference_grasp()
00264
00265 def refresh_list(self, value = 0):
00266 """
00267 refreash list of grasps
00268 """
00269 self.list.clear()
00270 first_item = None
00271 grasps = self.plugin_parent.sr_lib.grasp_parser.grasps.keys()
00272 grasps.sort()
00273 for grasp_name in grasps:
00274 item = QtGui.QListWidgetItem(grasp_name)
00275 if first_item == None:
00276 first_item = item
00277 self.list.addItem(item)
00278 return first_item
00279
00280 class GraspSlider(QtGui.QWidget):
00281 """
00282 Slide from one grasp to another.
00283 """
00284 def __init__(self, parent, plugin_parent):
00285 QtGui.QWidget.__init__(self, parent)
00286 self.plugin_parent = plugin_parent
00287
00288 def draw(self):
00289 """
00290 Draw the gui and connect signals
00291 """
00292 self.frame = QtGui.QFrame(self)
00293 label_frame = QtGui.QFrame(self.frame)
00294 from_label = QtGui.QLabel()
00295 from_label.setText("From")
00296 ref_label = QtGui.QLabel()
00297 ref_label.setText("Reference")
00298 to_label = QtGui.QLabel()
00299 to_label.setText("To")
00300 label_layout = QtGui.QHBoxLayout()
00301 label_layout.addWidget(from_label)
00302 label_layout.addWidget(ref_label)
00303 label_layout.addWidget(to_label)
00304
00305 label_frame.setLayout(label_layout)
00306
00307 self.slider = QtGui.QSlider()
00308 self.slider.setOrientation(QtCore.Qt.Horizontal)
00309 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00310 self.slider.setTickInterval(100)
00311 self.slider.setTickPosition(QSlider.TicksAbove)
00312 self.slider.setMinimum(-100)
00313 self.slider.setMaximum(100)
00314
00315 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
00316
00317 self.layout = QtGui.QVBoxLayout()
00318 self.layout.addWidget(label_frame)
00319 self.layout.addWidget(self.slider)
00320
00321 self.frame.setLayout(self.layout)
00322 layout = QtGui.QVBoxLayout()
00323 layout.addWidget(self.frame)
00324 self.frame.show()
00325 self.setLayout(layout)
00326 self.show()
00327
00328 def changeValue(self, value):
00329 """
00330 interpolate from the current grasp to new value
00331 """
00332 self.plugin_parent.interpolate_grasps(value)
00333
00334 class SrGuiGraspController(Plugin):
00335 """
00336 Main GraspController plugin Dock window.
00337 """
00338
00339 reloadGraspSig = QtCore.pyqtSignal(int)
00340
00341 def __init__(self, context):
00342 super(SrGuiGraspController, self).__init__(context)
00343
00344 self.setObjectName('SrGuiGraspController')
00345
00346 self.icon_dir = os.path.join(rospkg.RosPack().get_path('sr_visualization_icons'), '/icons')
00347
00348 self.sr_lib = ShadowHand_ROS()
00349
00350 ui_file = os.path.join(rospkg.RosPack().get_path('sr_gui_grasp_controller'), 'uis', 'SrGuiGraspController.ui')
00351 self._widget = QWidget()
00352 loadUi(ui_file, self._widget)
00353 context.add_widget(self._widget)
00354
00355 self.current_grasp = Grasp()
00356 self.current_grasp.name = 'CURRENT_UNSAVED'
00357 self.grasp_interpoler_1 = None
00358 self.grasp_interpoler_2 = None
00359
00360 self.layout = self._widget.layout
00361
00362 subframe = QtGui.QFrame()
00363 sublayout = QtGui.QVBoxLayout()
00364
00365 self.grasp_slider = GraspSlider(self._widget, self)
00366 sublayout.addWidget(self.grasp_slider)
00367
00368 btn_frame = QtGui.QFrame()
00369 btn_layout = QtGui.QHBoxLayout()
00370 self.btn_save = QtGui.QPushButton()
00371 self.btn_save.setText("Save")
00372 self.btn_save.setFixedWidth(130)
00373 self.btn_save.setIcon(QtGui.QIcon(self.icon_dir + '/save.png'))
00374 btn_frame.connect(self.btn_save, QtCore.SIGNAL('clicked()'), self.save_grasp)
00375 btn_layout.addWidget(self.btn_save)
00376 btn_set_ref = QtGui.QPushButton()
00377 btn_set_ref.setText("Set Reference")
00378 btn_set_ref.setFixedWidth(130)
00379 btn_set_ref.setIcon(QtGui.QIcon(self.icon_dir + '/iconHand.png'))
00380 btn_frame.connect(btn_set_ref, QtCore.SIGNAL('clicked()'), self.set_reference_grasp)
00381 btn_layout.addWidget(btn_set_ref)
00382
00383 btn_frame.setLayout(btn_layout)
00384 sublayout.addWidget(btn_frame)
00385 subframe.setLayout(sublayout)
00386
00387 self.grasp_from_chooser = GraspChooser(self._widget, self, "From: ")
00388 self.layout.addWidget(self.grasp_from_chooser)
00389 self.layout.addWidget(subframe)
00390
00391 self.grasp_to_chooser = GraspChooser(self._widget, self, "To: ")
00392 self.layout.addWidget(self.grasp_to_chooser)
00393
00394 self.grasp_slider.draw()
00395 self.grasp_to_chooser.draw()
00396 self.grasp_from_chooser.draw()
00397
00398 time.sleep(0.2)
00399 self.set_reference_grasp()
00400
00401 def shutdown_plugin(self):
00402 self._widget.close()
00403 self._widget.deleteLater()
00404
00405 def save_settings(self, global_settings, perspective_settings):
00406 pass
00407
00408 def restore_settings(self, global_settings, perspective_settings):
00409 pass
00410
00411 def save_grasp(self):
00412 all_joints = self.sr_lib.read_all_current_positions()
00413 GraspSaver(self._widget, all_joints, self)
00414
00415 def set_reference_grasp(self):
00416 """
00417 Set the current grasp as a reference for interpolation
00418 """
00419 self.current_grasp.joints_and_positions = self.sr_lib.read_all_current_positions()
00420
00421 if self.current_grasp.joints_and_positions is None:
00422
00423 self.sr_lib.activate_etherCAT_hand()
00424
00425 rospy.sleep(0.5)
00426 self.current_grasp.joints_and_positions = self.sr_lib.read_all_current_positions()
00427
00428 if self.current_grasp.joints_and_positions is None:
00429 QMessageBox.warning(self._widget, "Warning", "Could not read current grasp.\nCheck that the hand controllers are running.\nThen click \"Set Reference\"")
00430 return
00431
00432 self.grasp_interpoler_1 = GraspInterpoler(self.grasp_from_chooser.grasp, self.current_grasp)
00433 self.grasp_interpoler_2 = GraspInterpoler(self.current_grasp, self.grasp_to_chooser.grasp)
00434
00435 self.grasp_slider.slider.setValue(0)
00436
00437 def grasp_changed(self):
00438 """
00439 interpolate grasps from chosen to current one and from current to chosen
00440 hand controllers must be running and reference must be set
00441 """
00442 self.current_grasp.joints_and_positions = self.sr_lib.read_all_current_positions()
00443
00444 if self.current_grasp.joints_and_positions is None:
00445 QMessageBox.warning(self._widget, "Warning", "Could not read current grasp.\nCheck that the hand controllers are running.\nThen click \"Set Reference\"")
00446 return
00447
00448 self.grasp_interpoler_1 = GraspInterpoler(self.grasp_from_chooser.grasp, self.current_grasp)
00449 self.grasp_interpoler_2 = GraspInterpoler(self.current_grasp, self.grasp_to_chooser.grasp)
00450
00451 def interpolate_grasps(self, value):
00452 """
00453 interpolate grasp from the current one to the one indicated by value
00454 or in the opposite direction if value < 0
00455 hand controllers must be running and reference must be set
00456 """
00457 if self.grasp_interpoler_1 is None \
00458 or self.grasp_interpoler_2 is None:
00459 QMessageBox.warning(self._widget, "Warning", "Could not read current grasp.\nCheck that the hand controllers are running.\nThen click \"Set Reference\"")
00460 return
00461
00462 if value < 0:
00463 targets_to_send = self.grasp_interpoler_1.interpolate(100 + value)
00464 self.sr_lib.sendupdate_from_dict(targets_to_send)
00465 else:
00466 targets_to_send = self.grasp_interpoler_2.interpolate(value)
00467 self.sr_lib.sendupdate_from_dict(targets_to_send)