00001 #include <math.h>
00002 #include <string.h>
00003
00004 #include <gsl/gsl_matrix.h>
00005
00006 #include <gpc/gpc.h>
00007 #include <egsl/egsl_macros.h>
00008
00009 #include "../csm_all.h"
00010
00011 #include "icp.h"
00012
00013 int icp_loop(struct sm_params*params, const double*q0, double*x_new,
00014 double*total_error, int*valid, int*iterations) {
00015 if(any_nan(q0,3)) {
00016 sm_error("icp_loop: Initial pose contains nan: %s\n", friendly_pose(q0));
00017 return 0;
00018 }
00019
00020
00021 LDP laser_sens = params->laser_sens;
00022 double x_old[3], delta[3], delta_old[3] = {0,0,0};
00023 copy_d(q0, 3, x_old);
00024 unsigned int hashes[params->max_iterations];
00025 int iteration;
00026
00027 sm_debug("icp: starting at q0 = %s \n", friendly_pose(x_old));
00028
00029 if(JJ) jj_loop_enter("iterations");
00030
00031 int all_is_okay = 1;
00032
00033 for(iteration=0; iteration<params->max_iterations;iteration++) {
00034 if(JJ) jj_loop_iteration();
00035 if(JJ) jj_add_double_array("x_old", x_old, 3);
00036
00037 egsl_push_named("icp_loop iteration");
00038 sm_debug("== icp_loop: starting iteration. %d \n", iteration);
00039
00042 ld_compute_world_coords(laser_sens, x_old);
00043
00045 if(params->use_corr_tricks)
00046 find_correspondences_tricks(params);
00047 else
00048 find_correspondences(params);
00049
00052 if(params->debug_verify_tricks)
00053 debug_correspondences(params);
00054
00055
00056 int num_corr = ld_num_valid_correspondences(laser_sens);
00057 double fail_perc = 0.05;
00058 if(num_corr < fail_perc * laser_sens->nrays) {
00059 sm_error(" : before trimming, only %d correspondences.\n",num_corr);
00060 all_is_okay = 0;
00061 egsl_pop_named("icp_loop iteration");
00062 break;
00063 }
00064
00065 if(JJ) jj_add("corr0", corr_to_json(laser_sens->corr, laser_sens->nrays));
00066
00067
00068 if(params->outliers_remove_doubles)
00069 kill_outliers_double(params);
00070
00071 int num_corr2 = ld_num_valid_correspondences(laser_sens);
00072
00073 if(JJ) jj_add("corr1", corr_to_json(laser_sens->corr, laser_sens->nrays));
00074
00075 double error=0;
00076
00077 kill_outliers_trim(params, &error);
00078 int num_corr_after = ld_num_valid_correspondences(laser_sens);
00079
00080 if(JJ) {
00081 jj_add("corr2", corr_to_json(laser_sens->corr, laser_sens->nrays));
00082 jj_add_int("num_corr0", num_corr);
00083 jj_add_int("num_corr1", num_corr2);
00084 jj_add_int("num_corr2", num_corr_after);
00085 }
00086
00087 *total_error = error;
00088 *valid = num_corr_after;
00089
00090 sm_debug(" icp_loop: total error: %f valid %d mean = %f\n", *total_error, *valid, *total_error/ *valid);
00091
00092
00093 if(num_corr_after < fail_perc * laser_sens->nrays){
00094 sm_error(" icp_loop: failed: after trimming, only %d correspondences.\n",num_corr_after);
00095 all_is_okay = 0;
00096 egsl_pop_named("icp_loop iteration");
00097 break;
00098 }
00099
00100
00101 if(!compute_next_estimate(params, x_old, x_new)) {
00102 sm_error(" icp_loop: Cannot compute next estimate.\n");
00103 all_is_okay = 0;
00104 egsl_pop_named("icp_loop iteration");
00105 break;
00106 }
00107
00108 pose_diff_d(x_new, x_old, delta);
00109
00110 {
00111 sm_debug(" icp_loop: killing. laser_sens has %d/%d rays valid, %d corr found -> %d after double cut -> %d after adaptive cut \n", count_equal(laser_sens->valid, laser_sens->nrays, 1), laser_sens->nrays, num_corr, num_corr2, num_corr_after);
00112 if(JJ) {
00113 jj_add_double_array("x_new", x_new, 3);
00114 jj_add_double_array("delta", delta, 3);
00115 }
00116 }
00118 hashes[iteration] = ld_corr_hash(laser_sens);
00119
00120 {
00121 sm_debug(" icp_loop: it. %d hash=%d nvalid=%d mean error = %f, x_new= %s\n",
00122 iteration, hashes[iteration], *valid, *total_error/ *valid,
00123 friendly_pose(x_new));
00124 }
00125
00126
00128 if(params->use_point_to_line_distance) {
00129 int loop_detected = 0;
00130 int a; for(a=iteration-1;a>=0;a--) {
00131 if(hashes[a]==hashes[iteration]) {
00132 sm_debug("icpc: oscillation detected (cycle length = %d)\n", iteration-a);
00133 loop_detected = 1;
00134 break;
00135 }
00136 }
00137 if(loop_detected) {
00138 egsl_pop_named("icp_loop iteration");
00139 break;
00140 }
00141 }
00142
00143
00144
00145
00146 if(termination_criterion(params, delta)) {
00147 egsl_pop_named("icp_loop iteration");
00148 break;
00149 }
00150
00151 copy_d(x_new, 3, x_old);
00152 copy_d(delta, 3, delta_old);
00153
00154
00155 egsl_pop_named("icp_loop iteration");
00156 }
00157
00158 if(JJ) jj_loop_exit();
00159
00160 *iterations = iteration+1;
00161
00162 return all_is_okay;
00163 }
00164
00165 int termination_criterion(struct sm_params*params, const double*delta){
00166 double a = norm_d(delta);
00167 double b = fabs(delta[2]);
00168 return (a<params->epsilon_xy) && (b<params->epsilon_theta);
00169 }
00170
00171 int compute_next_estimate(struct sm_params*params,
00172 const double x_old[3], double x_new[3])
00173 {
00174 LDP laser_ref = params->laser_ref;
00175 LDP laser_sens = params->laser_sens;
00176
00177 struct gpc_corr c[laser_sens->nrays];
00178
00179 int i; int k=0;
00180 for(i=0;i<laser_sens->nrays;i++) {
00181 if(!laser_sens->valid[i])
00182 continue;
00183
00184 if(!ld_valid_corr(laser_sens,i))
00185 continue;
00186
00187 int j1 = laser_sens->corr[i].j1;
00188 int j2 = laser_sens->corr[i].j2;
00189
00190 c[k].valid = 1;
00191
00192 if(laser_sens->corr[i].type == corr_pl) {
00193
00194 c[k].p[0] = laser_sens->points[i].p[0];
00195 c[k].p[1] = laser_sens->points[i].p[1];
00196 c[k].q[0] = laser_ref->points[j1].p[0];
00197 c[k].q[1] = laser_ref->points[j1].p[1];
00198
00200 double diff[2];
00201 diff[0] = laser_ref->points[j1].p[0]-laser_ref->points[j2].p[0];
00202 diff[1] = laser_ref->points[j1].p[1]-laser_ref->points[j2].p[1];
00203 const double length_diff = sqrt(diff[0]*diff[0]+diff[1]*diff[1]);
00204 double normal[2];
00205 if (length_diff < 1e-10) {
00206 normal[0] = 1.0;
00207 normal[1] = 0.0;
00208 }
00209 else {
00210 double one_on_norm = 1 / length_diff;
00211 normal[0] = +diff[1] * one_on_norm;
00212 normal[1] = -diff[0] * one_on_norm;
00213 }
00214
00215 double cos_alpha = normal[0];
00216 double sin_alpha = normal[1];
00217
00218 c[k].C[0][0] = cos_alpha*cos_alpha;
00219 c[k].C[1][0] =
00220 c[k].C[0][1] = cos_alpha*sin_alpha;
00221 c[k].C[1][1] = sin_alpha*sin_alpha;
00222
00223
00224
00225
00226 #if 0
00227
00228
00229 double det = c[k].C[0][0] * c[k].C[1][1] - c[k].C[0][1] * c[k].C[1][0];
00230 double trace = c[k].C[0][0] + c[k].C[1][1];
00231
00232 int semidef = (det >= 0) && (trace>0);
00233 if(!semidef) {
00234
00235 double eps = -det;
00236 c[k].C[0][0] += 2*sqrt(eps);
00237 c[k].C[1][1] += 2*sqrt(eps);
00238 }
00239 #endif
00240 } else {
00241 c[k].p[0] = laser_sens->points[i].p[0];
00242 c[k].p[1] = laser_sens->points[i].p[1];
00243
00244 projection_on_segment_d(
00245 laser_ref->points[j1].p,
00246 laser_ref->points[j2].p,
00247 laser_sens->points_w[i].p,
00248 c[k].q);
00249
00250
00251 c[k].C[0][0] = 1;
00252 c[k].C[1][0] = 0;
00253 c[k].C[0][1] = 0;
00254 c[k].C[1][1] = 1;
00255 }
00256
00257
00258 double factor = 1;
00259
00260
00261
00262 if(params->use_ml_weights) {
00263 int have_alpha = 0;
00264 double alpha = 0;
00265 if(!is_nan(laser_ref->true_alpha[j1])) {
00266 alpha = laser_ref->true_alpha[j1];
00267 have_alpha = 1;
00268 } else if(laser_ref->alpha_valid[j1]) {
00269 alpha = laser_ref->alpha[j1];;
00270 have_alpha = 1;
00271 } else have_alpha = 0;
00272
00273 if(have_alpha) {
00274 double pose_theta = x_old[2];
00279 double beta = alpha - (pose_theta + laser_sens->theta[i]);
00280 factor = 1 / square(cos(beta));
00281 } else {
00282 static int warned_before = 0;
00283 if(!warned_before) {
00284 sm_error("Param use_ml_weights was active, but not valid alpha[] or true_alpha[]."
00285 "Perhaps, if this is a single ray not having alpha, you should mark it as inactive.\n");
00286 sm_error("Writing laser_ref: \n");
00287 ld_write_as_json(laser_ref, stderr);
00288 warned_before = 1;
00289 }
00290 }
00291 }
00292
00293
00294 if(params->use_sigma_weights) {
00295 if(!is_nan(laser_sens->readings_sigma[i])) {
00296 factor *= 1 / square(laser_sens->readings_sigma[i]);
00297 } else {
00298 static int warned_before = 0;
00299 if(!warned_before) {
00300 sm_error("Param use_sigma_weights was active, but the field readings_sigma[] was not filled in.\n");
00301 sm_error("Writing laser_sens: \n");
00302 ld_write_as_json(laser_sens, stderr);
00303 }
00304 }
00305 }
00306
00307 c[k].C[0][0] *= factor;
00308 c[k].C[1][0] *= factor;
00309 c[k].C[0][1] *= factor;
00310 c[k].C[1][1] *= factor;
00311
00312 k++;
00313 }
00314
00315
00316 double std = 0.11;
00317 const double inv_cov_x0[9] =
00318 {1/(std*std), 0, 0,
00319 0, 1/(std*std), 0,
00320 0, 0, 0};
00321
00322
00323 int ok = gpc_solve(k, c, 0, inv_cov_x0, x_new);
00324 if(!ok) {
00325 sm_error("gpc_solve_valid failed\n");
00326 return 0;
00327 }
00328
00329 double old_error = gpc_total_error(c, k, x_old);
00330 double new_error = gpc_total_error(c, k, x_new);
00331
00332 sm_debug("\tcompute_next_estimate: old error: %f x_old= %s \n", old_error, friendly_pose(x_old));
00333 sm_debug("\tcompute_next_estimate: new error: %f x_new= %s \n", new_error, friendly_pose(x_new));
00334 sm_debug("\tcompute_next_estimate: new error - old_error: %g \n", new_error-old_error);
00335
00336 double epsilon = 0.000001;
00337 if(new_error > old_error + epsilon) {
00338 sm_error("\tcompute_next_estimate: something's fishy here! Old error: %lf new error: %lf x_old %lf %lf %lf x_new %lf %lf %lf\n",old_error,new_error,x_old[0],x_old[1],x_old[2],x_new[0],x_new[1],x_new[2]);
00339 }
00340
00341 return 1;
00342 }
00343
00344
00345