$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 = 'collect_data_node' 00058 import roslib; roslib.load_manifest(PKG) 00059 import rospy 00060 00061 import message_filters 00062 from sensor_msgs.msg import * 00063 from cob_calibration_msgs.msg import * 00064 from cv_bridge import CvBridge, CvBridgeError 00065 00066 from cob_calibration_srvs.srv import * 00067 from cob_camera_calibration import Checkerboard, CheckerboardDetector, cv2util 00068 00069 CHECKERBOARD_PATTERN_SIZE = (9,6) 00070 CHECKERBOARD_SQUARE_SIZE = 0.03 00071 CHECKERBOARD_NAME = "cb_9x6" 00072 CHECKERBOARD_CHAIN = "arm_chain" 00073 00074 class DataCollector(): 00075 ''' 00076 @summary: Collects data for robot calibration. 00077 00078 Subscribes to various topics needed (e.g. images, camera infos, joint angles) and 00079 provides a service. When service is called, a set of samples is recorded, 00080 processed (e.g. checkerboards are detected) and combined to a RobotMeasurement message 00081 which is published as /robot_measurement. 00082 ''' 00083 00084 def __init__(self): 00085 ''' 00086 Set up subscribers, publishers and local storage 00087 ''' 00088 rospy.init_node(NODE) 00089 print "==> %s started " % NODE 00090 00091 # get joint names for arm 00092 if rospy.has_param("arm_controller/joint_names"): # real hardware 00093 self.arm_joint_names = rospy.get_param("arm_controller/joint_names") 00094 elif rospy.has_param("arm_controller/joints"): # simulation 00095 self.arm_joint_names = rospy.get_param("arm_controller/joints") 00096 else: 00097 print "Could not get joint names for arm from parameter server. exiting..." 00098 exit(-1) 00099 00100 # get joint names for torso 00101 if rospy.has_param("torso_controller/joint_names"): # real hardware 00102 self.torso_joint_names = rospy.get_param("torso_controller/joint_names") 00103 elif rospy.has_param("torso_controller/joints"): # simulation 00104 self.torso_joint_names = rospy.get_param("torso_controller/joints") 00105 else: 00106 print "Could not get joint names for torso from parameter server. exiting..." 00107 exit(-1) 00108 00109 # CvBridge 00110 self.bridge = CvBridge() 00111 00112 # initialize private storage 00113 self._arm_joint_msg_received = False 00114 self._arm_joint_msg = None 00115 self._torso_joint_msg_received = False 00116 self._torso_joint_msg = None 00117 self._left = {} 00118 self._left_received = False 00119 self._right = {} 00120 self._right_received = False 00121 self._kinect_rgb = {} 00122 self._kinect_rgb_received = False 00123 self.counter = 1 00124 00125 # init publisher / subscriber 00126 self._robot_measurement_pub = rospy.Publisher("/robot_measurement", RobotMeasurement) 00127 self._image_pub_left = rospy.Publisher("/robot_measurement_image_left", Image) #DEBUG 00128 self._image_pub_right = rospy.Publisher("/robot_measurement_image_right", Image) #DEBUG 00129 self._image_pub_kinect_rgb = rospy.Publisher("/robot_measurement_image_kinect_rgb", Image) #DEBUG 00130 self._sub_joint_states = rospy.Subscriber( "/joint_states", JointState, self._callback_joints) 00131 00132 # left camera 00133 self._sub_left_info = message_filters.Subscriber("/stereo/left/camera_info", CameraInfo) 00134 self._sub_left_image_color = message_filters.Subscriber("/stereo/left/image_rect_color", Image) 00135 self._sub_left_image_rect = message_filters.Subscriber("/stereo/left/image_rect", Image) 00136 self._sub_left = message_filters.TimeSynchronizer([self._sub_left_info, 00137 self._sub_left_image_color, 00138 self._sub_left_image_rect], 15) 00139 self._sub_left.registerCallback(self._callback_left) 00140 00141 # right camera 00142 self._sub_right_info = message_filters.Subscriber("/stereo/right/camera_info", CameraInfo) 00143 self._sub_right_image_color = message_filters.Subscriber("/stereo/right/image_rect_color", Image) 00144 self._sub_right_image_rect = message_filters.Subscriber("/stereo/right/image_rect", Image) 00145 self._sub_right = message_filters.TimeSynchronizer([self._sub_right_info, 00146 self._sub_right_image_color, 00147 self._sub_right_image_rect], 15) 00148 self._sub_right.registerCallback(self._callback_right) 00149 00150 # kinect rgb 00151 self._sub_kinect_rgb_info = message_filters.Subscriber("/cam3d/rgb/camera_info", CameraInfo) 00152 self._sub_kinect_rgb_image_color = message_filters.Subscriber("/cam3d/rgb/image_color", Image) 00153 self._sub_kinect_rgb = message_filters.TimeSynchronizer([self._sub_kinect_rgb_info, 00154 self._sub_kinect_rgb_image_color], 15) 00155 self._sub_kinect_rgb.registerCallback(self._callback_kinect_rgb) 00156 print "==> done with initialization" 00157 00158 def _callback_left(self, camera_info, image_color, image_rect): 00159 ''' 00160 Callback function for left camera message filter 00161 ''' 00162 #print "DEBUG: callback left" 00163 self._left["camera_info"] = camera_info 00164 self._left["image_color"] = image_color 00165 self._left["image_rect"] = image_rect 00166 # if self._left_received == False: 00167 # print "--> left sample received (this only prints once!)" 00168 self._left_received = True 00169 00170 def _callback_right(self, camera_info, image_color, image_rect): 00171 ''' 00172 Callback function for right camera message filter 00173 ''' 00174 #print "DEBUG: callback right" 00175 self._right["camera_info"] = camera_info 00176 self._right["image_color"] = image_color 00177 self._right["image_rect"] = image_rect 00178 # if self._right_received == False: 00179 # print "--> right sample received (this only prints once!)" 00180 self._right_received = True 00181 00182 def _callback_kinect_rgb(self, camera_info, image_color): 00183 ''' 00184 Callback function for kinect rgb message filter 00185 ''' 00186 #print "DEBUG: callback kinect_rgb" 00187 self._kinect_rgb["camera_info"] = camera_info 00188 self._kinect_rgb["image_color"] = image_color 00189 # if self._kinect_rgb_received == False: 00190 # print "--> kinect sample received (this only prints once!)" 00191 self._kinect_rgb_received = True 00192 00193 def _callback_joints(self, msg): 00194 ''' 00195 Callback function for joint angles messages 00196 ''' 00197 #print "DEBUG: callback joints" 00198 00199 # torso 00200 if self.torso_joint_names[0] in msg.name: 00201 pos = [] 00202 header = msg.header 00203 for name in self.torso_joint_names: 00204 pos.append(msg.position[msg.name.index(name)]) 00205 00206 # create JointState message 00207 joint_msg = JointState() 00208 joint_msg.header = msg.header 00209 joint_msg.name = self.torso_joint_names 00210 joint_msg.position = pos 00211 00212 # safe joint state msg 00213 self._torso_joint_msg = joint_msg 00214 # if self._torso_joint_msg_received == False: 00215 # print "--> torso joint state received (this only prints once!)" 00216 self._torso_joint_msg_received = True 00217 00218 # arm 00219 if self.arm_joint_names[0] in msg.name: 00220 pos = [] 00221 header = msg.header 00222 for name in self.arm_joint_names: 00223 pos.append(msg.position[msg.name.index(name)]) 00224 00225 # create JointState message 00226 joint_msg = JointState() 00227 joint_msg.header = msg.header 00228 joint_msg.name = self.arm_joint_names 00229 joint_msg.position = pos 00230 00231 # safe joint state msg 00232 self._arm_joint_msg = joint_msg 00233 # if self._arm_joint_msg_received == False: 00234 # print "--> arm joint state received (this only prints once!)" 00235 self._arm_joint_msg_received = True 00236 00237 def run(self): 00238 ''' 00239 Main method, starts service to provide capture functionality 00240 ''' 00241 rospy.sleep(1) 00242 00243 # Start service 00244 srv = rospy.Service('/collect_data/capture', Capture, self._collect) 00245 rospy.loginfo("service '/collect_data/capture' started, waiting for requests...") 00246 rospy.spin() 00247 00248 def _collect(self, data): 00249 ''' 00250 Executed on service call. Logs and calls _capture_and_pub 00251 ''' 00252 rospy.loginfo("capturing sample %.2i"%self.counter) 00253 res = self._capture_and_pub("sample%.2i"%self.counter, CHECKERBOARD_NAME, 00254 CHECKERBOARD_CHAIN, 00255 CHECKERBOARD_PATTERN_SIZE, 00256 CHECKERBOARD_SQUARE_SIZE) 00257 self.counter += 1 00258 return CaptureResponse(res) 00259 00260 def _capture_and_pub(self, sample_id, target_id, chain_id, pattern_size, square_size): 00261 ''' 00262 Main capturing function. Gets a set of recent messages for all needed topics. 00263 Processes messages and creates RobotMeasuerment message which is published. 00264 00265 @param sample_id: Sample identifier (e.g. sample01) 00266 @type sample_id: string 00267 00268 @param target_id: Name of checkerboard (e.g. cb_9x6) 00269 @type target_id: string 00270 00271 @param chain_id: Name of dh chain to which checkerboard is attached (e.g. arm_chain) 00272 @type chain_id: string 00273 00274 @param pattern_size: Size of checkerboard pattern as defined by opencv (e.g. (9, 6)) 00275 @type pattern_size: tuple(x, y) 00276 00277 @param square_size: Size of checkerboard sqaures (im m) 00278 @type square_size: float 00279 ''' 00280 # capture measurements 00281 # -------------------- 00282 self._left_received = False 00283 self._right_received = False 00284 self._kinect_rgb_received = False 00285 start_time = rospy.Time.now() 00286 while (not self._left_received or not self._right_received or not self._kinect_rgb_received): 00287 rospy.sleep(0.005) 00288 # print warning every 2 seconds if one of the messages is still missing... 00289 if start_time + rospy.Duration(2.0) < rospy.Time.now(): 00290 if not self._left_received: print "--> still waiting for sample from left" 00291 if not self._right_received: print "--> still waiting for sample from right" 00292 if not self._kinect_rgb_received: print "--> still waiting for sample from kinect" 00293 start_time = rospy.Time.now() 00294 latest_left = self._left 00295 latest_right = self._right 00296 latest_kinect_rgb = self._kinect_rgb 00297 00298 self._torso_joint_msg_received = False 00299 self._arm_joint_msg_received = False 00300 start_time = rospy.Time.now() 00301 while (not self._torso_joint_msg_received or not self._arm_joint_msg_received): 00302 rospy.sleep(0.005) 00303 # print warning every 2 seconds if one of the messages is still missing... 00304 if start_time + rospy.Duration(2.0) < rospy.Time.now(): 00305 if not self._torso_joint_msg_received: print "--> still waiting for torso joint states" 00306 if not self._arm_joint_msg_received: print "--> still waiting for srm joint states" 00307 start_time = rospy.Time.now() 00308 latest_torso = self._torso_joint_msg 00309 latest_arm = self._arm_joint_msg 00310 00311 # set up checkerboard and checkerboard detector 00312 # --------------------------------------------- 00313 checkerboard = Checkerboard(pattern_size, square_size) 00314 checkerboard_detector = CheckerboardDetector(checkerboard) 00315 00316 # detect cb left 00317 # -------------- 00318 cvImage = self.bridge.imgmsg_to_cv(latest_left["image_rect"], "mono8") 00319 image = cv2util.cvmat2np(cvImage) 00320 00321 corners = checkerboard_detector.detect_image_points(image, is_grayscale=True) 00322 if corners != None: 00323 print "cb found: left" 00324 img_points_left = [] 00325 for (x, y) in corners.reshape(-1, 2): 00326 img_points_left.append(ImagePoint(x, y)) 00327 else: 00328 # cb not found 00329 return False 00330 00331 # create camera msg left 00332 # ---------------------- 00333 cam_msg_left = CameraMeasurement() 00334 cam_msg_left.camera_id = "left" 00335 cam_msg_left.header.stamp = latest_left["camera_info"].header.stamp 00336 cam_msg_left.cam_info = latest_left["camera_info"] 00337 cam_msg_left.image_points = img_points_left 00338 cam_msg_left.verbose = False 00339 #cam_ms_leftg.image = latest_left["image_color"] 00340 #cam_msg_left.image_rect = latest_left["image_rect"] 00341 #cam_msg_left.features = # Not implemented here 00342 00343 # detect cb right 00344 # -------------- 00345 cvImage = self.bridge.imgmsg_to_cv(latest_right["image_rect"], "mono8") 00346 image = cv2util.cvmat2np(cvImage) 00347 00348 corners = checkerboard_detector.detect_image_points(image, is_grayscale=True) 00349 if corners != None: 00350 print "cb found: right" 00351 img_points_right = [] 00352 for (x, y) in corners.reshape(-1, 2): 00353 img_points_right.append(ImagePoint(x, y)) 00354 else: 00355 # cb not found 00356 return False 00357 00358 # create camera msg right 00359 # ----------------------- 00360 cam_msg_right = CameraMeasurement() 00361 cam_msg_right.camera_id = "right" 00362 cam_msg_right.header.stamp = latest_right["camera_info"].header.stamp 00363 cam_msg_right.cam_info = latest_right["camera_info"] 00364 cam_msg_right.image_points = img_points_right 00365 cam_msg_right.verbose = False 00366 #cam_msg_right.image = latest_right["image_color"] 00367 #cam_msg_right.image_rect = latest_right["image_rect"] 00368 #cam_msg_right.features = # Not implemented here 00369 00370 # detect cb kinect_rgb 00371 # -------------------- 00372 cvImage = self.bridge.imgmsg_to_cv(latest_kinect_rgb["image_color"], "mono8") 00373 image = cv2util.cvmat2np(cvImage) 00374 00375 corners = checkerboard_detector.detect_image_points(image, is_grayscale=True) 00376 if corners != None: 00377 print "cb found: kinect_rgb" 00378 img_points_kinect_rgb = [] 00379 for (x, y) in corners.reshape(-1, 2): 00380 img_points_kinect_rgb.append(ImagePoint(x, y)) 00381 else: 00382 # cb not found 00383 return False 00384 00385 # create camera msg kinect_rgb 00386 # ---------------------------- 00387 cam_msg_kinect_rgb = CameraMeasurement() 00388 cam_msg_kinect_rgb.camera_id = "kinect_rgb" 00389 cam_msg_kinect_rgb.header.stamp = latest_kinect_rgb["camera_info"].header.stamp 00390 cam_msg_kinect_rgb.cam_info = latest_kinect_rgb["camera_info"] 00391 cam_msg_kinect_rgb.image_points = img_points_kinect_rgb 00392 cam_msg_kinect_rgb.verbose = False 00393 #cam_ms_kinect_rgbg.image = latest_kinect_rgb["image_color"] 00394 #cam_msg_kinect_rgb.image_rect = latest_kinect_rgb["image_rect"] 00395 #cam_msg_kinect_rgb.features = # Not implemented here 00396 00397 # create torso_chain msg 00398 # ---------------------- 00399 torso_chain_msg = ChainMeasurement() 00400 torso_chain_msg.header = latest_torso.header 00401 torso_chain_msg.chain_id = "torso_chain" 00402 torso_chain_msg.chain_state = latest_torso 00403 00404 # create arm_chain msg 00405 # -------------------- 00406 arm_chain_msg = ChainMeasurement() 00407 arm_chain_msg.header = latest_arm.header 00408 arm_chain_msg.chain_id = "arm_chain" 00409 arm_chain_msg.chain_state = latest_arm 00410 00411 # DEBUG publish pic 00412 # ----------------- 00413 self._image_pub_left.publish(latest_left["image_color"]) 00414 self._image_pub_right.publish(latest_right["image_color"]) 00415 self._image_pub_kinect_rgb.publish(latest_kinect_rgb["image_color"]) 00416 00417 # create robot measurement msg and publish 00418 # ----------------- 00419 robot_msg = RobotMeasurement() 00420 robot_msg.sample_id = sample_id 00421 robot_msg.target_id = target_id 00422 robot_msg.chain_id = chain_id 00423 robot_msg.M_cam = [cam_msg_left, cam_msg_right, cam_msg_kinect_rgb] 00424 robot_msg.M_chain = [torso_chain_msg, arm_chain_msg] 00425 self._robot_measurement_pub.publish(robot_msg) 00426 00427 return True 00428 00429 00430 if __name__ == "__main__": 00431 collector = DataCollector() 00432 collector.run()