fancy_touch_demo.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2011 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 # This demo is a simple script that reads data from the tactile sensors in the finger tips and does some actions in response.
00020 # This version can work with PST tactiles and (with a modification in the subscriber topic name) with Biotac sensors
00021 # When a finger tip is pressed and the value of the pressure exceeds a predefined threshold an action is triggered
00022 # There is a different action defined for each finger. Actions involve one of the following things:
00023 # - send a predefined pose command to the hand
00024 # - send a predefined pose command to the arm (if there is not an arm the arm commands will be ignored)
00025 # - the PC beeps (you should install the beep (sudo apt-get install beep)
00026 
00027 
00028 import roslib; roslib.load_manifest('sr_example')
00029 import rospy
00030 
00031 import time, mutex, subprocess, math
00032 
00033 from sr_robot_msgs.msg import sendupdate, joint, Biotac, BiotacAll, ShadowPST
00034 from sensor_msgs.msg import *
00035 from std_msgs.msg import Float64
00036 
00037 #the threshold for pdc above which the Biotac tactile is considered "pressed"
00038 PDC_THRESHOLD = 2000
00039 #the threshold for the PSTs above which the tactile is considered "pressed"
00040 PST_THRESHOLD = 400
00041 
00042 class FancyDemo(object):
00043     # If you use the simulated hand (in gazebo) use the mixed controllers
00044     #controller_type = "_mixed_position_velocity_controller"
00045     # If you use the real hand, generally use the position controller (comment the previous line and uncomment the following)
00046     controller_type = "_position_controller"
00047     
00048     # starting position for the hand (DON't use until reviewed. Should be executed in two movement sequences)
00049     start_pos_hand = { "THJ1":21,
00050                        "THJ2":25,
00051                        "THJ3":0,
00052                        "THJ4":50,
00053                        "THJ5":-6,
00054                        "FFJ0":180,
00055                        "FFJ3":90,
00056                        "FFJ4":0,
00057                        "MFJ0":180,
00058                        "MFJ3":90,
00059                        "MFJ4":0,
00060                        "RFJ0":180,
00061                        "RFJ3":90,
00062                        "RFJ4":0,
00063                        "LFJ0":180,
00064                        "LFJ3":90,
00065                        "LFJ4":0,
00066                        "LFJ5":0,
00067                        "WRJ1":0,
00068                        "WRJ2":0 }
00069     # starting position for the hand
00070     extended_pos_hand = {  "THJ1":0,
00071                            "THJ2":0,
00072                            "THJ3":0,
00073                            "THJ4":0,
00074                            "THJ5":-6,
00075                            "FFJ0":0,
00076                            "FFJ3":0,
00077                            "FFJ4":0,
00078                            "MFJ0":0,
00079                            "MFJ3":0,
00080                            "MFJ4":0,
00081                            "RFJ0":0,
00082                            "RFJ3":0,
00083                            "RFJ4":0,
00084                            "LFJ0":0,
00085                            "LFJ3":0,
00086                            "LFJ4":0,
00087                            "LFJ5":0,
00088                            "WRJ1":0,
00089                            "WRJ2":0 }
00090 
00091     #thumb up position for the hand
00092     thumb_up_pos_hand = {  "THJ1":0,
00093                            "THJ2":0,
00094                            "THJ3":0,
00095                            "THJ4":0,
00096                            "THJ5":0,
00097                            "FFJ0":180,
00098                            "FFJ3":90,
00099                            "FFJ4":0,
00100                            "MFJ0":180,
00101                            "MFJ3":90,
00102                            "MFJ4":0,
00103                            "RFJ0":180,
00104                            "RFJ3":90,
00105                            "RFJ4":0,
00106                            "LFJ0":180,
00107                            "LFJ3":90,
00108                            "LFJ4":0,
00109                            "LFJ5":0,
00110                            "WRJ1":0,
00111                            "WRJ2":10 }
00112 
00113     #starting position for the arm
00114     start_pos_arm = [ joint(joint_name = "ElbowJRotate", joint_target = 0),
00115                       joint(joint_name = "ElbowJSwing", joint_target = 59),
00116                       joint(joint_name = "ShoulderJRotate", joint_target = 0),
00117                       joint(joint_name = "ShoulderJSwing", joint_target = 33)
00118                       ]
00119 
00120 
00121     #The arm publisher:
00122     # publish the message to the /sr_arm/sendupdate topic.
00123     arm_publisher = rospy.Publisher('/sr_arm/sendupdate', sendupdate)
00124 
00125     #A boolean used in this demo: set to true while an action is running
00126     # just so we don't do 2 actions at once
00127     action_running = mutex.mutex()
00128 
00129     def __init__(self):
00130         #A vector containing the different callbacks, in the same order
00131         # as the tactiles.
00132         self.fingers_pressed_functions = [self.ff_pressed, self.mf_pressed, self.rf_pressed,
00133                                           self.lf_pressed, self.th_pressed]
00134 
00135         #The hand publishers:
00136         # we use a dictionnary of publishers, because on the etherCAT hand
00137         # you have one publisher per controller.
00138         self.hand_publishers = self.create_hand_publishers()
00139 
00140         #send the start position to the hand
00141         self.hand_publish(self.start_pos_hand)
00142         #send the start position to the arm
00143         self.arm_publisher.publish( sendupdate(len(self.start_pos_arm), self.start_pos_arm) )
00144 
00145         #wait for the node to be initialized and then go to the starting position
00146         time.sleep(1)
00147         rospy.loginfo("OK, ready for the demo")
00148 
00149         # We subscribe to the data being published by the biotac sensors.
00150         self.sub_biotacs = rospy.Subscriber("tactiles", BiotacAll, self.callback_biotacs, queue_size=1)
00151         self.sub_psts    = rospy.Subscriber("tactile", ShadowPST, self.callback_psts, queue_size=1)
00152 
00153     def create_hand_publishers(self):
00154         """
00155         Creates a dictionnary of publishers to send the targets to the controllers
00156         on /sh_??j?_position_controller/command
00157         """
00158         hand_pub = {}
00159 
00160         for joint in ["FFJ0", "FFJ3", "FFJ4",
00161                       "MFJ0", "MFJ3", "MFJ4",
00162                       "RFJ0", "RFJ3", "RFJ4",
00163                       "LFJ0", "LFJ3", "LFJ4", "LFJ5",
00164                       "THJ1", "THJ2", "THJ3", "THJ4", "THJ5",
00165                       "WRJ1", "WRJ2" ]:
00166             hand_pub[joint] = rospy.Publisher('sh_'+joint.lower() + self.controller_type + '/command', Float64, latch=True)
00167 
00168         return hand_pub
00169 
00170     def hand_publish(self, pose):
00171         """
00172         Publishes the given pose to the correct controllers for the hand.
00173         The targets are converted in radians.
00174         """
00175         for joint, pos in pose.iteritems():
00176             self.hand_publishers[joint].publish( math.radians(pos) )
00177 
00178     def callback_biotacs(self, msg):
00179         """
00180         The callback function for the biotacs. Checks if one of the fingers
00181         was pressed (filter the noise). If it is the case, call the
00182         corresponding function.
00183 
00184         @msg is the message containing the biotac data
00185         """
00186         #loop through the five tactiles
00187         for index,tactile in enumerate(msg.tactiles):
00188             #here we're just checking pdc (the pressure)
00189             # to see if a finger has been pressed, but you have
00190             # access to the whole data from the sensor
00191             # (look at sr_robot_msgs/msg/Biotac.msg)
00192             if tactile.pdc >= PDC_THRESHOLD:
00193                 # the tactile has been pressed, call the
00194                 # corresponding function
00195                 self.fingers_pressed_functions[index](tactile.pdc)
00196 
00197     def callback_psts(self, msg):
00198         """
00199         The callback function for the PSTs. Checks if one of the fingers
00200         was pressed (filter the noise). If it is the case, call the
00201         corresponding function.
00202 
00203         @msg is the message containing the biotac data
00204         """
00205         #loop through the five tactiles
00206         for index,tactile in enumerate(msg.pressure):
00207             #here we're just checking the pressure
00208             # to see if a finger has been pressed
00209             # 18456 is the value the PST takes when the sensor is not plugged in
00210             if tactile >= PST_THRESHOLD and tactile != 18456:
00211                 # the tactile has been pressed, call the
00212                 # corresponding function
00213                 self.fingers_pressed_functions[index](tactile)
00214 
00215     def ff_pressed(self,data):
00216         """
00217         The first finger was pressed.
00218 
00219         If no action is currently running, we set the ShoulderJRotate
00220         to a negative value proportional to the pressure received.
00221 
00222         @param data: the pressure value (pdc)
00223         """
00224         #if we're already performing an action, don't do anything
00225         if not self.action_running.testandset():
00226             return
00227 
00228         #ok the finger sensor was pressed
00229         p = subprocess.Popen('beep')
00230 
00231         #rotate the trunk to (data_received * min_pos)
00232         # convert data to be in [0., 1.]
00233         data /= 4000.
00234         if data > 1.:
00235             data = 1.
00236         target_sh_rot    = 0.  + data * (-45.0)
00237         target_sh_swing  = 20. + data * (-10.0)
00238         target_elb_swing = 90. + data * (-10.0)
00239         target_elb_rot   = 0.  + data * (-45.0)
00240 
00241         rospy.loginfo("FF touched, going to new target ")
00242 
00243         #wait 1s for the user to release the sensor
00244         time.sleep(.2)
00245         message = [joint(joint_name = "ShoulderJRotate", joint_target = target_sh_rot),
00246                    joint(joint_name = "ShoulderJSwing", joint_target = target_sh_swing),
00247                    joint(joint_name = "ElbowJRotate", joint_target = target_elb_rot),
00248                    joint(joint_name = "ElbowJSwing", joint_target = target_elb_swing)
00249                    ]
00250 
00251         self.arm_publisher.publish(sendupdate(len(message), message))
00252 
00253         #send the start position to the hand
00254         self.hand_publish( self.extended_pos_hand )
00255 
00256         #wait before next possible action
00257         time.sleep(.2)
00258         self.action_running.unlock()
00259 
00260     def mf_pressed(self, data):
00261         """
00262         The middle finger was pressed.
00263 
00264         If no action is currently running, we move the arm angles
00265         to a positive value proportional to the pressure received.
00266 
00267         @param data: the pressure value (pdc)
00268         """
00269         #if we're already performing an action, don't do anything
00270         if not self.action_running.testandset():
00271             return
00272 
00273         #ok finger was pressed
00274         p = subprocess.Popen('beep')
00275 
00276         #rotate the trunk to (data_received * min_pos)
00277         # convert data to be in [0., 1.]
00278         data /= 4000.
00279         if data > 1.:
00280             data = 1.
00281         target_sh_rot    = 0.  + data * (45.0)
00282         target_sh_swing  = 20. + data * (20.0)
00283         target_elb_swing = 90. + data * (20.0)
00284         target_elb_rot   = 0.  + data * (45.0)
00285 
00286         rospy.loginfo("MF touched, going to new target ")
00287 
00288         #wait 1s for the user to release the sensor
00289         time.sleep(.2)
00290         message = [joint(joint_name = "ShoulderJRotate", joint_target = target_sh_rot),
00291                    joint(joint_name = "ShoulderJSwing", joint_target = target_sh_swing),
00292                    joint(joint_name = "ElbowJRotate", joint_target = target_elb_rot),
00293                    joint(joint_name = "ElbowJSwing", joint_target = target_elb_swing)
00294                    ]
00295 
00296         self.arm_publisher.publish(sendupdate(len(message), message))
00297 
00298         #wait before next possible action
00299         time.sleep(.2)
00300         self.action_running.unlock()
00301 
00302 
00303     def rf_pressed(self, data):
00304         """
00305         The ring finger was pressed.
00306 
00307         If no action is currently running, we make a beep
00308         but don't do anything else.
00309 
00310         @param data: the pressure value (pdc)
00311         """
00312         #if we're already performing an action, don't do anything
00313         if not self.action_running.testandset():
00314             return
00315 
00316         #ok finger was pressed
00317         p = subprocess.Popen('beep')
00318 
00319         rospy.loginfo("RF touched, not doing anything.")
00320 
00321         #wait before next possible action
00322         time.sleep(.2)
00323         self.action_running.unlock()
00324 
00325     def lf_pressed(self, data):
00326         """
00327         The little finger was pressed.
00328 
00329         If no action is currently running, we reset the arm and
00330         hand to their starting position
00331 
00332         @param data: the pressure value (pdc)
00333         """
00334         #if we're already performing an action, don't do anything
00335         if not self.action_running.testandset():
00336             return
00337 
00338         #ok finger pressed
00339         p = subprocess.Popen('beep')
00340 
00341         rospy.loginfo("LF touched, going to start position.")
00342 
00343         #wait 1s for the user to release the sensor
00344         time.sleep(.2)
00345 
00346         #send the start position to the hand
00347         self.hand_publish( self.start_pos_hand )
00348         #send the start position to the arm
00349         self.arm_publisher.publish(sendupdate(len(self.start_pos_arm), self.start_pos_arm))
00350 
00351         #wait before next possible action
00352         time.sleep(.2)
00353         self.action_running.unlock()
00354 
00355     def th_pressed(self, data):
00356         """
00357         The thumb was pressed.
00358 
00359         If no action is currently running, we send the thumb_up
00360         targets to the hand.
00361 
00362         @param data: the pressure value (pdc)
00363         """
00364         #if we're already performing an action, don't do anything
00365         if not self.action_running.testandset():
00366             return
00367 
00368         #ok the finger was pressed
00369         p = subprocess.Popen('beep')
00370 
00371         rospy.loginfo("TH touched, going to thumb up position.")
00372 
00373         #wait 1s for the user to release the sensor
00374         time.sleep(.2)
00375 
00376         #send the thumb_up_position to the hand
00377         self.hand_publish( self.thumb_up_pos_hand )
00378 
00379         #wait before next possible action
00380         time.sleep(.2)
00381         self.action_running.unlock()
00382 
00383 def main():
00384     """
00385     The main function
00386     """
00387     # init the ros node
00388     rospy.init_node('fancy_touch_demo', anonymous=True)
00389 
00390     fancy_demo = FancyDemo()
00391 
00392     # subscribe until interrupted
00393     rospy.spin()
00394 
00395 
00396 if __name__ == '__main__':
00397     main()
00398 


sr_example
Author(s): Ugo Cupcic
autogenerated on Mon Oct 6 2014 07:49:30