00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/mapping/internal/2d/scan_matching/tsdf_match_cost_function_2d.h"
00018
00019 #include "cartographer/common/lua_parameter_dictionary.h"
00020 #include "cartographer/common/lua_parameter_dictionary_test_helpers.h"
00021 #include "cartographer/mapping/2d/tsdf_2d.h"
00022 #include "cartographer/mapping/2d/tsdf_range_data_inserter_2d.h"
00023 #include "gmock/gmock.h"
00024 #include "gtest/gtest.h"
00025
00026 namespace cartographer {
00027 namespace mapping {
00028 namespace scan_matching {
00029 namespace {
00030
00031 using ::testing::DoubleNear;
00032 using ::testing::ElementsAre;
00033
00034 class TSDFSpaceCostFunction2DTest : public ::testing::Test {
00035 protected:
00036 TSDFSpaceCostFunction2DTest()
00037 : tsdf_(MapLimits(0.1, Eigen::Vector2d(2.05, 2.05), CellLimits(40, 40)),
00038 0.3, 1.0, &conversion_tables_) {
00039 auto parameter_dictionary = common::MakeDictionary(
00040 "return { "
00041 "truncation_distance = 0.3,"
00042 "maximum_weight = 1.0,"
00043 "update_free_space = false,"
00044 "normal_estimation_options = {"
00045 "num_normal_samples = 2,"
00046 "sample_radius = 10.,"
00047 "},"
00048 "project_sdf_distance_to_scan_normal = true,"
00049 "update_weight_range_exponent = 0,"
00050 "update_weight_angle_scan_normal_to_ray_kernel_bandwidth = 0,"
00051 "update_weight_distance_cell_to_hit_kernel_bandwidth = 0,"
00052 "}");
00053 options_ = CreateTSDFRangeDataInserterOptions2D(parameter_dictionary.get());
00054 range_data_inserter_ = absl::make_unique<TSDFRangeDataInserter2D>(options_);
00055 }
00056
00057 void InsertPointcloud() {
00058 auto range_data = sensor::RangeData();
00059 for (float x = -.5; x < 0.5f; x += 0.1) {
00060 range_data.returns.push_back({Eigen::Vector3f{x, 1.0f, 0.f}});
00061 }
00062 range_data.origin.x() = -0.5f;
00063 range_data.origin.y() = -0.5f;
00064 range_data_inserter_->Insert(range_data, &tsdf_);
00065 tsdf_.FinishUpdate();
00066 }
00067
00068 ValueConversionTables conversion_tables_;
00069 proto::TSDFRangeDataInserterOptions2D options_;
00070 TSDF2D tsdf_;
00071 std::unique_ptr<TSDFRangeDataInserter2D> range_data_inserter_;
00072 };
00073
00074 TEST_F(TSDFSpaceCostFunction2DTest, MatchEmptyTSDF) {
00075 const sensor::PointCloud matching_cloud = {{Eigen::Vector3f{0.f, 0.f, 0.f}}};
00076 std::unique_ptr<ceres::CostFunction> cost_function(
00077 CreateTSDFMatchCostFunction2D(1.f, matching_cloud, tsdf_));
00078 const std::array<double, 3> pose_estimate{{0., 0., 0.}};
00079 const std::array<const double*, 1> parameter_blocks{{pose_estimate.data()}};
00080 std::array<double, 1> residuals;
00081 std::array<std::array<double, 3>, 1> jacobians;
00082 std::array<double*, 1> jacobians_ptrs;
00083 for (int i = 0; i < 1; ++i) jacobians_ptrs[i] = jacobians[i].data();
00084 bool valid_result = cost_function->Evaluate(
00085 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00086 EXPECT_FALSE(valid_result);
00087 }
00088
00089 TEST_F(TSDFSpaceCostFunction2DTest, ExactInitialPose) {
00090 InsertPointcloud();
00091 const sensor::PointCloud matching_cloud = {{Eigen::Vector3f{0.f, 1.0f, 0.f}}};
00092 std::unique_ptr<ceres::CostFunction> cost_function(
00093 CreateTSDFMatchCostFunction2D(1.f, matching_cloud, tsdf_));
00094 const std::array<double, 3> pose_estimate{{0., 0., 0.}};
00095 const std::array<const double*, 1> parameter_blocks{{pose_estimate.data()}};
00096 std::array<double, 1> residuals;
00097 std::array<std::array<double, 3>, 1> jacobians;
00098 std::array<double*, 1> jacobians_ptrs;
00099 for (int i = 0; i < 1; ++i) jacobians_ptrs[i] = jacobians[i].data();
00100 const bool valid_result = cost_function->Evaluate(
00101 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00102 EXPECT_TRUE(valid_result);
00103 EXPECT_THAT(residuals, ElementsAre(DoubleNear(0., 1e-3)));
00104 EXPECT_THAT(jacobians[0],
00105 ElementsAre(DoubleNear(0., 1e-3), DoubleNear(-1., 1e-3),
00106 DoubleNear(0., 1e-3)));
00107 }
00108
00109 TEST_F(TSDFSpaceCostFunction2DTest, PertubatedInitialPose) {
00110 InsertPointcloud();
00111 sensor::PointCloud matching_cloud = {{Eigen::Vector3f{0.f, 1.0f, 0.f}}};
00112 std::unique_ptr<ceres::CostFunction> cost_function(
00113 CreateTSDFMatchCostFunction2D(1.f, matching_cloud, tsdf_));
00114 std::array<double, 3> pose_estimate{{0., 0.1, 0.}};
00115 std::array<const double*, 1> parameter_blocks{{pose_estimate.data()}};
00116 std::array<double, 1> residuals;
00117 std::array<std::array<double, 3>, 1> jacobians;
00118 std::array<double*, 1> jacobians_ptrs;
00119 for (int i = 0; i < 1; ++i) jacobians_ptrs[i] = jacobians[i].data();
00120
00121 bool valid_result = cost_function->Evaluate(
00122 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00123 EXPECT_TRUE(valid_result);
00124 EXPECT_THAT(residuals, ElementsAre(DoubleNear(-0.1, 1e-3)));
00125 EXPECT_THAT(jacobians[0],
00126 ElementsAre(DoubleNear(0., 1e-3), DoubleNear(-1., 1e-3),
00127 DoubleNear(0., 1e-3)));
00128
00129 pose_estimate[1] = -0.1;
00130 parameter_blocks = {{pose_estimate.data()}};
00131 valid_result = cost_function->Evaluate(
00132 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00133 EXPECT_TRUE(valid_result);
00134 EXPECT_THAT(residuals, ElementsAre(DoubleNear(0.1, 1e-3)));
00135 EXPECT_THAT(jacobians[0],
00136 ElementsAre(DoubleNear(0., 1e-3), DoubleNear(-1., 1e-3),
00137 DoubleNear(0., 1e-3)));
00138 }
00139
00140 TEST_F(TSDFSpaceCostFunction2DTest, InvalidInitialPose) {
00141 InsertPointcloud();
00142 sensor::PointCloud matching_cloud = {{Eigen::Vector3f{0.f, 1.0f, 0.f}}};
00143 std::unique_ptr<ceres::CostFunction> cost_function(
00144 CreateTSDFMatchCostFunction2D(1.f, matching_cloud, tsdf_));
00145 std::array<double, 3> pose_estimate{{0., 0.4, 0.}};
00146 std::array<const double*, 1> parameter_blocks{{pose_estimate.data()}};
00147 std::array<double, 1> residuals;
00148 std::array<std::array<double, 3>, 1> jacobians;
00149 std::array<double*, 1> jacobians_ptrs;
00150 for (int i = 0; i < 1; ++i) jacobians_ptrs[i] = jacobians[i].data();
00151
00152 bool valid_result = cost_function->Evaluate(
00153 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00154 EXPECT_FALSE(valid_result);
00155
00156 pose_estimate[1] = -0.4;
00157 parameter_blocks = {{pose_estimate.data()}};
00158 valid_result = cost_function->Evaluate(
00159 parameter_blocks.data(), residuals.data(), jacobians_ptrs.data());
00160 EXPECT_FALSE(valid_result);
00161 }
00162
00163 }
00164 }
00165 }
00166 }