00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 import roslib; roslib.load_manifest('calibration_launch')
00035 import rospy
00036 import yaml
00037 import sys
00038 import actionlib
00039 import joint_states_settler.msg
00040 import time
00041 import threading
00042 import os
00043 import string
00044
00045 import capture_executive
00046 from capture_executive.config_manager import ConfigManager
00047 from capture_executive.sensor_managers import *
00048 from capture_executive.robot_measurement_cache import RobotMeasurementCache
00049
00050 from calibration_msgs.msg import RobotMeasurement
00051
00052
00053 roslib.load_manifest('calibration_estimation')
00054 from urdf_python.urdf import *
00055
00056
00057 class CaptureExecutive:
00058 def __init__(self, config_dir, system, robot_desc, output_debug=False):
00059
00060 self.cam_config = yaml.load(open(config_dir + "/cam_config.yaml"))
00061 self.chain_config = yaml.load(open(config_dir + "/chain_config.yaml"))
00062 self.laser_config = yaml.load(open(config_dir + "/laser_config.yaml"))
00063 self.controller_config = yaml.load(open(config_dir + "/controller_config.yaml"))
00064
00065 if self.laser_config == None:
00066 self.laser_config = dict()
00067
00068 self.output_debug = output_debug
00069
00070
00071 self.message = None
00072
00073
00074 self.interval_status = None
00075
00076
00077 links = URDF().parse(robot_desc).links.keys()
00078
00079
00080 system = yaml.load(open(system))
00081
00082
00083 for cam in self.cam_config.keys():
00084 try:
00085 link = system['sensors']['rectified_cams'][cam]['frame_id']
00086 if not link in links:
00087 print 'URDF does not contain link [%s]. Removing camera [%s]' % (link, cam)
00088 del self.cam_config[cam]
00089 except:
00090 print 'System description does not contain camera [%s]' % cam
00091 del self.cam_config[cam]
00092
00093
00094 for chain in self.chain_config.keys():
00095 try:
00096 link = system['sensors']['chains'][chain]['tip']
00097 if not link in links:
00098 print 'URDF does not contain link [%s]. Removing chain [%s]' % (link, chain)
00099 del self.chain_config[chain]
00100 except:
00101 print 'System description does not contain chain [%s]' % chain
00102 del self.chain_config[chain]
00103
00104 self.cache = RobotMeasurementCache()
00105 self.lock = threading.Lock()
00106
00107
00108 self.active = False
00109
00110
00111 self.config_manager = ConfigManager(self.cam_config,
00112 self.chain_config,
00113 self.laser_config,
00114 self.controller_config)
00115
00116
00117 self.cam_managers = [ (cam_id, CamManager( cam_id, self.add_cam_measurement) ) for cam_id in self.cam_config.keys() ]
00118 self.chain_managers = [ (chain_id, ChainManager(chain_id, self.add_chain_measurement) ) for chain_id in self.chain_config.keys() ]
00119 self.laser_managers = [ (laser_id, LaserManager(laser_id, self.add_laser_measurement) ) for laser_id in self.laser_config.keys() ]
00120
00121
00122 self.request_interval_sub = rospy.Subscriber("intersected_interval", calibration_msgs.msg.Interval, self.request_callback)
00123
00124
00125 self.interval_status_sub = rospy.Subscriber(
00126 "intersected_interval_status",
00127 calibration_msgs.msg.IntervalStatus, self.status_callback)
00128
00129
00130
00131
00132 def capture(self, next_configuration, timeout):
00133 done = False
00134 self.m_robot = None
00135 self.message = None
00136 self.interval_status = None
00137
00138 timeout_time = rospy.Time().now() + timeout
00139
00140 self.lock.acquire()
00141 if self.active:
00142 rospy.logerr("Can't capture since we're already active")
00143 done = True
00144 self.lock.release()
00145
00146 camera_measurements = next_configuration["camera_measurements"]
00147 next_configuration["camera_measurements"] = []
00148
00149 for (i, cam) in enumerate(camera_measurements):
00150 if self.cam_config.has_key(cam["cam_id"]):
00151 next_configuration["camera_measurements"].append(cam)
00152 else:
00153 rospy.logdebug("Not capturing measurement for camera: %s"%(cam["cam_id"]))
00154
00155
00156 self.config_manager.reconfigure(next_configuration)
00157
00158 time.sleep(2.0)
00159
00160
00161 cam_ids = [x["cam_id"] for x in next_configuration["camera_measurements"]]
00162 chain_ids = [x["chain_id"] for x in next_configuration["joint_measurements"]]
00163 try:
00164 laser_ids = [x["laser_id"] for x in next_configuration["laser_measurements"]]
00165 except:
00166 laser_ids = list()
00167 self.cache.reconfigure(cam_ids, chain_ids, laser_ids)
00168
00169 rospy.logdebug("Setting up sensor managers")
00170 enable_list = []
00171 disable_list = []
00172
00173 for cam_id, cam_manager in self.cam_managers:
00174 if cam_id in [x["cam_id"] for x in next_configuration["camera_measurements"]]:
00175 enable_list.append(cam_id)
00176 cam_manager.enable(self.output_debug)
00177 else:
00178 disable_list.append(cam_id)
00179 cam_manager.disable()
00180
00181 for chain_id, chain_manager in self.chain_managers:
00182 if chain_id in [x["chain_id"] for x in next_configuration["joint_measurements"]]:
00183 enable_list.append(chain_id)
00184 chain_manager.enable()
00185 else:
00186 disable_list.append(chain_id)
00187 chain_manager.disable()
00188
00189 for laser_id, laser_manager in self.laser_managers:
00190 enabled_lasers = [x["laser_id"] for x in next_configuration["laser_measurements"]]
00191 if laser_id in enabled_lasers:
00192 enable_list.append(laser_id)
00193 laser_manager.enable(self.output_debug)
00194 else:
00195 disable_list.append(laser_id)
00196 laser_manager.disable()
00197
00198 print "Enabling:"
00199 for cur_enabled in enable_list:
00200 print " + %s" % cur_enabled
00201 print "Disabling:"
00202 for cur_disabled in disable_list:
00203 print " - %s" % cur_disabled
00204
00205 self.lock.acquire()
00206 self.active = True
00207 self.lock.release()
00208
00209 print "\nCollecting sensor data.."
00210
00211 while (not rospy.is_shutdown()) and (not done) and (rospy.Time().now() < timeout_time):
00212 time.sleep(.1)
00213 self.lock.acquire()
00214 if self.m_robot is not None:
00215 done = True
00216 self.lock.release()
00217
00218 print "Stopping sensor streams..\n"
00219
00220 for cam_id, cam_manager in self.cam_managers:
00221 cam_manager.disable()
00222 for chain_id, chain_manager in self.chain_managers:
00223 chain_manager.disable()
00224 for laser_id, laser_manager in self.laser_managers:
00225 laser_manager.disable()
00226
00227
00228 self.config_manager.stop()
00229
00230
00231 if self.m_robot is not None:
00232 self.m_robot.sample_id = next_configuration["sample_id"]
00233 self.m_robot.target_id = next_configuration["target"]["target_id"]
00234 self.m_robot.chain_id = next_configuration["target"]["chain_id"]
00235 elif self.interval_status is not None:
00236 total = 0
00237 bad_sensors = []
00238 l = len(self.interval_status.names)
00239 if l != len(self.interval_status.yeild_rates):
00240 rospy.logerr("Invalid interval status message; names and yeild rates have different lengths")
00241 l = min(l, len(self.interval_status.yeild_rates))
00242
00243 for i in range(l):
00244 if self.interval_status.yeild_rates[i] == 0.0:
00245 bad_sensors.append(self.interval_status.names[i])
00246 total += self.interval_status.yeild_rates[i]
00247
00248
00249 if len(bad_sensors) > 0:
00250 print "Didn't get good data from %s"%(', '.join(bad_sensors))
00251 else:
00252
00253
00254 avg = total / l
00255 for i in range(l):
00256 if self.interval_status.yeild_rates[i] <= avg:
00257 bad_sensors.append(self.interval_status.names[i])
00258 print "%s may be performing poorly"%(", ".join(bad_sensors))
00259 elif self.message is not None:
00260 print self.message
00261
00262 self.lock.acquire()
00263 self.active = False
00264 self.lock.release()
00265
00266 return self.m_robot
00267
00268 def request_callback(self, msg):
00269
00270 if (msg.end - msg.start) < rospy.Duration(1,0):
00271 return
00272
00273 self.lock.acquire()
00274 if self.active:
00275
00276 m = self.cache.request_robot_measurement(msg.start, msg.end)
00277 if isinstance(m, basestring):
00278 self.message = m
00279 else:
00280 self.m_robot = m
00281
00282 if self.m_robot is not None:
00283 self.active = False
00284 self.lock.release()
00285
00286 def status_callback(self, msg):
00287 self.lock.acquire()
00288 if self.active:
00289 self.interval_status = msg
00290 self.lock.release()
00291
00292 def add_cam_measurement(self, cam_id, msg):
00293 if len(msg.image_points) > 0:
00294 self.lock.acquire()
00295 self.cache.add_cam_measurement(cam_id, msg)
00296 self.lock.release()
00297
00298 def add_chain_measurement(self, chain_id, msg):
00299 self.lock.acquire()
00300 self.cache.add_chain_measurement(chain_id, msg)
00301 self.lock.release()
00302
00303 def add_laser_measurement(self, laser_id, msg, interval_start, interval_end):
00304 self.lock.acquire()
00305 self.cache.add_laser_measurement(laser_id, msg, interval_start, interval_end)
00306 self.lock.release()
00307
00308 if __name__=='__main__':
00309 rospy.init_node("capture_executive_node")
00310
00311 rospy.logdebug("Starting executive...")
00312 rospy.sleep(5.0)
00313
00314
00315 samples_dir = rospy.myargv()[1]
00316 config_dir = rospy.myargv()[2]
00317 system = rospy.myargv()[3]
00318
00319 try:
00320 robot_description = rospy.get_param('robot_description')
00321 except:
00322 rospy.logfatal('robot_description not set, exiting')
00323 sys.exit(-1)
00324
00325 executive = CaptureExecutive(config_dir, system, robot_description)
00326 time.sleep(1.0)
00327
00328
00329 sample_steps = list()
00330 sample_names = dict()
00331 sample_options = dict()
00332 sample_success = dict()
00333 sample_failure = dict()
00334 for directory in os.listdir(samples_dir):
00335 try:
00336 sample_options[directory] = yaml.load(open(samples_dir + '/' + directory + '/config.yaml'))
00337 sample_steps.append(directory)
00338 except IOError:
00339 continue
00340 sample_names[directory] = [x for x in os.listdir(samples_dir + '/' + directory + '/') if '.yaml' in x and x != 'config.yaml']
00341 sample_names[directory].sort()
00342 sample_success[directory] = 0
00343 sample_failure[directory] = 0
00344 sample_steps.sort()
00345
00346 for step in sample_steps:
00347 rospy.logdebug("%s Samples: \n - %s" % (sample_options[step]['group'], "\n - ".join(sample_names[step])))
00348
00349 pub = rospy.Publisher("robot_measurement", RobotMeasurement)
00350
00351 try:
00352 for step in sample_steps:
00353 keep_collecting = True
00354 full_paths = [samples_dir + '/' + step + '/' + x for x in sample_names[step] ]
00355 cur_config = yaml.load(open(full_paths[0]))
00356 m_robot = executive.capture(cur_config, rospy.Duration(0.01))
00357 while not rospy.is_shutdown() and keep_collecting:
00358 print
00359 print sample_options[step]["prompt"]
00360 print "Press <enter> to continue, type N to exit this step"
00361 resp = raw_input(">>>")
00362 if string.upper(resp) == "N":
00363 print sample_options[step]["finish"]
00364 keep_collecting = False
00365 else:
00366 for cur_sample_path in full_paths:
00367 print "On %s sample [%s]" % (sample_options[step]["group"], cur_sample_path)
00368 cur_config = yaml.load(open(cur_sample_path))
00369 m_robot = executive.capture(cur_config, rospy.Duration(40))
00370 if m_robot is None:
00371 print "--------------- Failed To Capture a %s Sample -----------------" % sample_options[step]["group"]
00372 if not sample_options[step]["repeat"]:
00373 sample_failure[step] += 1
00374 else:
00375 print "++++++++++++++ Successfully Captured a %s Sample ++++++++++++++" % sample_options[step]["group"]
00376 sample_success[step] += 1
00377 pub.publish(m_robot)
00378 print "Succeeded on %u %s samples" % (sample_success[step], sample_options[step]["group"])
00379 if rospy.is_shutdown():
00380 break
00381 keep_collecting = sample_options[step]["repeat"]
00382 except EOFError:
00383 print "Exiting"
00384
00385 time.sleep(1)
00386
00387 print "Calibration data collection has completed!"
00388 for step in sample_steps:
00389 if sample_options[step]["repeat"]:
00390 print "%s Samples: %u" % (sample_options[step]["group"], sample_success[step])
00391 else:
00392 print "%s Samples: %u/%u" % (sample_options[step]["group"], sample_success[step], sample_success[step] + sample_failure[step])
00393 print ""
00394 print "You can now kill this node, along with any other calibration nodes that are running."
00395
00396