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 <cmath>
00020 #include <memory>
00021
00022 #include "Eigen/Geometry"
00023 #include "absl/memory/memory.h"
00024 #include "cartographer/common/lua_parameter_dictionary_test_helpers.h"
00025 #include "cartographer/mapping/2d/probability_grid.h"
00026 #include "cartographer/mapping/2d/probability_grid_range_data_inserter_2d.h"
00027 #include "cartographer/mapping/2d/tsdf_2d.h"
00028 #include "cartographer/mapping/2d/tsdf_range_data_inserter_2d.h"
00029 #include "cartographer/mapping/internal/scan_matching/real_time_correlative_scan_matcher.h"
00030 #include "cartographer/sensor/point_cloud.h"
00031 #include "cartographer/transform/transform.h"
00032 #include "gtest/gtest.h"
00033
00034 namespace cartographer {
00035 namespace mapping {
00036 namespace scan_matching {
00037 namespace {
00038
00039 proto::RealTimeCorrelativeScanMatcherOptions
00040 CreateRealTimeCorrelativeScanMatcherTestOptions2D() {
00041 auto parameter_dictionary = common::MakeDictionary(
00042 "return {"
00043 "linear_search_window = 0.6, "
00044 "angular_search_window = 0.16, "
00045 "translation_delta_cost_weight = 0., "
00046 "rotation_delta_cost_weight = 0., "
00047 "}");
00048 return CreateRealTimeCorrelativeScanMatcherOptions(
00049 parameter_dictionary.get());
00050 }
00051
00052 class RealTimeCorrelativeScanMatcherTest : public ::testing::Test {
00053 protected:
00054 RealTimeCorrelativeScanMatcherTest() {
00055 point_cloud_.push_back({Eigen::Vector3f{0.025f, 0.175f, 0.f}});
00056 point_cloud_.push_back({Eigen::Vector3f{-0.025f, 0.175f, 0.f}});
00057 point_cloud_.push_back({Eigen::Vector3f{-0.075f, 0.175f, 0.f}});
00058 point_cloud_.push_back({Eigen::Vector3f{-0.125f, 0.175f, 0.f}});
00059 point_cloud_.push_back({Eigen::Vector3f{-0.125f, 0.125f, 0.f}});
00060 point_cloud_.push_back({Eigen::Vector3f{-0.125f, 0.075f, 0.f}});
00061 point_cloud_.push_back({Eigen::Vector3f{-0.125f, 0.025f, 0.f}});
00062 real_time_correlative_scan_matcher_ =
00063 absl::make_unique<RealTimeCorrelativeScanMatcher2D>(
00064 CreateRealTimeCorrelativeScanMatcherTestOptions2D());
00065 }
00066
00067 void SetUpTSDF() {
00068 grid_ = absl::make_unique<TSDF2D>(
00069 MapLimits(0.05, Eigen::Vector2d(0.3, 0.5), CellLimits(20, 20)), 0.3,
00070 1.0, &conversion_tables_);
00071 {
00072 auto parameter_dictionary = common::MakeDictionary(R"text(
00073 return {
00074 truncation_distance = 0.3,
00075 maximum_weight = 10.,
00076 update_free_space = false,
00077 normal_estimation_options = {
00078 num_normal_samples = 4,
00079 sample_radius = 0.5,
00080 },
00081 project_sdf_distance_to_scan_normal = true,
00082 update_weight_range_exponent = 0,
00083 update_weight_angle_scan_normal_to_ray_kernel_bandwidth = 0.5,
00084 update_weight_distance_cell_to_hit_kernel_bandwidth = 0.5,
00085 })text");
00086 range_data_inserter_ = absl::make_unique<TSDFRangeDataInserter2D>(
00087 CreateTSDFRangeDataInserterOptions2D(parameter_dictionary.get()));
00088 }
00089 range_data_inserter_->Insert(
00090 sensor::RangeData{Eigen::Vector3f(0.5f, -0.5f, 0.f), point_cloud_, {}},
00091 grid_.get());
00092 grid_->FinishUpdate();
00093 }
00094
00095 void SetUpProbabilityGrid() {
00096 grid_ = absl::make_unique<ProbabilityGrid>(
00097 MapLimits(0.05, Eigen::Vector2d(0.05, 0.25), CellLimits(6, 6)),
00098 &conversion_tables_);
00099 {
00100 auto parameter_dictionary = common::MakeDictionary(
00101 "return { "
00102 "insert_free_space = true, "
00103 "hit_probability = 0.7, "
00104 "miss_probability = 0.4, "
00105 "}");
00106 range_data_inserter_ =
00107 absl::make_unique<ProbabilityGridRangeDataInserter2D>(
00108 CreateProbabilityGridRangeDataInserterOptions2D(
00109 parameter_dictionary.get()));
00110 }
00111 range_data_inserter_->Insert(
00112 sensor::RangeData{Eigen::Vector3f::Zero(), point_cloud_, {}},
00113 grid_.get());
00114 grid_->FinishUpdate();
00115 }
00116
00117 ValueConversionTables conversion_tables_;
00118 std::unique_ptr<Grid2D> grid_;
00119 std::unique_ptr<RangeDataInserterInterface> range_data_inserter_;
00120 sensor::PointCloud point_cloud_;
00121 std::unique_ptr<RealTimeCorrelativeScanMatcher2D>
00122 real_time_correlative_scan_matcher_;
00123 };
00124
00125 TEST_F(RealTimeCorrelativeScanMatcherTest,
00126 ScorePerfectHighResolutionCandidateProbabilityGrid) {
00127 SetUpProbabilityGrid();
00128 const std::vector<sensor::PointCloud> scans =
00129 GenerateRotatedScans(point_cloud_, SearchParameters(0, 0, 0., 0.));
00130 const std::vector<DiscreteScan2D> discrete_scans =
00131 DiscretizeScans(grid_->limits(), scans, Eigen::Translation2f::Identity());
00132 std::vector<Candidate2D> candidates;
00133 candidates.emplace_back(0, 0, 0, SearchParameters(0, 0, 0., 0.));
00134 real_time_correlative_scan_matcher_->ScoreCandidates(
00135 *grid_, discrete_scans, SearchParameters(0, 0, 0., 0.), &candidates);
00136 EXPECT_EQ(0, candidates[0].scan_index);
00137 EXPECT_EQ(0, candidates[0].x_index_offset);
00138 EXPECT_EQ(0, candidates[0].y_index_offset);
00139
00140 EXPECT_NEAR(0.7, candidates[0].score, 1e-2);
00141 }
00142
00143 TEST_F(RealTimeCorrelativeScanMatcherTest,
00144 ScorePerfectHighResolutionCandidateTSDF) {
00145 SetUpTSDF();
00146 const std::vector<sensor::PointCloud> scans =
00147 GenerateRotatedScans(point_cloud_, SearchParameters(0, 0, 0., 0.));
00148 const std::vector<DiscreteScan2D> discrete_scans =
00149 DiscretizeScans(grid_->limits(), scans, Eigen::Translation2f::Identity());
00150 std::vector<Candidate2D> candidates;
00151 candidates.emplace_back(0, 0, 0, SearchParameters(0, 0, 0., 0.));
00152 real_time_correlative_scan_matcher_->ScoreCandidates(
00153 *grid_, discrete_scans, SearchParameters(0, 0, 0., 0.), &candidates);
00154 EXPECT_EQ(0, candidates[0].scan_index);
00155 EXPECT_EQ(0, candidates[0].x_index_offset);
00156 EXPECT_EQ(0, candidates[0].y_index_offset);
00157
00158 EXPECT_NEAR(1.0, candidates[0].score, 1e-1);
00159 EXPECT_LT(0.95, candidates[0].score);
00160 }
00161
00162 TEST_F(RealTimeCorrelativeScanMatcherTest,
00163 ScorePartiallyCorrectHighResolutionCandidateProbabilityGrid) {
00164 SetUpProbabilityGrid();
00165 const std::vector<sensor::PointCloud> scans =
00166 GenerateRotatedScans(point_cloud_, SearchParameters(0, 0, 0., 0.));
00167 const std::vector<DiscreteScan2D> discrete_scans =
00168 DiscretizeScans(grid_->limits(), scans, Eigen::Translation2f::Identity());
00169 std::vector<Candidate2D> candidates;
00170 candidates.emplace_back(0, 0, 1, SearchParameters(0, 0, 0., 0.));
00171 real_time_correlative_scan_matcher_->ScoreCandidates(
00172 *grid_, discrete_scans, SearchParameters(0, 0, 0., 0.), &candidates);
00173 EXPECT_EQ(0, candidates[0].scan_index);
00174 EXPECT_EQ(0, candidates[0].x_index_offset);
00175 EXPECT_EQ(1, candidates[0].y_index_offset);
00176
00177 EXPECT_LT(0.7 * 3. / 7., candidates[0].score);
00178 EXPECT_GT(0.7, candidates[0].score);
00179 }
00180
00181 TEST_F(RealTimeCorrelativeScanMatcherTest,
00182 ScorePartiallyCorrectHighResolutionCandidateTSDF) {
00183 SetUpTSDF();
00184 const std::vector<sensor::PointCloud> scans =
00185 GenerateRotatedScans(point_cloud_, SearchParameters(0, 0, 0., 0.));
00186 const std::vector<DiscreteScan2D> discrete_scans =
00187 DiscretizeScans(grid_->limits(), scans, Eigen::Translation2f::Identity());
00188 std::vector<Candidate2D> candidates;
00189 candidates.emplace_back(0, 0, 1, SearchParameters(0, 0, 0., 0.));
00190 real_time_correlative_scan_matcher_->ScoreCandidates(
00191 *grid_, discrete_scans, SearchParameters(0, 0, 0., 0.), &candidates);
00192 EXPECT_EQ(0, candidates[0].scan_index);
00193 EXPECT_EQ(0, candidates[0].x_index_offset);
00194 EXPECT_EQ(1, candidates[0].y_index_offset);
00195
00196 EXPECT_LT(1.0 - 4. / (7. * 6.), candidates[0].score);
00197 EXPECT_GT(1.0, candidates[0].score);
00198 }
00199
00200 }
00201 }
00202 }
00203 }