real_time_correlative_scan_matcher_2d.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright 2016 The Cartographer Authors
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
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 }  // namespace
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 }  // namespace scan_matching
00179 }  // namespace mapping
00180 }  // namespace cartographer


cartographer
Author(s): The Cartographer Authors
autogenerated on Thu May 9 2019 02:27:35