jointSlider.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2012 Shadow Robot Company Ltd.
00004 #
00005 # This program is free software: you can redistribute it and/or modify it
00006 # under the terms of the GNU General Public License as published by the Free
00007 # Software Foundation, either version 2 of the License, or (at your option)
00008 # any later version.
00009 #
00010 # This program is distributed in the hope that it will be useful, but WITHOUT
00011 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00013 # more details.
00014 #
00015 # You should have received a copy of the GNU General Public License along
00016 # with this program.  If not, see <http://www.gnu.org/licenses/>.
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 #import xml.dom.minidom
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         for index, joint_controller in enumerate(self.joint.controller_list):
00153             for controller in current_controllers:
00154                 if (controller.find(self.joint.name.lower() + '_' + joint_controller.name) != -1):
00155                     return index
00156         return -1
00157 
00158     def get_current_controllers(self):
00159         success = True
00160         list_controllers = rospy.ServiceProxy('pr2_controller_manager/list_controllers', ListControllers)
00161         try:
00162             resp1 = list_controllers()
00163         except rospy.ServiceException:
00164             success = False
00165 
00166         current_controllers = []
00167 
00168         if success:
00169             all_loaded_controllers = resp1.controllers
00170             for state,tmp_contrl in zip(resp1.state,resp1.controllers):
00171                 if state == "running":
00172                     current_controllers.append(tmp_contrl)
00173         else:
00174             rospy.loginfo("Couldn't get list of controllers from pr2_controller_manager/list_controllers service")
00175 
00176         return current_controllers
00177 
00178     def sendupdate(self, value):
00179         if (self.current_controller_index == -1):
00180             self.initialize_controller()
00181 
00182         if (self.current_controller_index != -1):
00183             if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position"):
00184                 self.pub.publish(radians(float(value)))
00185             elif self.joint.controller_list[self.current_controller_index].name == "velocity":
00186                 self.pub.publish(float(value) / 100.0)
00187             else:
00188                 self.pub.publish(float(value))
00189 
00190     def update(self):
00191         try:
00192             if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position"):
00193                 self.current_value = round(degrees(self.robot_lib.get_position(self.joint.name)),1)
00194             elif (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00195                 self.current_value = round(self.robot_lib.get_velocity(self.joint.name),1)
00196             elif (self.joint.controller_list[self.current_controller_index].name == "effort"):
00197                 self.current_value = round(self.robot_lib.get_effort(self.joint.name),1)
00198             self.value.setText("Val: " + str(self.current_value))
00199             if self.first_update_done == False:
00200                 if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position"):
00201                     self.slider.setSliderPosition(self.current_value)
00202                     self.slider.setValue(self.current_value)
00203                     self.target.setText("Tgt: " + str(self.current_value))
00204                 else:
00205                     self.target.setText("Tgt: 0.0")
00206                 self.first_update_done = True
00207         except:
00208             pass
00209         
00210     def refresh(self):
00211         """
00212         Refresh the current position of the slider
00213         """
00214         if (self.current_controller_index != -1):
00215             if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position"):
00216                 self.slider.setSliderPosition(self.current_value)
00217                 self.slider.setValue(self.current_value)
00218                 self.target.setText("Tgt: " + str(self.current_value))
00219 
00220     def set_slider_behaviour(self):
00221         """
00222         Depending on the type of controllers we may want a different behaviour
00223         """
00224         if (self.joint.controller_list[self.current_controller_index].name == "mixed_position_velocity") or (self.joint.controller_list[self.current_controller_index].name == "position"):
00225             if self.pos_slider_tracking_behaviour:
00226                 self.slider.setTracking(True)
00227             else:
00228                 self.slider.setTracking(False)
00229         elif (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00230             self.slider.setTracking(True)
00231             self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00232         elif (self.joint.controller_list[self.current_controller_index].name == "effort"):
00233             self.slider.setTracking(True)
00234             self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00235 
00236     def on_slider_released(self):
00237         if (self.joint.controller_list[self.current_controller_index].name == "effort") or (self.joint.controller_list[self.current_controller_index].name == "velocity"):
00238             self.slider.setSliderPosition(0)
00239             self.changeValue(0)
00240         
00241 
00242 class CANHandSlider(ExtendedSlider):
00243     """
00244     Slider for the CAN Hand.
00245     """
00246     def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00247         ExtendedSlider.__init__(self, joint, uiFile, robot_lib, plugin_parent, parent)
00248         self.set_slider_behaviour()
00249         self.pub = rospy.Publisher(self.joint.controller_list[self.current_controller_index].command_topic, sendupdate, latch=True)
00250 
00251     def sendupdate(self, value):
00252         message=[]
00253         message.append(joint(joint_name=self.joint.name, joint_target=value))
00254         self.pub.publish(sendupdate(len(message), message))
00255 
00256     def update(self):
00257         try:
00258             self.current_value = round(self.robot_lib.valueof(self.joint.name),1)
00259             self.value.setText("Val: " + str(self.current_value))
00260             if self.first_update_done == False:
00261                 self.slider.setSliderPosition(self.current_value)
00262                 self.slider.setValue(self.current_value)
00263                 self.target.setText("Tgt: " + str(self.current_value))
00264                 self.first_update_done = True
00265         except:
00266             pass
00267     
00268     def refresh(self):
00269         """
00270         Refresh the current position of the slider
00271         """
00272         self.slider.setSliderPosition(self.current_value)
00273         self.slider.setValue(self.current_value)
00274         self.target.setText("Tgt: " + str(self.current_value))
00275 
00276     def set_slider_behaviour(self):
00277         if self.pos_slider_tracking_behaviour:
00278             self.slider.setTracking(True)
00279         else:
00280             self.slider.setTracking(False)
00281 
00282 
00283 class ArmSlider(ExtendedSlider):
00284     """
00285     Slider for the CAN Arm.
00286     """
00287     def __init__(self, joint, uiFile, robot_lib, plugin_parent, parent=None):
00288         ExtendedSlider.__init__(self, joint, uiFile, robot_lib, plugin_parent, parent)
00289         self.set_slider_behaviour()
00290         self.pub = rospy.Publisher(self.joint.controller_list[self.current_controller_index].command_topic, sendupdate, latch=True)
00291 
00292     def sendupdate(self, value):
00293         message=[]
00294         message.append(joint(joint_name=self.joint.name, joint_target=value))
00295         self.pub.publish(sendupdate(len(message), message))
00296 
00297     def update(self):
00298         try:
00299             self.current_value = round(self.robot_lib.valueof(self.joint.name),1)
00300             self.value.setText("Val: " + str(self.current_value))
00301             if self.first_update_done == False:
00302                 self.slider.setSliderPosition(self.current_value)
00303                 self.slider.setValue(self.current_value)
00304                 self.target.setText("Tgt: " + str(self.current_value))
00305                 self.first_update_done = True
00306         except:
00307             pass
00308     
00309     def refresh(self):
00310         """
00311         Refresh the current position of the slider
00312         """
00313         self.slider.setSliderPosition(self.current_value)
00314         self.slider.setValue(self.current_value)
00315         self.target.setText("Tgt: " + str(self.current_value))
00316     
00317     def set_slider_behaviour(self):
00318         if self.pos_slider_tracking_behaviour:
00319             self.slider.setTracking(True)
00320         else:
00321             self.slider.setTracking(False)
00322 
00323 class SelectionSlider(QFrame):
00324     """
00325     This slider allows the user to move the selected sliders.
00326     """
00327     def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00328         QFrame.__init__(self, parent)
00329         ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), uiFile)
00330         loadUi(ui_file, self)
00331 
00332         self.plugin_parent = plugin_parent
00333         self.label.setText(name)
00334 
00335         self.slider.setFocusPolicy(QtCore.Qt.NoFocus)
00336         self.slider.setTracking(False)
00337         self.is_selected = False
00338 
00339         self.slider.setMinimum(min)
00340         self.slider.setMaximum(max)
00341         self.min_label.setText(str(min))
00342         self.max_label.setText(str(max))
00343 
00344         self.connect(self.slider, QtCore.SIGNAL('valueChanged(int)'), self.changeValue)
00345 
00346         self.connect(self.selected, QtCore.SIGNAL('stateChanged(int)'), self.checkbox_click)
00347 
00348     def changeValue(self, value):
00349         raise NotImplementedError, "Virtual method, please implement."
00350 
00351     def checkbox_click(self, value):
00352         self.is_selected = value
00353         for slider in self.plugin_parent.sliders:
00354             if slider.is_selected != value:
00355                 slider.is_selected = value
00356                 slider.selected.setChecked(value)
00357 
00358 class EtherCATSelectionSlider(SelectionSlider):
00359     """
00360     This slider allows the user to move the selected sliders for an etherCAT hand.
00361     """
00362     def __init__(self, name, min, max, uiFile, plugin_parent, parent=None):
00363         SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00364         self.set_slider_behaviour()
00365 
00366     def set_slider_behaviour(self):
00367         """
00368         Depending on the type of controllers we may want a different behaviour
00369         """
00370         #Currently we set the tracking to true for all the slide types
00371         self.slider.setTracking(True)
00372         #If any of the controllers is an effort or velocity controller we will activate the slider released signal detection
00373         #And set the slider halfway (50) as that is the position of the 0 for effort and velocity controllers
00374         for slider in self.plugin_parent.sliders:
00375             if (slider.joint.controller_list[slider.current_controller_index].name == "effort")  or (slider.joint.controller_list[slider.current_controller_index].name == "velocity"):
00376                 self.connect(self.slider, QtCore.SIGNAL('sliderReleased()'), self.on_slider_released)
00377                 self.slider.setSliderPosition(50)
00378                 self.current_value = 50
00379                 self.target.setText("Tgt: " + str(50) + "%")
00380                 break
00381 
00382     def changeValue(self, value):
00383         #modify the values from the selected sliders.
00384         for slider in self.plugin_parent.sliders:
00385             if slider.is_selected:
00386                 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00387                 slider.slider.setSliderPosition(temp_value)
00388                 slider.changeValue(temp_value)
00389 
00390         self.current_value = value
00391         self.target.setText("Tgt: " + str(value) + "%")
00392 
00393     def on_slider_released(self):
00394         for slider in self.plugin_parent.sliders:
00395             if slider.is_selected:
00396                 if (slider.joint.controller_list[slider.current_controller_index].name == "effort") or (slider.joint.controller_list[slider.current_controller_index].name == "velocity"):
00397                     slider.slider.setSliderPosition(0)
00398                     slider.changeValue(0)
00399         self.slider.setSliderPosition(50)
00400         self.current_value = 50
00401         self.target.setText("Tgt: " + str(50) + "%")
00402 
00403 class CANHandSelectionSlider(SelectionSlider):
00404     """
00405     This slider allows the user to move the selected sliders for a ShadowArm.
00406     """
00407     def __init__(self, name, min, max, uiFile, robot_lib, plugin_parent, parent=None):
00408         SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00409         self.robot_lib = robot_lib
00410         self.slider.setTracking(True)
00411 
00412     def changeValue(self, value):
00413         #modify the values from the selected sliders.
00414         joint_dict = {}
00415         for slider in self.plugin_parent.sliders:
00416             if slider.is_selected:
00417                 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00418                 slider.slider.setSliderPosition(temp_value)
00419                 slider.target.setText("Tgt: " + str(temp_value))
00420                 joint_dict[slider.joint.name] = temp_value
00421 
00422         self.robot_lib.sendupdate_from_dict(joint_dict)
00423         self.current_value = value
00424         self.target.setText("Tgt: " + str(value) + "%")
00425 
00426 class ArmSelectionSlider(SelectionSlider):
00427     """
00428     This slider allows the user to move the selected sliders for a ShadowArm.
00429     """
00430     def __init__(self, name, min, max, uiFile, robot_lib, plugin_parent, parent=None):
00431         SelectionSlider.__init__(self, name, min, max, uiFile, plugin_parent, parent)
00432         self.robot_lib = robot_lib
00433         self.slider.setTracking(True)
00434 
00435     def changeValue(self, value):
00436         #modify the values from the selected sliders.
00437         joint_dict = {}
00438         for slider in self.plugin_parent.sliders:
00439             if slider.is_selected:
00440                 temp_value = ((slider.slider.maximum() - slider.slider.minimum()) * float(value) / 100.0) + slider.slider.minimum()
00441                 slider.slider.setSliderPosition(temp_value)
00442                 slider.target.setText("Tgt: " + str(temp_value))
00443                 joint_dict[slider.joint.name] = temp_value
00444 
00445         self.robot_lib.sendupdate_arm_from_dict(joint_dict)
00446         self.current_value = value
00447         self.target.setText("Tgt: " + str(value) + "%")
00448 
00449 
00450 
00451 
00452 


sr_gui_joint_slider
Author(s): Toni Oliver
autogenerated on Fri Jan 3 2014 12:07:23