$search
00001 #!/usr/bin/env python 00002 ################################################################# 00003 ##\file 00004 # 00005 # \note 00006 # Copyright (c) 2011-2012 \n 00007 # Fraunhofer Institute for Manufacturing Engineering 00008 # and Automation (IPA) \n\n 00009 # 00010 ################################################################# 00011 # 00012 # \note 00013 # Project name: care-o-bot 00014 # \note 00015 # ROS stack name: cob_calibration 00016 # \note 00017 # ROS package name: cob_calibration_executive 00018 # 00019 # \author 00020 # Author: Sebastian Haug, email:sebhaug@gmail.com 00021 # \author 00022 # Supervised by: Florian Weisshardt, email:florian.weisshardt@ipa.fhg.de 00023 # 00024 # \date Date of creation: January 2012 00025 # 00026 ################################################################# 00027 # 00028 # Redistribution and use in source and binary forms, with or without 00029 # modification, are permitted provided that the following conditions are met: 00030 # 00031 # - Redistributions of source code must retain the above copyright 00032 # notice, this list of conditions and the following disclaimer. \n 00033 # - Redistributions in binary form must reproduce the above copyright 00034 # notice, this list of conditions and the following disclaimer in the 00035 # documentation and/or other materials provided with the distribution. \n 00036 # - Neither the name of the Fraunhofer Institute for Manufacturing 00037 # Engineering and Automation (IPA) nor the names of its 00038 # contributors may be used to endorse or promote products derived from 00039 # this software without specific prior written permission. \n 00040 # 00041 # This program is free software: you can redistribute it and/or modify 00042 # it under the terms of the GNU Lesser General Public License LGPL as 00043 # published by the Free Software Foundation, either version 3 of the 00044 # License, or (at your option) any later version. 00045 # 00046 # This program is distributed in the hope that it will be useful, 00047 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00048 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00049 # GNU Lesser General Public License LGPL for more details. 00050 # 00051 # You should have received a copy of the GNU Lesser General Public 00052 # License LGPL along with this program. 00053 # If not, see <http://www.gnu.org/licenses/>. 00054 # 00055 ################################################################# 00056 PKG = 'cob_calibration_executive' 00057 NODE = 'arm_ik_node' 00058 import roslib; roslib.load_manifest(PKG) 00059 import rospy 00060 00061 import numpy as np 00062 import yaml 00063 from math import pi, sqrt 00064 00065 from simple_script_server import simple_script_server 00066 from kinematics_msgs.srv import GetPositionIK, GetPositionIKRequest 00067 from sensor_msgs.msg import JointState 00068 from geometry_msgs.msg import PoseStamped 00069 import tf 00070 00071 def getIk(arm_ik, (t, q), link, seed=None): 00072 ''' 00073 query arm_ik server for joint_position which put arm_7_link to pose (t, q) 00074 00075 @param arm_ik: arm_ik service proxy 00076 @param t: translation 00077 @param q: rotation as quaternion 00078 @param link: frame in which pose (t, q) is defined 00079 @param seed: initial joint positions for ik calculation, in None current joint pos of arm is used. 00080 00081 @return: tuple of joint_positions or None if ik was not found 00082 ''' 00083 # get joint names for arm from parameter server 00084 joint_names = None 00085 try: joint_names = rospy.get_param("arm_controller/joint_names") # real hardware 00086 except KeyError: pass 00087 try: joint_names = rospy.get_param("arm_controller/joints") # simulation 00088 except KeyError: pass 00089 if joint_names == None: 00090 print "Could not get arm joint_names from parameter server." 00091 return None 00092 00093 # if seed == None get current joint angles from arm as seed position 00094 if seed == None: 00095 seed = [] 00096 for tries in range(20): 00097 try: msg = rospy.wait_for_message("/joint_states", JointState) 00098 except rospy.exceptions.ROSInterruptException: pass 00099 if joint_names[0] in msg.name: 00100 # message is from arm, save current angles 00101 for name in joint_names: seed.append(msg.position[msg.name.index(name)]) 00102 break 00103 if seed == []: 00104 print "Could not get /joint_states message from arm controller. " 00105 return None 00106 assert len(seed) == len(joint_names) 00107 00108 # create and send ik request 00109 req = GetPositionIKRequest() 00110 req.timeout = rospy.Duration(1.0) 00111 req.ik_request.ik_link_name = "arm_7_link" 00112 req.ik_request.ik_seed_state.joint_state.position = seed 00113 req.ik_request.ik_seed_state.joint_state.name = joint_names 00114 req.ik_request.pose_stamped.header.frame_id = link 00115 req.ik_request.pose_stamped.pose.position.x = t[0] 00116 req.ik_request.pose_stamped.pose.position.y = t[1] 00117 req.ik_request.pose_stamped.pose.position.z = t[2] 00118 req.ik_request.pose_stamped.pose.orientation.x = q[0] 00119 req.ik_request.pose_stamped.pose.orientation.y = q[1] 00120 req.ik_request.pose_stamped.pose.orientation.z = q[2] 00121 req.ik_request.pose_stamped.pose.orientation.w = q[3] 00122 00123 # try to get inverse kinecmatics for at least 3 times 00124 for i in range(3): 00125 resp = arm_ik(req) 00126 if resp.error_code.val == resp.error_code.SUCCESS: 00127 break 00128 00129 # report sucess or return None on error 00130 if resp.error_code.val == resp.error_code.SUCCESS: 00131 result = list(resp.solution.joint_state.position) 00132 return result 00133 else: 00134 print "Inverse kinematics request failed with error code", resp.error_code.val, ", seed was", seed 00135 return None 00136 00137 def tadd(t1, t2): 00138 ''' 00139 Shortcut function to add two translations t1 and t2 00140 ''' 00141 return map(lambda (t1x, t2x): t1x+t2x, zip(t1, t2)) 00142 00143 def qmult(q1, q2): 00144 ''' 00145 Shortcut function to multiply two quaternions q1 and q2 00146 ''' 00147 return tuple(tf.transformations.quaternion_multiply(q1, q2)) 00148 00149 def rpy2q(r, p, y, axes=None): 00150 ''' 00151 Shortcut function to convert rpy to quaternion 00152 ''' 00153 if axes == None: 00154 return tuple(tf.transformations.quaternion_from_euler(r, p, y)) 00155 else: 00156 return tuple(tf.transformations.quaternion_from_euler(r, p, y, axes)) 00157 00158 # main 00159 def main(): 00160 rospy.init_node(NODE) 00161 print "==> started " + NODE 00162 00163 # init 00164 arm_ik = rospy.ServiceProxy('/arm_kinematics/get_ik', GetPositionIK) 00165 00166 # translation and rotation for main calibration position 00167 # ------------------------------------------------------ 00168 t_calib = (-0.73, 0.0, 1.05) 00169 t_calib_handeye = (-0.777, -0.016, 1.006) 00170 q_calib = (0, 0, sqrt(2), -sqrt(2)) 00171 00172 # define translations 00173 # ------------------- 00174 t_c = tadd(t_calib, ( 0.12, 0.00, 0.00)) # closer 00175 t_cr = tadd(t_calib, ( 0.10, -0.05, 0.00)) # closer right 00176 t_f = tadd(t_calib, (-0.05, 0.00, 0.00)) # further 00177 t_f1 = tadd(t_calib, (-0.10, 0.00, 0.00)) # further more 00178 t_r = tadd(t_calib, ( 0.00, -0.05, 0.00)) # right 00179 t_l = tadd(t_calib, ( 0.00, 0.05, 0.00)) # left 00180 t_t = tadd(t_calib, ( 0.00, 0.00, 0.15)) # top 00181 t_b = tadd(t_calib, ( 0.00, 0.00, -0.15)) # bottom 00182 t_tr = tadd(t_calib, ( 0.00, -0.15, 0.15)) # top right 00183 t_tl = tadd(t_calib, ( 0.00, 0.10, 0.15)) # top left 00184 t_br = tadd(t_calib, ( 0.00, -0.15, -0.15)) # bottom right 00185 t_bl = tadd(t_calib, ( 0.00, 0.10, -0.13)) # bottom left 00186 00187 # define translations (robot calibration) 00188 # --------------------------------------- 00189 t_rob_tr = tadd(t_calib, ( 0.00, -0.10, 0.12)) # top right 00190 t_rob_tl = tadd(t_calib, ( 0.00, 0.05, 0.12)) # top left 00191 t_rob_br = tadd(t_calib, ( 0.00, -0.10, -0.12)) # bottom right 00192 t_rob_bl = tadd(t_calib, ( 0.00, 0.05, -0.12)) # bottom left 00193 00194 t_rob_rr = tadd(t_calib, ( 0.05, -0.175, -0.02)) # right right 00195 t_rob_ll = tadd(t_calib, ( 0.05, 0.175, -0.02)) # left left 00196 t_rob_brr = tadd(t_calib, ( 0.05, -0.125, -0.12)) # bottom right right 00197 t_rob_bll = tadd(t_calib, ( 0.05, 0.125, -0.12)) # bottom left left 00198 00199 t_rob_bb = tadd(t_calib, ( 0.00, 0.0, -0.33)) # bottom bottom 00200 00201 # define quaternions 00202 # ------------------ 00203 q_a = qmult(q_calib, rpy2q( pi/6, 0, 0)) # tilt away 00204 q_as1 = qmult(q_calib, rpy2q( pi/12, pi/10, 0)) # tilt away side 1 00205 q_as2 = qmult(q_calib, rpy2q( pi/8, -pi/8, 0)) # tilt away side 2 00206 q_as2m = qmult(q_calib, rpy2q( pi/8, -pi/4, 0)) # tilt away side 2 more 00207 q_n = qmult(q_calib, rpy2q(-pi/6, 0, 0)) # tilt near 00208 q_ns1 = qmult(q_calib, rpy2q(-pi/8, pi/10, 0)) # tilt near side 1 00209 q_ns2 = qmult(q_calib, rpy2q(-pi/8, -pi/8, 0)) # tilt near side 2 00210 q_ns2m = qmult(q_calib, rpy2q(-pi/6, -pi/8, 0)) # tilt near side 2 more 00211 00212 # generate poses from defined translations and positions 00213 # ------------------------------------------------------ 00214 poses = {} 00215 00216 # hand eye calibration pose 00217 poses["calibration"] = (t_calib_handeye, q_calib) 00218 00219 # stereo camera intrinsic calibration poses 00220 poses["intrinsic_00"] = (t_calib, q_calib) 00221 poses["intrinsic_01"] = (t_r, q_as1) 00222 poses["intrinsic_02"] = (t_l, q_as2) 00223 poses["intrinsic_03"] = (t_calib, q_ns1) 00224 poses["intrinsic_04"] = (t_calib, q_ns2) 00225 poses["intrinsic_05"] = (t_c, q_a) 00226 poses["intrinsic_06"] = (t_cr, q_n) 00227 poses["intrinsic_07"] = (t_f1, q_as2m) 00228 poses["intrinsic_08"] = (t_f, q_ns2m) 00229 poses["intrinsic_09"] = (t_tr, q_as1) 00230 poses["intrinsic_10"] = (t_tl, q_as2) 00231 poses["intrinsic_11"] = (t_bl, q_as2) 00232 poses["intrinsic_12"] = (t_br, q_as1) 00233 00234 # robot calibration poses 00235 poses["robot_center_00"] = (t_calib, q_calib) 00236 poses["robot_center_01"] = (t_r, q_as1) 00237 poses["robot_center_02"] = (t_l, q_as2) 00238 poses["robot_center_03"] = (t_calib, q_ns1) 00239 poses["robot_center_04"] = (t_calib, q_ns2) 00240 poses["robot_center_05"] = (t_c, q_a) 00241 poses["robot_center_06"] = (t_c, q_n) 00242 poses["robot_center_07"] = (t_f1, q_as2m) 00243 poses["robot_center_08"] = (t_f, q_ns2m) 00244 poses["robot_center_09"] = (t_rob_tr, q_as1) 00245 poses["robot_center_10"] = (t_rob_tl, q_as2) 00246 poses["robot_center_11"] = (t_rob_bl, q_as2) 00247 poses["robot_center_12"] = (t_rob_br, q_as1) 00248 00249 # NOTE: in keys left and right are defined like the torso 00250 poses["robot_right_00"] = (t_rob_ll, q_calib) 00251 poses["robot_right_01"] = (t_rob_ll, q_as1) 00252 poses["robot_right_02"] = (t_rob_bll, q_as2) 00253 00254 poses["robot_left_00"] = (t_rob_rr, q_calib) 00255 poses["robot_left_01"] = (t_rob_rr, q_as2) 00256 poses["robot_left_02"] = (t_rob_brr, q_as1) 00257 00258 poses["robot_back_00"] = (t_rob_bb, q_a) 00259 poses["robot_back_01"] = (t_rob_bb, q_as2) 00260 poses["robot_back_02"] = (t_rob_bb, q_as1) 00261 00262 00263 # converting to joint_positions 00264 # ----------------------------- 00265 print "==> converting poses to joint_states" 00266 # stable seed for center position 00267 # IMPORTANT: adjust this to something reasonable if you change the main t_calib, q_calib position 00268 prev_state = [0.13771, -1.61107, 1.60103, -0.90346, 2.30279, -1.28408, -0.93369] 00269 00270 arm_states = {} 00271 for key in sorted(poses.keys()): 00272 print "--> calling getIk for '%s'" % key 00273 00274 # query ik server for ik solution: 00275 # use previous joint angles as inital seed, if this fails 00276 # use current arm position and finally try zero position 00277 for seed in [prev_state, None, [0,0,0,0,0,0,0]]: 00278 joint_positions = getIk(arm_ik, poses[key], "base_link", seed) 00279 if joint_positions != None: 00280 arm_states[key] = [joint_positions] 00281 # remember current position as prev positions for next ik call 00282 prev_state = joint_positions 00283 break 00284 else: 00285 print "--> ERROR no IK solution was found..." 00286 00287 # convert to yaml_string manually (easier to achieve compact notation) 00288 # -------------------------------------------------------------------- 00289 yaml_string = "" 00290 for key in sorted(arm_states.keys()): 00291 # set prcision to 5 digits 00292 tmp = map(lambda x: "%.5f"%x, arm_states[key][0]) 00293 yaml_string += "%s: [[%s]]\n" % (key, ', '.join(tmp)) 00294 00295 # manually add group trajectories 00296 yaml_string += '''all_intrinsic: ["intrinsic_00", "intrinsic_01", "intrinsic_02", "intrinsic_03", "intrinsic_04", "intrinsic_05", "intrinsic_06", "intrinsic_07", "intrinsic_08", "intrinsic_09", "intrinsic_10", "intrinsic_11", "intrinsic_12"]\n''' 00297 yaml_string += '''all_robot_center: ["robot_center_00", "robot_center_01", "robot_center_02", "robot_center_03", "robot_center_04", "robot_center_05", "robot_center_06", "robot_center_07", "robot_center_08", "robot_center_09", "robot_center_10", "robot_center_11", "robot_center_12"]\n''' 00298 yaml_string += '''all_robot_left: ["robot_left_00", "robot_left_01", "robot_left_02"]\n''' 00299 yaml_string += '''all_robot_right: ["robot_right_00", "robot_right_01", "robot_right_02"]\n''' 00300 yaml_string += '''all_robot_back: ["robot_back_00", "robot_back_01", "robot_back_02"]\n''' 00301 00302 # print joint angles 00303 print "==> RESULT: joint_positions, please add to config/ROBOT/arm_joint_configurations.yaml" 00304 print yaml_string 00305 00306 # # DEBUG move arm 00307 # # -------------- 00308 # sss = simple_script_server() 00309 # print "==> moving arm" 00310 # for key in sorted(arm_states.keys()): 00311 # print "--> moving to '%s'" % key 00312 # sss.move("arm", arm_states[key]) 00313 # sss.wait_for_input() 00314 00315 if __name__ == '__main__': 00316 main() 00317 rospy.signal_shutdown(rospy.Time.now()) 00318 print "==> done exiting"