shadowhand_commander.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 # Copyright 2014 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 import rospy
00019 import threading
00020 
00021 from sr_robot_msgs.msg import sendupdate, joint
00022 from sr_hand.shadowhand_ros import ShadowHand_ROS
00023 from sr_hand.grasps_interpoler import GraspInterpoler
00024 from sr_hand.Grasp import Grasp
00025 
00026 """
00027 Module to provide a quick and easy way to script the Shadow Hand.
00028 This is done via creating a short script with a Commander object then calling
00029 methods on the commander to script the motion.
00030 
00031 Basic script will look like:
00032 
00033     #!/usr/bin/python
00034     import rospy
00035     from sr_hand.shadowhand_commander import Commander
00036 
00037     rospy.init_node('basic_example')
00038     c = Commander()
00039 
00040     c.move_hand({
00041         "THJ1": 0, "THJ2": 6, "THJ3": 10, "THJ4": 37, "THJ5": 9,
00042         "FFJ0": 21, "FFJ3": 26, "FFJ4": 0,
00043         "MFJ0": 18, "MFJ3": 24, "MFJ4": 0,
00044         "RFJ0": 30, "RFJ3": 16, "RFJ4": 0,
00045         "LFJ0": 30, "LFJ3": 0, "LFJ4": -10, "LFJ5": 10
00046     })
00047     rospy.sleep(3.0)
00048     
00049 
00050 See the examples directory in the package sr_examples.
00051 """
00052 
00053 class Commander(object):
00054     def __init__(self):
00055         # Mutex to control thread access to certain operations 
00056         self.mutex = threading.Lock()
00057 
00058         # This is used to store the grasp interpolators for the different threads.
00059         self.grasp_interpolators = {}
00060 
00061         # Shadow hand setup
00062         self.hand = ShadowHand_ROS()
00063 
00064         # Period in seconds between interpolated commands (e.g. if we want an interpolation time of 1s and have a period of 0.1, 
00065         # the interpoler will use 10 steps
00066         self.hand_interpolation_period = 0.01
00067         if self.hand.check_hand_type() == "gazebo":
00068             # Interpolation is slower under simulation compared to real hand
00069             self.hand_interpolation_period = 0.1
00070 
00071 
00072     def move_hand(self, command):
00073         """
00074         Move the Shadow Hand.
00075 
00076         This call is non blocking. It will return before the motion has finished.
00077 
00078         If called with interpolation time of 0.0 the joints will move to the target position
00079         at maximum velocity (i.e. the max. vel. allowed by the position controller for that joint)
00080         
00081         If called with interpolation time greater than self.hand_interpolation_period,
00082         a separate thread will deal with the interpolation time and will keep 
00083         sending targets to the hand until the last target is sent.
00084         
00085         If move_hand() is called again before the previous movements have finished,
00086         the new call will override only the conciding joints. The others will keep moving
00087         to their previous targets at their previous velocity.
00088 
00089         @param command - Dictionary of joint names in the keys and angles in
00090         degrees in the values. The key interpolation_time gives the time in seconds that 
00091         the movement will last.
00092         """
00093         
00094         # Copy the dictionary, so that we will not affect the original user command
00095         joints = dict(command)
00096         
00097         interpolation_time = 0.0
00098         if 'interpolation_time' in joints:
00099             interpolation_time = joints['interpolation_time']
00100             del joints['interpolation_time']
00101 
00102         if interpolation_time == 0.0:
00103             self.mutex.acquire()
00104             self._prune_interpolators(joints)            
00105             self.mutex.release()
00106             self.hand.sendupdate_from_dict(joints)
00107         else:
00108             threading.Thread(target=self._move_hand_interpolation,
00109                              args=(joints, interpolation_time)).start()
00110 
00111 
00112     def _move_hand_interpolation(self, joints, interpolation_time=1.0):
00113         """
00114         Remove the coinciding joints from the currently running interpolators.
00115         It actually removes the joints from the 'grasp_to' list of the interpolator.
00116 
00117         @param joints - Dictionary of joint names in the keys and angles in
00118         degrees in the values.
00119         @param interpolation_time - A float. Interpolation time in seconds.
00120         """
00121         
00122         rospy.logdebug("call interpolation")
00123         thread_name = threading.current_thread().name
00124         try:
00125             self.mutex.acquire()
00126             self._prune_interpolators(joints)
00127             self.mutex.release()
00128           
00129             rospy.logdebug("start interpolation")
00130             current_grasp = Grasp()
00131             current_grasp.joints_and_positions = self.hand.read_all_current_positions()
00132             target_grasp = Grasp()
00133             target_grasp.joints_and_positions = joints
00134 
00135             interpolator = GraspInterpoler(current_grasp, target_grasp)
00136             self.grasp_interpolators[thread_name] = interpolator
00137             
00138             r = rospy.Rate(1.0 / self.hand_interpolation_period)
00139             
00140             for interpolation in range (1, int(interpolation_time / self.hand_interpolation_period) + 1):
00141                 self.mutex.acquire()
00142                 targets_to_send = interpolator.interpolate(100.0 * interpolation * self.hand_interpolation_period / interpolation_time)
00143                 self.mutex.release()
00144                 self.hand.sendupdate_from_dict(targets_to_send)
00145                 #rospy.loginfo("sent cmd n: %s" %(str(interpolation), ))
00146                 r.sleep()
00147         finally:
00148             self.mutex.acquire()
00149             self.grasp_interpolators.pop(thread_name, None)
00150             self.mutex.release()
00151             rospy.logdebug("end interpolation")
00152 
00153 
00154     def _prune_interpolators(self, joints):
00155         """
00156         Remove the coinciding joints from the currently running interpolators.
00157         It actually removes the joints from the 'grasp_to' list of the interpolator.
00158 
00159         @param joints - Dictionary of joint names in the keys and angles in
00160         degrees in the values.
00161         """
00162         rospy.logdebug("Call prune from thread %s", threading.current_thread().name )
00163         for thread_id in self.grasp_interpolators.keys():
00164             for joint_name in joints.keys():
00165                 self.grasp_interpolators[thread_id].grasp_to.joints_and_positions.pop(joint_name, None)
00166                 rospy.logdebug("Prune joint %s thread %s", joint_name, thread_id )
00167 
00168 
00169     def get_hand_position(self):
00170         """
00171         Returns a dictionary with the position of each joint in degrees.
00172         """
00173         return dict(self.hand.read_all_current_positions())
00174     
00175     def get_hand_velocity(self):
00176         """
00177         Returns a dictionary with the velocity of each joint in degrees/s.
00178         """
00179         return dict(self.hand.read_all_current_velocities())
00180     
00181     def get_hand_effort(self):
00182         """
00183         Returns a dictionary with the effort of each joint. Currently in ADC units, as no calibration is performed on the strain gauges.
00184         """
00185         return dict(self.hand.read_all_current_efforts())
00186     
00187     def get_tactile_type(self):
00188         """
00189         Returns a string indicating the type of tactile sensors present. Possible values are: PST, biotac, UBI0 .
00190         """
00191         return self.hand.get_tactile_type()
00192     
00193     def get_tactile_state(self):
00194         """
00195         Returns an object containing tactile data. The structure of the data is different for every tactile_type .
00196         """
00197         return self.hand.get_tactile_state()
00198     
00199 


sr_hand
Author(s): Ugo Cupcic
autogenerated on Fri Aug 28 2015 13:08:51