fast_correlative_scan_matcher_2d_test.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2016 The Cartographer Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
18 
19 #include <algorithm>
20 #include <cmath>
21 #include <limits>
22 #include <random>
23 #include <string>
24 
30 #include "gtest/gtest.h"
31 
32 namespace cartographer {
33 namespace mapping {
34 namespace scan_matching {
35 namespace {
36 
37 TEST(PrecomputationGridTest, CorrectValues) {
38  // Create a probability grid with random values that can be exactly
39  // represented by uint8 values.
40  std::mt19937 prng(42);
41  std::uniform_int_distribution<int> distribution(0, 255);
42  ProbabilityGrid probability_grid(
43  MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(250, 250)));
44  std::vector<float> reusable_intermediate_grid;
45  PrecomputationGrid2D precomputation_grid_dummy(
46  probability_grid, probability_grid.limits().cell_limits(), 1,
47  &reusable_intermediate_grid);
48  for (const Eigen::Array2i& xy_index :
49  XYIndexRangeIterator(Eigen::Array2i(50, 50), Eigen::Array2i(249, 249))) {
50  probability_grid.SetProbability(
51  xy_index, precomputation_grid_dummy.ToScore(distribution(prng)));
52  }
53 
54  reusable_intermediate_grid.clear();
55  for (const int width : {1, 2, 3, 8}) {
56  PrecomputationGrid2D precomputation_grid(
57  probability_grid, probability_grid.limits().cell_limits(), width,
58  &reusable_intermediate_grid);
59  for (const Eigen::Array2i& xy_index :
60  XYIndexRangeIterator(probability_grid.limits().cell_limits())) {
61  float max_score = -std::numeric_limits<float>::infinity();
62  for (int y = 0; y != width; ++y) {
63  for (int x = 0; x != width; ++x) {
64  max_score = std::max<float>(
65  max_score,
66  probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y)));
67  }
68  }
69  EXPECT_NEAR(
70  max_score,
71  precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)),
72  1e-4);
73  }
74  }
75 }
76 
77 TEST(PrecomputationGridTest, TinyProbabilityGrid) {
78  std::mt19937 prng(42);
79  std::uniform_int_distribution<int> distribution(0, 255);
80  ProbabilityGrid probability_grid(
81  MapLimits(0.05, Eigen::Vector2d(0.1, 0.1), CellLimits(4, 4)));
82  std::vector<float> reusable_intermediate_grid;
83  PrecomputationGrid2D precomputation_grid_dummy(
84  probability_grid, probability_grid.limits().cell_limits(), 1,
85  &reusable_intermediate_grid);
86  for (const Eigen::Array2i& xy_index :
87  XYIndexRangeIterator(probability_grid.limits().cell_limits())) {
88  probability_grid.SetProbability(
89  xy_index, precomputation_grid_dummy.ToScore(distribution(prng)));
90  }
91 
92  reusable_intermediate_grid.clear();
93  for (const int width : {1, 2, 3, 8, 200}) {
94  PrecomputationGrid2D precomputation_grid(
95  probability_grid, probability_grid.limits().cell_limits(), width,
96  &reusable_intermediate_grid);
97  for (const Eigen::Array2i& xy_index :
98  XYIndexRangeIterator(probability_grid.limits().cell_limits())) {
99  float max_score = -std::numeric_limits<float>::infinity();
100  for (int y = 0; y != width; ++y) {
101  for (int x = 0; x != width; ++x) {
102  max_score = std::max<float>(
103  max_score,
104  probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y)));
105  }
106  }
107  EXPECT_NEAR(
108  max_score,
109  precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)),
110  1e-4);
111  }
112  }
113 }
114 
115 proto::FastCorrelativeScanMatcherOptions2D
116 CreateFastCorrelativeScanMatcherTestOptions2D(
117  const int branch_and_bound_depth) {
118  auto parameter_dictionary =
119  common::MakeDictionary(R"text(
120  return {
121  linear_search_window = 3.,
122  angular_search_window = 1.,
123  branch_and_bound_depth = )text" +
124  std::to_string(branch_and_bound_depth) + "}");
125  return CreateFastCorrelativeScanMatcherOptions2D(parameter_dictionary.get());
126 }
127 
128 mapping::proto::ProbabilityGridRangeDataInserterOptions2D
129 CreateRangeDataInserterTestOptions2D() {
130  auto parameter_dictionary = common::MakeDictionary(R"text(
131  return {
132  insert_free_space = true,
133  hit_probability = 0.7,
134  miss_probability = 0.4,
135  })text");
137  parameter_dictionary.get());
138 }
139 
140 TEST(FastCorrelativeScanMatcherTest, CorrectPose) {
141  std::mt19937 prng(42);
142  std::uniform_real_distribution<float> distribution(-1.f, 1.f);
143  ProbabilityGridRangeDataInserter2D range_data_inserter(
144  CreateRangeDataInserterTestOptions2D());
145  constexpr float kMinScore = 0.1f;
146  const auto options = CreateFastCorrelativeScanMatcherTestOptions2D(3);
147 
148  sensor::PointCloud point_cloud;
149  point_cloud.emplace_back(-2.5f, 0.5f, 0.f);
150  point_cloud.emplace_back(-2.f, 0.5f, 0.f);
151  point_cloud.emplace_back(0.f, -0.5f, 0.f);
152  point_cloud.emplace_back(0.5f, -1.6f, 0.f);
153  point_cloud.emplace_back(2.5f, 0.5f, 0.f);
154  point_cloud.emplace_back(2.5f, 1.7f, 0.f);
155 
156  for (int i = 0; i != 50; ++i) {
157  const transform::Rigid2f expected_pose(
158  {2. * distribution(prng), 2. * distribution(prng)},
159  0.5 * distribution(prng));
160 
161  ProbabilityGrid probability_grid(
162  MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(200, 200)));
163  range_data_inserter.Insert(
164  sensor::RangeData{
165  Eigen::Vector3f(expected_pose.translation().x(),
166  expected_pose.translation().y(), 0.f),
168  point_cloud, transform::Embed3D(expected_pose.cast<float>())),
169  {}},
170  &probability_grid);
171  probability_grid.FinishUpdate();
172 
173  FastCorrelativeScanMatcher2D fast_correlative_scan_matcher(probability_grid,
174  options);
175  transform::Rigid2d pose_estimate;
176  float score;
177  EXPECT_TRUE(fast_correlative_scan_matcher.Match(
178  transform::Rigid2d::Identity(), point_cloud, kMinScore, &score,
179  &pose_estimate));
180  EXPECT_LT(kMinScore, score);
181  EXPECT_THAT(expected_pose,
182  transform::IsNearly(pose_estimate.cast<float>(), 0.03f))
183  << "Actual: " << transform::ToProto(pose_estimate).DebugString()
184  << "\nExpected: " << transform::ToProto(expected_pose).DebugString();
185  }
186 }
187 
188 TEST(FastCorrelativeScanMatcherTest, FullSubmapMatching) {
189  std::mt19937 prng(42);
190  std::uniform_real_distribution<float> distribution(-1.f, 1.f);
191  ProbabilityGridRangeDataInserter2D range_data_inserter(
192  CreateRangeDataInserterTestOptions2D());
193  constexpr float kMinScore = 0.1f;
194  const auto options = CreateFastCorrelativeScanMatcherTestOptions2D(6);
195 
196  sensor::PointCloud unperturbed_point_cloud;
197  unperturbed_point_cloud.emplace_back(-2.5f, 0.5f, 0.f);
198  unperturbed_point_cloud.emplace_back(-2.25f, 0.5f, 0.f);
199  unperturbed_point_cloud.emplace_back(0.f, 0.5f, 0.f);
200  unperturbed_point_cloud.emplace_back(0.25f, 1.6f, 0.f);
201  unperturbed_point_cloud.emplace_back(2.5f, 0.5f, 0.f);
202  unperturbed_point_cloud.emplace_back(2.f, 1.8f, 0.f);
203 
204  for (int i = 0; i != 20; ++i) {
205  const transform::Rigid2f perturbation(
206  {10. * distribution(prng), 10. * distribution(prng)},
207  1.6 * distribution(prng));
209  unperturbed_point_cloud, transform::Embed3D(perturbation));
210  const transform::Rigid2f expected_pose =
211  transform::Rigid2f({2. * distribution(prng), 2. * distribution(prng)},
212  0.5 * distribution(prng)) *
213  perturbation.inverse();
214 
215  ProbabilityGrid probability_grid(
216  MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(200, 200)));
217  range_data_inserter.Insert(
218  sensor::RangeData{
219  transform::Embed3D(expected_pose * perturbation).translation(),
220  sensor::TransformPointCloud(point_cloud,
221  transform::Embed3D(expected_pose)),
222  {}},
223  &probability_grid);
224  probability_grid.FinishUpdate();
225 
226  FastCorrelativeScanMatcher2D fast_correlative_scan_matcher(probability_grid,
227  options);
228  transform::Rigid2d pose_estimate;
229  float score;
230  EXPECT_TRUE(fast_correlative_scan_matcher.MatchFullSubmap(
231  point_cloud, kMinScore, &score, &pose_estimate));
232  EXPECT_LT(kMinScore, score);
233  EXPECT_THAT(expected_pose,
234  transform::IsNearly(pose_estimate.cast<float>(), 0.03f))
235  << "Actual: " << transform::ToProto(pose_estimate).DebugString()
236  << "\nExpected: " << transform::ToProto(expected_pose).DebugString();
237  }
238 }
239 
240 } // namespace
241 } // namespace scan_matching
242 } // namespace mapping
243 } // namespace cartographer
PointCloud TransformPointCloud(const PointCloud &point_cloud, const transform::Rigid3f &transform)
Definition: point_cloud.cc:25
proto::FastCorrelativeScanMatcherOptions2D CreateFastCorrelativeScanMatcherOptions2D(common::LuaParameterDictionary *const parameter_dictionary)
proto::ProbabilityGridRangeDataInserterOptions2D CreateProbabilityGridRangeDataInserterOptions2D(common::LuaParameterDictionary *parameter_dictionary)
std::unique_ptr< LuaParameterDictionary > MakeDictionary(const std::string &code)
Rigid3< T > Embed3D(const Rigid2< T > &transform)
Definition: transform.h:110
static Rigid2< FloatType > Identity()
Rigid2< double > Rigid2d
proto::Rigid2d ToProto(const transform::Rigid2d &transform)
Definition: transform.cc:48
std::vector< Eigen::Vector3f > PointCloud
Definition: point_cloud.h:32
TEST(TrajectoryConnectivityStateTest, UnknownTrajectory)


cartographer
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:00:58