arms.py
Go to the documentation of this file.
00001 #
00002 # Copyright (c) 2009, Georgia Tech Research Corporation
00003 # All rights reserved.
00004 # 
00005 # Redistribution and use in source and binary forms, with or without
00006 # modification, are permitted provided that the following conditions are met:
00007 #     * Redistributions of source code must retain the above copyright
00008 #       notice, this list of conditions and the following disclaimer.
00009 #     * Redistributions in binary form must reproduce the above copyright
00010 #       notice, this list of conditions and the following disclaimer in the
00011 #       documentation and/or other materials provided with the distribution.
00012 #     * Neither the name of the Georgia Tech Research Corporation nor the
00013 #       names of its contributors may be used to endorse or promote products
00014 #       derived from this software without specific prior written permission.
00015 # 
00016 # THIS SOFTWARE IS PROVIDED BY GEORGIA TECH RESEARCH CORPORATION ''AS IS'' AND
00017 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 # DISCLAIMED. IN NO EVENT SHALL GEORGIA TECH BE LIABLE FOR ANY DIRECT, INDIRECT,
00020 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00021 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00022 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00023 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00024 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00025 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 #
00027 
00028 # Author: Advait Jain
00029 
00030 
00031 import math
00032 import numpy as np
00033 import copy
00034 import sys, time, os
00035 
00036 import PyKDL as kdl
00037 import create_IK_guess_dict as cgd
00038 
00039 import roslib; roslib.load_manifest('hrl_cody_arms')
00040 
00041 import hrl_lib.transforms as tr
00042 import hrl_lib.util as ut
00043 import hrl_lib.kdl_utils as ku
00044 
00045 #-------------- TF stuff ---------------
00046 def link_tf_name(arm, link_number):
00047     if arm == 'right_arm':
00048         nm = 'r_arm'
00049     else:
00050         nm = 'l_arm'
00051 
00052     if link_number == 0:
00053         nm = 'torso_link'
00054     elif link_number == 7:
00055         nm = nm + '_ee'
00056     else:
00057         nm = nm + '_' + str(link_number)
00058     return nm
00059 
00060 
00061 class M3HrlRobot():
00062     def __init__(self, end_effector_length):
00063         # create joint limit dicts
00064         self.joint_lim_dict = {}
00065         self.joint_lim_dict['right_arm'] = {'max': np.radians([ 120.00, 122.15, 77.5, 144., 122.,  45.,  45.]),
00066                                             'min': np.radians([ -47.61,  -20., -77.5,   0., -80., -45., -45.])}
00067 
00068         self.joint_lim_dict['left_arm'] = {'max': np.radians([ 120.00,   20.,  77.5, 144.,   80.,  45.,  45.]),
00069                                            'min': np.radians([ -47.61, -122.15, -77.5,   0., -122., -45., -45.])}
00070 
00071         end_effector_length += 0.0135 + 0.04318 # add wrist linkange and FT sensor lengths
00072         self.setup_kdl_mekabot(end_effector_length)
00073         q_guess_pkl_l = os.environ['HOME']+'/svn/gt-ros-pkg/hrl/hrl_arm_control/hrl_cody_arms/src/hrl_cody_arms/q_guess_left_dict.pkl'
00074         q_guess_pkl_r = os.environ['HOME']+'/svn/gt-ros-pkg/hrl/hrl_arm_control/hrl_cody_arms/src/hrl_cody_arms/q_guess_right_dict.pkl'
00075 
00076         self.q_guess_dict_left = ut.load_pickle(q_guess_pkl_l)
00077         self.q_guess_dict_right = ut.load_pickle(q_guess_pkl_r)
00078 
00079     # KDL joint array to meka joint list. (7->7)
00080     # arm - 'left_arm' or 'right_arm'  
00081     def kdl_angles_to_meka(self, arm, q_jnt_arr):
00082         if q_jnt_arr == None:
00083             return None
00084 
00085         q_rad = [0. for i in range(7)]
00086         q_rad[0] = -q_jnt_arr[0]
00087         q_rad[1] = -q_jnt_arr[1]
00088         q_rad[2] = -q_jnt_arr[2]
00089         q_rad[3] = -q_jnt_arr[3]
00090         q_rad[4] = -q_jnt_arr[4]
00091         q_rad[5] = -q_jnt_arr[5]
00092         q_rad[6] = -q_jnt_arr[6]
00093         return q_rad
00094 
00095     # meka joint list to KDL joint array (7->7)
00096     # arm - 'left_arm' or 'right_arm'
00097     def meka_angles_to_kdl(self,arm,q_list):
00098         if q_list == None:
00099             return None
00100 
00101         n_joints = len(q_list)
00102         q = kdl.JntArray(n_joints)
00103         q[0] = -q_list[0]
00104         q[1] = -q_list[1]
00105         q[2] = -q_list[2]
00106         if n_joints > 3:
00107             q[3] = -q_list[3]
00108         if n_joints == 7:
00109             q[4] = -q_list[4]
00110             q[5] = -q_list[5]
00111             q[6] = -q_list[6]
00112         return q
00113 
00114     def create_right_chain(self, end_effector_length):
00115         ch = kdl.Chain()
00116         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,-0.18493,0.))))
00117         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotX),kdl.Frame(kdl.Vector(0.,-0.03175,0.))))
00118         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotZ),kdl.Frame(kdl.Vector(0.00635,0.,-0.27795))))
00119         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,0.,-0.27853))))
00120         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotZ),kdl.Frame(kdl.Vector(0.,0.,0.))))
00121         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,0.,0.))))
00122         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotX),kdl.Frame(kdl.Vector(0.,0.,-end_effector_length))))
00123         return ch
00124 
00125     def create_left_chain(self, end_effector_length):
00126         ch = kdl.Chain()
00127         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,0.18493,0.))))
00128         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotX),kdl.Frame(kdl.Vector(0.,0.03175,0.))))
00129         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotZ),kdl.Frame(kdl.Vector(0.00635,0.,-0.27795))))
00130         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,0.,-0.27853))))
00131         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotZ),kdl.Frame(kdl.Vector(0.,0.,0.))))
00132         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotY),kdl.Frame(kdl.Vector(0.,0.,0.))))
00133         ch.addSegment(kdl.Segment(kdl.Joint(kdl.Joint.RotX),kdl.Frame(kdl.Vector(0.,0.,-end_effector_length))))
00134         return ch
00135 
00136     def create_solvers(self, ch):
00137          fk = kdl.ChainFkSolverPos_recursive(ch)
00138          ik_v = kdl.ChainIkSolverVel_pinv(ch)
00139          ik_p = kdl.ChainIkSolverPos_NR(ch, fk, ik_v)
00140          jac = kdl.ChainJntToJacSolver(ch)
00141          return fk, ik_v, ik_p, jac
00142 
00143     def setup_kdl_mekabot(self, end_effector_length):
00144         #right arm
00145         ch = self.create_right_chain(end_effector_length)
00146         fk, ik_v, ik_p, jac = self.create_solvers(ch)
00147 
00148         kdl_rightarm = {}
00149         kdl_rightarm['chain'] = ch
00150         kdl_rightarm['nJnts'] = ch.getNrOfJoints()
00151         kdl_rightarm['fk_p'] = fk
00152         kdl_rightarm['ik_v'] = ik_v
00153         kdl_rightarm['ik_p'] = ik_p
00154         kdl_rightarm['jacobian_solver'] = jac
00155 
00156         #left arm
00157         kdl_leftarm = {}
00158         ch = self.create_left_chain(end_effector_length)
00159         fk, ik_v, ik_p, jac = self.create_solvers(ch)
00160 
00161         kdl_leftarm['chain'] = ch
00162         kdl_leftarm['nJnts'] = ch.getNrOfJoints()
00163         kdl_leftarm['fk_p'] = fk
00164         kdl_leftarm['ik_v'] = ik_v
00165         kdl_leftarm['ik_p'] = ik_p
00166         kdl_leftarm['jacobian_solver'] = jac
00167 
00168         #Add both chains to dictionary
00169         self.cody_kdl = {'right_arm':kdl_rightarm,'left_arm':kdl_leftarm}
00170 
00171     def FK_kdl(self, arm, q, link_number):
00172         fk_solver = self.cody_kdl[arm]['fk_p']
00173         endeffec_frame = kdl.Frame()
00174         kinematics_status = fk_solver.JntToCart(q, endeffec_frame,
00175                                                 link_number)
00176         if kinematics_status >= 0:
00177 #            print 'End effector transformation matrix:', endeffec_frame
00178             return endeffec_frame
00179         else:
00180             print 'Could not compute forward kinematics.'
00181             return None
00182 
00183     def Jac_kdl(self,arm,q):
00184         ''' returns the Jacobian, given the joint angles
00185         '''
00186         J_kdl = kdl.Jacobian(7)
00187         self.cody_kdl[arm]['jacobian_solver'].JntToJac(q,J_kdl)
00188 
00189         kdl_jac =  np.matrix([
00190             [J_kdl[0,0],J_kdl[0,1],J_kdl[0,2],J_kdl[0,3],J_kdl[0,4],J_kdl[0,5],J_kdl[0,6]],
00191             [J_kdl[1,0],J_kdl[1,1],J_kdl[1,2],J_kdl[1,3],J_kdl[1,4],J_kdl[1,5],J_kdl[1,6]],
00192             [J_kdl[2,0],J_kdl[2,1],J_kdl[2,2],J_kdl[2,3],J_kdl[2,4],J_kdl[2,5],J_kdl[2,6]],
00193             [J_kdl[3,0],J_kdl[3,1],J_kdl[3,2],J_kdl[3,3],J_kdl[3,4],J_kdl[3,5],J_kdl[3,6]],
00194             [J_kdl[4,0],J_kdl[4,1],J_kdl[4,2],J_kdl[4,3],J_kdl[4,4],J_kdl[4,5],J_kdl[4,6]],
00195             [J_kdl[5,0],J_kdl[5,1],J_kdl[5,2],J_kdl[5,3],J_kdl[5,4],J_kdl[5,5],J_kdl[5,6]],
00196             ])
00197         return kdl_jac
00198         
00199     def IK_kdl(self,arm,frame, q_init):
00200         ''' IK, returns jointArray (None if impossible)
00201             frame - desired frame of the end effector
00202             q_init - initial guess for the joint angles. (JntArray)
00203         '''
00204         nJnts = self.cody_kdl[arm]['nJnts']
00205         ik_solver = self.cody_kdl[arm]['ik_p']
00206         q = kdl.JntArray(nJnts)
00207         if ik_solver.CartToJnt(q_init,frame,q)>=0:
00208             for i in range(nJnts):
00209                 q[i] = tr.angle_within_mod180(q[i])
00210             return q
00211         else:
00212             if arm == 'right_arm':
00213                 ik_solver = self.cody_kdl[arm]['ik_p_nolim']
00214                 if ik_solver.CartToJnt(q_init,frame,q)>=0:
00215                     for i in range(nJnts):
00216                         q[i] = tr.angle_within_mod180(q[i])
00217                     return q
00218             print 'Error: could not calculate inverse kinematics'
00219             return None
00220 
00221     def FK_rot(self, arm, q, link_number = 7):
00222         pos, rot = self.FK_all(arm, q, link_number)
00223         return rot
00224 
00225     # @param arm - 'left_arm' or 'right_arm'
00226     # @param q - list of 7 joint angles (RADIANs)
00227     # @param link_number - perform FK up to this link. (1-7)
00228     # @return 3x1 numpy matrix
00229     def FK(self, arm, q, link_number = 7):
00230         pos, rot = self.FK_all(arm, q, link_number)
00231         return pos
00232 
00233     def FK_all(self, arm, q, link_number = 7):
00234         q = self.meka_angles_to_kdl(arm, q)
00235         frame = self.FK_kdl(arm, q, link_number)
00236         pos = frame.p
00237         pos = ku.kdl_vec_to_np(pos)
00238         m = frame.M
00239         rot = ku.kdl_rot_to_np(m)
00240         return pos, rot
00241 
00242     def Jac(self,arm,q):
00243         ''' q - list of 7 joint angles (meka axes) in RADIANS.
00244             arm - 'right_arm' or 'left_arm'
00245             returns 6x7 numpy matrix.
00246         '''
00247         jntarr = self.meka_angles_to_kdl(arm,q)
00248         kdl_jac = self.Jac_kdl(arm,jntarr)
00249         meka_jac = -kdl_jac  # the kdl jacobian is the negative of meka jacobian (see kdl_angles_to_meka)
00250         return meka_jac
00251 
00252     ## compute Jacobian at point pos.
00253     # p is in the torso_lift_link coord frame.
00254     def Jacobian(self, arm, q, pos):
00255         chain = self.cody_kdl[arm]['chain']
00256         v_list = []
00257         w_list = []
00258         for i in range(self.n_joints):
00259             p, rot = self.FK_all(arm, q, i)
00260             r = pos - p
00261             z_idx = chain.getSegment(i).getJoint().getType() - 1
00262             z = rot[:, z_idx]
00263             v_list.append(np.matrix(np.cross(z.A1, r.A1)).T)
00264             w_list.append(z)
00265 
00266         J = np.row_stack((np.column_stack(v_list), np.column_stack(w_list)))
00267         #J = -J # the kdl jacobian is the negative of meka jacobian (see kdl_angles_to_meka)
00268         J = self.Jac(arm, q)
00269         return J
00270 
00271     ##
00272     # Inverse Kinematics using KDL.
00273     # @param p - 3X1 numpy matrix.
00274     # @param rot - 3X3 numpy matrix. It transforms a  vector in the
00275     # end effector frame to the torso frame. (or it is the orientation
00276     # of the end effector wrt the torso)
00277     # @return list of 7 joint angles, or None if IK soln not found.
00278     def IK(self,arm,p,rot,q_guess=None):
00279         p_kdl = ku.np_vec_to_kdl(p)
00280         rot_kdl = ku.np_rot_to_kdl(rot)
00281         fr = kdl.Frame(rot_kdl,p_kdl)
00282 
00283         if q_guess == None:
00284             if arm == 'left_arm':
00285                 q_guess = cgd.find_good_config(p,self.q_guess_dict_left)
00286             elif arm == 'right_arm':    
00287                 q_guess = cgd.find_good_config(p,self.q_guess_dict_right)
00288 
00289         q_guess = self.meka_angles_to_kdl(arm,q_guess)
00290 
00291         q_res = self.IK_kdl(arm,fr,q_guess)
00292         q_res = self.kdl_angles_to_meka(arm,q_res)
00293 
00294         if self.within_joint_limits(arm,q_res):
00295             if arm == 'right_arm':  
00296                 if q_res[1]<0.:
00297                     q_res[1] = math.radians(10.)
00298                     qg = self.meka_angles_to_kdl(arm,q_res)
00299                     q_res = self.IK_kdl(arm,fr,qg)
00300                     q_res = self.kdl_angles_to_meka(arm,q_res)
00301                 if self.within_joint_limits(arm,q_res):
00302                     return q_res
00303                 else:
00304                     return None
00305             else:
00306                 return q_res
00307         else:
00308             return None
00309 
00310     ## clamp joint angles to their physical limits.
00311     # @param arm - 'left_arm' or 'right_arm'
00312     # @param q - list of 7 joint angles.
00313     # The joint limits for IK are larger that the physical limits.
00314     def clamp_to_joint_limits(self, arm, q, delta_list=[0.,0.,0.,0.,0.,0.,0.]):
00315         d = self.joint_lim_dict[arm]
00316         max_arr = d['max']
00317         min_arr = d['min']
00318         q_arr = np.array(q)
00319         d_arr = np.array(delta_list)
00320         return np.clip(q_arr, min_arr-d_arr, max_arr+d_arr)
00321 
00322     def within_joint_limits(self, arm, q, delta_list=[0.,0.,0.,0.,0.,0.,0.]):
00323         d = self.joint_lim_dict[arm]
00324         max_arr = d['max']
00325         min_arr = d['min']
00326         q_arr = np.array(q)
00327         d_arr = np.array(delta_list)
00328         return np.all((q_arr <= max_arr+d_arr, q_arr >= min_arr-d_arr))
00329 
00330 
00331 
00332 
00333 if __name__ == '__main__':
00334     import roslib; roslib.load_manifest('hrl_cody_arms')
00335     import hrl_cody_arms.cody_arm_kinematics as cak
00336 
00337     h = M3HrlRobot(0.16)
00338     k = cak.CodyArmKinematics('r')
00339     p = np.matrix([0., 0., -0.16]).T
00340     k.set_tooltip(p)
00341 
00342     J_old = h.Jacobian
00343 
00344 
00345 
00346 
00347 
00348 


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