kalman_local_trajectory_builder.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 
21 #include "cartographer/kalman_filter/proto/pose_tracker_options.pb.h"
22 #include "cartographer/mapping_2d/scan_matching/proto/real_time_correlative_scan_matcher_options.pb.h"
23 #include "cartographer/mapping_3d/proto/local_trajectory_builder_options.pb.h"
24 #include "cartographer/mapping_3d/proto/submaps_options.pb.h"
25 #include "cartographer/mapping_3d/scan_matching/proto/ceres_scan_matcher_options.pb.h"
26 #include "glog/logging.h"
27 
28 namespace cartographer {
29 namespace mapping_3d {
30 
32  const proto::LocalTrajectoryBuilderOptions& options)
33  : options_(options),
34  submaps_(common::make_unique<Submaps>(options.submaps_options())),
35  scan_matcher_pose_estimate_(transform::Rigid3d::Identity()),
36  motion_filter_(options.motion_filter_options()),
38  common::make_unique<scan_matching::RealTimeCorrelativeScanMatcher>(
39  options_.kalman_local_trajectory_builder_options()
40  .real_time_correlative_scan_matcher_options())),
41  ceres_scan_matcher_(common::make_unique<scan_matching::CeresScanMatcher>(
42  options_.ceres_scan_matcher_options())),
43  num_accumulated_(0),
44  first_pose_prediction_(transform::Rigid3f::Identity()),
45  accumulated_range_data_{Eigen::Vector3f::Zero(), {}, {}} {}
46 
48 
50  return submaps_.get();
51 }
52 
54  const common::Time time, const Eigen::Vector3d& linear_acceleration,
55  const Eigen::Vector3d& angular_velocity) {
56  if (!pose_tracker_) {
57  pose_tracker_ = common::make_unique<kalman_filter::PoseTracker>(
58  options_.kalman_local_trajectory_builder_options()
59  .pose_tracker_options(),
60  time);
61  }
62 
63  pose_tracker_->AddImuLinearAccelerationObservation(time, linear_acceleration);
64  pose_tracker_->AddImuAngularVelocityObservation(time, angular_velocity);
65 
67  kalman_filter::PoseCovariance unused_covariance_estimate;
68  pose_tracker_->GetPoseEstimateMeanAndCovariance(time, &pose_estimate,
69  &unused_covariance_estimate);
70 }
71 
72 std::unique_ptr<KalmanLocalTrajectoryBuilder::InsertionResult>
74  const common::Time time, const Eigen::Vector3f& origin,
75  const sensor::PointCloud& ranges) {
76  if (!pose_tracker_) {
77  LOG(INFO) << "PoseTracker not yet initialized.";
78  return nullptr;
79  }
80 
81  transform::Rigid3d pose_prediction;
82  kalman_filter::PoseCovariance unused_covariance_prediction;
83  pose_tracker_->GetPoseEstimateMeanAndCovariance(
84  time, &pose_prediction, &unused_covariance_prediction);
85  if (num_accumulated_ == 0) {
86  first_pose_prediction_ = pose_prediction.cast<float>();
88  sensor::RangeData{Eigen::Vector3f::Zero(), {}, {}};
89  }
90 
91  const transform::Rigid3f tracking_delta =
92  first_pose_prediction_.inverse() * pose_prediction.cast<float>();
93  const sensor::RangeData range_data_in_first_tracking =
95  tracking_delta);
96  for (const Eigen::Vector3f& hit : range_data_in_first_tracking.returns) {
97  const Eigen::Vector3f delta = hit - range_data_in_first_tracking.origin;
98  const float range = delta.norm();
99  if (range >= options_.min_range()) {
100  if (range <= options_.max_range()) {
101  accumulated_range_data_.returns.push_back(hit);
102  } else {
103  // We insert a ray cropped to 'max_range' as a miss for hits beyond the
104  // maximum range. This way the free space up to the maximum range will
105  // be updated.
107  range_data_in_first_tracking.origin +
108  options_.max_range() / range * delta);
109  }
110  }
111  }
113 
114  if (num_accumulated_ >= options_.scans_per_accumulation()) {
115  num_accumulated_ = 0;
118  tracking_delta.inverse()));
119  }
120  return nullptr;
121 }
122 
123 std::unique_ptr<KalmanLocalTrajectoryBuilder::InsertionResult>
125  const common::Time time, const sensor::RangeData& range_data_in_tracking) {
126  const sensor::RangeData filtered_range_data = {
127  range_data_in_tracking.origin,
128  sensor::VoxelFiltered(range_data_in_tracking.returns,
129  options_.voxel_filter_size()),
130  sensor::VoxelFiltered(range_data_in_tracking.misses,
131  options_.voxel_filter_size())};
132 
133  if (filtered_range_data.returns.empty()) {
134  LOG(WARNING) << "Dropped empty range data.";
135  return nullptr;
136  }
137 
138  transform::Rigid3d pose_prediction;
139  kalman_filter::PoseCovariance unused_covariance_prediction;
140  pose_tracker_->GetPoseEstimateMeanAndCovariance(
141  time, &pose_prediction, &unused_covariance_prediction);
142 
143  const Submap* const matching_submap =
144  submaps_->Get(submaps_->matching_index());
145  transform::Rigid3d initial_ceres_pose =
146  matching_submap->local_pose().inverse() * pose_prediction;
147  sensor::AdaptiveVoxelFilter adaptive_voxel_filter(
148  options_.high_resolution_adaptive_voxel_filter_options());
149  const sensor::PointCloud filtered_point_cloud_in_tracking =
150  adaptive_voxel_filter.Filter(filtered_range_data.returns);
151  if (options_.kalman_local_trajectory_builder_options()
152  .use_online_correlative_scan_matching()) {
153  // We take a copy since we use 'intial_ceres_pose' as an output argument.
154  const transform::Rigid3d initial_pose = initial_ceres_pose;
156  initial_pose, filtered_point_cloud_in_tracking,
157  matching_submap->high_resolution_hybrid_grid(), &initial_ceres_pose);
158  }
159 
160  transform::Rigid3d pose_observation_in_submap;
161  ceres::Solver::Summary summary;
162 
163  sensor::AdaptiveVoxelFilter low_resolution_adaptive_voxel_filter(
164  options_.low_resolution_adaptive_voxel_filter_options());
165  const sensor::PointCloud low_resolution_point_cloud_in_tracking =
166  low_resolution_adaptive_voxel_filter.Filter(filtered_range_data.returns);
167  ceres_scan_matcher_->Match(scan_matcher_pose_estimate_, initial_ceres_pose,
168  {{&filtered_point_cloud_in_tracking,
169  &matching_submap->high_resolution_hybrid_grid()},
170  {&low_resolution_point_cloud_in_tracking,
171  &matching_submap->low_resolution_hybrid_grid()}},
172  &pose_observation_in_submap, &summary);
173  const transform::Rigid3d pose_observation =
174  matching_submap->local_pose() * pose_observation_in_submap;
175  pose_tracker_->AddPoseObservation(
176  time, pose_observation,
177  options_.kalman_local_trajectory_builder_options()
178  .scan_matcher_variance() *
179  kalman_filter::PoseCovariance::Identity());
180 
181  kalman_filter::PoseCovariance unused_covariance_estimate;
182  pose_tracker_->GetPoseEstimateMeanAndCovariance(
183  time, &scan_matcher_pose_estimate_, &unused_covariance_estimate);
184 
187  sensor::TransformPointCloud(filtered_range_data.returns,
188  pose_observation.cast<float>())};
189 
190  return InsertIntoSubmap(time, filtered_range_data, pose_observation);
191 }
192 
194  const common::Time time, const transform::Rigid3d& pose) {
195  if (!pose_tracker_) {
197  options_.kalman_local_trajectory_builder_options()
198  .pose_tracker_options(),
199  time));
200  }
201  pose_tracker_->AddOdometerPoseObservation(
202  time, pose,
204  options_.kalman_local_trajectory_builder_options()
205  .odometer_translational_variance(),
206  options_.kalman_local_trajectory_builder_options()
207  .odometer_rotational_variance()));
208 }
209 
212  return last_pose_estimate_;
213 }
214 
215 std::unique_ptr<KalmanLocalTrajectoryBuilder::InsertionResult>
217  const common::Time time, const sensor::RangeData& range_data_in_tracking,
218  const transform::Rigid3d& pose_observation) {
219  if (motion_filter_.IsSimilar(time, pose_observation)) {
220  return nullptr;
221  }
222  const Submap* const matching_submap =
223  submaps_->Get(submaps_->matching_index());
224  std::vector<const Submap*> insertion_submaps;
225  for (int insertion_index : submaps_->insertion_indices()) {
226  insertion_submaps.push_back(submaps_->Get(insertion_index));
227  }
228  submaps_->InsertRangeData(
229  sensor::TransformRangeData(range_data_in_tracking,
230  pose_observation.cast<float>()),
231  pose_tracker_->gravity_orientation());
232  return std::unique_ptr<InsertionResult>(
233  new InsertionResult{time, range_data_in_tracking, pose_observation,
234  matching_submap, insertion_submaps});
235 }
236 
237 } // namespace mapping_3d
238 } // namespace cartographer
proto::RangeDataInserterOptions options_
PointCloud TransformPointCloud(const PointCloud &point_cloud, const transform::Rigid3f &transform)
Definition: point_cloud.cc:25
std::unique_ptr< RealTimeCorrelativeScanMatcher > real_time_correlative_scan_matcher_
bool IsSimilar(common::Time time, const transform::Rigid3d &pose)
Rigid3< double > Rigid3d
const HybridGrid & high_resolution_hybrid_grid() const
Definition: 3d/submaps.h:55
PointCloud VoxelFiltered(const PointCloud &point_cloud, const float size)
Definition: voxel_filter.cc:80
transform::Rigid3d local_pose() const
Definition: submaps.h:65
Rigid3< OtherType > cast() const
Eigen::Matrix< double, 6, 6 > PoseCovariance
Definition: pose_tracker.h:40
UniversalTimeScaleClock::time_point Time
Definition: time.h:44
std::unique_ptr< scan_matching::RealTimeCorrelativeScanMatcher > real_time_correlative_scan_matcher_
RangeData TransformRangeData(const RangeData &range_data, const transform::Rigid3f &transform)
Definition: range_data.cc:41
transform::Rigid3d pose
PoseCovariance BuildPoseCovariance(const double translational_variance, const double rotational_variance)
PointCloud Filter(const PointCloud &point_cloud) const
const HybridGrid & low_resolution_hybrid_grid() const
Definition: 3d/submaps.h:58
std::vector< Eigen::Vector3f > PointCloud
Definition: point_cloud.h:30
void AddImuData(common::Time time, const Eigen::Vector3d &linear_acceleration, const Eigen::Vector3d &angular_velocity) override
bool hit
Definition: 3d/submaps.cc:36
std::unique_ptr< InsertionResult > InsertIntoSubmap(common::Time time, const sensor::RangeData &range_data_in_tracking, const transform::Rigid3d &pose_observation)
std::unique_ptr< InsertionResult > AddRangefinderData(common::Time time, const Eigen::Vector3f &origin, const sensor::PointCloud &ranges) override
std::unique_ptr< scan_matching::CeresScanMatcher > ceres_scan_matcher_
KalmanLocalTrajectoryBuilder(const proto::LocalTrajectoryBuilderOptions &options)
std::unique_ptr< InsertionResult > AddAccumulatedRangeData(common::Time time, const sensor::RangeData &range_data_in_tracking)
_Unique_if< T >::_Single_object make_unique(Args &&...args)
Definition: make_unique.h:46
void AddOdometerData(common::Time time, const transform::Rigid3d &pose) override
std::unique_ptr< Submaps > submaps_
std::unique_ptr< kalman_filter::PoseTracker > pose_tracker_
std::unique_ptr< CeresScanMatcher > ceres_scan_matcher_


cartographer
Author(s):
autogenerated on Mon Jun 10 2019 12:51:38