00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 import os
00020 import rospy
00021
00022 from python_qt_binding import loadUi
00023
00024 from PyQt4 import QtCore, Qt
00025 from QtGui import QFrame
00026 from controller_manager_msgs.srv import ListControllers
00027 from sr_robot_msgs.msg import sendupdate, joint
00028 from std_msgs.msg import Float64
00029 from math import radians, degrees
00030 from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
00031
00032
00033 class JointController():
00034
00035 """
00036 Contains the min and the max and the command and state topics for the joint controller.
00037 """
00038
00039 def __init__(self, name, controller_type, controller_state_type,
00040 controller_category, subscribe_status_cb_list=None,
00041 cmd_publisher=None, traj_target=None):
00042 self.name = name
00043 self.controller_type = controller_type
00044 self.controller_state_type = controller_state_type
00045 self.controller_category = controller_category
00046 self.subscribe_status_cb_list = subscribe_status_cb_list
00047 self.cmd_publisher = cmd_publisher
00048 self.traj_target = traj_target
00049
00050
00051 class Joint():
00052
00053 """
00054 Contains the name, and a controllers list for the joint.
00055 """
00056
00057 def __init__(self, name, min, max, vel, joint_controller):
00058 self.name = name
00059 self.controller = joint_controller
00060
00061
00062
00063 self.min = round(degrees(min), 1)
00064 self.max = round(degrees(max), 1)
00065 self.vel = round(degrees(vel), 1)
00066 if self.controller.controller_category == "velocity":
00067 self.min = -self.vel
00068 self.max = self.vel
00069 elif self.controller.controller_category == "effort":
00070
00071
00072 self.min = -900
00073 self.max = 900
00074
00075
00076 class ExtendedSlider(QFrame):
00077
00078 """
00079 This slider displays the current position and the target as well.
00080 """
00081
00082 def __init__(self, joint, uiFile, plugin_parent, parent=None):
00083 QFrame.__init__(self, parent)
00084 ui_file = os.path.join(
00085 os.path.dirname(os.path.realpath(__file__)), uiFile)
00086 loadUi(ui_file, self)
00087
00088 self.state = None
00089
00090 self.plugin_parent = plugin_parent
00091 self.joint = joint
00092 self.current_controller_index = -1
00093 self.label.setText(joint.name)
00094 self.current_value = 0
00095
00096 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00097 self.slider.setTracking(True)
00098 self.pos_slider_tracking_behaviour = True
00099 self.is_selected = False
00100 self.first_update_done = False
00101
00102 self.current_controller_index = 0
00103 self.slider.setMinimum(joint.min)
00104 self.slider.setMaximum(joint.max)
00105 self.min_label.setText(str(joint.min))
00106 self.max_label.setText(str(joint.max))
00107
00108 self.connect(self.selected, QtCore.SIGNAL(
00109 'stateChanged(int)'), self.checkbox_click)
00110 self.connect(self.slider, QtCore.SIGNAL(
00111 'valueChanged(int)'), self.changeValue)
00112
00113 self.timer = Qt.QTimer(self)
00114 self.connect(self.timer, QtCore.SIGNAL('timeout()'), self.update)
00115 self.timer.start(200)
00116
00117 def changeValue(self, value):
00118 self.target.setText("Tgt: " + str(value))
00119 self.sendupdate(value)
00120
00121 def sendupdate(self, value):
00122 raise NotImplementedError("Virtual method, please implement.")
00123
00124 def update(self):
00125 raise NotImplementedError("Virtual method, please implement.")
00126
00127 def refresh(self):
00128 raise NotImplementedError("Virtual method, please implement.")
00129
00130 def checkbox_click(self, value):
00131 self.is_selected = value
00132
00133 def set_slider_behaviour(self):
00134 raise NotImplementedError("Virtual method, please implement.")
00135
00136 def set_new_slider_behaviour(self, tracking):
00137 if tracking:
00138 self.pos_slider_tracking_behaviour = True
00139 else:
00140 self.pos_slider_tracking_behaviour = False
00141 self.set_slider_behaviour()
00142
00143
00144 class EtherCATHandSlider(ExtendedSlider):
00145
00146 """
00147 Slider for the EtherCAT Hand.
00148 """
00149
00150 def __init__(self, joint, uiFile, plugin_parent, parent=None):
00151 ExtendedSlider.__init__(self, joint, uiFile, plugin_parent, parent)
00152
00153 self.initialize_controller()
00154
00155 def initialize_controller(self):
00156 self.slider.setMinimum(self.joint.min)
00157 self.slider.setMaximum(self.joint.max)
00158 self.min_label.setText(str(self.joint.min))
00159 self.max_label.setText(str(self.joint.max))
00160
00161 self.pub = rospy.Publisher(
00162 self.joint.controller.name + "/command",
00163 Float64,
00164 queue_size=1,
00165 latch=True
00166 )
00167 self.set_slider_behaviour()
00168 self.state_sub = rospy.Subscriber(
00169 self.joint.controller.name + "/state", self.joint.controller.controller_state_type, self._state_cb)
00170
00171 def _state_cb(self, msg):
00172 self.state = msg
00173
00174 def sendupdate(self, value):
00175 if (self.joint.controller.controller_category == "position")\
00176 or (self.joint.controller.controller_category == "velocity"):
00177 self.pub.publish(radians(float(value)))
00178 else:
00179 self.pub.publish(float(value))
00180
00181 def update(self):
00182 try:
00183 if (self.joint.controller.controller_category == "position")\
00184 or (self.joint.controller.controller_category == "velocity"):
00185 self.current_value = round(
00186 degrees(self.state.process_value), 1)
00187 elif (self.joint.controller.controller_category == "effort"):
00188 self.current_value = round(self.state.process_value, 1)
00189 self.value.setText("Val: " + str(self.current_value))
00190
00191 if not self.first_update_done:
00192 if (self.joint.controller.controller_category == "position"):
00193 self.slider.setSliderPosition(self.current_value)
00194 self.slider.setValue(self.current_value)
00195 self.target.setText("Tgt: " + str(self.current_value))
00196 else:
00197 self.target.setText("Tgt: 0.0")
00198 self.first_update_done = True
00199 except:
00200 pass
00201
00202 def refresh(self):
00203 """
00204 Refresh the current position of the slider with index = self.current_controller_index
00205 """
00206 if (self.joint.controller.controller_category == "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
00211 def set_slider_behaviour(self):
00212 """
00213 Set the behaviour of the slider according to controller type
00214 """
00215 if (self.joint.controller.controller_category == "position"):
00216 if self.pos_slider_tracking_behaviour:
00217 self.slider.setTracking(True)
00218 else:
00219 self.slider.setTracking(False)
00220 elif (self.joint.controller.controller_category == "velocity"):
00221 self.slider.setTracking(True)
00222 self.connect(self.slider, QtCore.SIGNAL(
00223 'sliderReleased()'), self.on_slider_released)
00224 elif (self.joint.controller.controller_category == "effort"):
00225 self.slider.setTracking(True)
00226 self.connect(self.slider, QtCore.SIGNAL(
00227 'sliderReleased()'), self.on_slider_released)
00228
00229 def on_slider_released(self):
00230 if (self.joint.controller.controller_category == "effort")\
00231 or (self.joint.controller.controller_category == "velocity"):
00232 self.slider.setSliderPosition(0)
00233 self.changeValue(0)
00234
00235
00236 class EtherCATHandTrajectorySlider(ExtendedSlider):
00237
00238 """
00239 Slider for one EtherCAT Hand joint, that uses the trajectory controller interface.
00240 """
00241
00242 def __init__(self, joint, uiFile, plugin_parent, parent=None):
00243 ExtendedSlider.__init__(self, joint, uiFile, plugin_parent, parent)
00244
00245 self.initialize_controller()
00246
00247 def initialize_controller(self):
00248 self.slider.setMinimum(self.joint.min)
00249 self.slider.setMaximum(self.joint.max)
00250 self.min_label.setText(str(self.joint.min))
00251 self.max_label.setText(str(self.joint.max))
00252
00253 self.pub = self.joint.controller.cmd_publisher
00254 self.set_slider_behaviour()
00255
00256 self.joint.controller.subscribe_status_cb_list.append(self._state_cb)
00257
00258 def _state_cb(self, msg):
00259 self.state = msg.actual.positions[
00260 msg.joint_names.index(self.joint.name)]
00261
00262 def sendupdate(self, value):
00263 if self.joint.controller.traj_target.joint_names \
00264 and self.joint.controller.traj_target.points:
00265 self.joint.controller.traj_target.points[0].positions[
00266 self.joint.controller.traj_target.joint_names.index(self.joint.name)] = radians(float(value))
00267 self.pub.publish(self.joint.controller.traj_target)
00268
00269 def update(self):
00270 try:
00271 self.current_value = round(degrees(self.state), 1)
00272 self.value.setText("Val: " + str(self.current_value))
00273
00274 if not self.first_update_done:
00275 self.slider.setSliderPosition(self.current_value)
00276 self.slider.setValue(self.current_value)
00277 self.target.setText("Tgt: " + str(self.current_value))
00278
00279 self.first_update_done = True
00280 except:
00281 pass
00282
00283 def refresh(self):
00284 """
00285 Refresh the current position of the slider with index = self.current_controller_index
00286 """
00287 self.slider.setSliderPosition(self.current_value)
00288 self.slider.setValue(self.current_value)
00289 self.target.setText("Tgt: " + str(self.current_value))
00290
00291 def set_slider_behaviour(self):
00292 """
00293 Set the behaviour of the slider according to controller type
00294 """
00295 if (self.joint.controller.controller_category == "position_trajectory"):
00296 if self.pos_slider_tracking_behaviour:
00297 self.slider.setTracking(True)
00298 else:
00299 self.slider.setTracking(False)
00300
00301 def on_slider_released(self):
00302 pass
00303
00304
00305 class SelectionSlider(QFrame):
00306
00307 """
00308 This slider allows the user to move the selected sliders.
00309 """
00310
00311 def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00312 QFrame.__init__(self, parent)
00313 ui_file = os.path.join(
00314 os.path.dirname(os.path.realpath(__file__)), uiFile)
00315 loadUi(ui_file, self)
00316
00317 self.plugin_parent = plugin_parent
00318 self.label.setText(name)
00319
00320 self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00321 self.slider.setTracking(False)
00322 self.is_selected = False
00323
00324 self.slider.setMinimum(min)
00325 self.slider.setMaximum(max)
00326 self.min_label.setText(str(min))
00327 self.max_label.setText(str(max))
00328
00329 self.connect(self.slider, QtCore.SIGNAL(
00330 'valueChanged(int)'), self.changeValue)
00331
00332 self.connect(self.selected, QtCore.SIGNAL(
00333 'stateChanged(int)'), self.checkbox_click)
00334
00335 def changeValue(self, value):
00336 raise NotImplementedError("Virtual method, please implement.")
00337
00338 def checkbox_click(self, value):
00339 self.is_selected = value
00340 for slider in self.plugin_parent.sliders:
00341 if slider.is_selected != value:
00342 slider.is_selected = value
00343 slider.selected.setChecked(value)
00344
00345
00346 class EtherCATSelectionSlider(SelectionSlider):
00347
00348 """
00349 This slider allows the user to move the selected sliders for an etherCAT hand.
00350 """
00351
00352 def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00353 SelectionSlider.__init__(
00354 self, name, min, max, uiFile, plugin_parent, parent)
00355 self.set_slider_behaviour()
00356
00357 def set_slider_behaviour(self):
00358 """
00359 Set the behaviour of the slider according to controller type
00360 Currently we set the tracking to true for all the slide types
00361 If any of the controllers is an effort or velocity controller
00362 we will activate the slider released signal detection
00363 And set the slider halfway (50) as that is the position of the 0
00364 for effort and velocity controllers
00365 """
00366 self.slider.setTracking(True)
00367 for slider in self.plugin_parent.sliders:
00368 if (slider.joint.controller.controller_category == "effort")\
00369 or (slider.joint.controller.controller_category == "velocity"):
00370 self.connect(self.slider, QtCore.SIGNAL(
00371 'sliderReleased()'), self.on_slider_released)
00372 self.slider.setSliderPosition(50)
00373 self.current_value = 50
00374 self.target.setText("Tgt: " + str(50) + "%")
00375 break
00376
00377 def changeValue(self, value):
00378 """
00379 modify the values from the selected sliders.
00380 """
00381 for slider in self.plugin_parent.sliders:
00382 if slider.is_selected:
00383 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(
00384 value) / 100.0) + slider.slider.minimum()
00385 slider.slider.setSliderPosition(temp_value)
00386 slider.changeValue(temp_value)
00387
00388 self.current_value = value
00389 self.target.setText("Tgt: " + str(value) + "%")
00390
00391 def on_slider_released(self):
00392 for slider in self.plugin_parent.sliders:
00393 if slider.is_selected:
00394 if (slider.joint.controller.controller_category == "effort")\
00395 or (slider.joint.controller.controller_category == "velocity"):
00396 slider.slider.setSliderPosition(0)
00397 slider.changeValue(0)
00398 self.slider.setSliderPosition(50)
00399 self.current_value = 50
00400 self.target.setText("Tgt: " + str(50) + "%")