Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/mapping/internal/2d/scan_matching/real_time_correlative_scan_matcher_2d.h"
00018
00019 #include <algorithm>
00020 #include <cmath>
00021 #include <functional>
00022 #include <limits>
00023
00024 #include "Eigen/Geometry"
00025 #include "cartographer/common/lua_parameter_dictionary.h"
00026 #include "cartographer/common/math.h"
00027 #include "cartographer/mapping/2d/probability_grid.h"
00028 #include "cartographer/mapping/2d/tsdf_2d.h"
00029 #include "cartographer/sensor/point_cloud.h"
00030 #include "cartographer/transform/transform.h"
00031 #include "glog/logging.h"
00032
00033 namespace cartographer {
00034 namespace mapping {
00035 namespace scan_matching {
00036 namespace {
00037
00038 float ComputeCandidateScore(const TSDF2D& tsdf,
00039 const DiscreteScan2D& discrete_scan,
00040 int x_index_offset, int y_index_offset) {
00041 float candidate_score = 0.f;
00042 float summed_weight = 0.f;
00043 for (const Eigen::Array2i& xy_index : discrete_scan) {
00044 const Eigen::Array2i proposed_xy_index(xy_index.x() + x_index_offset,
00045 xy_index.y() + y_index_offset);
00046 const std::pair<float, float> tsd_and_weight =
00047 tsdf.GetTSDAndWeight(proposed_xy_index);
00048 const float normalized_tsd_score =
00049 (tsdf.GetMaxCorrespondenceCost() - std::abs(tsd_and_weight.first)) /
00050 tsdf.GetMaxCorrespondenceCost();
00051 const float weight = tsd_and_weight.second;
00052 candidate_score += normalized_tsd_score * weight;
00053 summed_weight += weight;
00054 }
00055 if (summed_weight == 0.f) return 0.f;
00056 candidate_score /= summed_weight;
00057 CHECK_GE(candidate_score, 0.f);
00058 return candidate_score;
00059 }
00060
00061 float ComputeCandidateScore(const ProbabilityGrid& probability_grid,
00062 const DiscreteScan2D& discrete_scan,
00063 int x_index_offset, int y_index_offset) {
00064 float candidate_score = 0.f;
00065 for (const Eigen::Array2i& xy_index : discrete_scan) {
00066 const Eigen::Array2i proposed_xy_index(xy_index.x() + x_index_offset,
00067 xy_index.y() + y_index_offset);
00068 const float probability =
00069 probability_grid.GetProbability(proposed_xy_index);
00070 candidate_score += probability;
00071 }
00072 candidate_score /= static_cast<float>(discrete_scan.size());
00073 CHECK_GT(candidate_score, 0.f);
00074 return candidate_score;
00075 }
00076
00077 }
00078
00079 RealTimeCorrelativeScanMatcher2D::RealTimeCorrelativeScanMatcher2D(
00080 const proto::RealTimeCorrelativeScanMatcherOptions& options)
00081 : options_(options) {}
00082
00083 std::vector<Candidate2D>
00084 RealTimeCorrelativeScanMatcher2D::GenerateExhaustiveSearchCandidates(
00085 const SearchParameters& search_parameters) const {
00086 int num_candidates = 0;
00087 for (int scan_index = 0; scan_index != search_parameters.num_scans;
00088 ++scan_index) {
00089 const int num_linear_x_candidates =
00090 (search_parameters.linear_bounds[scan_index].max_x -
00091 search_parameters.linear_bounds[scan_index].min_x + 1);
00092 const int num_linear_y_candidates =
00093 (search_parameters.linear_bounds[scan_index].max_y -
00094 search_parameters.linear_bounds[scan_index].min_y + 1);
00095 num_candidates += num_linear_x_candidates * num_linear_y_candidates;
00096 }
00097 std::vector<Candidate2D> candidates;
00098 candidates.reserve(num_candidates);
00099 for (int scan_index = 0; scan_index != search_parameters.num_scans;
00100 ++scan_index) {
00101 for (int x_index_offset = search_parameters.linear_bounds[scan_index].min_x;
00102 x_index_offset <= search_parameters.linear_bounds[scan_index].max_x;
00103 ++x_index_offset) {
00104 for (int y_index_offset =
00105 search_parameters.linear_bounds[scan_index].min_y;
00106 y_index_offset <= search_parameters.linear_bounds[scan_index].max_y;
00107 ++y_index_offset) {
00108 candidates.emplace_back(scan_index, x_index_offset, y_index_offset,
00109 search_parameters);
00110 }
00111 }
00112 }
00113 CHECK_EQ(candidates.size(), num_candidates);
00114 return candidates;
00115 }
00116
00117 double RealTimeCorrelativeScanMatcher2D::Match(
00118 const transform::Rigid2d& initial_pose_estimate,
00119 const sensor::PointCloud& point_cloud, const Grid2D& grid,
00120 transform::Rigid2d* pose_estimate) const {
00121 CHECK(pose_estimate != nullptr);
00122
00123 const Eigen::Rotation2Dd initial_rotation = initial_pose_estimate.rotation();
00124 const sensor::PointCloud rotated_point_cloud = sensor::TransformPointCloud(
00125 point_cloud,
00126 transform::Rigid3f::Rotation(Eigen::AngleAxisf(
00127 initial_rotation.cast<float>().angle(), Eigen::Vector3f::UnitZ())));
00128 const SearchParameters search_parameters(
00129 options_.linear_search_window(), options_.angular_search_window(),
00130 rotated_point_cloud, grid.limits().resolution());
00131
00132 const std::vector<sensor::PointCloud> rotated_scans =
00133 GenerateRotatedScans(rotated_point_cloud, search_parameters);
00134 const std::vector<DiscreteScan2D> discrete_scans = DiscretizeScans(
00135 grid.limits(), rotated_scans,
00136 Eigen::Translation2f(initial_pose_estimate.translation().x(),
00137 initial_pose_estimate.translation().y()));
00138 std::vector<Candidate2D> candidates =
00139 GenerateExhaustiveSearchCandidates(search_parameters);
00140 ScoreCandidates(grid, discrete_scans, search_parameters, &candidates);
00141
00142 const Candidate2D& best_candidate =
00143 *std::max_element(candidates.begin(), candidates.end());
00144 *pose_estimate = transform::Rigid2d(
00145 {initial_pose_estimate.translation().x() + best_candidate.x,
00146 initial_pose_estimate.translation().y() + best_candidate.y},
00147 initial_rotation * Eigen::Rotation2Dd(best_candidate.orientation));
00148 return best_candidate.score;
00149 }
00150
00151 void RealTimeCorrelativeScanMatcher2D::ScoreCandidates(
00152 const Grid2D& grid, const std::vector<DiscreteScan2D>& discrete_scans,
00153 const SearchParameters& search_parameters,
00154 std::vector<Candidate2D>* const candidates) const {
00155 for (Candidate2D& candidate : *candidates) {
00156 switch (grid.GetGridType()) {
00157 case GridType::PROBABILITY_GRID:
00158 candidate.score = ComputeCandidateScore(
00159 static_cast<const ProbabilityGrid&>(grid),
00160 discrete_scans[candidate.scan_index], candidate.x_index_offset,
00161 candidate.y_index_offset);
00162 break;
00163 case GridType::TSDF:
00164 candidate.score = ComputeCandidateScore(
00165 static_cast<const TSDF2D&>(grid),
00166 discrete_scans[candidate.scan_index], candidate.x_index_offset,
00167 candidate.y_index_offset);
00168 break;
00169 }
00170 candidate.score *=
00171 std::exp(-common::Pow2(std::hypot(candidate.x, candidate.y) *
00172 options_.translation_delta_cost_weight() +
00173 std::abs(candidate.orientation) *
00174 options_.rotation_delta_cost_weight()));
00175 }
00176 }
00177
00178 }
00179 }
00180 }