00001 #include <place_matcher_csm/dissimilarity_getter.h>
00002
00003 namespace place_matcher_csm
00004 {
00005
00010 void polygonToLDP(const geometry_msgs::Polygon& poly, LDP& ldp)
00011 {
00012 const size_t n = poly.points.size();
00013
00014 ldp = ld_alloc_new(n);
00015
00016 for (size_t i = 0; i < n; ++i)
00017 {
00018
00019 if (is_nan(poly.points[i].x) || is_nan(poly.points[i].y))
00020 {
00021 ROS_WARN("place_matcher_csm: polygon input contains NaN values. \
00022 Please use a filtered polygon input.");
00023 }
00024 else
00025 {
00026 ldp->valid[i] = 1;
00027 ldp->points[i].p[0] = poly.points[i].x;
00028 ldp->points[i].p[1] = poly.points[i].y;
00029 ldp->points[i].rho = GSL_NAN;
00030 ldp->points[i].phi = GSL_NAN;
00031 }
00032 ldp->cluster[i] = -1;
00033 }
00034
00035 ldp->odometry[0] = 0.0;
00036 ldp->odometry[1] = 0.0;
00037 ldp->odometry[2] = 0.0;
00038
00039 ldp->true_pose[0] = 0.0;
00040 ldp->true_pose[1] = 0.0;
00041 ldp->true_pose[2] = 0.0;
00042 }
00043
00044 DissimilarityGetter::DissimilarityGetter(ros::NodeHandle& nh_private) :
00045 optimization_count_(36),
00046 nh_private_(nh_private)
00047 {
00048 initParams();
00049 }
00050
00051
00052
00053 void DissimilarityGetter::initParams()
00054 {
00055 csm_input_.min_reading = 0;
00056 csm_input_.max_reading = std::numeric_limits<double>::max();
00057
00058 nh_private_.getParam("optimization_count", optimization_count_);
00059 if (optimization_count_ < 1)
00060 {
00061 ROS_WARN_STREAM(nh_private_.getNamespace() << "/optimization_count should be at least 1, setting to default");
00062 optimization_count_ = 36;
00063 nh_private_.setParam("optimization_count", optimization_count_);
00064 }
00065
00066
00067
00068
00069
00070 csm_input_.max_angular_correction_deg = 180.0;
00071 nh_private_.getParam("max_angular_correction_deg", csm_input_.max_angular_correction_deg);
00072
00073
00074 csm_input_.max_linear_correction = 50.0;
00075 nh_private_.getParam("max_linear_correction", csm_input_.max_linear_correction);
00076
00077
00078 csm_input_.max_iterations = 10;
00079 nh_private_.getParam("max_iterations", csm_input_.max_iterations);
00080
00081
00082 csm_input_.epsilon_xy = 0.000001;
00083 nh_private_.getParam("epsilon_xy", csm_input_.epsilon_xy);
00084
00085
00086 csm_input_.epsilon_theta = 0.000001;
00087 nh_private_.getParam("epsilon_theta", csm_input_.epsilon_theta);
00088
00089
00090 csm_input_.max_correspondence_dist = 0.5;
00091 nh_private_.getParam("max_correspondence_dist", csm_input_.max_correspondence_dist);
00092
00093
00094 csm_input_.sigma = 0.010;
00095 nh_private_.getParam("sigma", csm_input_.sigma);
00096
00097
00098 csm_input_.use_corr_tricks = 1;
00099 nh_private_.getParam("use_corr_tricks", csm_input_.use_corr_tricks);
00100
00101
00102 csm_input_.restart = 0;
00103 nh_private_.getParam("restart", csm_input_.restart);
00104
00105
00106 csm_input_.restart_threshold_mean_error = 0.01;
00107 nh_private_.getParam("restart_threshold_mean_error", csm_input_.restart_threshold_mean_error);
00108
00109
00110 csm_input_.restart_dt = 1.0;
00111 nh_private_.getParam("restart_dt", csm_input_.restart_dt);
00112
00113
00114 csm_input_.restart_dtheta = 0.1;
00115 nh_private_.getParam("restart_dtheta", csm_input_.restart_dtheta);
00116
00117
00118 csm_input_.clustering_threshold = 0.25;
00119 nh_private_.getParam("clustering_threshold", csm_input_.clustering_threshold);
00120
00121
00122 csm_input_.orientation_neighbourhood = 20;
00123 nh_private_.getParam("orientation_neighbourhood", csm_input_.orientation_neighbourhood);
00124
00125
00126 csm_input_.use_point_to_line_distance = 1;
00127 nh_private_.getParam("use_point_to_line_distance", csm_input_.use_point_to_line_distance);
00128
00129
00130 csm_input_.do_alpha_test = 0;
00131 nh_private_.getParam("do_alpha_test", csm_input_.do_alpha_test);
00132
00133
00134 csm_input_.do_alpha_test_thresholdDeg = 20.0;
00135 nh_private_.getParam("do_alpha_test_thresholdDeg", csm_input_.do_alpha_test_thresholdDeg);
00136
00137
00138
00139 csm_input_.outliers_maxPerc = 0.90;
00140 nh_private_.getParam("outliers_maxPerc", csm_input_.outliers_maxPerc);
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 csm_input_.outliers_adaptive_order = 0.7;
00151 nh_private_.getParam("outliers_adaptive_order", csm_input_.outliers_adaptive_order);
00152
00153 csm_input_.outliers_adaptive_mult = 2.0;
00154 nh_private_.getParam("outliers_adaptive_mult", csm_input_.outliers_adaptive_mult);
00155
00156
00157
00158
00159
00160 csm_input_.do_visibility_test = 0;
00161 nh_private_.getParam("do_visibility_test", csm_input_.do_visibility_test);
00162
00163
00164 csm_input_.outliers_remove_doubles = 1;
00165 nh_private_.getParam("outliers_remove_doubles", csm_input_.outliers_remove_doubles);
00166
00167
00168 csm_input_.do_compute_covariance = 0;
00169 nh_private_.getParam("do_compute_covariance", csm_input_.do_compute_covariance);
00170
00171
00172 csm_input_.debug_verify_tricks = 0;
00173 nh_private_.getParam("debug_verify_tricks", csm_input_.debug_verify_tricks);
00174
00175
00176
00177 csm_input_.use_ml_weights = 0;
00178 nh_private_.getParam("use_ml_weights", csm_input_.use_ml_weights);
00179
00180
00181
00182 csm_input_.use_sigma_weights = 0;
00183 nh_private_.getParam("use_sigma_weights", csm_input_.use_sigma_weights);
00184 }
00185
00186
00187
00188
00189
00190
00191
00192 void sm_icp_xy(struct sm_params* params, struct sm_result* res)
00193 {
00194 res->valid = 0;
00195
00196 LDP laser_ref = params->laser_ref;
00197 LDP laser_sens = params->laser_sens;
00198
00199 if(params->use_corr_tricks || params->debug_verify_tricks)
00200 {
00201 ld_create_jump_tables(laser_ref);
00202 }
00203
00204
00205
00206
00207
00208 gsl_vector* x_new = gsl_vector_alloc(3);
00209 gsl_vector* x_old = vector_from_array(3, params->first_guess);
00210
00211 if(params->do_visibility_test)
00212 {
00213 sm_debug("laser_ref:\n");
00214 visibilityTest(laser_ref, x_old);
00215
00216 sm_debug("laser_sens:\n");
00217 gsl_vector* minus_x_old = gsl_vector_alloc(3);
00218 ominus(x_old, minus_x_old);
00219 visibilityTest(laser_sens, minus_x_old);
00220 gsl_vector_free(minus_x_old);
00221 }
00222
00223 double error;
00224 int iterations;
00225 int nvalid;
00226 if(!icp_loop(params, x_old->data, x_new->data, &error, &nvalid, &iterations))
00227 {
00228 ROS_ERROR("icp: ICP failed for some reason. \n");
00229 res->valid = 0;
00230 res->iterations = iterations;
00231 res->nvalid = 0;
00232 }
00233 else
00234 {
00235
00236
00237 double best_error = error;
00238 gsl_vector* best_x = gsl_vector_alloc(3);
00239 gsl_vector_memcpy(best_x, x_new);
00240
00241 if (params->restart && (error/nvalid) > (params->restart_threshold_mean_error))
00242 {
00243 ROS_DEBUG("Restarting: %f > %f \n", error/nvalid, params->restart_threshold_mean_error);
00244 double dt = params->restart_dt;
00245 double dth = params->restart_dtheta;
00246 ROS_DEBUG("icp_loop: dt = %f dtheta= %f deg\n", dt, rad2deg(dth));
00247
00248 double perturb[6][3] = {
00249 {dt, 0, 0}, {-dt, 0, 0},
00250 {0, dt, 0}, {0, -dt, 0},
00251 {0, 0, dth}, {0, 0, -dth}
00252 };
00253
00254 for(int a = 0; a < 6; a++)
00255 {
00256 ROS_DEBUG("-- Restarting with perturbation #%d\n", a);
00257 struct sm_params my_params = *params;
00258 gsl_vector* start = gsl_vector_alloc(3);
00259 gvs(start, 0, gvg(x_new, 0) + perturb[a][0]);
00260 gvs(start, 1, gvg(x_new, 1) + perturb[a][1]);
00261 gvs(start, 2, gvg(x_new, 2) + perturb[a][2]);
00262 gsl_vector* x_a = gsl_vector_alloc(3);
00263 double my_error;
00264 int my_valid;
00265 int my_iterations;
00266 if (!icp_loop(&my_params, start->data, x_a->data, &my_error, &my_valid, &my_iterations))
00267 {
00268 ROS_ERROR("Error during restart #%d/%d. \n", a, 6);
00269 break;
00270 }
00271 iterations += my_iterations;
00272
00273 if (my_error < best_error)
00274 {
00275 ROS_DEBUG("--Perturbation #%d resulted in error %f < %f\n", a, my_error, best_error);
00276 gsl_vector_memcpy(best_x, x_a);
00277 best_error = my_error;
00278 }
00279 gsl_vector_free(x_a);
00280 gsl_vector_free(start);
00281 }
00282 }
00283
00284
00285 res->valid = 1;
00286 vector_to_array(best_x, res->x);
00287 ROS_DEBUG("icp: final x = %s \n", gsl_friendly_pose(best_x));
00288
00289 if(params->do_compute_covariance)
00290 {
00291 val cov0_x;
00292 val dx_dy1;
00293 val dx_dy2;
00294 compute_covariance_exact(
00295 laser_ref, laser_sens, best_x,
00296 &cov0_x, &dx_dy1, &dx_dy2);
00297
00298 val cov_x = sc(square(params->sigma), cov0_x);
00299
00300 res->cov_x_m = egsl_v2gslm(cov_x);
00301 res->dx_dy1_m = egsl_v2gslm(dx_dy1);
00302 res->dx_dy2_m = egsl_v2gslm(dx_dy2);
00303
00304 }
00305
00306 res->error = best_error;
00307 res->iterations = iterations;
00308 res->nvalid = nvalid;
00309
00310 gsl_vector_free(best_x);
00311 }
00312 gsl_vector_free(x_new);
00313 gsl_vector_free(x_old);
00314 }
00315
00316 bool DissimilarityGetter::getDissimilarity(place_matcher_msgs::PolygonDissimilarityRequest& req, place_matcher_msgs::PolygonDissimilarityResponse& res)
00317 {
00318 ros::WallTime start = ros::WallTime::now();
00319
00320 LDP ldp1;
00321 polygonToLDP(req.polygon1, ldp1);
00322 csm_input_.laser_ref = ldp1;
00323
00324 LDP ldp2;
00325 polygonToLDP(req.polygon2, ldp2);
00326 csm_input_.laser_sens = ldp2;
00327
00328
00329
00330 double best_error = std::numeric_limits<double>::max();
00331 double best_x = 0.0;
00332 double best_y = 0.0;
00333 double best_yaw = 0.0;
00334 for (int i = 0; i < optimization_count_; ++i)
00335 {
00336 const double init_yaw = 2 * M_PI * i / optimization_count_;
00337
00338 csm_input_.first_guess[2] = init_yaw;
00339
00340
00341 sm_result csm_output;
00342 sm_icp_xy(&csm_input_, &csm_output);
00343 if (!csm_output.valid)
00344 {
00345 ROS_ERROR("Canonical scan match failed with initial angle %.3f rad", init_yaw);
00346 continue;
00347 }
00348 if (csm_output.error < best_error)
00349 {
00350 best_x = csm_output.x[0];
00351 best_y = csm_output.x[1];
00352 best_yaw = csm_output.x[2];
00353 best_error = csm_output.error;
00354 }
00355 ROS_DEBUG("Canonical scan match return value = %f with initial angle %.3f rad", csm_output.error, init_yaw);
00356 }
00357
00358 if (best_error == std::numeric_limits<double>::max())
00359 {
00360 ROS_INFO("Canonical scan match failed for all initial angles");
00361 res.raw_dissimilarity = best_error;
00362 res.pose.orientation.w = 1.0;
00363 res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00364 return false;
00365 }
00366
00367 res.raw_dissimilarity = best_error;
00368
00369
00370 const double cos_ = std::cos(best_yaw);
00371 const double sin_ = std::sin(best_yaw);
00372 res.pose.position.x = -best_x * cos_ - best_y * sin_;
00373 res.pose.position.y = best_x * sin_ - best_y * cos_;
00374 res.pose.orientation = tf::createQuaternionMsgFromYaw(-best_yaw);
00375 res.processing_time = ros::Duration((ros::WallTime::now() - start).toSec());
00376
00377 csm_input_.laser_ref = NULL;
00378 csm_input_.laser_sens = NULL;
00379 ld_free(ldp1);
00380 ld_free(ldp2);
00381 return true;
00382 }
00383
00384 }
00385