odom_estimation.cpp
Go to the documentation of this file.
1 
3 
4 // Original Author of FLOAM: Wang Han
5 // Email wh200720041@gmail.com
6 // Homepage https://wanghan.pro
7 
10 
11 #include <iostream>
12 
13 namespace floam
14 {
15 namespace odom
16 {
17 
19 {
20  // constructor
21 }
22 
23 void OdomEstimation::init(const double & mapResolution) {
24  //init local map
25  m_lidarCloudCornerMap = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
26  m_lidarCloudSurfMap = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>());
27  //downsampling size
28  m_downSizeFilterEdge.setLeafSize(mapResolution, mapResolution, mapResolution);
29  m_downSizeFilterSurf.setLeafSize(mapResolution * 2, mapResolution * 2, mapResolution * 2);
30  //kd-tree
31  m_kdTreeEdgeMap = pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr(new pcl::KdTreeFLANN<pcl::PointXYZ>());
32  m_kdTreeSurfMap = pcl::KdTreeFLANN<pcl::PointXYZ>::Ptr(new pcl::KdTreeFLANN<pcl::PointXYZ>());
33 
34  m_odom = Eigen::Isometry3d::Identity();
35  m_lastOdom = Eigen::Isometry3d::Identity();
36 
38 }
39 
41  const pcl::PointCloud<pcl::PointXYZ>::Ptr & edges,
42  const pcl::PointCloud<pcl::PointXYZ>::Ptr & surfaces)
43 {
44  *m_lidarCloudCornerMap += *edges;
45  *m_lidarCloudSurfMap += *surfaces;
48 }
49 
50 
52  const pcl::PointCloud<pcl::PointXYZ>::Ptr & edges,
53  const pcl::PointCloud<pcl::PointXYZ>::Ptr & surfaces)
54 {
56  if (m_optimizationCount > 2) {
58  }
59 
60  // init temp odom prediction object
61  Eigen::Isometry3d odomPrediction = m_odom * (m_lastOdom.inverse() * m_odom);
62 
63  // update odom objects
65  m_odom = odomPrediction;
66 
67  m_currentTranslation = m_odom.translation();
68  m_currentRotation = Eigen::Quaterniond(m_odom.rotation());
69 
70  pcl::PointCloud<pcl::PointXYZ>::Ptr downsampledEdgeCloud(new pcl::PointCloud<pcl::PointXYZ>());
71  pcl::PointCloud<pcl::PointXYZ>::Ptr downsampledSurfCloud(new pcl::PointCloud<pcl::PointXYZ>());
72 
74  downSamplingToMap(edges, downsampledEdgeCloud, surfaces, downsampledSurfCloud);
75 
76  // TODO(flynneva): make these limits parameters?
77  if (m_lidarCloudCornerMap->points.size() > 10 &&
78  m_lidarCloudSurfMap->points.size() > 50)
79  {
80  m_kdTreeEdgeMap->setInputCloud(m_lidarCloudCornerMap);
81  m_kdTreeSurfMap->setInputCloud(m_lidarCloudSurfMap);
82 
83  for (int optCount = 0; optCount < m_optimizationCount; optCount++) {
84  ceres::LossFunction *loss_function = new ceres::HuberLoss(0.1);
85 
86  ceres::Problem::Options problem_options;
87  ceres::Problem problem(problem_options);
88  problem.AddParameterBlock(m_parameters, 7, new floam::lidar::PoseSE3Parameterization());
89 
90  addEdgeCostFactor(downsampledEdgeCloud, m_lidarCloudCornerMap, problem, loss_function);
91  addSurfCostFactor(downsampledSurfCloud, m_lidarCloudSurfMap, problem, loss_function);
92  ceres::Solver::Options options;
94  options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
95  options.max_num_iterations = 4;
96  options.minimizer_progress_to_stdout = false;
97  options.check_gradients = false;
98  options.gradient_check_relative_precision = 1e-4;
99  ceres::Solver::Summary summary;
100  ceres::Solve(options, &problem, &summary);
101  }
102  } else {
103  printf("[ updatePointsToMap ] not enough points in map to associate\n");
104  printf("[ updatePointsToMap ] corners: %li [ minimum required: > 10]\n", m_lidarCloudCornerMap->points.size());
105  printf("[ updatePointsToMap ] surfaces: %li [ minimum required: > 50]\n", m_lidarCloudSurfMap->points.size());
106  }
107 
109  m_odom = Eigen::Isometry3d::Identity();
110  m_odom.linear() = m_currentRotation.toRotationMatrix();
111  m_odom.translation() = m_currentTranslation;
112 
113  addPointsToMap(downsampledEdgeCloud, downsampledSurfCloud);
114 }
115 
117  const std::shared_ptr<pcl::PointXYZ> & pointIn,
118  std::shared_ptr<pcl::PointXYZ> & pointOut)
119 {
120  Eigen::Vector3d pointCurrent(pointIn->x, pointIn->y, pointIn->z);
121  Eigen::Vector3d point_w = m_currentRotation * pointCurrent + m_currentTranslation;
122 
123  pointOut->x = point_w.x();
124  pointOut->y = point_w.y();
125  pointOut->z = point_w.z();
126 }
127 
129  const pcl::PointCloud<pcl::PointXYZ>::Ptr & edgesIn,
130  pcl::PointCloud<pcl::PointXYZ>::Ptr & edgesOut,
131  const pcl::PointCloud<pcl::PointXYZ>::Ptr & surfacesIn,
132  pcl::PointCloud<pcl::PointXYZ>::Ptr & surfacesOut)
133 {
134  m_downSizeFilterEdge.setInputCloud(edgesIn);
135  m_downSizeFilterEdge.filter(*edgesOut);
136  m_downSizeFilterSurf.setInputCloud(surfacesIn);
137  m_downSizeFilterSurf.filter(*surfacesOut);
138 }
139 
141  const pcl::PointCloud<pcl::PointXYZ>::Ptr & points,
142  const pcl::PointCloud<pcl::PointXYZ>::Ptr & map,
143  ceres::Problem & problem,
144  ceres::LossFunction *loss_function)
145 {
146  int corner_num=0;
147  auto pointTemp = std::make_shared<pcl::PointXYZ>();
148  auto pointToAdd = std::make_shared<pcl::PointXYZ>();
149  for (int i = 0; i < (int)points->points.size(); i++)
150  {
151  pointTemp.reset(new pcl::PointXYZ());
152  pointToAdd.reset(new pcl::PointXYZ(points->points[i]));
153  pointAssociateToMap(pointToAdd, pointTemp);
154 
155  // nearest k neighbors search
156  const int k = 5;
157  std::vector<int> pointSearchInd(k);
158  std::vector<float> pointSearchSqDis(k);
159 
160  if (m_kdTreeEdgeMap->nearestKSearch(*pointTemp, k, pointSearchInd, pointSearchSqDis) > 0) {
161  // check if last nearest point is within 1.0m sq away
162  if (pointSearchSqDis[k - 1] < 1.0)
163  {
164  std::vector<Eigen::Vector3d> nearCorners;
165  Eigen::Vector3d center(0, 0, 0);
166 
167  for (int j = 0; j < k; j++)
168  {
169  Eigen::Vector3d tmp(
170  map->points[pointSearchInd[j]].x,
171  map->points[pointSearchInd[j]].y,
172  map->points[pointSearchInd[j]].z);
173  center = center + tmp;
174  nearCorners.push_back(tmp);
175  }
176  // average
177  center = center / (float)k;
178  Eigen::Matrix3d covMat = Eigen::Matrix3d::Zero();
179 
180  for (int j = 0; j < k; j++)
181  {
182  Eigen::Matrix<double, 3, 1> tmpZeroMean = nearCorners[j] - center;
183  covMat = covMat + tmpZeroMean * tmpZeroMean.transpose();
184  }
185 
186  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> saes(covMat);
187  Eigen::Vector3d unit_direction = saes.eigenvectors().col(2);
188  Eigen::Vector3d curr_point(points->points[i].x, points->points[i].y, points->points[i].z);
189 
190  if (saes.eigenvalues()[2] > 3 * saes.eigenvalues()[1])
191  {
192  Eigen::Vector3d point_on_line = center;
193  Eigen::Vector3d point_a, point_b;
194  point_a = 0.1 * unit_direction + point_on_line;
195  point_b = -0.1 * unit_direction + point_on_line;
196  ceres::CostFunction* cost_function =
197  new floam::lidar::LidarEdgeFunctor(curr_point, point_a, point_b);
198  problem.AddResidualBlock(cost_function, loss_function, m_parameters);
199  corner_num++;
200  }
201  }
202  }
203  }
204 
205  if(corner_num < 20){
206  printf("not enough correct corner points: %i\n", corner_num);
207  }
208 
209 }
210 
212  const pcl::PointCloud<pcl::PointXYZ>::Ptr & points,
213  const pcl::PointCloud<pcl::PointXYZ>::Ptr & map,
214  ceres::Problem & problem,
215  ceres::LossFunction * lossFunction)
216 {
217  int surf_num=0;
218  const int k = 5;
219  auto pointTemp = std::make_shared<pcl::PointXYZ>();
220  auto pointToAdd = std::make_shared<pcl::PointXYZ>();
221  for (int i = 0; i < (int)points->points.size(); i++)
222  {
223  pointTemp.reset(new pcl::PointXYZ());
224  pointToAdd.reset(new pcl::PointXYZ(points->points[i]));
225  pointAssociateToMap(pointToAdd, pointTemp);
226 
227  std::vector<int> pointSearchInd;
228  std::vector<float> pointSearchSqDis;
229  // check if last nearest point is within 1.0m sq away
230  if (m_kdTreeSurfMap->nearestKSearch(*pointTemp, k, pointSearchInd, pointSearchSqDis) > 0) {
231  if (pointSearchSqDis[k - 1] < 1.0)
232  {
233  Eigen::Matrix<double, k, 3> matA0;
234  Eigen::Matrix<double, k, 1> matB0 = -1 * Eigen::Matrix<double, k, 1>::Ones();
235 
236  for (int j = 0; j < k; j++)
237  {
238  matA0(j, 0) = map->points[pointSearchInd[j]].x;
239  matA0(j, 1) = map->points[pointSearchInd[j]].y;
240  matA0(j, 2) = map->points[pointSearchInd[j]].z;
241  }
242  // find the norm of plane
243  Eigen::Vector3d norm = matA0.colPivHouseholderQr().solve(matB0);
244  double negative_OA_dot_norm = 1 / norm.norm();
245  norm.normalize();
246 
247  bool planeValid = true;
248  for (int j = 0; j < k; j++)
249  {
250  // if OX * n > 0.2, then plane is not fit well
251  if (
252  fabs(
253  norm(0) * map->points[pointSearchInd[j]].x +
254  norm(1) * map->points[pointSearchInd[j]].y +
255  norm(2) * map->points[pointSearchInd[j]].z + negative_OA_dot_norm) > 0.2)
256  {
257  planeValid = false;
258  break;
259  }
260  }
261  Eigen::Vector3d curr_point(points->points[i].x, points->points[i].y, points->points[i].z);
262  if (planeValid)
263  {
264  ceres::CostFunction *cost_function =
265  new floam::lidar::LidarSurfaceFunctor(curr_point, norm, negative_OA_dot_norm);
266  problem.AddResidualBlock(cost_function, lossFunction, m_parameters);
267  surf_num++;
268  }
269  }
270  }
271  }
272  if (surf_num < 20) {
273  printf("not enough correct surface points: %i\n", surf_num);
274  }
275 }
276 
278  const pcl::PointCloud<pcl::PointXYZ>::Ptr & downsampledEdgeCloud,
279  const pcl::PointCloud<pcl::PointXYZ>::Ptr & downsampledSurfCloud)
280 {
281  int i = 0;
282  auto pointTemp = std::make_shared<pcl::PointXYZ>();
283  auto pointToAdd = std::make_shared<pcl::PointXYZ>();
284  for (i = 0; i < (int)downsampledEdgeCloud->points.size(); i++) {
285  pointTemp.reset(new pcl::PointXYZ());
286  pointToAdd.reset(new pcl::PointXYZ(downsampledEdgeCloud->points[i]));
287  pointAssociateToMap(pointToAdd, pointTemp);
288  m_lidarCloudCornerMap->push_back(*pointTemp.get());
289  }
290 
291  for (i = 0; i < (int)downsampledSurfCloud->points.size(); i++) {
292  pointTemp.reset(new pcl::PointXYZ());
293  pointToAdd.reset(new pcl::PointXYZ(downsampledSurfCloud->points[i]));
294  pointAssociateToMap(pointToAdd, pointTemp);
295  m_lidarCloudSurfMap->push_back(*pointTemp.get());
296  }
297 
298  double x_min = +m_currentTranslation.x() - 100;
299  double y_min = +m_currentTranslation.y() - 100;
300  double z_min = +m_currentTranslation.z() - 100;
301  double x_max = +m_currentTranslation.x() + 100;
302  double y_max = +m_currentTranslation.y() + 100;
303  double z_max = +m_currentTranslation.z() + 100;
304 
305  //ROS_INFO("size : %f,%f,%f,%f,%f,%f", x_min, y_min, z_min,x_max, y_max, z_max);
306  m_cropBoxFilter.setMin(Eigen::Vector4f(x_min, y_min, z_min, 1.0));
307  m_cropBoxFilter.setMax(Eigen::Vector4f(x_max, y_max, z_max, 1.0));
308  m_cropBoxFilter.setNegative(false);
309 
310  pcl::PointCloud<pcl::PointXYZ>::Ptr tmpCorner(new pcl::PointCloud<pcl::PointXYZ>());
311  pcl::PointCloud<pcl::PointXYZ>::Ptr tmpSurf(new pcl::PointCloud<pcl::PointXYZ>());
312 
313  m_cropBoxFilter.setInputCloud(m_lidarCloudSurfMap);
314  m_cropBoxFilter.filter(*tmpSurf);
315 
316  m_cropBoxFilter.setInputCloud(m_lidarCloudCornerMap);
317  m_cropBoxFilter.filter(*tmpCorner);
318 
319  m_downSizeFilterSurf.setInputCloud(tmpSurf);
321 
322  m_downSizeFilterEdge.setInputCloud(tmpCorner);
324 }
325 
327  pcl::PointCloud<pcl::PointXYZ>::Ptr & lidarCloudMap)
328 {
329  *lidarCloudMap += *m_lidarCloudSurfMap;
330  *lidarCloudMap += *m_lidarCloudCornerMap;
331 }
332 
333 } // namespace odom
334 } // namespace floam
floam::odom::OdomEstimation::m_odom
Eigen::Isometry3d m_odom
Odometry.
Definition: odom_estimation.hpp:61
floam::odom::OdomEstimation::pointAssociateToMap
void pointAssociateToMap(const std::shared_ptr< pcl::PointXYZ > &pointsIn, std::shared_ptr< pcl::PointXYZ > &pointsOut)
Definition: odom_estimation.cpp:116
floam::odom::OdomEstimation::updatePointsToMap
void updatePointsToMap(const pcl::PointCloud< pcl::PointXYZ >::Ptr &edges, const pcl::PointCloud< pcl::PointXYZ >::Ptr &surfaces)
Definition: odom_estimation.cpp:51
floam::odom::OdomEstimation::addPointsToMap
void addPointsToMap(const pcl::PointCloud< pcl::PointXYZ >::Ptr &downsampledEdgeCloud, const pcl::PointCloud< pcl::PointXYZ >::Ptr &downsampledSurfCloud)
Definition: odom_estimation.cpp:277
floam::lidar::LidarSurfaceFunctor
Definition: lidar_optimization.hpp:64
floam::odom::OdomEstimation::m_parameters
double m_parameters[7]
Optimization parameters that ceres solvers update each loop.
Definition: odom_estimation.hpp:64
floam::odom::OdomEstimation::getMap
void getMap(pcl::PointCloud< pcl::PointXYZ >::Ptr &lidarCloudMap)
Definition: odom_estimation.cpp:326
floam::odom::OdomEstimation::OdomEstimation
OdomEstimation()
constructor / destructor
Definition: odom_estimation.cpp:18
floam::odom::OdomEstimation::m_kdTreeSurfMap
pcl::KdTreeFLANN< pcl::PointXYZ >::Ptr m_kdTreeSurfMap
Definition: odom_estimation.hpp:71
floam::lidar::PoseSE3Parameterization
Definition: lidar_optimization.hpp:99
floam::odom::OdomEstimation::m_kdTreeEdgeMap
pcl::KdTreeFLANN< pcl::PointXYZ >::Ptr m_kdTreeEdgeMap
kd-tree
Definition: odom_estimation.hpp:70
floam::odom::OdomEstimation::m_lidarCloudSurfMap
pcl::PointCloud< pcl::PointXYZ >::Ptr m_lidarCloudSurfMap
Definition: odom_estimation.hpp:75
floam::odom::OdomEstimation::addSurfCostFactor
void addSurfCostFactor(const pcl::PointCloud< pcl::PointXYZ >::Ptr &points, const pcl::PointCloud< pcl::PointXYZ >::Ptr &map, ceres::Problem &problem, ceres::LossFunction *lossFunction)
Definition: odom_estimation.cpp:211
floam::odom::OdomEstimation::m_currentRotation
Eigen::Map< Eigen::Quaterniond > m_currentRotation
Definition: odom_estimation.hpp:66
floam::odom::OdomEstimation::downSamplingToMap
void downSamplingToMap(const pcl::PointCloud< pcl::PointXYZ >::Ptr &edgesIn, pcl::PointCloud< pcl::PointXYZ >::Ptr &edgesOut, const pcl::PointCloud< pcl::PointXYZ >::Ptr &surfacesIn, pcl::PointCloud< pcl::PointXYZ >::Ptr &surfacesOut)
Definition: odom_estimation.cpp:128
floam::odom::OdomEstimation::m_lastOdom
Eigen::Isometry3d m_lastOdom
Definition: odom_estimation.hpp:61
floam::odom::OdomEstimation::m_lidarCloudCornerMap
pcl::PointCloud< pcl::PointXYZ >::Ptr m_lidarCloudCornerMap
corner and surface map objects
Definition: odom_estimation.hpp:74
floam::odom::OdomEstimation::m_optimizationCount
int m_optimizationCount
optimization count
Definition: odom_estimation.hpp:85
floam::odom::OdomEstimation::m_downSizeFilterSurf
pcl::VoxelGrid< pcl::PointXYZ > m_downSizeFilterSurf
Definition: odom_estimation.hpp:79
odom_estimation.hpp
floam::odom::OdomEstimation::m_downSizeFilterEdge
pcl::VoxelGrid< pcl::PointXYZ > m_downSizeFilterEdge
points downsampling before add to map
Definition: odom_estimation.hpp:78
floam::odom::OdomEstimation::m_cropBoxFilter
pcl::CropBox< pcl::PointXYZ > m_cropBoxFilter
local map
Definition: odom_estimation.hpp:82
lidar_optimization.hpp
floam::lidar::LidarEdgeFunctor
Definition: lidar_optimization.hpp:25
floam::odom::OdomEstimation::init
void init(const double &mapResolution)
Definition: odom_estimation.cpp:23
floam
Major rewrite Author: Evan Flynn.
Definition: lidar.hpp:15
floam::odom::OdomEstimation::initMapWithPoints
void initMapWithPoints(const pcl::PointCloud< pcl::PointXYZ >::Ptr &edges, const pcl::PointCloud< pcl::PointXYZ >::Ptr &surfaces)
Definition: odom_estimation.cpp:40
floam::odom::OdomEstimation::addEdgeCostFactor
void addEdgeCostFactor(const pcl::PointCloud< pcl::PointXYZ >::Ptr &points, const pcl::PointCloud< pcl::PointXYZ >::Ptr &map, ceres::Problem &problem, ceres::LossFunction *lossFunction)
function
Definition: odom_estimation.cpp:140
floam::odom::OdomEstimation::m_currentTranslation
Eigen::Map< Eigen::Vector3d > m_currentTranslation
Definition: odom_estimation.hpp:67


floam
Author(s): Han Wang
autogenerated on Wed Mar 2 2022 00:23:09