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 import roslib; roslib.load_manifest('tabletop_pushing')
00034 from geometry_msgs.msg import Point, Pose2D, Twist
00035 import tf.transformations as tr
00036 from push_primitives import *
00037 from tabletop_pushing.srv import *
00038 from tabletop_pushing.msg import *
00039 import rospy
00040 import cv2
00041 import numpy as np
00042 import sys
00043 from math import sin, cos, pi, sqrt, fabs, atan2, hypot, acos, isnan
00044
00045 import matplotlib.pyplot as plotter
00046 import random
00047 import os
00048 import subprocess
00049
00050 _VERSION_LINE = '# v0.6'
00051 _LEARN_TRIAL_HEADER_LINE = '# object_id/trial_id init_x init_y init_z init_theta final_x final_y final_z final_theta goal_x goal_y goal_theta push_start_point.x push_start_point.y push_start_point.z behavior_primitive controller proxy which_arm push_time precondition_method score [shape_descriptors]'
00052 _CONTROL_HEADER_LINE = '# x.x x.y x.theta x_dot.x x_dot.y x_dot.theta x_desired.x x_desired.y x_desired.theta theta0 u.linear.x u.linear.y u.linear.z u.angular.x u.angular.y u.angular.z time hand.x hand.y hand.z'
00053 _BAD_TRIAL_HEADER_LINE='#BAD_TRIAL'
00054 _DEBUG_IO = False
00055
00056 def subPIAngle(theta):
00057 while theta < -pi:
00058 theta += 2.0*pi
00059 while theta > pi:
00060 theta -= 2.0*pi
00061 return theta
00062
00063 def point_line_dist(pt, a, b):
00064 '''
00065 Get the perpendicular distance from pt to the line defined through (a,b)
00066 '''
00067 A = np.asarray(a)
00068 B = np.asarray(b)
00069 P = np.asarray(pt)
00070 q = A - P
00071 n = B-A
00072 n_hat = n / np.linalg.norm(n)
00073 return np.linalg.norm(q-np.dot(q,n_hat)*n_hat)
00074
00075 class PushTrial:
00076 def __init__(self):
00077 self.object_id = ''
00078 self.controller = ''
00079 self.behavior_primitive = ''
00080 self.proxy = ''
00081 self.which_arm = ''
00082 self.precondition_method = ''
00083 self.init_centroid = Point()
00084 self.init_orientation = 0.0
00085 self.final_centroid = Point()
00086 self.final_orientation = 0.0
00087 self.goal_pose = Pose2D()
00088 self.start_point = Point()
00089 self.push_time = 0.0
00090
00091 self.push_angle = 0.0
00092 self.push_dist = 0.0
00093 self.continuation = False
00094 self.score = -1.0
00095 self.shape_descriptor = []
00096
00097 def __str__(self):
00098 return (self.object_id +
00099 ' (' + self.proxy + ', ' + self.controller + ', ' + self.behavior_primitive + ', ' +
00100 self.which_arm + '_arm'+', ' +self.precondition_method+'):\n' +
00101 'init_centroid:\n' + str(self.init_centroid) + '\n'+
00102 'init_orientation: ' + str(self.init_orientation) +'\n'+
00103 'final_centroid:\n' + str(self.final_centroid) + '\n'+
00104 'final_orientation: ' + str(self.final_orientation) + '\n'+
00105 'goal_pose:\n' + str(self.goal_pose) + '\n'+
00106 'push_time: ' + str(self.push_time))
00107
00108 class ControlTimeStep:
00109 def __init__(self, x, x_dot, x_desired, theta0, u, t):
00110 self.x = x
00111 self.x_dot = x_dot
00112 self.x_desired = x_desired
00113 self.theta0 = theta0
00114 self.u = u
00115 self.t = t
00116
00117 class PushCtrlTrial:
00118 def __init__(self):
00119 self.trial_start = None
00120 self.trial_end = None
00121 self.trial_trajectory = []
00122
00123 def __str__(self):
00124 return (str(self.trial_start) + '\n' + str(self.trial_trajectory) + '\n' + str(self.trial_end))
00125
00126 class PushLearningIO:
00127 def __init__(self):
00128 self.data_out = None
00129 self.data_in = None
00130
00131 def write_line(self, init_centroid, init_orientation, final_centroid,
00132 final_orientation, goal_pose, push_start_point, behavior_primitive,
00133 controller, proxy, which_arm, push_time, object_id,
00134 push_point, precondition_method='centroid_push', push_score=-1):
00135 if self.data_out is None:
00136 rospy.logerr('Attempting to write to file that has not been opened.')
00137 return
00138 rospy.logdebug('Writing output line.\n')
00139 data_line = object_id+' '+str(init_centroid.x)+' '+str(init_centroid.y)+' '+str(init_centroid.z)+' '+\
00140 str(init_orientation)+' '+str(final_centroid.x)+' '+str(final_centroid.y)+' '+\
00141 str(final_centroid.z)+' '+str(final_orientation)+' '+\
00142 str(goal_pose.x)+' '+str(goal_pose.y)+' '+str(goal_pose.theta)+' '+\
00143 str(push_start_point.x)+' '+str(push_start_point.y)+' '+str(push_start_point.z)+' '+\
00144 behavior_primitive+' '+controller+' '+proxy+' '+which_arm+' '+str(push_time)+' '+precondition_method+' '+\
00145 str(push_score)+'\n'
00146 self.data_out.write(_LEARN_TRIAL_HEADER_LINE+'\n')
00147 self.data_out.write(data_line)
00148 self.data_out.flush()
00149
00150 def parse_line(self, line):
00151 if line.startswith('#'):
00152 return None
00153 l = line.split()
00154 l.reverse()
00155 num_objs = len(l)
00156 push = PushTrial()
00157 push.object_id = l.pop()
00158 push.init_centroid.x = float(l.pop())
00159 push.init_centroid.y = float(l.pop())
00160 push.init_centroid.z = float(l.pop())
00161 push.init_orientation = float(l.pop())
00162 push.final_centroid.x = float(l.pop())
00163 push.final_centroid.y = float(l.pop())
00164 push.final_centroid.z = float(l.pop())
00165 push.final_orientation = float(l.pop())
00166 push.goal_pose.x = float(l.pop())
00167 push.goal_pose.y = float(l.pop())
00168 push.goal_pose.theta = float(l.pop())
00169 push.start_point.x = float(l.pop())
00170 push.start_point.y = float(l.pop())
00171 push.start_point.z = float(l.pop())
00172 push.behavior_primitive = l.pop()
00173 push.controller = l.pop()
00174 push.proxy = l.pop()
00175 push.which_arm = l.pop()
00176 push.push_time = float(l.pop())
00177 if len(l) > 0:
00178 push.precondition_method = l.pop()
00179 else:
00180 push.precondition_method = 'push_centroid'
00181 if len(l) > 0:
00182 push.score = float(l.pop())
00183 else:
00184 push.score = -1.0
00185 push.shape_descriptor = []
00186 while len(l) > 0:
00187 push.shape_descriptor.append(float(l.pop()))
00188
00189 push.push_angle = atan2(push.goal_pose.y-push.init_centroid.y,
00190 push.goal_pose.x-push.init_centroid.x)
00191 push.push_dist = hypot(push.goal_pose.y-push.init_centroid.y,
00192 push.goal_pose.x-push.init_centroid.x)
00193 if push.init_centroid.x > 1.0:
00194 print 'Greater than 1.0 x: ', str(push)
00195 return push
00196
00197 def write_pre_push_line(self, init_centroid, init_orientation, goal_pose, push_start_point, behavior_primitive,
00198 controller, proxy, which_arm, object_id, precondition_method,
00199 predicted_score=-1.0, shape_descriptor=None):
00200 if self.data_out is None:
00201 rospy.logerr('Attempting to write to file that has not been opened.')
00202 return
00203 rospy.logdebug('Writing pre push output line.\n')
00204 data_line = object_id+' '+str(init_centroid.x)+' '+str(init_centroid.y)+' '+str(init_centroid.z)+' '+\
00205 str(init_orientation)+' '+str(0.0)+' '+str(0.0)+' '+\
00206 str(0.0)+' '+str(0.0)+' '+\
00207 str(goal_pose.x)+' '+str(goal_pose.y)+' '+str(goal_pose.theta)+' '+\
00208 str(push_start_point.x)+' '+str(push_start_point.y)+' '+str(push_start_point.z)+' '+\
00209 behavior_primitive+' '+controller+' '+proxy+' '+which_arm+' '+str(0.0)+' '+precondition_method+ ' ' +\
00210 str(predicted_score)
00211
00212 if shape_descriptor is not None:
00213 for s in shape_descriptor:
00214 data_line += ' '+str(s)
00215 data_line+='\n'
00216 self.data_out.write(_LEARN_TRIAL_HEADER_LINE+'\n')
00217 self.data_out.write(data_line)
00218 self.data_out.flush()
00219
00220 def write_bad_trial_line(self):
00221 self.data_out.write(_BAD_TRIAL_HEADER_LINE+'\n')
00222 self.data_out.flush()
00223
00224 def read_in_data_file(self, file_name):
00225 data_in = file(file_name, 'r')
00226 x = [self.parse_line(l) for l in data_in.readlines()]
00227 data_in.close()
00228 x = filter(None, x)
00229 return self.link_repeat_trials(x)
00230
00231 def link_repeat_trials(self, trials):
00232 for i in range(1,len(trials)):
00233 if (trials[i].goal_pose.y == trials[i-1].goal_pose.y and
00234 trials[i].goal_pose.x == trials[i-1].goal_pose.x and
00235 trials[i].behavior_primitive == trials[i-1].behavior_primitive and
00236 trials[i].proxy == trials[i-1].proxy and
00237 trials[i].controller == trials[i-1].controller):
00238 if trials[i].which_arm == trials[i-1].which_arm:
00239
00240 pass
00241 else:
00242 trials[i].continuation = True
00243 return trials
00244
00245 def open_out_file(self, file_name):
00246 self.data_out = file(file_name, 'a')
00247 self.data_out.write(_VERSION_LINE+'\n')
00248
00249 self.data_out.flush()
00250
00251 def close_out_file(self):
00252 self.data_out.close()
00253
00254 class ControlAnalysisIO:
00255 def __init__(self):
00256 self.data_out = None
00257 self.data_in = None
00258
00259 def write_line(self, x, x_dot, x_desired, theta0, u, time, hand_pose):
00260 if self.data_out is None:
00261 rospy.logerr('Attempting to write to file that has not been opened.')
00262 return
00263 data_line = str(x.x)+' '+str(x.y)+' '+str(x.theta)+' '+\
00264 str(x_dot.x)+' '+str(x_dot.y)+' '+str(x_dot.theta)+' '+\
00265 str(x_desired.x)+' '+str(x_desired.y)+' '+str(x_desired.theta)+' '+\
00266 str(theta0)+' '+str(u.linear.x)+' '+str(u.linear.y)+' '+str(u.linear.z)+' '+\
00267 str(u.angular.x)+' '+str(u.angular.y)+' '+str(u.angular.z)+' '+str(time)+' '+\
00268 str(hand_pose.position.x)+' '+str(hand_pose.position.y)+' '+str(hand_pose.position.z)+\
00269 '\n'
00270 self.data_out.write(data_line)
00271 self.data_out.flush()
00272
00273 def parse_line(self, line):
00274 if line.startswith('#'):
00275 return None
00276 data = [float(s) for s in line.split()]
00277 x = Pose2D()
00278 x_dot = Pose2D()
00279 x_desired = Pose2D()
00280 u = Twist()
00281 x.x = data[0]
00282 x.y = data[1]
00283 x.theta = data[2]
00284 x_dot.x = data[3]
00285 x_dot.y = data[4]
00286 x_dot.theta = data[5]
00287 x_desired.x = data[6]
00288 x_desired.y = data[7]
00289 x_desired.theta = data[8]
00290 theta0 = data[9]
00291 u.linear.x = data[10]
00292 u.linear.y = data[11]
00293 u.linear.z = data[12]
00294 u.angular.x = data[13]
00295 u.angular.y = data[14]
00296 u.angular.z = data[15]
00297 t = data[16]
00298 ee_x = data[17]
00299 ee_y = data[18]
00300 ee_z = data[19]
00301 cts = ControlTimeStep(x, x_dot, x_desired, theta0, u, t)
00302 return cts
00303
00304 def read_in_data_file(self, file_name):
00305 data_in = file(file_name, 'r')
00306 x = [self.parse_line(l) for l in data_in.readlines()[1:]]
00307 data_in.close()
00308 return filter(None, x)
00309
00310 def open_out_file(self, file_name):
00311 self.data_out = file(file_name, 'a')
00312 self.data_out.write(_CONTROL_HEADER_LINE+'\n')
00313 self.data_out.flush()
00314
00315 def close_out_file(self):
00316 self.data_out.close()
00317
00318 class CombinedPushLearnControlIO:
00319 def __init__(self):
00320 self.pl_io = PushLearningIO()
00321 self.ctrl_io = ControlAnalysisIO()
00322 self.push_trials = []
00323
00324 def read_in_data_file(self, file_name):
00325 data_in = file(file_name, 'r')
00326 read_pl_trial_line = False
00327 read_ctrl_line = False
00328 trial_is_start = True
00329
00330 trial_starts = 0
00331 bad_stops = 0
00332 object_comments = 0
00333 control_headers = 0
00334
00335 self.push_trials = []
00336 current_trial = PushCtrlTrial()
00337 for line in data_in.readlines():
00338 if line.startswith(_VERSION_LINE):
00339 if _DEBUG_IO:
00340 print 'Ignoring version line'
00341 continue
00342 elif line.startswith(_LEARN_TRIAL_HEADER_LINE):
00343 object_comments += 1
00344
00345 if _DEBUG_IO:
00346 print 'Read learn trial header'
00347 if trial_is_start:
00348 trial_starts += 1
00349 read_pl_trial_line = True
00350 read_ctrl_line = False
00351 elif line.startswith(_CONTROL_HEADER_LINE):
00352 if _DEBUG_IO:
00353 print 'Read control header'
00354 control_headers += 1
00355 read_ctrl_line = True
00356 elif line.startswith(_BAD_TRIAL_HEADER_LINE):
00357 bad_stops += 1
00358 if _DEBUG_IO:
00359 print 'BAD TRIAL: not adding current trial to list'
00360
00361 current_trial = PushCtrlTrial()
00362 trial_is_start = True
00363 elif read_pl_trial_line:
00364 if _DEBUG_IO:
00365 print 'Reading trial'
00366 trial = self.pl_io.parse_line(line)
00367 read_pl_trial_line = False
00368 if trial_is_start:
00369 current_trial.trial_start = trial
00370 if _DEBUG_IO:
00371 print 'Trial is start trial'
00372 else:
00373 if _DEBUG_IO:
00374 print 'Trial is end trial'
00375 current_trial.trial_end = trial
00376 self.push_trials.append(current_trial)
00377 current_trial = PushCtrlTrial()
00378 trial_is_start = not trial_is_start
00379 elif read_ctrl_line:
00380 if _DEBUG_IO:
00381 print 'Read ctrl pt'
00382 traj_pt = self.ctrl_io.parse_line(line)
00383 current_trial.trial_trajectory.append(traj_pt)
00384 else:
00385 if _DEBUG_IO:
00386 print 'None of these?'
00387 data_in.close()
00388
00389 print 'Read in', file_name
00390 print 'trial_starts',trial_starts
00391 print 'bad_stops',bad_stops
00392
00393 print 'num trials', len(self.push_trials), '\n'
00394
00395 def write_example_file(self, file_name, X, Y, normalize=False, debug=False):
00396 data_out = file(file_name, 'w')
00397
00398 k = 0
00399 for x,y in zip(X,Y):
00400 k += 1
00401 if debug:
00402 print y, x
00403 if isnan(y):
00404 print 'Skipping writing example: ', k
00405 continue
00406 data_line = str(y)
00407 if normalize:
00408 feature_sum = 0.0
00409 for xi in x:
00410 feature_sum += xi
00411 for i, xi in enumerate(x):
00412 if xi > 0:
00413 data_line += ' ' + str(i+1)+':'+str(sqrt(xi/float(feature_sum)))
00414 else:
00415 for i, xi in enumerate(x):
00416 if xi > 0:
00417 data_line += ' ' + str(i+1)+':'+str(xi)
00418 data_line +='\n'
00419 data_out.write(data_line)
00420 print 'Wrote', k, 'examples'
00421 data_out.close()
00422
00423 def read_example_file(self, file_name):
00424 data_in = file(file_name, 'r')
00425 lines = [l.split() for l in data_in.readlines()]
00426 data_in.close()
00427 Y = []
00428 X = []
00429 for line in lines:
00430 y = float(line.pop(0))
00431 Y.append(y)
00432 x = []
00433 for pair in line:
00434 idx, val = pair.split(':')
00435 idx = int(idx) - 1
00436 val = float(val)
00437 while len(x) < idx:
00438 x.append(0)
00439 x.append(val)
00440 X.append(x)
00441 return (X,Y)
00442
00443 def read_regression_prediction_file(self, file_name):
00444 data_in = file(file_name, 'r')
00445 Y_hat = [float(y.strip()) for y in data_in.readlines()]
00446 data_in.close()
00447 return Y_hat
00448
00449 class StartLocPerformanceAnalysis:
00450
00451 def __init__(self):
00452 self.analyze_straight_line_push = self.analyze_straight_line_push_line_dist
00453 self.analyze_spin_push = self.analyze_spin_push_net_spin
00454
00455
00456 def compare_predicted_and_observed_push_scores(self, in_file_name, out_file_name=None, use_spin=False):
00457
00458 plio = CombinedPushLearnControlIO()
00459 plio.read_in_data_file(in_file_name)
00460 file_out = None
00461 if out_file_name is not None:
00462 file_out = file(out_file_name, 'w')
00463 for i, p in enumerate(plio.push_trials):
00464 pred_score = p.trial_start.score
00465
00466 if use_spin:
00467 observed_score = self.analyze_spin_push(p)
00468 else:
00469 observed_score = self.analyze_straight_line_push(p)
00470 print 'Trial [',i,'] : Pred: ', pred_score, '\tObserved: ', observed_score
00471 if file_out is not None:
00472 trial_line = str(pred_score) + ' ' + str(observed_score) + '\n'
00473 file_out.write(trial_line)
00474 if file_out is not None:
00475 file_out.close()
00476
00477 def compute_observed_push_scores_final_errors(self, in_file_name, out_file_name=None, use_spin=False):
00478
00479 plio = CombinedPushLearnControlIO()
00480 plio.read_in_data_file(in_file_name)
00481 file_out = None
00482 if out_file_name is not None:
00483 file_out = file(out_file_name, 'w')
00484 for i, p in enumerate(plio.push_trials):
00485 final_pose = p.trial_end.final_centroid
00486 final_orientation = p.trial_end.final_orientation
00487 goal_pose = p.trial_start.goal_pose
00488 if use_spin:
00489 final_error = abs(subPIAngle(goal_pose.theta - final_orientation))
00490 else:
00491
00492 err_x = goal_pose.x - final_pose.x
00493 err_y = goal_pose.y - final_pose.y
00494 final_error = hypot(err_x, err_y)
00495 if file_out is not None:
00496 trial_line = str(final_error)+'\n'
00497 file_out.write(trial_line)
00498 if file_out is not None:
00499 file_out.close()
00500
00501 def get_trial_features(self, file_name, use_spin=False):
00502 self.plio = CombinedPushLearnControlIO()
00503 self.plio.read_in_data_file(file_name)
00504 Y = []
00505 X = []
00506 for i, p in enumerate(self.plio.push_trials):
00507 if use_spin:
00508 y = self.analyze_spin_push(p)
00509 else:
00510 y = self.analyze_straight_line_push(p)
00511 if y < 0:
00512 continue
00513 x = p.trial_start.shape_descriptor
00514 Y.append(y)
00515 X.append(x)
00516 return (X,Y)
00517
00518 def generate_example_file(self, file_in_name, file_out_name, normalize=False, set_train=False,
00519 set_test=False, use_spin=False):
00520 (X, Y) = self.get_trial_features(file_in_name, use_spin)
00521 print 'Read in', len(X), 'sample locations'
00522 self.plio.write_example_file(file_out_name, X, Y, normalize)
00523 if set_train:
00524 self.X_train = X[:]
00525 self.Y_train = Y[:]
00526 if set_test:
00527 self.X_test = X[:]
00528 self.Y_test = Y[:]
00529
00530 def generate_train_and_test_files(self, file_in, file_out, normalize=False, train_percent=0.6,
00531 must_move_epsilon=0.05):
00532 (X,Y) = self.get_trial_features(file_in)
00533 Z = zip(X,Y)
00534
00535 if file_out.endswith('.txt'):
00536 train_file_out = file_out[:-4]+'_train'+'.txt'
00537 test_file_out = file_out[:-4]+'_test'+'.txt'
00538 else:
00539 train_file_out = file_out+'_train'
00540 test_file_out = file_out+'_test'
00541
00542
00543 num_train_examples = int(train_percent*len(X))
00544 print 'Read in', len(X), 'examples'
00545 print 'Training file has', num_train_examples, 'examples'
00546 print 'Test file has', len(X)-num_train_examples, 'examples'
00547 self.Y_train = []
00548 self.X_train = []
00549 self.Y_test = []
00550 self.X_test = []
00551
00552 for i, xy in enumerate(Z):
00553 x = xy[0]
00554 y = xy[1]
00555 if i < num_train_examples:
00556 self.Y_train.append(y)
00557 self.X_train.append(x)
00558 else:
00559 self.Y_test.append(y)
00560 self.X_test.append(x)
00561 print 'len(Y_train)', len(self.Y_train)
00562 self.plio.write_example_file(train_file_out, self.X_train, self.Y_train, normalize)
00563 print 'len(Y_test)', len(self.Y_test)
00564 self.plio.write_example_file(test_file_out, self.X_test, self.Y_test, normalize)
00565
00566 def plot_svm_results(self, pred_file):
00567 self.Y_hat = self.plio.read_regression_prediction_file(pred_file)
00568
00569 max_score = 0.0
00570 Y_test_norm = self.Y_test[:]
00571 Y_hat_norm = self.Y_hat[:]
00572 Y_diffs = []
00573 for i in xrange(len(Y_test_norm)):
00574
00575 if self.Y_test[i] > max_score:
00576 max_score = self.Y_test[i]
00577 if self.Y_hat[i] > max_score:
00578 max_score = self.Y_hat[i]
00579 Y_diffs.append(fabs(self.Y_hat[i]-self.Y_test[i]))
00580 for i in xrange(len(Y_test_norm)):
00581 Y_test_norm[i] = self.Y_test[i]/max_score
00582 Y_hat_norm[i] = self.Y_hat[i]/max_score
00583 print 'Average error is', sum(Y_diffs)/len(Y_diffs)
00584 print 'Max error is', max(Y_diffs)
00585 print 'Min error is', min(Y_diffs)
00586 p1, = plotter.plot(Y_test_norm, Y_hat_norm,'bx')
00587 plotter.xlabel('True Score')
00588 plotter.ylabel('Predicted score')
00589 plotter.title('Push Scoring Evaluation')
00590 plotter.xlim((0.0,1.0))
00591 plotter.ylim((0.0,1.0))
00592 plotter.show()
00593
00594 def plot_svm_results_old(self, pred_file):
00595 self.Y_hat = self.plio.read_regression_prediction_file(pred_file)
00596
00597 Ys_ordered = zip(self.Y_test[:], self.Y_hat[:])
00598 Ys_ordered.sort(key=lambda test_value: test_value[0])
00599 Y_test_ordered = []
00600 Y_hat_ordered = []
00601 Y_diffs = []
00602 for Ys in Ys_ordered:
00603 Y_test_ordered.append(Ys[0])
00604 Y_hat_ordered.append(Ys[1])
00605 Y_diffs.append(fabs(Ys[0]-Ys[1]))
00606 print 'Average error is', sum(Y_diffs)/len(Y_diffs)
00607 print 'Max error is', max(Y_diffs)
00608 print 'Min error is', min(Y_diffs)
00609 p1, = plotter.plot(Y_test_ordered,'bx')
00610 p2, = plotter.plot(Y_hat_ordered, 'r+')
00611 plotter.xlabel('Test index')
00612 plotter.ylabel('Straight push score')
00613 plotter.title('Push Scoring Evaluation')
00614 plotter.legend([p1,p2],['True Score', 'Predicted Score'], loc=2)
00615 plotter.show()
00616
00617 def lookup_push_trial_by_shape_descriptor(self, trials, descriptor):
00618 for t in trials:
00619 match = True
00620 for a,b in zip(t.trial_start.shape_descriptor, descriptor):
00621 if a != b:
00622 match = False
00623 if match:
00624 print t
00625 return t
00626 return None
00627
00628 def analyze_straight_line_push_delta_theta(self, push_trial):
00629 '''
00630 Compute the average frame to frame change in orientation while pushing
00631 '''
00632 init_theta = push_trial.trial_start.init_orientation
00633 angle_errs = []
00634 for i, pt in enumerate(push_trial.trial_trajectory):
00635 if i == 0:
00636 theta_prev = init_theta
00637 else:
00638 theta_prev = push_trial.trial_trajectory[i-1].x.theta
00639 angle_errs.append(abs(subPIAngle(pt.x.theta - theta_prev)))
00640
00641 if len(angle_errs) < 1:
00642 return -1
00643 mean_angle_errs = sum(angle_errs)/len(angle_errs)
00644
00645
00646 return mean_angle_errs
00647
00648 def analyze_straight_line_push_line_dist(self, push_trial):
00649 '''
00650 Get the average distance of the current point to the desired straight line path
00651 '''
00652 init_pose = push_trial.trial_start.init_centroid
00653 goal_pose = push_trial.trial_start.goal_pose
00654 init_loc = (init_pose.x, init_pose.y)
00655 goal_loc = (goal_pose.x, goal_pose.y)
00656
00657 line_dists = []
00658 for i, pt in enumerate(push_trial.trial_trajectory):
00659 cur_pt = (pt.x.x, pt.x.y)
00660 line_dist = point_line_dist(cur_pt, init_loc, goal_loc)
00661 line_dists.append(line_dist)
00662
00663 if len(line_dists) < 1:
00664 return -1
00665 mean_line_dist = sum(line_dists)/len(line_dists)
00666 return mean_line_dist
00667
00668 def analyze_straight_line_push_goal_vector_diff(self, push_trial, normalize_score=False):
00669 '''
00670 Get the average angler error between the instantaneous velocity direction of the object and the
00671 direction towards the goal
00672 '''
00673 init_pose = push_trial.trial_start.init_centroid
00674 goal_pose = push_trial.trial_start.goal_pose
00675 final_pose = push_trial.trial_end.final_centroid
00676 push_trial.trial_trajectory
00677 err_x = goal_pose.x - final_pose.x
00678 err_y = goal_pose.y - final_pose.y
00679 final_error = hypot(err_x, err_y)
00680 total_change = hypot(final_pose.x - init_pose.x, final_pose.y - init_pose.y)
00681 angle_errs = []
00682 init_goal_vector = np.asarray([goal_pose.x - init_pose.x, goal_pose.y - init_pose.y])
00683 init_final_vector = np.asarray([final_pose.x - init_pose.x, final_pose.y - init_pose.y])
00684 final_angle_diff = self.angle_between_vectors(init_goal_vector, init_final_vector)
00685 final_angle_area = 0.5*fabs(init_goal_vector[0]*init_final_vector[1]-
00686 init_goal_vector[1]*init_final_vector[0])
00687 for i, pt in enumerate(push_trial.trial_trajectory):
00688 if i == 0:
00689 continue
00690 prev_pt = push_trial.trial_trajectory[i-1]
00691 goal_vector = np.asarray([goal_pose.x - prev_pt.x.x, goal_pose.y - prev_pt.x.y])
00692 push_vector = np.asarray([pt.x.x - prev_pt.x.x, pt.x.y - prev_pt.x.y])
00693 if hypot(push_vector[0], push_vector[1]) == 0:
00694 continue
00695 else:
00696 angle_errs.append(self.angle_between_vectors(goal_vector, push_vector))
00697 mean_angle_errs = sum(angle_errs)/len(angle_errs)
00698
00699
00700 if normalize_score:
00701 score = 1.0-mean_angle_errs/pi
00702 else:
00703 score = mean_angle_errs
00704
00705 return (score, final_error, total_change, final_angle_diff, final_angle_area)
00706
00707 def analyze_spin_push_total_spin(self, push_trial):
00708 '''
00709 Get the average change in heading aggregated over the entire trial
00710 '''
00711 init_theta = push_trial.trial_start.init_orientation
00712 goal_theta = push_trial.trial_start.goal_pose.theta
00713
00714 delta_thetas = []
00715 prev_theta = init_theta
00716 for i, pt in enumerate(push_trial.trial_trajectory):
00717 cur_theta = pt.x.theta
00718 delta_thetas.append(abs(cur_theta-prev_theta))
00719 prev_theta = cur_theta
00720
00721 if len(delta_thetas) < 1:
00722 return -1
00723 mean_delta_theta = sum(delta_thetas)/len(line_dists)
00724 return mean_delta_theta
00725
00726 def analyze_spin_push_net_spin(self, push_trial):
00727 init_theta = push_trial.trial_start.init_orientation
00728 final_theta = push_trial.trial_end.final_orientation
00729 return abs(subPIAngle(final_theta - init_theta))
00730
00731 def analyze_spin_push_net_spin_signed(self, push_trial):
00732 init_theta = push_trial.trial_start.init_orientation
00733 final_theta = push_trial.trial_end.final_orientation
00734 return subPIAngle(final_theta - init_theta)
00735
00736 def angle_between_vectors(self, a, b):
00737 a_dot_b = sum(a*b)
00738 norm_a = hypot(a[0], a[1])
00739 norm_b = hypot(b[0], b[1])
00740 if norm_a == 0 or norm_b == 0:
00741
00742 return pi
00743 return acos(a_dot_b/(norm_a*norm_b))
00744
00745 def show_data_affinity(self):
00746 X = self.X_train[:]
00747 X.extend(self.X_test[:])
00748 Y = self.Y_train[:]
00749 Y.extend(self.Y_test[:])
00750 X_aff = np.zeros((len(X),len(X)))
00751 Y_aff = np.zeros((len(Y),len(Y)))
00752 for r in xrange(len(X)):
00753 for c in range(r, len(X)):
00754 X_aff[r,c] = sum(np.fabs(np.asarray(X[r]) - np.asarray(X[c])))
00755 Y_aff[r,c] = fabs(Y[r] - Y[c])
00756 print '(',r,',',c,'): ', X_aff[r,c], '\t', Y_aff[r,c]
00757 plotter.imshow(X_aff, plotter.cm.gray,interpolation='nearest')
00758 plotter.title('Xaff')
00759 plotter.figure()
00760 plotter.imshow(Y_aff, plotter.cm.gray, interpolation='nearest')
00761 plotter.title('Yaff')
00762 plotter.show()
00763 return X_aff,Y_aff
00764
00765 class BruteForceKNN:
00766 def __init__(self, data):
00767 self.data = data
00768
00769 def find_k_neighbors(self, element, k=3, comp_func=None):
00770 if comp_func is None:
00771 comp_func = self.xy_dist
00772 k_closest = []
00773 k_dists = []
00774 for d in self.data:
00775 comp_dist = comp_func(element, d)
00776 inserted = False
00777 for i, close in enumerate(k_closest):
00778 if comp_dist < close:
00779 k_closest.insert(d, i)
00780 k_dists.insert(comp_dist,i)
00781 inserted = True
00782 if not inserted and len(k_closest) < k:
00783 k_closest.append(d)
00784 k_dists.append(comp_dist)
00785 elif len(k_closest) > k:
00786 k_closest = k_closest[:k]
00787 k_dists = k_dists[:k]
00788 return (k_closest, k_dists)
00789
00790 def xy_dist(self, a, b):
00791 return hypot(a.init_centroid.x - b.init_centroid.x,
00792 a.init_centroid.y - b.init_centroid.y)
00793
00794 class PushLearningAnalysis:
00795
00796 def __init__(self):
00797 self.raw_data = None
00798 self.io = PushLearningIO()
00799 self.xy_hash_precision = 20.0
00800 self.num_angle_bins = 8
00801
00802 def workspace_span(self, push):
00803
00804 score_fnc = self.compute_push_error_xy
00805
00806
00807 for t in self.all_trials:
00808 t.score = score_fnc(t)
00809 knn = BruteForceKNN(self.all_trials)
00810 neighbors, dists = knn.find_k_neighbors(push)
00811
00812
00813
00814
00815
00816 def workspace_ranking(self):
00817
00818
00819 likelihood_arg=['behavior_primitive','proxy','controller']
00820 score_fnc=self.compute_change_in_push_error_xy
00821 score_fnc=self.compute_push_error_xy
00822 workspace_ranks = self.rank_avg_pushes(trial_hash_fnc=self.hash_push_xy_angle,
00823 likelihood_arg=likelihood_arg,
00824 mean_push_fnc=self.get_mean_workspace_push,
00825 score_fnc=score_fnc)
00826
00827 for ranks in workspace_ranks:
00828 self.output_push_ranks(ranks,
00829 ['init_centroid.x','init_centroid.y','push_angle'],
00830 likelihood_arg, n=3)
00831 return workspace_ranks
00832
00833 def object_ranking(self, use_raw=False, count_successes=True):
00834 '''
00835 Method to find the best performing (on average) behavior_primitive as a function of object_id
00836 '''
00837 cond_arg='object_id'
00838 likelihood_arg=['behavior_primitive','proxy','controller']
00839
00840 score_fnc=self.compute_push_error_xy
00841
00842 if use_raw:
00843 rankings = self.rank_raw_pushes(trial_grouping_arg=cond_arg,
00844 score_fnc=score_fnc)
00845 print "\Raw object behavior rankings:"
00846 for ranks in rankings:
00847 self.output_push_ranks(ranks, cond_arg, likelihood_arg, n=5)
00848 elif count_successes:
00849 rankings = self.count_successful_pushes(trial_grouping_arg=cond_arg,
00850 likelihood_arg=likelihood_arg,
00851 score_fnc=score_fnc)
00852 print "\Successful counts for affordance-behaviors on different objects:"
00853 total_good = 0
00854 total_attempts = 0
00855 for ranks in rankings:
00856 num_good, num_attempts = self.output_push_counts(ranks, cond_arg, likelihood_arg, n=50)
00857 total_good += num_good
00858 total_attempts += num_attempts
00859 print 'Total good', total_good
00860 print 'Total attempts', total_attempts
00861 else:
00862 rankings = self.rank_avg_pushes(trial_grouping_arg=cond_arg,
00863 likelihood_arg=likelihood_arg,
00864 score_fnc=score_fnc)
00865 print "\nObject behavior rankings:"
00866 for ranks in rankings:
00867 self.output_push_ranks(ranks, cond_arg, likelihood_arg, n=1)
00868 return rankings
00869
00870 def object_proxy_ranking(self):
00871 '''
00872 Method to find the best performing (on average) behavior_primitive as a function of object_id
00873 '''
00874 cond_arg='object_id'
00875 likelihood_arg='proxy'
00876
00877
00878 score_fnc=self.compute_change_in_push_error_xy
00879 rankings = self.rank_avg_pushes(trial_grouping_arg=cond_arg,
00880 likelihood_arg=likelihood_arg,
00881 score_fnc=score_fnc)
00882 print "\nObject proxy rankings:"
00883 for ranks in rankings:
00884 self.output_push_ranks(ranks, cond_arg, likelihood_arg, n=3)
00885 return rankings
00886
00887 def angle_ranking(self):
00888 '''
00889 Method to find the best performing (on average) behavior_primitive as a function of push_angle
00890 '''
00891 likelihood_arg=['behavior_primitive','proxy','controller']
00892 angle_ranks = self.rank_avg_pushes(
00893 trial_hash_fnc=self.hash_push_angle, likelihood_arg=likelihood_arg,
00894 mean_push_fnc=self.get_mean_angle_push)
00895 print "Angle push rankings:"
00896 for rank in angle_ranks:
00897 self.output_push_ranks(rank, 'push_angle', likelihood_arg, n=3)
00898 return angle_ranks
00899
00900 def rank_avg_pushes(self, trial_hash_fnc=None, trial_grouping_arg=None,
00901 likelihood_arg=None, mean_push_fnc=None,score_fnc=None):
00902 '''
00903 '''
00904
00905 if score_fnc is None:
00906 score_fnc = self.compute_push_error_xy
00907 for t in self.all_trials:
00908 t.score = score_fnc(t)
00909
00910 if trial_hash_fnc is not None:
00911 trial_groups = self.group_trials(self.all_trials, hash_function=trial_hash_fnc)
00912 else:
00913 trial_groups = self.group_trials(self.all_trials, trial_grouping_arg)
00914
00915
00916 mean_groups = []
00917 for i, group_key in enumerate(trial_groups):
00918 trial_group = trial_groups[group_key]
00919 likelihood_arg_dict = self.group_trials(trial_group, likelihood_arg)
00920
00921 mean_group = []
00922 for arg_key in likelihood_arg_dict:
00923 if trial_grouping_arg is not None:
00924 mean_push = self.get_mean_push(likelihood_arg_dict[arg_key],
00925 trial_grouping_arg, likelihood_arg)
00926 else:
00927 mean_push = mean_push_fnc(likelihood_arg_dict[arg_key])
00928 mean_group.append(mean_push)
00929 mean_groups.append(mean_group)
00930
00931
00932 ranked_pushes = []
00933 for i, group in enumerate(mean_groups):
00934 group.sort(compare_pushes)
00935 ranked_pushes.append(group)
00936 return ranked_pushes
00937
00938 def count_successful_pushes(self, trial_hash_fnc=None, trial_grouping_arg=None,
00939 likelihood_arg=None, mean_push_fnc=None,score_fnc=None, score_thresh=0.02):
00940 '''
00941 '''
00942
00943 if score_fnc is None:
00944 score_fnc = self.compute_push_error_xy
00945 for t in self.all_trials:
00946 t.score = score_fnc(t)
00947
00948 if trial_hash_fnc is not None:
00949 trial_groups = self.group_trials(self.all_trials, hash_function=trial_hash_fnc)
00950 else:
00951 trial_groups = self.group_trials(self.all_trials, trial_grouping_arg)
00952
00953
00954 count_groups = []
00955 for i, group_key in enumerate(trial_groups):
00956 trial_group = trial_groups[group_key]
00957 likelihood_arg_dict = self.group_trials(trial_group, likelihood_arg)
00958
00959 count_group = []
00960 for arg_key in likelihood_arg_dict:
00961 push_count = self.get_count_push(likelihood_arg_dict[arg_key],
00962 trial_grouping_arg, likelihood_arg, score_thresh)
00963 count_group.append(push_count)
00964 count_groups.append(count_group)
00965
00966
00967 ranked_pushes = []
00968 for i, group in enumerate(count_groups):
00969 group.sort(compare_counts)
00970 ranked_pushes.append(group)
00971 return ranked_pushes
00972
00973 def get_successful_pushes(self, trial_hash_fnc=None, trial_grouping_arg=None,
00974 likelihood_arg=None, mean_push_fnc=None,score_fnc=None, score_thresh=0.02):
00975 '''
00976 '''
00977
00978 if score_fnc is None:
00979 score_fnc = self.compute_push_error_xy
00980 for t in self.all_trials:
00981 t.score = score_fnc(t)
00982
00983 if trial_hash_fnc is not None:
00984 trial_groups = self.group_trials(self.all_trials, hash_function=trial_hash_fnc)
00985 else:
00986 trial_groups = self.group_trials(self.all_trials, trial_grouping_arg)
00987
00988
00989 count_groups = []
00990 for i, group_key in enumerate(trial_groups):
00991 trial_group = trial_groups[group_key]
00992 likelihood_arg_dict = self.group_trials(trial_group, likelihood_arg)
00993
00994 count_group = []
00995 for arg_key in likelihood_arg_dict:
00996 for push in likelihood_arg_dict[arg_key]:
00997 if push.score < score_thresh:
00998 count_group.append(push)
00999 count_groups.append(count_group)
01000 return count_groups
01001
01002 def rank_raw_pushes(self, trial_hash_fnc=None, trial_grouping_arg=None, score_fnc=None):
01003 '''
01004 '''
01005
01006 if score_fnc is None:
01007 score_fnc = self.compute_push_error_xy
01008 for t in self.all_trials:
01009 t.score = score_fnc(t)
01010
01011 if trial_hash_fnc is not None:
01012 trial_groups = self.group_trials(self.all_trials, hash_function=trial_hash_fnc)
01013 else:
01014 trial_groups = self.group_trials(self.all_trials, trial_grouping_arg)
01015
01016
01017 ranked_pushes = []
01018 for i, group_key in enumerate(trial_groups):
01019 trial_group = trial_groups[group_key]
01020 trial_group.sort(compare_pushes)
01021 ranked_pushes.append(trial_group)
01022 return ranked_pushes
01023
01024 def get_mean_push(self, arg_list, trial_grouping_arg, likelihood_arg):
01025 mean_push = PushTrial()
01026 mean_score, score_var = self.mean_and_variance(arg_list)
01027 mean_push.score = mean_score
01028 mean_push.var = score_var
01029 if type(trial_grouping_arg) is not list:
01030 trial_grouping_arg = [trial_grouping_arg]
01031 if type(likelihood_arg) is not list:
01032 likelihood_arg = [likelihood_arg]
01033 for arg in trial_grouping_arg:
01034 setattr(mean_push,arg, get_attr(arg_list[0],arg))
01035 for arg in likelihood_arg:
01036 setattr(mean_push,arg, get_attr(arg_list[0],arg))
01037 return mean_push
01038
01039
01040 def get_count_push(self, pushes, trial_grouping_arg, likelihood_arg, score_thresh):
01041 count_push = PushTrial()
01042 successful_count = 0
01043 for push in pushes:
01044 if push.score < score_thresh:
01045 successful_count += 1
01046 count_push.successful_count = successful_count
01047 count_push.total_count = len(pushes)
01048 if type(trial_grouping_arg) is not list:
01049 trial_grouping_arg = [trial_grouping_arg]
01050 if type(likelihood_arg) is not list:
01051 likelihood_arg = [likelihood_arg]
01052 for arg in trial_grouping_arg:
01053 setattr(count_push,arg, get_attr(pushes[0],arg))
01054 for arg in likelihood_arg:
01055 setattr(count_push,arg, get_attr(pushes[0],arg))
01056 return count_push
01057
01058 def get_mean_angle_push(self, arg_list):
01059 mean_push = PushTrial()
01060 mean_score, score_var = self.mean_and_variance(arg_list)
01061 mean_push.score = mean_score
01062 mean_push.var = score_var
01063 mean_push.push_angle = self.hash_angle(arg_list[0].push_angle)
01064 mean_push.behavior_primitive = arg_list[0].behavior_primitive
01065 mean_push.controller = arg_list[0].controller
01066 mean_push.proxy = arg_list[0].proxy
01067 return mean_push
01068
01069 def get_mean_workspace_push(self, arg_list):
01070 mean_push = PushTrial()
01071 mean_score, score_var = self.mean_and_variance(arg_list)
01072 mean_push.score = mean_score
01073 mean_push.var = score_var
01074 mean_push.init_centroid.x, mean_push.init_centroid.y = self.hash_xy(
01075 arg_list[0].init_centroid.x, arg_list[0].init_centroid.y)
01076 mean_push.push_angle = self.hash_angle(arg_list[0].push_angle)
01077 mean_push.behavior_primitive = arg_list[0].behavior_primitive
01078 mean_push.controller = arg_list[0].controller
01079 mean_push.proxy = arg_list[0].proxy
01080 mean_push.which_arm = arg_list[0].which_arm
01081 return mean_push
01082
01083 def mean_and_variance(self, pushes):
01084 n = len(pushes)
01085 mean_score = 0
01086 for push in pushes:
01087 mean_score += push.score
01088 mean_score = mean_score / n
01089
01090 if n <= 1:
01091 return (mean_score, 0)
01092
01093 var_sum = 0
01094 for push in pushes:
01095 var_sum += push.score**2
01096 score_var = (var_sum-n*mean_score**2)/(n-1)
01097
01098 return (mean_score, score_var)
01099
01100
01101
01102 def group_trials(self, all_trials, hash_attribute=None, hash_function=None):
01103 group_dict = {}
01104
01105 for t in all_trials:
01106 if hash_function is not None:
01107 group_key = hash_function(t)
01108 elif type(hash_attribute) == list and len(hash_attribute) > 1:
01109 group_key = []
01110 for attr in hash_attribute:
01111 group_key.append(get_attr(t,attr))
01112 group_key = tuple(group_key)
01113 elif type(hash_attribute) == list:
01114 group_key = get_attr(t, hash_attribute[0])
01115 else:
01116 group_key = get_attr(t, hash_attribute)
01117 try:
01118 group_dict[group_key].append(t)
01119 except KeyError:
01120 group_dict[group_key] = [t]
01121 return group_dict
01122
01123 def group_trials_by_xy_and_push_angle(self, all_trials):
01124 '''
01125 Method to group all trials by initial table location and push angle
01126 '''
01127 groups = {}
01128
01129 for t in all_trials:
01130 angle_key = self.hash_angle(t.push_angle)
01131 x_key, y_key = self.hash_xy(t.init_centroid.x, t.init_centroid.y)
01132 group_key = (x_key, y_key, angle_key)
01133 try:
01134 groups[group_key].append(t)
01135 except KeyError:
01136 groups[group_key] = [t]
01137 return groups
01138
01139 def group_trials_by_push_angle(self, all_trials):
01140 '''
01141 Method to group all trials by initial table location and push angle
01142 '''
01143 return self.group_trials(all_trials, hash_function=self.hash_push_angle)
01144
01145 def group_trials_by_xy(self, all_trials):
01146 '''
01147 Method to group all trials by initial table location and push angle
01148 '''
01149 xy_dict = {}
01150 for t in all_trials:
01151 xy_key = self.hash_xy(t.init_centroid.x, t.init_centroid.y)
01152
01153 try:
01154 xy_dict[xy_key].append(t)
01155 except KeyError:
01156 xy_dict[xy_key] = [t]
01157 return xy_dict
01158
01159
01160
01161 def visualize_push_choices(self, ranks, score_threshold=None, object_id=None):
01162 choices = []
01163 for rank in ranks:
01164 choices.append(rank[0])
01165
01166 disp_img = cv2.imread('/u/thermans/Dropbox/Data/choose_push/use_for_display.png')
01167
01168 xy_groups = self.group_trials_by_xy(choices)
01169
01170 for group_key in xy_groups:
01171 disp_img = self.draw_push_choices_on_image(xy_groups[group_key], disp_img,
01172 score_threshold=score_threshold)
01173 cv2.imshow('Chosen pushes', disp_img)
01174 file_name = '/u/thermans/Desktop/push_learn_out'
01175 if object_id is not None:
01176 file_name += '_'+object_id
01177 if score_threshold is not None:
01178 file_name += '_'+str(score_threshold)
01179
01180 file_name += '.png'
01181 cv2.imwrite(file_name, disp_img)
01182 cv2.waitKey()
01183
01184 def draw_push_choices_on_image(self, choices, img, score_threshold=None):
01185
01186
01187 K = np.matrix([[525, 0, 319.5, 0.0],
01188 [0, 525, 239.5, 0.0],
01189 [0, 0, 1, 0.0]])
01190 tl = np.asarray([-0.0115423, 0.441939, 0.263569])
01191 q = np.asarray([0.693274, -0.685285, 0.157732, 0.157719])
01192 num_downsamples = 0
01193 table_height = -0.3
01194 P_w = np.matrix([[choices[0].init_centroid.x], [choices[0].init_centroid.y],
01195 [table_height], [1.0]])
01196
01197 T = (np.matrix(tr.translation_matrix(tl)) *
01198 np.matrix(tr.quaternion_matrix(q)))
01199 P_c = T*P_w
01200
01201 P_i = K*P_c
01202 P_i = P_i / P_i[2]
01203 u = P_i[0]/pow(2,num_downsamples)
01204 v = P_i[1]/pow(2,num_downsamples)
01205
01206 valid_choices = 0
01207 for c in choices:
01208 if score_threshold is None:
01209 valid_choices += 1
01210 elif c.score < score_threshold:
01211 valid_choices += 1
01212 if valid_choices == 0:
01213 return img
01214
01215 radius = 13
01216 cv2.circle(img, (u,v), 3, [0.0,0.0,0.0],3)
01217 cv2.circle(img, (u,v), 3, [255.0,255.0,255.0], 1)
01218
01219 for c in choices:
01220 if score_threshold is None:
01221 pass
01222 elif c.score > score_threshold:
01223 continue
01224 end_point = (u-sin(c.push_angle)*(radius), v-cos(c.push_angle)*(radius))
01225 color = [0.0, 0.0, 0.0]
01226
01227 for c in choices:
01228 if score_threshold is None:
01229 pass
01230 elif c.score > score_threshold:
01231 continue
01232
01233 if True or c.which_arm == 'l':
01234 if c.behavior_primitive == GRIPPER_PUSH:
01235 color = [255.0, 0.0, 0.0]
01236 elif c.behavior_primitive == GRIPPER_SWEEP:
01237 color = [0.0, 255.0, 0.0]
01238 elif c.behavior_primitive == OVERHEAD_PUSH:
01239 color = [0.0, 0.0, 255.0]
01240 elif c.behavior_primitive == GRIPPER_PULL:
01241 color = [0.0, 255.0, 255.0]
01242
01243 else:
01244 if c.behavior_primitive == GRIPPER_PUSH:
01245 color = [128.0, 0.0, 128.0]
01246 elif c.behavior_primitive == GRIPPER_SWEEP:
01247 color = [0.0, 64.0, 129.0]
01248 elif c.behavior_primitive == OVERHEAD_PUSH:
01249 color = [128.0, 128.0, 0.0]
01250 elif c.behavior_primitive == GRIPPER_PULL:
01251 color = [200.0, 200.0, 200.0]
01252
01253
01254 end_point = (u-sin(c.push_angle)*(radius), v-cos(c.push_angle)*(radius))
01255 cv2.line(img, (u,v), end_point, color, 2)
01256 return img
01257
01258 def visualize_angle_push_choices(self, ranks, score_threshold=None):
01259 choices = []
01260 for rank in ranks:
01261 choices.append(rank[0])
01262
01263 disp_img = cv2.imread('/u/thermans/Dropbox/Data/choose_push/use_for_display.png')
01264
01265
01266
01267 for x in x_locs:
01268 for y in y_locs:
01269 for c in choices:
01270 c.init_centroid.x = x
01271 c.init_centroid.y = y
01272 disp_img = self.draw_push_choices_on_image(choices,
01273 disp_img,
01274 score_threshold=score_threshold)
01275 cv2.imshow('Chosen pushes', disp_img)
01276 cv2.imwrite('/u/thermans/Desktop/push_learn_angle_out.png', disp_img)
01277 cv2.waitKey()
01278
01279
01280
01281
01282 def read_in_push_trials(self, file_name, object_id=None):
01283 self.all_trials = []
01284 object_ids = {}
01285 if object_id is not None:
01286 all_trials = self.io.read_in_data_file(file_name)
01287 for t in all_trials:
01288 if t.object_id in object_ids:
01289 pass
01290 else:
01291 object_ids[t.object_id] = t.object_id
01292 print "object_id is:", t.object_id
01293 if object_id == t.object_id:
01294 self.all_trials.append(t)
01295 else:
01296 self.all_trials = self.io.read_in_data_file(file_name)
01297
01298
01299
01300 def output_push_choice(self, c, conditional_value, arg_value):
01301 '''
01302 Method takes strings [or lists of strings] of what attributes of PushTrail instance c to display
01303 '''
01304 if type(conditional_value) == list:
01305 conditional_str = ''
01306 for val in conditional_value:
01307 conditional_str += str(get_attr(c,val))+', '
01308 conditional_str = conditional_str[:-2]
01309 else:
01310 conditional_str = str(get_attr(c,conditional_value))
01311 if type(arg_value) == list:
01312 arg_str = ''
01313 for val in arg_value:
01314 arg_str += str(get_attr(c,val))+', '
01315 arg_str = arg_str[:-2]
01316 else:
01317 arg_str = str(get_attr(c,arg_value))
01318 print 'Choice for (' + conditional_str + '): ('+ arg_str+ ') : ' + str(c.score) + ', ' + str(c.var)
01319
01320 def output_push_ranks(self, ranks, conditional_value, arg_value, n=3):
01321 '''
01322 Method takes strings [or lists of strings] of what attributes of PushTrail instance c to display
01323 '''
01324 if len(ranks) == 0:
01325 return
01326 if type(conditional_value) == list:
01327 conditional_str = ''
01328 for val in conditional_value:
01329 conditional_str += str(get_attr(ranks[0], val))+', '
01330 conditional_str = conditional_str[:-2]
01331 else:
01332 conditional_str = str(get_attr(ranks[0], conditional_value))
01333
01334 for i, c in enumerate(ranks):
01335 if i >= n:
01336 break
01337 if type(arg_value) == list:
01338 arg_str = ''
01339 for val in arg_value:
01340 arg_str += str(get_attr(c,val))+', '
01341 arg_str = arg_str[:-2]
01342 else:
01343 arg_str = str(get_attr(c,arg_value))
01344
01345
01346 def output_push_counts(self, ranks, conditional_value, arg_value, n=3):
01347 '''
01348 Method takes strings [or lists of strings] of what attributes of PushTrail instance c to display
01349 '''
01350 total_good = 0
01351 total_attempts = 0
01352 if len(ranks) == 0:
01353 return
01354 if type(conditional_value) == list:
01355 conditional_str = ''
01356 for val in conditional_value:
01357 conditional_str += str(get_attr(ranks[0], val))+', '
01358 conditional_str = conditional_str[:-2]
01359 else:
01360 conditional_str = str(get_attr(ranks[0], conditional_value))
01361 print conditional_str + ''
01362 for i, c in enumerate(ranks):
01363 if i >= n:
01364 break
01365 if type(arg_value) == list:
01366 arg_str = ''
01367 for val in arg_value:
01368 arg_str += str(get_attr(c,val))+' & '
01369 arg_str = arg_str[:-3]
01370 else:
01371 arg_str = str(get_attr(c,arg_value))
01372 if c.successful_count > 0:
01373 total_good += c.successful_count
01374 total_attempts += c.total_count
01375
01376
01377
01378 return total_good, total_attempts
01379 def output_loc_push_choices(self, choices):
01380 print "Loc push choices:"
01381 for c in choices:
01382 self.output_push_choice(c, ['init_centroid.x','init_centroid.y','push_angle'],
01383 ['behavior_primitive','controller','proxy'])
01384
01385
01386
01387
01388
01389 def hash_push_angle(self, push):
01390 return self.hash_angle(push.push_angle)
01391
01392 def hash_push_xy_angle(self, push):
01393 x_prime, y_prime = self.hash_xy(push.init_centroid.x, push.init_centroid.y)
01394 return (x_prime, y_prime, self.hash_angle(push.push_angle))
01395
01396 def hash_angle(self, theta):
01397
01398 bin = int((theta + pi)/(2.0*pi)*self.num_angle_bins)
01399 bin = max(min(bin, self.num_angle_bins-1), 0)
01400 return -pi+(2.0*pi)*float(bin)/self.num_angle_bins
01401
01402 def hash_xy(self, x,y):
01403
01404 x_prime = (round(x*self.xy_hash_precision)-1)/self.xy_hash_precision
01405 y_prime = (round(y*self.xy_hash_precision)-1)/self.xy_hash_precision
01406 return (x_prime, y_prime)
01407
01408
01409
01410
01411
01412 def compute_push_error_xy(self, push):
01413 err_x = push.goal_pose.x - push.final_centroid.x
01414 err_y = push.goal_pose.y - push.final_centroid.y
01415 return hypot(err_x,err_y)
01416
01417 def compute_change_in_push_error_xy(self, push):
01418 init_x_error = push.goal_pose.x - push.init_centroid.x
01419 init_y_error = push.goal_pose.y - push.init_centroid.y
01420 final_x_error = push.goal_pose.x - push.final_centroid.x
01421 final_y_error = push.goal_pose.y - push.final_centroid.y
01422
01423 if push.final_centroid == 0.0 and push.final_centroid.y == 0.0:
01424 print 'Knocked off object'
01425 return 100.0
01426 init_error = hypot(init_x_error, init_y_error)
01427 final_error = hypot(final_x_error, final_y_error)
01428 return final_error / init_error
01429
01430 def compute_push_error_push_dist_diff(self, push):
01431 desired_x = push.init_centroid.x + cos(push.push_angle)*push.push_dist
01432 desired_y = push.init_centroid.y + sin(push.push_angle)*push.push_dist
01433 d_x = push.final_centroid.x - push.init_centroid.x
01434 d_y = push.final_centroid.y - push.init_centroid.y
01435 actual_dist = sqrt(d_x*d_x + d_y*d_y)
01436 return fabs(actual_dist - push.push_dist)
01437
01438 def compute_normalized_push_time(self, push):
01439 return push.push_time / push.push_dist
01440
01441
01442 def get_attr(instance, attribute):
01443 '''
01444 A wrapper for the builtin python getattr which handles recursive attributes of attributes
01445 '''
01446 attr_list = attribute.split('.')
01447 def get_nested_attr(instance, attr_list):
01448 if len(attr_list) == 1:
01449 return getattr(instance, attr_list[0])
01450 return get_nested_attr(getattr(instance, attr_list[0]), attr_list[1:])
01451 return get_nested_attr(instance, attr_list)
01452
01453 def compare_pushes(a, b):
01454 if a.score < b.score:
01455 return -1
01456 elif a.score > b.score:
01457 return 1
01458 else:
01459 return 0
01460
01461 def compare_counts(a, b):
01462 if a.successful_count > b.successful_count:
01463 return -1
01464 elif a.successful_count < b.successful_count:
01465 return 1
01466 else:
01467 return 0
01468
01469 def plot_controller_results(file_name, spin=False):
01470
01471 io = ControlAnalysisIO()
01472 controls = io.read_in_data_file(file_name)
01473 XS = [c.x.x for c in controls]
01474 YS = [c.x.y for c in controls]
01475 Thetas = [c.x.y for c in controls]
01476 init_x = XS[0]
01477 init_y = YS[0]
01478 goal_x = controls[0].x_desired.x
01479 goal_y = controls[0].x_desired.y
01480 goal_theta = controls[0].x_desired.theta
01481 plotter.figure()
01482 plotter.plot(XS,YS)
01483 plotter.scatter(XS,YS)
01484 ax = plotter.gca()
01485 print ylim()
01486 print ax.set_xlim(xlim()[1]-(ylim()[1]-ylim()[0]), xlim()[1])
01487 headings = [plotter.Arrow(c.x.x, c.x.y, cos(c.x.theta)*0.01, sin(c.x.theta)*0.01, 0.05, axes=ax) for c in controls]
01488 arrows = [ax.add_patch(h) for h in headings]
01489 init_arrow = plotter.Arrow(controls[0].x.x, controls[0].x.y,
01490 cos(controls[0].x.theta)*0.01,
01491 sin(controls[0].x.theta)*0.01, 0.05,
01492 axes=ax, facecolor='red')
01493 goal_arrow = plotter.Arrow(controls[0].x_desired.x, controls[0].x_desired.y,
01494 cos(controls[0].x_desired.theta)*0.01,
01495 sin(controls[0].x_desired.theta)*0.01, 0.05,
01496 axes=ax, facecolor='green')
01497 ax.add_patch(goal_arrow)
01498 ax.add_patch(init_arrow)
01499 plotter.scatter(init_x, init_y, c='r')
01500 plotter.scatter(goal_x, goal_y, c='g')
01501 plotter.xlabel('x (meters)')
01502 plotter.ylabel('y (meters)')
01503 plotter.title('Tracker Ouput')
01504 plotter.savefig('/home/thermans/sandbox/tracker-output.png')
01505 plotter.figure()
01506 ux = [c.u.linear.x for c in controls]
01507 uy = [c.u.linear.y for c in controls]
01508 if spin:
01509 uy = [c.u.linear.z for c in controls]
01510 plotter.plot(ux)
01511 plotter.plot(uy)
01512 plotter.xlabel('Time')
01513 plotter.ylabel('Velocity (m/s)')
01514 plotter.legend(['u_x', 'u_y'])
01515 plotter.title('Feedback Controller - Input Velocities')
01516 plotter.savefig('/home/thermans/sandbox/feedback-input.png')
01517 plotter.figure()
01518 xdots = [c.x_dot.x for c in controls]
01519 ydots = [c.x_dot.y for c in controls]
01520 plotter.plot(xdots)
01521 plotter.plot(ydots)
01522 plotter.xlabel('Time')
01523 plotter.ylabel('Velocity (m/s)')
01524 plotter.title('Tracker Velocities')
01525 plotter.legend(['x_dot', 'y_dot'])
01526 plotter.savefig('/home/thermans/sandbox/tracker-velocities.png')
01527 plotter.figure()
01528 thetadots = [c.x_dot.theta for c in controls]
01529 plotter.plot(thetadots,c='r')
01530 plotter.xlabel('Time')
01531 plotter.ylabel('Velocity (rad/s)')
01532 plotter.title('Tracker Velocities')
01533 plotter.legend(['theta_dot'])
01534 plotter.savefig('/home/thermans/sandbox/tracker-theta-vel.png')
01535 plotter.figure()
01536 x_err = [c.x_desired.x - c.x.x for c in controls]
01537 y_err = [c.x_desired.y - c.x.y for c in controls]
01538 plotter.plot(x_err)
01539 plotter.plot(y_err)
01540 plotter.xlabel('Time')
01541 plotter.ylabel('Error (meters)')
01542 plotter.title('Position Error')
01543 plotter.legend(['x_err', 'y_err'])
01544 plotter.savefig('/home/thermans/sandbox/pos-err.png')
01545 plotter.figure()
01546 if spin:
01547 theta_err = [c.x_desired.theta - c.x.theta for c in controls]
01548 else:
01549 theta_err = [c.theta0 - c.x.theta for c in controls]
01550 plotter.plot(theta_err, c='r')
01551 plotter.xlabel('Time')
01552 plotter.ylabel('Error (radians)')
01553 if spin:
01554 plotter.title('Error in Orientation')
01555 else:
01556 plotter.title('Heading Deviation from Initial')
01557 plotter.savefig('/home/thermans/sandbox/theta-err.png')
01558 plotter.show()
01559
01560 def plot_junk():
01561
01562 req_object_id = None
01563 thresh = 1.0
01564
01565 if len(sys.argv) > 1:
01566 data_path = str(sys.argv[1])
01567 else:
01568 print 'Usage:',sys.argv[0],'input_file [object_id] [distance_thresh]'
01569 quit()
01570 if len(sys.argv) > 2:
01571 req_object_id = str(sys.argv[2])
01572 if req_object_id == "None":
01573 req_object_id = None
01574 if len(sys.argv) > 3:
01575 thresh = float(sys.argv[3])
01576 print "thresh:", thresh
01577
01578 pla = PushLearningAnalysis()
01579 pla.read_in_push_trials(data_path, req_object_id)
01580
01581
01582 workspace_ranks = pla.workspace_ranking()
01583 pla.visualize_push_choices(workspace_ranks, thresh, object_id=req_object_id)
01584
01585
01586
01587 print 'Num trials: ' + str(len(pla.all_trials))
01588
01589 def read_example_file(file_name):
01590 data_in = file(file_name, 'r')
01591 lines = [l.split() for l in data_in.readlines()]
01592 data_in.close()
01593 Y = []
01594 X = []
01595 for line in lines:
01596 y = float(line.pop(0))
01597 Y.append(y)
01598 x = []
01599 for pair in line:
01600 idx, val = pair.split(':')
01601 idx = int(idx) - 1
01602 val = float(val)
01603 while len(x) < idx:
01604 x.append(0)
01605 x.append(val)
01606 X.append(x)
01607 return (X,Y)
01608
01609 def read_feature_file(file_name):
01610 data_in = file(file_name, 'r')
01611 lines = [l.split() for l in data_in.readlines()]
01612 data_in.close()
01613 X = []
01614 for line in lines:
01615 x = []
01616 for val in line:
01617 x.append(float(val))
01618 X.append(x)
01619 return X
01620
01621 def write_example_file(file_name, X, Y, normalize=False, debug=False):
01622 data_out = file(file_name, 'w')
01623
01624 i = 0
01625 for x,y in zip(X,Y):
01626 i += 1
01627 if debug:
01628 print y, x
01629 if isnan(y):
01630 print 'Skipping writing example: ', i
01631 continue
01632 data_line = str(y)
01633 if normalize:
01634 feature_sum = 0.0
01635 for xi in x:
01636 feature_sum += xi
01637 for i, xi in enumerate(x):
01638 if xi > 0:
01639 data_line += ' ' + str(i+1)+':'+str(sqrt(xi/float(feature_sum)))
01640 else:
01641 for i, xi in enumerate(x):
01642 if xi > 0:
01643 data_line += ' ' + str(i+1)+':'+str(xi)
01644 data_line +='\n'
01645 data_out.write(data_line)
01646 data_out.close()
01647 return (X,Y)
01648
01649 def rewrite_example_file_features(original_file_name, feat_file_name, out_file_name, normalize=False, debug=False):
01650 old_X, Y = read_example_file(original_file_name)
01651 X = read_feature_file(feat_file_name)
01652 write_example_file(out_file_name, X, Y, normalize, debug)
01653
01654 def extract_shape_features_batch():
01655 base_dir = '/home/thermans/Dropbox/Data/ichr2013-results/icdl_data/'
01656 class_dirs = ['camcorder3', 'food_box3', 'large_brush3', 'small_brush3','soap_box3', 'toothpaste3']
01657
01658
01659 base_dir = '/home/thermans/Dropbox/Data/ichr2013-results/rotate_to_heading_train_and_validate/'
01660 class_dirs = ['camcorder0', 'food_box0', 'large_brush0', 'small_brush0','soap_box0', 'toothpaste0']
01661
01662 out_dir = base_dir+'examples_line_dist/'
01663 feat_dir = base_dir+'examples_line_dist/'
01664
01665 for c in class_dirs:
01666 print 'Class:', c
01667 class_dir = base_dir+c+'/'
01668 files = os.listdir(class_dir)
01669 data_file = None
01670 for f in files:
01671 if f.startswith('aff_learn_out'):
01672 data_file = f
01673 if data_file is None:
01674 print 'ERROR: No data file in directory:', c
01675 continue
01676 aff_file = class_dir+data_file
01677 score_file = base_dir+'example_files/'+c+'.txt'
01678
01679 file_out = base_dir+'analysis/'+c+'_gt_scores.png'
01680 print '/home/thermans/src/gt-ros-pkg/cpl/tabletop_pushing/bin/extract_shape_features', aff_file, \
01681 class_dir, file_out, score_file
01682 p = subprocess.Popen(['/home/thermans/src/gt-ros-pkg/cpl/tabletop_pushing/bin/extract_shape_features',
01683 aff_file, class_dir, file_out, score_file], shell=False)
01684 p.wait()
01685
01686 def read_and_score_raw_files():
01687
01688
01689
01690 base_dir = '/home/thermans/Dropbox/Data/ichr2013-results/rotate_to_heading_train_and_validate/'
01691 class_dirs = ['camcorder0', 'food_box0', 'large_brush0', 'small_brush0','soap_box0', 'toothpaste0']
01692 out_dir = base_dir+'example_files/'
01693 use_spin = True
01694 for i, c in enumerate(class_dirs):
01695 in_dir = base_dir+c+'/'
01696 files = os.listdir(in_dir)
01697 file_name = None
01698 for f in files:
01699 if f.startswith('aff_learn_out'):
01700 file_name = f
01701 if file_name is None:
01702 continue
01703 file_in = in_dir+file_name
01704 file_out = out_dir+c+'.txt'
01705 print 'Out file:', file_out
01706 slp = StartLocPerformanceAnalysis()
01707 slp.generate_example_file(file_in, file_out, use_spin=use_spin)
01708
01709 def compare_predicted_and_observed_push_scores(in_file_name, out_file_name=None, use_spin=False):
01710 slp = StartLocPerformanceAnalysis()
01711 slp.compare_predicted_and_observed_push_scores(in_file_name, out_file_name, use_spin)
01712
01713 def compute_predicted_and_observed_push_scores(in_file_name, out_file_name=None, use_spin=False):
01714 slp = StartLocPerformanceAnalysis()
01715 slp.compute_observed_push_scores_final_errors(in_file_name, out_file_name, use_spin)
01716
01717 def analyze_predicted_and_observed_batch():
01718
01719
01720
01721 base_dir = '/home/thermans/Dropbox/Data/ichr2013-results/rotate_to_heading_rand_results/'
01722
01723 class_dirs = ['camcorder0', 'food_box0', 'large_brush0', 'small_brush0','soap_box0', 'toothpaste0']
01724 out_dir = base_dir+'analysis/'
01725 use_spin = True
01726
01727 for c in class_dirs:
01728 in_dir = base_dir+c+'/'
01729 files = os.listdir(in_dir)
01730 file_name = None
01731 for f in files:
01732 if f.startswith('aff_learn_out'):
01733 file_name = f
01734 if file_name is None:
01735 continue
01736 file_in = in_dir+file_name
01737 file_out = out_dir+c+'.txt'
01738 file_out_final_error = out_dir+c+'-final-error.txt'
01739 compare_predicted_and_observed_push_scores(file_in, file_out, use_spin)
01740 compute_predicted_and_observed_push_scores(file_in, file_out_final_error, use_spin)
01741
01742 def rank_straw_scores(file_path):
01743 straw_file = file(file_path, 'r')
01744 lines = [l.split() for l in straw_file.readlines()]
01745 scores = [float(l[0])*100 for l in lines]
01746 major_dists = [float(l[1]) for l in lines]
01747 minor_dists = [float(l[2]) for l in lines]
01748 min_major_dist = 10000
01749 major_dist_idx = 0
01750 min_minor_dist = 10000
01751 minor_dist_idx = 0
01752 for i in xrange(len(major_dists)):
01753 if major_dists[i] < min_major_dist:
01754 min_major_dist = major_dists[i]
01755 major_dist_idx = i
01756 if minor_dists[i] < min_minor_dist:
01757 min_minor_dist = minor_dists[i]
01758 minor_dist_idx = i
01759 major_score = scores[major_dist_idx]
01760 minor_score = scores[minor_dist_idx]
01761 scores.sort()
01762 print 'Major idx score: ' + str(major_score) + ' is ranked ' + str(scores.index(major_score)+1)
01763 print 'Minor idx score: ' + str(minor_score) + ' is ranked ' + str(scores.index(minor_score)+1)
01764 print 'Scores are: ' + str(scores)
01765
01766 def rank_straw_scores_batch():
01767 base_dir = '/home/thermans/Dropbox/Data/start_loc_learning/point_push/major_minor_axis_point_data/'
01768 classes = ['camcorder3', 'food_box3', 'large_brush3', 'small_brush3','soap_box3', 'toothpaste3']
01769 for c in classes:
01770 file_path = base_dir + 'straw_scores_' + c + '.txt'
01771 print 'Ranks for: ', c
01772 rank_straw_scores(file_path)
01773 print '\n'
01774
01775 def convert_robot_attempts_to_example_file(in_file_name, out_file_name):
01776 scores = []
01777 feats = []
01778 loc = []
01779 in_file = file(in_file_name,'r')
01780 raw_lines = in_file.readlines()
01781 in_file.close()
01782 for i, l in enumerate(raw_lines):
01783 line = l.split()
01784 loc.append((float(line[0]), float(line[1])))
01785 scores.append(float(line[2]))
01786 feats.append([float(f) for f in line[3:]])
01787 print i, len(feats[i])
01788 normalize = False
01789 debug = False
01790 return write_example_file(out_file_name, feats, scores, normalize, debug)
01791
01792 def convert_robot_attempts_file_batch():
01793 pass
01794
01795 def rank_straw_scores(file_path):
01796 straw_file = file(file_path, 'r')
01797 lines = [l.split() for l in straw_file.readlines()]
01798 scores = [float(l[0])*100 for l in lines]
01799 major_dists = [float(l[1]) for l in lines]
01800 minor_dists = [float(l[2]) for l in lines]
01801 min_major_dist = 10000
01802 major_dist_idx = 0
01803 min_minor_dist = 10000
01804 minor_dist_idx = 0
01805 for i in xrange(len(major_dists)):
01806 if major_dists[i] < min_major_dist:
01807 min_major_dist = major_dists[i]
01808 major_dist_idx = i
01809 if minor_dists[i] < min_minor_dist:
01810 min_minor_dist = minor_dists[i]
01811 minor_dist_idx = i
01812 major_score = scores[major_dist_idx]
01813 minor_score = scores[minor_dist_idx]
01814 scores.sort()
01815 print 'Major idx score: ' + str(major_score) + ' is ranked ' + str(scores.index(major_score)+1)
01816 print 'Minor idx score: ' + str(minor_score) + ' is ranked ' + str(scores.index(minor_score)+1)
01817 print 'Scores are: ' + str(scores)
01818
01819 def rank_straw_scores_batch():
01820 base_dir = '/home/thermans/Dropbox/Data/start_loc_learning/point_push/major_minor_axis_point_data/'
01821 classes = ['camcorder3', 'food_box3', 'large_brush3', 'small_brush3','soap_box3', 'toothpaste3']
01822 for c in classes:
01823 file_path = base_dir + 'straw_scores_' + c + '.txt'
01824 print 'Ranks for: ', c
01825 rank_straw_scores(file_path)
01826 print '\n'
01827
01828 if __name__ == '__main__':
01829 analyze_predicted_and_observed_batch()
01830
01831
01832