00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 import os
00020 import rospkg
00021 import rospy
00022 import math
00023
00024 from xml.etree import ElementTree as ET
00025
00026 from qt_gui.plugin import Plugin
00027 from python_qt_binding import loadUi
00028
00029 from QtCore import Qt
00030 from QtGui import QWidget, QMessageBox
00031
00032 from controller_manager_msgs.srv import ListControllers
00033 from control_msgs.msg import JointControllerState
00034 from sr_robot_msgs.msg import JointControllerState as SrJointControllerState
00035 from sr_robot_msgs.msg import JointMusclePositionControllerState
00036 from control_msgs.msg import JointTrajectoryControllerState
00037 from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
00038
00039 from sr_gui_joint_slider.sliders import JointController, Joint, EtherCATHandSlider
00040 from sr_gui_joint_slider.sliders import EtherCATHandTrajectorySlider, EtherCATSelectionSlider
00041
00042
00043 class SrGuiJointSlider(Plugin):
00044
00045 """
00046 A rosgui plugin to change the position of the different joints
00047 """
00048
00049
00050
00051
00052 controller_state_types = {
00053 "sr_mechanism_controllers/SrhJointPositionController": ("position", JointControllerState),
00054 "sr_mechanism_controllers/SrhEffortJointController": ("effort", JointControllerState),
00055 "sr_mechanism_controllers/SrhJointVelocityController": ("velocity", JointControllerState),
00056 "sr_mechanism_controllers/SrhMixedPositionVelocityJointController": ("position", SrJointControllerState),
00057 "sr_mechanism_controllers/SrhMuscleJointPositionController": ("position", JointMusclePositionControllerState),
00058 "position_controllers/JointTrajectoryController": ("position_trajectory", JointTrajectoryControllerState),
00059 "effort_controllers/JointTrajectoryController": ("position_trajectory", JointTrajectoryControllerState)}
00060
00061 def __init__(self, context):
00062 super(SrGuiJointSlider, self).__init__(context)
00063 self.setObjectName('SrGuiJointSlider')
00064
00065 self._robot_description_xml_root = None
00066
00067 self._widget = QWidget()
00068
00069 ui_file = os.path.join(rospkg.RosPack().get_path(
00070 'sr_gui_joint_slider'), 'uis', 'SrJointSlider.ui')
00071 loadUi(ui_file, self._widget)
00072
00073 self._widget.setObjectName('SrJointSliderUi')
00074 context.add_widget(self._widget)
00075
00076 self.joints = []
00077
00078 self.sliders = []
00079 self.selection_slider = None
00080
00081
00082 self.trajectory_state_sub = []
00083
00084 self.trajectory_state_slider_cb = []
00085 self.trajectory_pub = []
00086 self.trajectory_target = []
00087
00088 self._widget.reloadButton.pressed.connect(
00089 self.on_reload_button_cicked_)
00090 self._widget.refreshButton.pressed.connect(
00091 self.on_refresh_button_cicked_)
00092 self._widget.sliderReleaseCheckBox.stateChanged.connect(
00093 self.on_slider_release_checkbox_clicked_)
00094
00095 self._widget.reloadButton.setEnabled(True)
00096 self.on_reload_button_cicked_()
00097
00098 def _unregister(self):
00099 pass
00100
00101 def shutdown_plugin(self):
00102 self._unregister()
00103
00104 def save_settings(self, global_settings, perspective_settings):
00105 pass
00106
00107 def restore_settings(self, global_settings, perspective_settings):
00108 pass
00109
00110 def on_robot_type_changed_(self):
00111 pass
00112
00113 def on_reload_button_cicked_(self):
00114 """
00115 Clear existing slider widgets from layout
00116 Load the correct robot library
00117 Create and load the new slider widgets
00118 """
00119
00120 self._load_robot_description()
00121 controllers = self.get_current_controllers()
00122
00123 self.joints = self._create_joints(controllers)
00124
00125 self.delete_old_sliders_()
00126
00127 self._widget.sliderReleaseCheckBox.setCheckState(Qt.Unchecked)
00128
00129 self.load_new_sliders_()
00130
00131 def on_refresh_button_cicked_(self):
00132 """
00133 Call refresh for every slider
00134 """
00135 for slider in self.sliders:
00136 slider.refresh()
00137
00138 def on_slider_release_checkbox_clicked_(self, state):
00139 """
00140 Set tracking behaviour of each slider to false if checkbox is checked, true otherwise
00141 """
00142
00143 if state == Qt.Checked:
00144 for slider in self.sliders:
00145 slider.set_new_slider_behaviour(False)
00146 else:
00147 for slider in self.sliders:
00148 slider.set_new_slider_behaviour(True)
00149
00150 def delete_old_sliders_(self):
00151 """
00152 Clear existing slider widgets from layout
00153 Empty the slider list
00154 """
00155 for old_slider in self.sliders:
00156 self._widget.horizontalLayout.removeWidget(old_slider)
00157 old_slider.close()
00158 old_slider.deleteLater()
00159
00160 self.sliders = []
00161
00162 if(self.selection_slider is not None):
00163 self._widget.horizontalLayout.removeWidget(self.selection_slider)
00164 self.selection_slider.close()
00165 self.selection_slider.deleteLater()
00166 self.selection_slider = None
00167
00168 def load_new_sliders_(self):
00169 """
00170 Create the new slider widgets
00171 Load the new slider
00172 Put the slider in the list
00173 """
00174 self.sliders = list()
00175 for joint in self.joints:
00176 slider = None
00177 slider_ui_file = os.path.join(
00178 rospkg.RosPack().get_path('sr_gui_joint_slider'), 'uis', 'Slider.ui')
00179
00180 try:
00181 if joint.controller.controller_category == "position_trajectory":
00182 slider = EtherCATHandTrajectorySlider(
00183 joint, slider_ui_file, self, self._widget.scrollAreaWidgetContents)
00184 else:
00185 slider = EtherCATHandSlider(
00186 joint, slider_ui_file, self, self._widget.scrollAreaWidgetContents)
00187 except Exception, e:
00188 rospy.loginfo(e)
00189
00190 if slider is not None:
00191 slider.setMaximumWidth(100)
00192
00193 self._widget.horizontalLayout.addWidget(slider)
00194
00195 self.sliders.append(slider)
00196
00197
00198 selection_slider_ui_file = os.path.join(
00199 rospkg.RosPack().get_path('sr_gui_joint_slider'), 'uis', 'SelectionSlider.ui')
00200 self.selection_slider = EtherCATSelectionSlider(
00201 "Change sel.", 0, 100, selection_slider_ui_file, self, self._widget.scrollAreaWidgetContents)
00202
00203 self.selection_slider.setMaximumWidth(100)
00204 self._widget.horizontalLayout.addWidget(self.selection_slider)
00205
00206 def get_current_controllers(self):
00207 """
00208 @return: list of current controllers with associated data
00209 """
00210 success = True
00211 list_controllers = rospy.ServiceProxy(
00212 'controller_manager/list_controllers', ListControllers)
00213 try:
00214 resp1 = list_controllers()
00215 except rospy.ServiceException:
00216 success = False
00217
00218 if success:
00219 return [c for c in resp1.controller if c.state == "running"]
00220 else:
00221 rospy.loginfo(
00222 "Couldn't get list of controllers from controller_manager/list_controllers service")
00223 return []
00224
00225 def _load_robot_description(self):
00226 """
00227 Load the description from the param named in the edit as an ET element.
00228 Sets self._robot_description_xml_root to the element.
00229 """
00230 name = self._widget.robot_description_edit.text()
00231 self._robot_description_xml_root = None
00232 try:
00233 xml = rospy.get_param(name)
00234 self._robot_description_xml_root = ET.fromstring(xml)
00235 except KeyError as e:
00236 rospy.logerr(
00237 "Failed to get robot description from param %s : %s" % (name, e))
00238 return
00239 except:
00240 raise
00241
00242 def _get_joint_min_max_vel(self, jname):
00243 """Get the min and max from the robot description for a given joint."""
00244 root = self._robot_description_xml_root
00245 if root is not None:
00246 joint_type = root.findall(".joint[@name='" + jname + "']")[0].attrib['type']
00247 if joint_type == "continuous":
00248 limit = root.findall(".//joint[@name='" + jname + "']/limit")
00249 if limit is None or len(limit) == 0:
00250 return (-math.pi,
00251 math.pi,
00252 3.0)
00253 else:
00254 return (-math.pi,
00255 math.pi,
00256 float(limit[0].attrib['velocity']))
00257 else:
00258 limit = root.findall(".//joint[@name='" + jname + "']/limit")
00259 if limit is None or len(limit) == 0:
00260
00261
00262 limit = root.findall(
00263 ".//joint[@name='" + jname.upper() + "']/limit")
00264 if limit is not None and len(limit) > 0:
00265 return (float(limit[0].attrib['lower']),
00266 float(limit[0].attrib['upper']),
00267 float(limit[0].attrib['velocity']))
00268 else:
00269 rospy.logerr("Limit not found for joint %s", jname)
00270 else:
00271 rospy.logerr("robot_description_xml_root == None")
00272 return (None, None, None)
00273
00274 def _get_joint_min_max_vel_special(self, jname):
00275 if "J0" in jname:
00276 jname1 = jname.replace("J0", "J1")
00277 jname2 = jname.replace("J0", "J2")
00278 min1, max1, vel1 = self._get_joint_min_max_vel(jname1)
00279 min2, max2, vel2 = self._get_joint_min_max_vel(jname2)
00280 return (min1 + min2, max1 + max2, vel1 + vel2)
00281 else:
00282 return self._get_joint_min_max_vel(jname)
00283
00284 def _create_joints(self, controllers):
00285 joints = []
00286 trajectory_ctrl_joint_names = []
00287 self.trajectory_target = []
00288 self.trajectory_state_sub = []
00289
00290 self.trajectory_state_slider_cb = []
00291 self.trajectory_pub = []
00292
00293 for controller in controllers:
00294 if controller.type == "position_controllers/JointTrajectoryController":
00295 for j_name in controller.resources:
00296 trajectory_ctrl_joint_names.append(j_name)
00297
00298 for controller in controllers:
00299 if rospy.has_param(controller.name):
00300 ctrl_params = rospy.get_param(controller.name)
00301 controller_type = ctrl_params["type"]
00302 if controller_type in self.controller_state_types:
00303 controller_state_type = self.controller_state_types[
00304 controller_type][1]
00305 controller_category = self.controller_state_types[
00306 controller_type][0]
00307
00308 if controller_category == "position_trajectory":
00309
00310 self.trajectory_target.append(JointTrajectory())
00311 self.trajectory_state_sub.append(
00312 rospy.Subscriber(controller.name + "/state", controller_state_type,
00313 self._trajectory_state_cb,
00314 callback_args=len(self.trajectory_state_sub)))
00315
00316 self.trajectory_state_slider_cb.append([])
00317 self.trajectory_pub.append(
00318 rospy.Publisher(controller.name + "/command", JointTrajectory, queue_size=1, latch=True))
00319 for j_name in controller.resources:
00320 joint_controller = JointController(
00321 controller.name, controller_type, controller_state_type, controller_category,
00322 self.trajectory_state_slider_cb[
00323 len(self.trajectory_state_slider_cb) - 1],
00324 self.trajectory_pub[
00325 len(self.trajectory_pub) - 1],
00326 self.trajectory_target[len(self.trajectory_target) - 1])
00327 rospy.loginfo(
00328 "controller category: %s", controller_category)
00329
00330 if self._widget.joint_name_filter_edit.text() not in j_name:
00331 continue
00332
00333 min, max, vel = self._get_joint_min_max_vel_special(
00334 j_name)
00335 joint = Joint(
00336 j_name, min, max, vel, joint_controller)
00337 joints.append(joint)
00338 else:
00339 joint_name = ctrl_params["joint"]
00340 if joint_name in trajectory_ctrl_joint_names:
00341
00342 continue
00343
00344 if "J0" in joint_name:
00345 jname1 = joint_name.replace("J0", "J1")
00346 jname2 = joint_name.replace("J0", "J2")
00347 if jname1 in trajectory_ctrl_joint_names \
00348 and jname2 in trajectory_ctrl_joint_names:
00349 continue
00350
00351 joint_controller = JointController(
00352 controller.name, controller_type, controller_state_type, controller_category)
00353 rospy.loginfo(
00354 "controller category: %s", controller_category)
00355
00356 if self._widget.joint_name_filter_edit.text() not in joint_name:
00357 continue
00358
00359 min, max, vel = self._get_joint_min_max_vel_special(
00360 joint_name)
00361 joint = Joint(
00362 joint_name, min, max, vel, joint_controller)
00363 joints.append(joint)
00364 else:
00365 rospy.logwarn(
00366 "Controller %s of type %s not supported", controller.name, controller_type)
00367 continue
00368 else:
00369 rospy.logwarn(
00370 "Parameters for controller %s not found", controller.name)
00371 continue
00372
00373 return joints
00374
00375 def _trajectory_state_cb(self, msg, index):
00376 if not self.trajectory_target[index].joint_names:
00377 self.trajectory_target[index].joint_names = msg.joint_names
00378 point = JointTrajectoryPoint()
00379 point.positions = list(msg.actual.positions)
00380 point.velocities = [0] * len(msg.joint_names)
00381 point.time_from_start = rospy.Duration.from_sec(0.005)
00382 self.trajectory_target[index].points = [point]
00383
00384 for cb in self.trajectory_state_slider_cb[index]:
00385 cb(msg)