$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_robot_calibration 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_robot_calibration' 00057 NODE = 'update_cob_calibration_urdf' 00058 import roslib; roslib.load_manifest(PKG) 00059 import rospy 00060 import tf 00061 00062 import sys 00063 import yaml 00064 from math import pi 00065 from xml.dom import minidom, Node 00066 00067 from cob_robot_calibration_est import single_transform 00068 from cob_robot_calibration import calibration_urdf_updater 00069 00070 # Default values for files and debug output 00071 DEFAULT_CALIB_URDF_XACRO_IN = "/tmp/cal/calibration.urdf.xacro" 00072 DEFAULT_CALIB_URDF_XACRO_OUT = "/tmp/cal/calibration.urdf.xacro_updated" 00073 DEFAULT_YAML_CALIB_SYSTEM = "/tmp/cal/result_step_3.yaml" 00074 DEFAULT_YAML_INITIAL_SYSTEM = "/home/fmw-sh/git/cob_calibration/cob_robot_calibration/config/cob3-3/system.yaml" 00075 ENABLE_DEBUG_OUTPUT = False 00076 00077 class UpdateCobCalibrationUrdf(): 00078 ''' 00079 @summary: Updates calibration urdf file with calibration results 00080 00081 The results of the cob calibration process are read from the calibrated_system yaml 00082 file and propagated to the urdf robot calibration file. 00083 ''' 00084 00085 def __init__(self): 00086 ''' 00087 Get file locations from parameter server (or use defaults) and setup dictionary 00088 which specifies which values are updated. 00089 ''' 00090 rospy.init_node(NODE) 00091 print "==> started " + NODE 00092 00093 # get file names from parameter server 00094 self.file_urdf_in = rospy.get_param('~urdf_in', DEFAULT_CALIB_URDF_XACRO_IN) 00095 self.file_urdf_out = rospy.get_param('~urdf_out', DEFAULT_CALIB_URDF_XACRO_OUT) 00096 self.file_yaml_calib_system = rospy.get_param('~calib_system', DEFAULT_YAML_CALIB_SYSTEM) 00097 self.file_yaml_init_system = rospy.get_param('~initial_system', DEFAULT_YAML_INITIAL_SYSTEM) 00098 self.debug = rospy.get_param('~debug', ENABLE_DEBUG_OUTPUT) 00099 00100 # tfs2update stores the transform names [which need to be converted to (x, y, z, roll, pitch, yaw) 00101 # and updated in the urdf] and their corresponding property name prefixes as used in calibration.urdf.xarco 00102 self.tfs2update = {'arm_0_joint': 'arm_', 00103 'torso_0_joint': 'torso_', 00104 'head_color_camera_l_joint': 'cam_l_', 00105 #'head_color_camera_r_joint': 'cam_r_', 00106 'head_cam3d_rgb_optical_frame_joint': 'cam3d_'} 00107 00108 # chains2process stores the dh chain names of chains which need to be updated and their corresponding 00109 # property names/segments as used in calibration.urdf.xarco 00110 self.chains2update = {'arm_chain': ['arm_1_ref', 00111 'arm_2_ref', 00112 'arm_3_ref', 00113 'arm_4_ref', 00114 'arm_5_ref', 00115 'arm_6_ref', 00116 'arm_7_ref'], 00117 'torso_chain': ['torso_lower_neck_tilt_cal_offset', 00118 'torso_pan_cal_offset', 00119 'torso_upper_neck_tilt_cal_offset']} 00120 00121 def run(self): 00122 ''' 00123 Start the update process. Values are read from yaml files and are preprocessed for 00124 writing to xml 00125 ''' 00126 # load yaml files 00127 print "--> loading calibrated system from '%s'" % self.file_yaml_calib_system 00128 calib_system = yaml.load(file(self.file_yaml_calib_system)) 00129 print "--> loading initial system from '%s'" % self.file_yaml_init_system 00130 initial_system = yaml.load(file(self.file_yaml_init_system)) 00131 00132 attributes2update = {} 00133 00134 # process transforms 00135 for tf_name in self.tfs2update.keys(): 00136 prefix = self.tfs2update[tf_name] 00137 (x, y, z, roll, pitch, yaw) = self._convert_transform(calib_system['transforms'][tf_name]) 00138 00139 # add to attributes2update dict as "attribute name -> new_value" entries 00140 attributes2update[prefix+"x"] = round(x, 10) 00141 attributes2update[prefix+"y"] = round(y, 10) 00142 attributes2update[prefix+"z"] = round(z, 10) 00143 attributes2update[prefix+"roll"] = round(roll, 10) 00144 attributes2update[prefix+"pitch"] = round(pitch, 10) 00145 attributes2update[prefix+"yaw"] = round(yaw, 10) 00146 00147 # process dh chains 00148 for chain in self.chains2update: 00149 segments = self.chains2update[chain] 00150 for id in range(len(segments)): 00151 # process segment with id 00152 segment = segments[id] 00153 00154 # process segment of chain 00155 initial_value = initial_system["dh_chains"][chain]["dh"][id][0] # get initial theta value of segment for current chain 00156 calib_value = calib_system["dh_chains"][chain]["dh"][id][0] # get calibr. theta value of segment for current chain 00157 new_value = float(calib_value) - float(eval(str(initial_value))) 00158 new_value = round(new_value, 10) 00159 00160 # add to attributes2update dict as "attribute name -> new_value" entries 00161 attributes2update[segment] = new_value 00162 00163 # update calibration xml based on attributes2update dict 00164 urdf_updater = calibration_urdf_updater.CalibrationUrdfUpdater(self.file_urdf_in, self.file_urdf_out, self.debug) 00165 urdf_updater.update(attributes2update) 00166 00167 def _convert_transform(self, t): 00168 ''' 00169 Convert transform notation from (x, y, z, rotation_vector) as used in calibrated_system 00170 and initial_system to (x, y, z, roll, pitch, yaw) notation used in calibration.urdf.xacro 00171 00172 @param t: (x, y, z, rotation_vector) 00173 @type t: tuple 00174 00175 @return: (x, y, z, roll, pitch, yaw) 00176 @rtype: tuple 00177 ''' 00178 matrix = single_transform.SingleTransform(t).transform # convert to 4x4 transformation matrix 00179 roll, pitch, yaw = tf.transformations.euler_from_matrix(matrix) 00180 x, y, z = matrix[0,3], matrix[1,3], matrix[2,3] 00181 return (x, y, z, roll, pitch, yaw) 00182 00183 if __name__ == "__main__": 00184 # start main 00185 updateUrdf = UpdateCobCalibrationUrdf() 00186 updateUrdf.run() 00187 00188 # shutdown 00189 rospy.signal_shutdown(rospy.Time.now()) 00190 print "==> done! exiting..."