grasp_controller.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # Copyright 2011 Shadow Robot Company Ltd.
00003 #
00004 # This program is free software: you can redistribute it and/or modify it
00005 # under the terms of the GNU General Public License as published by the Free
00006 # Software Foundation, either version 2 of the License, or (at your option)
00007 # any later version.
00008 #
00009 # This program is distributed in the hope that it will be useful, but WITHOUT
00010 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00011 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00012 # more details.
00013 #
00014 # You should have received a copy of the GNU General Public License along
00015 # with this program.  If not, see <http://www.gnu.org/licenses/>.
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         # vectors to set the correct row in the layout for each col
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         # SIGNALS
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         # from -> current
00629         targets_to_send = dict()
00630         if value < 0:
00631             targets_to_send = self.grasp_interpoler_1.interpolate(100 + value)
00632         else:  # current -> to
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_()


sr_gui_grasp_controller
Author(s): Ugo Cupcic
autogenerated on Thu Jun 6 2019 21:13:54