cody_arm_client.py
Go to the documentation of this file.
00001 #
00002 # subscribe to thw joint angles and raw forces topics,  and provide FK
00003 # etc.
00004 #
00005 # Copyright (c) 2009, Georgia Tech Research Corporation
00006 # All rights reserved.
00007 # 
00008 # Redistribution and use in source and binary forms, with or without
00009 # modification, are permitted provided that the following conditions are met:
00010 #     * Redistributions of source code must retain the above copyright
00011 #       notice, this list of conditions and the following disclaimer.
00012 #     * Redistributions in binary form must reproduce the above copyright
00013 #       notice, this list of conditions and the following disclaimer in the
00014 #       documentation and/or other materials provided with the distribution.
00015 #     * Neither the name of the Georgia Tech Research Corporation nor the
00016 #       names of its contributors may be used to endorse or promote products
00017 #       derived from this software without specific prior written permission.
00018 # 
00019 # THIS SOFTWARE IS PROVIDED BY GEORGIA TECH RESEARCH CORPORATION ''AS IS'' AND
00020 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022 # DISCLAIMED. IN NO EVENT SHALL GEORGIA TECH BE LIABLE FOR ANY DIRECT, INDIRECT,
00023 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00024 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00025 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00027 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 #
00030 
00031 # Author: Advait Jain
00032 
00033 import math
00034 import numpy as np
00035 import copy
00036 import sys
00037 
00038 import roslib; roslib.load_manifest('hrl_cody_arms')
00039 import rospy
00040 
00041 from cody_arm_kinematics import CodyArmKinematics
00042 from equilibrium_point_control.hrl_arm import HRLArm
00043 import hrl_lib.viz as hv
00044 
00045 from hrl_msgs.msg import FloatArray, FloatArrayBare
00046 from std_msgs.msg import Header, Bool, Empty
00047 
00048 from visualization_msgs.msg import Marker
00049 
00050 
00051 # used in client and server.
00052 def get_joint_name_list(arm):
00053     if arm == 'r':
00054         return ['m3joint_ma1_j%d'%i for i in range(7)]
00055     else:
00056         return ['m3joint_ma2_j%d'%i for i in range(7)]
00057 
00058 
00059 class CodyArmClient(HRLArm):
00060     # arm - 'r' or 'l'
00061     def __init__(self, arm):
00062         kinematics = CodyArmKinematics(arm)
00063         HRLArm.__init__(self, kinematics)
00064 
00065         #stiffness from .yaml file [1800., 1300., 350., 600., 60., 80., 60.] mN-meter/deg
00066         self.nom_kp = [103, 74.5, 20.1, 4.4, 3.44] #N-m/rad
00067         # NB: Original value for joint 4 was 34.4, changed to 4.4
00068         # we don't use last two values becuase they are position controlled  - 4.58, 3.44] 
00069 
00070         if arm == 'r':
00071             #damping from .yaml file [100., 120., 10., 25., 1.25, 0.3, 0.25] mN-meter-sec/deg
00072             self.nom_kd = [5.73, 6.88, 0.573, 1.43, 0.0716] #N-m-s/deg
00073             # we don't use last two values becuase they are position controlled  - 0.0172, 0.0143]
00074         elif arm == 'l':
00075             #damping from .yaml file [80., 60., 10., 15., 1.25, 0.3, 0.20] mN-meter-sec/deg
00076             self.nom_kd = [4.58, 3.44, 0.573, 0.859, 0.0716] #N-m-s/deg
00077             # we don't use last two values becuase they are position controlled  - 0.0172, 0.0115
00078         else:
00079             rospy.logerr("You didn't give me a 'r' or 'l' for which arm ... Exiting")
00080             assert(False)
00081 
00082         self.alpha = None
00083         self.torque = None
00084         self.motor_temps = None
00085         self.ft_val = None
00086         self.pwr_state = False
00087 
00088         self.fts_bias = {'force': np.matrix(np.zeros(3)).T,
00089                          'torque': np.matrix(np.zeros(3)).T}
00090 
00091         self.joint_names_list = get_joint_name_list(arm)
00092 
00093         self.jep_cmd_pub = rospy.Publisher('/'+arm+'_arm/command/jep', FloatArray)
00094         self.alph_cmd_pub = rospy.Publisher('/'+arm+'_arm/command/joint_impedance_scale',
00095                                             FloatArray)
00096         self.stop_pub = rospy.Publisher('/arms/stop', Empty)
00097         self.motors_off_pub = rospy.Publisher('/arms/command/motors_off', Empty)
00098 
00099         self.marker_pub = rospy.Publisher('/'+arm+'_arm/viz/markers', Marker)
00100 
00101         ################## The following are for computing joint accelerations (added by Tapo, Jan 23-2013) ##################
00102         self.q_r = None 
00103         self.q_l = None 
00104         self.q_rHOT = None 
00105         self.q_lHOT = None 
00106         self.q_rHHOT = None 
00107         self.q_lHHOT = None
00108         self.time_stamp = None 
00109         ######################################################################################################################        
00110 
00111         rospy.Subscriber('/'+arm+'_arm/jep', FloatArray, self.ep_cb)
00112         rospy.Subscriber('/'+arm+'_arm/joint_impedance_scale', FloatArray, self.alpha_cb)
00113 
00114         rospy.Subscriber('/'+arm+'_arm/q', FloatArray, self.q_cb)
00115         rospy.Subscriber('/'+arm+'_arm/qdot', FloatArray, self.qdot_cb)
00116 
00117         rospy.Subscriber('/'+arm+'_arm/force', FloatArray, self.force_cb)
00118         rospy.Subscriber('/'+arm+'_arm/force_raw', FloatArray, self.raw_force_cb)
00119 
00120         rospy.Subscriber('/'+arm+'_arm/joint_torque', FloatArray, self.torque_cb)
00121 
00122         rospy.Subscriber('/'+arm+'_arm/joint_motor_temp', FloatArray, self.motor_temp_cb)
00123         rospy.Subscriber('/arms/pwr_state', Bool, self.pwr_state_cb)
00124         
00125         # Set desired joint angle - either through a delta from the current position, or as an absolute value.
00126         rospy.Subscriber ("/haptic_mpc/q_des", FloatArrayBare, self.set_ep_callback)
00127         rospy.Subscriber ("/haptic_mpc/delta_q_des", FloatArrayBare, self.set_delta_ep_callback)
00128 
00129         try:
00130             rospy.init_node(arm+'_arm_client', anonymous=False)
00131         except rospy.ROSException:
00132             pass
00133 
00134     #---------- ROS callbacks -----------------
00135     def pwr_state_cb(self, msg):
00136         with self.lock:
00137             self.pwr_state = msg.data
00138 
00139     def ep_cb(self, msg):
00140         with self.lock:
00141             self.ep = copy.copy(msg.data)
00142 
00143     def alpha_cb(self, msg):
00144         with self.lock:
00145             self.alpha = copy.copy(msg.data)
00146             self.kp = (np.array(self.alpha)*np.array(self.nom_kp)).tolist()
00147             self.kd = (np.array(self.alpha)*np.array(self.nom_kd)).tolist()
00148 
00149     def torque_cb(self, msg):
00150         with self.lock:
00151             self.torque = copy.copy(msg.data)
00152 
00153     def motor_temp_cb(self, msg):
00154         with self.lock:
00155             self.motor_temps = copy.copy(msg.data)
00156 
00157     def q_cb(self, msg):
00158         with self.lock:
00159             self.q = copy.copy(msg.data)
00160 
00161     def qdot_cb(self, msg):
00162         with self.lock:
00163             self.qdot = copy.copy(msg.data)
00164 
00165     def force_cb(self, msg):
00166         with self.lock:
00167             self.ft_val = copy.copy(msg.data)
00168 
00169     def raw_force_cb(self, msg):
00170         with self.lock:
00171             self.raw_force = copy.copy(msg.data)
00172 
00173     #--------- functions to use -----------------
00174 
00175     def publish_rviz_markers(self):
00176         # publish the CEP marker.
00177         o = np.matrix([0.,0.,0.,1.]).T
00178         jep = self.get_ep()
00179         cep, r = self.kinematics.FK(jep)
00180         cep_marker = hv.single_marker(cep, o, 'sphere',
00181                         '/torso_lift_link', color=(0., 0., 1., 1.),
00182                         scale = (0.02, 0.02, 0.02), duration=0.,
00183                         m_id=1)
00184         cep_marker.header.stamp = rospy.Time.now()
00185         self.marker_pub.publish(cep_marker)
00186 
00187         q = self.get_joint_angles()
00188         ee, r = self.kinematics.FK(q)
00189         ee_marker = hv.single_marker(ee, o, 'sphere',
00190                         '/torso_lift_link', color=(0., 1., 0., 1.),
00191                         scale = (0.02, 0.02, 0.02), duration=0.,
00192                         m_id=2)
00193         ee_marker.header.stamp = rospy.Time.now()
00194         self.marker_pub.publish(ee_marker)
00195 
00196 
00197     def get_wrist_force(self, bias=True, base_frame=True,
00198                         filtered = True):
00199         with self.lock:
00200             if filtered:
00201                 f = copy.copy(self.ft_val)
00202             else:
00203                 f = copy.copy(self.raw_force)
00204 
00205         f_mat = np.matrix(f).T
00206         f_mat = f_mat[0:3,:] # ignoring the torques.
00207 
00208         if bias:
00209             f_mat = f_mat - self.fts_bias['force']  #Tiffany added an 's' to 'ft'
00210         
00211         if base_frame:
00212             q = self.get_joint_angles()
00213             rot = self.kinematics.FK(q)[1]
00214             f_mat = rot*f_mat
00215         return f_mat
00216             
00217     def bias_wrist_ft(self):
00218         f_list = []
00219         t_list = []
00220         rospy.loginfo('Starting biasing...')
00221         for i in range(20):
00222             f_list.append(self.get_wrist_force(bias=False,
00223                                         base_frame=False))
00224             rospy.sleep(0.02)
00225 
00226         f_b = np.mean(np.column_stack(f_list), 1)
00227         # torque is unimplemented.
00228         t_b = self.get_wrist_torque(bias=False) #Tiffany Nov 8 2011 removed 'arm' arg
00229         self.fts_bias['force'] = f_b
00230         self.fts_bias['torque'] = t_b                
00231         rospy.loginfo('...done')
00232 
00233     # @return array-like of floats b/w 0 and 1.
00234     def get_impedance_scale(self):
00235         with self.lock:
00236             sc = copy.copy(self.alpha)
00237         return sc
00238 
00239     # @param s - list of floats b/w 0 and 1.
00240     def set_impedance_scale(self, s):
00241         time_stamp = rospy.Time.now()
00242         h = Header()
00243         h.stamp = time_stamp
00244         self.alph_cmd_pub.publish(FloatArray(h, s))
00245 
00246     def set_ep_callback(self, msg):
00247         des_jep = msg.data        
00248         self.set_ep(des_jep)
00249       
00250     def set_delta_ep_callback(self, msg):
00251         delta_jep = msg.data
00252         if self.ep == None:
00253             self.ep = self.get_joint_angles()
00254         des_jep = (np.array(self.ep) + np.array(delta_jep)).tolist()
00255       
00256         self.set_ep(des_jep)
00257 
00258     # @param duration - for compatibility with the PR2 class.
00259     def set_ep(self, jep, duration=None):
00260         time_stamp = rospy.Time.now()
00261         h = Header()
00262         h.stamp = time_stamp
00263         self.jep_cmd_pub.publish(FloatArray(h, jep))
00264         self.publish_rviz_markers()
00265 
00266     def is_motor_power_on(self):
00267         return self.pwr_state
00268 
00269     def motors_off(self):
00270         self.motors_off_pub.publish()
00271 
00272 
00273     #-------- unimplemented functions -----------------
00274 
00275     # leaving this unimplemented for now. Advait Nov 14, 2010.
00276     # Implemented Now - Tapo, Jan 23 2013
00277     def get_joint_accelerations(self, arm):
00278         t_now = rospy.get_time()
00279         q = self.get_joint_angles()
00280         if arm == 'r':
00281             if self.q_r != None and self.q_rHOT != None and self.q_rHHOT != None and self.time_stamp != None:
00282                 dt = t_now - self.time_stamp
00283                 qddot_r = (-np.array(q) + 4*np.array(self.q_r) - 5*np.array(self.q_rHOT) + 2*np.array(self.q_rHHOT)) / (dt*dt)
00284             else:
00285                 qddot_r = np.zeros(7)
00286             self.q_rHHOT = self.q_rHOT
00287             self.q_rHOT = self.q_r
00288             self.q_r = q
00289             self.time_stamp = t_now
00290             return qddot_r
00291         
00292         elif arm == 'l':
00293             if self.q_l != None and self.q_lHOT != None and self.q_lHHOT != None and self.time_stamp != None:
00294                 dt = t_now - self.time_stamp
00295                 qddot_l = (-np.array(q) + 4*np.array(self.q_l) - 5*np.array(self.q_lHOT) + 2*np.array(self.q_lHHOT)) / (dt*dt)
00296             else:
00297                 qddot_l = np.zeros(7)
00298             self.q_lHHOT = self.q_lHOT
00299             self.q_lHOT = self.q_l
00300             self.q_l = q
00301             self.time_stamp = t_now
00302             return qddot_l        
00303             
00304     # now implemented - marc Jul 2012
00305     def get_joint_torques(self):
00306         return self.torque
00307 
00308     # added this as a safety measure since fabrice skin is not
00309     # measuring real forces - marc Jul 2012
00310     def get_joint_motor_temps(self):
00311         return self.motor_temps
00312 
00313     # leaving this unimplemented for now. Advait Nov 14, 2010.
00314     def get_wrist_torque(self, bias=True):  #Tiffany Nov 8 2011 removed 'arm' arg
00315         pass
00316 
00317 
00318 
00319 
00320 # these two classes are specifically for the model predictive
00321 # controller that we developed for reaching in clutter with multiple
00322 # contacts.
00323 # We override the get_joint_impedance function to return values that
00324 # the model predictive controller will use.
00325 class CodyArmClient_7DOF(CodyArmClient):
00326     def __init__(self, arm):
00327         CodyArmClient.__init__(self, arm)
00328 
00329     # dummy kp values for the wrist, kd still of length five
00330     def get_joint_impedance(self):
00331         with self.lock:
00332             kp_t = [k for k in self.kp]
00333             kp_t[-1] = 30.
00334             kp_t.append(30.)
00335             kp_t.append(30.)
00336             return kp_t, copy.copy(self.kd)
00337 
00338 class CodyArmClient_5DOF(CodyArmClient):
00339     def __init__(self, arm):
00340         CodyArmClient.__init__(self, arm)
00341 
00342     def get_joint_impedance(self):
00343         with self.lock:
00344             return copy.copy(self.kp[0:5]), copy.copy(self.kd[0:5])
00345 
00346 
00347 
00348 if __name__ == '__main__':
00349     import m3.toolbox as m3t
00350     import hrl_lib.transforms as tr
00351     import optparse
00352 
00353     p = optparse.OptionParser()
00354     p.add_option('--arm_to_use', action='store', dest='arm',
00355                  type='string', help='which arm to use (l or r)',
00356                  default=None)
00357     opt, args = p.parse_args()
00358 
00359     if opt.arm == None:
00360         print 'Please specify an arm_to_use'
00361         print 'Exiting...'
00362         sys.exit()
00363 
00364     ac = CodyArmClient(opt.arm)
00365 
00366     # print FT sensor readings.
00367     if False:
00368         ac.bias_wrist_ft()
00369         while not rospy.is_shutdown():
00370             f = ac.get_wrist_force()
00371             print 'f:', f.A1
00372             rospy.sleep(0.05)
00373 
00374     # print joint angles.
00375     if False:
00376         while not rospy.is_shutdown():
00377             #jep = ac.get_ep()
00378             #print 'jep:', jep
00379             q = ac.get_joint_angles()
00380             print 'q:', np.degrees(q).tolist()[1]
00381             rospy.sleep(0.05)
00382 
00383     # publish end effector marker. useful to verify set_tooltip.
00384     if False:
00385         ac.kinematics.set_tooltip(np.matrix([0.,0.,-0.04]).T) # stub with mini45
00386         while not rospy.is_shutdown():
00387             ac.publish_rviz_markers()
00388             rospy.sleep(0.05)
00389 
00390     # print joint velocities
00391     if False:
00392         while not rospy.is_shutdown():
00393             qdot = ac.get_joint_velocities()
00394             print 'qdot:', np.degrees(qdot)
00395             rospy.sleep(0.05)
00396 
00397     # testing changing the impedance
00398     if False:
00399         rospy.sleep(1.)
00400         isc =  ac.get_impedance_scale()
00401         print isc
00402         isc[1] = 0.3
00403         ac.set_impedance_scale(isc)
00404         rospy.sleep(1.)
00405         isc =  ac.get_impedance_scale()
00406         print isc
00407 
00408 
00409 
00410 
00411 
00412 
00413 


hrl_cody_arms
Author(s): Advait Jain, Advisor: Prof. Charlie Kemp, Lab: Healthcare Robotics Lab
autogenerated on Wed Nov 27 2013 12:11:49