00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 import os
00020
00021 import roslib
00022 roslib.load_manifest('sr_gui_joint_slider')
00023 import rospy
00024
00025 from qt_gui.plugin import Plugin
00026 from python_qt_binding import loadUi
00027
00028
00029 from xml.etree import ElementTree as ET
00030
00031 from PyQt4 import QtCore, QtGui, Qt
00032 from QtGui import QShortcut, QMessageBox, QFrame
00033 from pr2_mechanism_msgs.srv import ListControllers, SwitchController, LoadController
00034 from sr_robot_msgs.msg import sendupdate, joint
00035 from std_msgs.msg import Float64
00036 from math import radians, degrees
00037
00038 class JointController():
00039 """
00040 Contains the min and the max and the command and state topics for the joint controller.
00041 """
00042 def __init__(self, name, command_topic, msg_type, min=0, max=90):
00043 self.name = name
00044 self.command_topic = command_topic
00045 self.msg_type = msg_type
00046 self.min = min
00047 self.max = max
00048
00049 class Joint():
00050 """
00051 Contains the name, and a controllers list for the joint.
00052 """
00053 def __init__(self, name="", joint_controller_list=None):
00054 self.name = name
00055 self.controller_list = joint_controller_list
00056
00057 class ExtendedSlider(QFrame):
00058 """
00059 This slider displays the current position and the target as well.
00060 """
00061 def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00062 QFrame.__init__(self, parent)
00063 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), uiFile)
00064 loadUi(ui_file, self)
00065
00066 self.robot_lib = robot_lib
00067
00068 self.plugin_parent = plugin_parent
00069 self.joint = joint
00070 self.current_controller_index = -1
00071 self.label.setText(joint.name)
00072 self.current_value = 0
00073
00074 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00075 self.slider.setTracking(True)
00076 self.pos_slider_tracking_behaviour = True
00077 self.is_selected = False
00078 self.first_update_done = False
00079
00080 if len(self.joint.controller_list) > 1:
00081 self.slider.setMinimum(0)
00082 self.slider.setMaximum(10)
00083 self.min_label.setText("Unknown")
00084 self.max_label.setText("Unknown")
00085 elif len(self.joint.controller_list) == 1:
00086 self.current_controller_index = 0
00087 self.slider.setMinimum(joint.controller_list[self.current_controller_index].min)
00088 self.slider.setMaximum(joint.controller_list[self.current_controller_index].max)
00089 self.min_label.setText(str(joint.controller_list[self.current_controller_index].min))
00090 self.max_label.setText(str(joint.controller_list[self.current_controller_index].max))
00091 else:
00092 rospy.logwarn("No controllers defined for this joint")
00093
00094 self.connect(self.selected, QtCore.SIGNAL('stateChanged(int)'), self.checkbox_click)
00095 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
00096
00097 self.timer = Qt.QTimer(self)
00098 self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.update)
00099 self.timer.start(200)
00100
00101 def changeValue(self, value):
00102 self.target.setText("Tgt: " + str(value))
00103 self.sendupdate(value)
00104
00105 def sendupdate(self, value):
00106 raise NotImplementedError, "Virtual method, please implement."
00107
00108 def update(self):
00109 raise NotImplementedError, "Virtual method, please implement."
00110
00111 def refresh(self):
00112 raise NotImplementedError, "Virtual method, please implement."
00113
00114 def checkbox_click(self, value):
00115 self.is_selected = value
00116
00117 def set_slider_behaviour(self):
00118 raise NotImplementedError, "Virtual method, please implement."
00119
00120 def set_new_slider_behaviour(self, tracking):
00121 if tracking:
00122 self.pos_slider_tracking_behaviour = True
00123 else:
00124 self.pos_slider_tracking_behaviour = False
00125 self.set_slider_behaviour()
00126
00127
00128 class EtherCATHandSlider(ExtendedSlider):
00129 """
00130 Slider for the EtherCAT Hand.
00131 """
00132 def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00133 ExtendedSlider.__init__(self, joint, uiFile, robot_lib, plugin_parent, parent)
00134
00135 self.initialize_controller()
00136
00137 def initialize_controller(self):
00138 self.current_controller_index = self.get_current_joint_controller(self.get_current_controllers())
00139
00140 if (self.current_controller_index == -1):
00141 raise Exception("No controller found for joint: " + self.joint.name)
00142 else:
00143 self.slider.setMinimum(self.joint.controller_list[self.current_controller_index].min)
00144 self.slider.setMaximum(self.joint.controller_list[self.current_controller_index].max)
00145 self.min_label.setText(str(self.joint.controller_list[self.current_controller_index].min))
00146 self.max_label.setText(str(self.joint.controller_list[self.current_controller_index].max))
00147
00148 self.pub = rospy.Publisher(self.joint.controller_list[self.current_controller_index].command_topic, Float64, latch=True)
00149 self.set_slider_behaviour()
00150
00151 def get_current_joint_controller(self, current_controllers):
00152 """
00153 @return: index of the current controller or -1 on failure
00154 """
00155 for index, joint_controller in enumerate(self.joint.controller_list):
00156 for controller in current_controllers:
00157 if (controller.find(self.joint.name.lower() + '_' + joint_controller.name) != -1):
00158 return index
00159 return -1
00160
00161 def get_current_controllers(self):
00162 """
00163 @return: list of current controllers
00164 """
00165 success = True
00166 list_controllers = rospy.ServiceProxy('pr2_controller_manager/list_controllers', ListControllers)
00167 try:
00168 resp1 = list_controllers()
00169 except rospy.ServiceException:
00170 success = False
00171
00172 current_controllers = []
00173
00174 if success:
00175 all_loaded_controllers = resp1.controllers
00176 for state,tmp_contrl in zip(resp1.state,resp1.controllers):
00177 if state == "running":
00178 current_controllers.append(tmp_contrl)
00179 else:
00180 rospy.loginfo("Couldn't get list of controllers from pr2_controller_manager/list_controllers service")
00181
00182 return current_controllers
00183
00184 def sendupdate(self, value):
00185 if (self.current_controller_index == -1):
00186 self.initialize_controller()
00187
00188 if (self.current_controller_index != -1):
00189 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position") or (self.joint.controller_list[self.current_controller_index].name == "muscle_position"):
00190 self.pub.publish(radians(float(value)))
00191 elif self.joint.controller_list[self.current_controller_index].name == "velocity":
00192 self.pub.publish(float(value) / 100.0)
00193 else:
00194 self.pub.publish(float(value))
00195
00196 def update(self):
00197 try:
00198 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position") or (self.joint.controller_list[self.current_controller_index].name == "muscle_position"):
00199 self.current_value = round(degrees(self.robot_lib.get_position(self.joint.name)),1)
00200 elif (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00201 self.current_value = round(self.robot_lib.get_velocity(self.joint.name),1)
00202 elif (self.joint.controller_list[self.current_controller_index].name == "effort"):
00203 self.current_value = round(self.robot_lib.get_effort(self.joint.name),1)
00204 self.value.setText("Val: " + str(self.current_value))
00205 if self.first_update_done == False:
00206 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position") or (self.joint.controller_list[self.current_controller_index].name == "muscle_position"):
00207 self.slider.setSliderPosition(self.current_value)
00208 self.slider.setValue(self.current_value)
00209 self.target.setText("Tgt: " + str(self.current_value))
00210 else:
00211 self.target.setText("Tgt: 0.0")
00212 self.first_update_done = True
00213 except:
00214 pass
00215
00216 def refresh(self):
00217 """
00218 Refresh the current position of the slider with index = self.current_controller_index
00219 """
00220 if (self.current_controller_index != -1):
00221 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position") or (self.joint.controller_list[self.current_controller_index].name == "muscle_position"):
00222 self.slider.setSliderPosition(self.current_value)
00223 self.slider.setValue(self.current_value)
00224 self.target.setText("Tgt: " + str(self.current_value))
00225
00226 def set_slider_behaviour(self):
00227 """
00228 Set the behaviour of the slider according to controller type
00229 """
00230 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position") or (self.joint.controller_list[self.current_controller_index].name == "muscle_position"):
00231 if self.pos_slider_tracking_behaviour:
00232 self.slider.setTracking(True)
00233 else:
00234 self.slider.setTracking(False)
00235 elif (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00236 self.slider.setTracking(True)
00237 self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00238 elif (self.joint.controller_list[self.current_controller_index].name == "effort"):
00239 self.slider.setTracking(True)
00240 self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00241
00242 def on_slider_released(self):
00243 if (self.joint.controller_list[self.current_controller_index].name == "effort") or (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00244 self.slider.setSliderPosition(0)
00245 self.changeValue(0)
00246
00247
00248 class CANHandSlider(ExtendedSlider):
00249 """
00250 Slider for the CAN Hand.
00251 """
00252 def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00253 ExtendedSlider.__init__(self, joint, uiFile, robot_lib, plugin_parent, parent)
00254 self.set_slider_behaviour()
00255 self.pub = rospy.Publisher(self.joint.controller_list[self.current_controller_index].command_topic, sendupdate, latch=True)
00256
00257 def sendupdate(self, value):
00258 message=[]
00259 message.append(joint(joint_name=self.joint.name, joint_target=value))
00260 self.pub.publish(sendupdate(len(message), message))
00261
00262 def update(self):
00263 try:
00264 self.current_value = round(self.robot_lib.valueof(self.joint.name),1)
00265 self.value.setText("Val: " + str(self.current_value))
00266 if self.first_update_done == False:
00267 self.slider.setSliderPosition(self.current_value)
00268 self.slider.setValue(self.current_value)
00269 self.target.setText("Tgt: " + str(self.current_value))
00270 self.first_update_done = True
00271 except:
00272 pass
00273
00274 def refresh(self):
00275 """
00276 Refresh the current position of the slider
00277 """
00278 self.slider.setSliderPosition(self.current_value)
00279 self.slider.setValue(self.current_value)
00280 self.target.setText("Tgt: " + str(self.current_value))
00281
00282 def set_slider_behaviour(self):
00283 if self.pos_slider_tracking_behaviour:
00284 self.slider.setTracking(True)
00285 else:
00286 self.slider.setTracking(False)
00287
00288
00289 class ArmSlider(ExtendedSlider):
00290 """
00291 Slider for the CAN Arm.
00292 """
00293 def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00294 ExtendedSlider.__init__(self, joint, uiFile, robot_lib, plugin_parent, parent)
00295 self.set_slider_behaviour()
00296 self.pub = rospy.Publisher(self.joint.controller_list[self.current_controller_index].command_topic, sendupdate, latch=True)
00297
00298 def sendupdate(self, value):
00299 message=[]
00300 message.append(joint(joint_name=self.joint.name, joint_target=value))
00301 self.pub.publish(sendupdate(len(message), message))
00302
00303 def update(self):
00304 try:
00305 self.current_value = round(self.robot_lib.valueof(self.joint.name),1)
00306 self.value.setText("Val: " + str(self.current_value))
00307 if self.first_update_done == False:
00308 self.slider.setSliderPosition(self.current_value)
00309 self.slider.setValue(self.current_value)
00310 self.target.setText("Tgt: " + str(self.current_value))
00311 self.first_update_done = True
00312 except:
00313 pass
00314
00315 def refresh(self):
00316 """
00317 Refresh the current position of the slider
00318 """
00319 self.slider.setSliderPosition(self.current_value)
00320 self.slider.setValue(self.current_value)
00321 self.target.setText("Tgt: " + str(self.current_value))
00322
00323 def set_slider_behaviour(self):
00324 if self.pos_slider_tracking_behaviour:
00325 self.slider.setTracking(True)
00326 else:
00327 self.slider.setTracking(False)
00328
00329 class SelectionSlider(QFrame):
00330 """
00331 This slider allows the user to move the selected sliders.
00332 """
00333 def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00334 QFrame.__init__(self, parent)
00335 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), uiFile)
00336 loadUi(ui_file, self)
00337
00338 self.plugin_parent = plugin_parent
00339 self.label.setText(name)
00340
00341 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00342 self.slider.setTracking(False)
00343 self.is_selected = False
00344
00345 self.slider.setMinimum(min)
00346 self.slider.setMaximum(max)
00347 self.min_label.setText(str(min))
00348 self.max_label.setText(str(max))
00349
00350 self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
00351
00352 self.connect(self.selected, QtCore.SIGNAL('stateChanged(int)'), self.checkbox_click)
00353
00354 def changeValue(self, value):
00355 raise NotImplementedError, "Virtual method, please implement."
00356
00357 def checkbox_click(self, value):
00358 self.is_selected = value
00359 for slider in self.plugin_parent.sliders:
00360 if slider.is_selected != value:
00361 slider.is_selected = value
00362 slider.selected.setChecked(value)
00363
00364 class EtherCATSelectionSlider(SelectionSlider):
00365 """
00366 This slider allows the user to move the selected sliders for an etherCAT hand.
00367 """
00368 def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00369 SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00370 self.set_slider_behaviour()
00371
00372 def set_slider_behaviour(self):
00373 """
00374 Set the behaviour of the slider according to controller type
00375 Currently we set the tracking to true for all the slide types
00376 If any of the controllers is an effort or velocity controller we will activate the slider released signal detection
00377 And set the slider halfway (50) as that is the position of the 0 for effort and velocity controllers
00378 """
00379 self.slider.setTracking(True)
00380 for slider in self.plugin_parent.sliders:
00381 if (slider.joint.controller_list[slider.current_controller_index].name == "effort") or (slider.joint.controller_list[slider.current_controller_index].name == "velocity"):
00382 self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00383 self.slider.setSliderPosition(50)
00384 self.current_value = 50
00385 self.target.setText("Tgt: " + str(50) + "%")
00386 break
00387
00388 def changeValue(self, value):
00389 """
00390 modify the values from the selected sliders.
00391 """
00392 for slider in self.plugin_parent.sliders:
00393 if slider.is_selected:
00394 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00395 slider.slider.setSliderPosition(temp_value)
00396 slider.changeValue(temp_value)
00397
00398 self.current_value = value
00399 self.target.setText("Tgt: " + str(value) + "%")
00400
00401 def on_slider_released(self):
00402 for slider in self.plugin_parent.sliders:
00403 if slider.is_selected:
00404 if (slider.joint.controller_list[slider.current_controller_index].name == "effort") or (slider.joint.controller_list[slider.current_controller_index].name == "velocity"):
00405 slider.slider.setSliderPosition(0)
00406 slider.changeValue(0)
00407 self.slider.setSliderPosition(50)
00408 self.current_value = 50
00409 self.target.setText("Tgt: " + str(50) + "%")
00410
00411 class CANHandSelectionSlider(SelectionSlider):
00412 """
00413 This slider allows the user to move the selected sliders for a ShadowArm.
00414 """
00415 def __init__(self, name, min, max, uiFile, robot_lib, plugin_parent, parent=None):
00416 SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00417 self.robot_lib = robot_lib
00418 self.slider.setTracking(True)
00419
00420 def changeValue(self, value):
00421 """
00422 modify the values from the selected sliders.
00423 """
00424 joint_dict = {}
00425 for slider in self.plugin_parent.sliders:
00426 if slider.is_selected:
00427 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00428 slider.slider.setSliderPosition(temp_value)
00429 slider.target.setText("Tgt: " + str(temp_value))
00430 joint_dict[slider.joint.name] = temp_value
00431
00432 self.robot_lib.sendupdate_from_dict(joint_dict)
00433 self.current_value = value
00434 self.target.setText("Tgt: " + str(value) + "%")
00435
00436 class ArmSelectionSlider(SelectionSlider):
00437 """
00438 This slider allows the user to move the selected sliders for a ShadowArm.
00439 """
00440 def __init__(self, name, min, max, uiFile, robot_lib, plugin_parent, parent=None):
00441 SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00442 self.robot_lib = robot_lib
00443 self.slider.setTracking(True)
00444
00445 def changeValue(self, value):
00446 """
00447 modify the values from the selected sliders.
00448 """
00449 joint_dict = {}
00450 for slider in self.plugin_parent.sliders:
00451 if slider.is_selected:
00452 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00453 slider.slider.setSliderPosition(temp_value)
00454 slider.target.setText("Tgt: " + str(temp_value))
00455 joint_dict[slider.joint.name] = temp_value
00456
00457 self.robot_lib.sendupdate_arm_from_dict(joint_dict)
00458 self.current_value = value
00459 self.target.setText("Tgt: " + str(value) + "%")