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/occupied_space_cost_function_2d.h"
00018
00019 #include "cartographer/mapping/probability_values.h"
00020 #include "ceres/cubic_interpolation.h"
00021
00022 namespace cartographer {
00023 namespace mapping {
00024 namespace scan_matching {
00025 namespace {
00026
00027
00028
00029
00030 class OccupiedSpaceCostFunction2D {
00031 public:
00032 OccupiedSpaceCostFunction2D(const double scaling_factor,
00033 const sensor::PointCloud& point_cloud,
00034 const Grid2D& grid)
00035 : scaling_factor_(scaling_factor),
00036 point_cloud_(point_cloud),
00037 grid_(grid) {}
00038
00039 template <typename T>
00040 bool operator()(const T* const pose, T* residual) const {
00041 Eigen::Matrix<T, 2, 1> translation(pose[0], pose[1]);
00042 Eigen::Rotation2D<T> rotation(pose[2]);
00043 Eigen::Matrix<T, 2, 2> rotation_matrix = rotation.toRotationMatrix();
00044 Eigen::Matrix<T, 3, 3> transform;
00045 transform << rotation_matrix, translation, T(0.), T(0.), T(1.);
00046
00047 const GridArrayAdapter adapter(grid_);
00048 ceres::BiCubicInterpolator<GridArrayAdapter> interpolator(adapter);
00049 const MapLimits& limits = grid_.limits();
00050
00051 for (size_t i = 0; i < point_cloud_.size(); ++i) {
00052
00053 const Eigen::Matrix<T, 3, 1> point((T(point_cloud_[i].position.x())),
00054 (T(point_cloud_[i].position.y())),
00055 T(1.));
00056 const Eigen::Matrix<T, 3, 1> world = transform * point;
00057 interpolator.Evaluate(
00058 (limits.max().x() - world[0]) / limits.resolution() - 0.5 +
00059 static_cast<double>(kPadding),
00060 (limits.max().y() - world[1]) / limits.resolution() - 0.5 +
00061 static_cast<double>(kPadding),
00062 &residual[i]);
00063 residual[i] = scaling_factor_ * residual[i];
00064 }
00065 return true;
00066 }
00067
00068 private:
00069 static constexpr int kPadding = INT_MAX / 4;
00070 class GridArrayAdapter {
00071 public:
00072 enum { DATA_DIMENSION = 1 };
00073
00074 explicit GridArrayAdapter(const Grid2D& grid) : grid_(grid) {}
00075
00076 void GetValue(const int row, const int column, double* const value) const {
00077 if (row < kPadding || column < kPadding || row >= NumRows() - kPadding ||
00078 column >= NumCols() - kPadding) {
00079 *value = kMaxCorrespondenceCost;
00080 } else {
00081 *value = static_cast<double>(grid_.GetCorrespondenceCost(
00082 Eigen::Array2i(column - kPadding, row - kPadding)));
00083 }
00084 }
00085
00086 int NumRows() const {
00087 return grid_.limits().cell_limits().num_y_cells + 2 * kPadding;
00088 }
00089
00090 int NumCols() const {
00091 return grid_.limits().cell_limits().num_x_cells + 2 * kPadding;
00092 }
00093
00094 private:
00095 const Grid2D& grid_;
00096 };
00097
00098 OccupiedSpaceCostFunction2D(const OccupiedSpaceCostFunction2D&) = delete;
00099 OccupiedSpaceCostFunction2D& operator=(const OccupiedSpaceCostFunction2D&) =
00100 delete;
00101
00102 const double scaling_factor_;
00103 const sensor::PointCloud& point_cloud_;
00104 const Grid2D& grid_;
00105 };
00106
00107 }
00108
00109 ceres::CostFunction* CreateOccupiedSpaceCostFunction2D(
00110 const double scaling_factor, const sensor::PointCloud& point_cloud,
00111 const Grid2D& grid) {
00112 return new ceres::AutoDiffCostFunction<OccupiedSpaceCostFunction2D,
00113 ceres::DYNAMIC ,
00114 3 >(
00115 new OccupiedSpaceCostFunction2D(scaling_factor, point_cloud, grid),
00116 point_cloud.size());
00117 }
00118
00119 }
00120 }
00121 }