31 #include "Eigen/Eigenvalues" 34 #include "cartographer/mapping/sparse_pose_graph/proto/constraint_builder_options.pb.h" 37 #include "glog/logging.h" 40 namespace mapping_2d {
43 const mapping::proto::SparsePoseGraphOptions& options,
47 constraint_builder_(
options_.constraint_builder_options(), thread_pool) {}
52 CHECK(scan_queue_ ==
nullptr);
56 const std::vector<const mapping::Submap*>& insertion_submaps) {
57 CHECK(!insertion_submaps.empty());
59 const int trajectory_id = first_submap_id.trajectory_id;
60 CHECK_GE(trajectory_id, 0);
62 if (insertion_submaps.size() == 1) {
64 CHECK_EQ(first_submap_id.submap_index, 0);
65 if (static_cast<size_t>(trajectory_id) >= submap_data.size() ||
66 submap_data[trajectory_id].empty()) {
72 CHECK_EQ(2, insertion_submaps.size());
73 const int next_submap_index = submap_data.at(trajectory_id).size();
77 CHECK_LE(second_submap_id.
submap_index, next_submap_index);
79 if (second_submap_id.
submap_index == next_submap_index) {
80 const auto& first_submap_pose =
81 submap_data.at(trajectory_id).at(first_submap_id.submap_index).pose;
95 const std::vector<const mapping::Submap*>& insertion_submaps) {
100 trajectory_nodes_.Append(
103 std::make_shared<const mapping::TrajectoryNode::Data>(
105 time, range_data_in_pose,
109 ++num_trajectory_nodes_;
110 trajectory_connectivity_.Add(trajectory_id);
112 if (submap_ids_.count(insertion_submaps.back()) == 0) {
114 submap_data_.Append(trajectory_id,
SubmapData());
115 submap_ids_.emplace(insertion_submaps.back(), submap_id);
116 submap_data_.at(submap_id).submap = insertion_submaps.back();
120 ? insertion_submaps.front()
124 if (!global_localization_samplers_[trajectory_id]) {
125 global_localization_samplers_[trajectory_id] =
126 common::make_unique<common::FixedRatioSampler>(
132 finished_submap, pose);
137 if (scan_queue_ ==
nullptr) {
140 scan_queue_->push_back(work_item);
145 const Eigen::Vector3d& linear_acceleration,
146 const Eigen::Vector3d& angular_velocity) {
160 global_localization_samplers_[node_id.
trajectory_id]->Pulse()) {
161 constraint_builder_.MaybeAddGlobalConstraint(
162 submap_id, submap_data_.at(submap_id).submap, node_id,
163 &trajectory_nodes_.at(node_id).constant_data->range_data_2d.returns,
164 &trajectory_connectivity_);
166 const bool scan_and_submap_trajectories_connected =
172 scan_and_submap_trajectories_connected) {
183 constraint_builder_.MaybeAddConstraint(
184 submap_id, submap_data_.at(submap_id).submap, node_id,
185 &trajectory_nodes_.at(node_id).constant_data->range_data_2d.returns,
186 initial_relative_pose);
194 const auto& submap_data = submap_data_.at(submap_id);
197 for (
size_t trajectory_id = 0; trajectory_id != node_data.size();
199 for (
size_t node_index = 0; node_index != node_data[trajectory_id].size();
202 static_cast<int>(node_index)};
203 if (!trajectory_nodes_.at(node_id).trimmed() &&
204 submap_data.node_ids.count(node_id) == 0) {
213 std::vector<const mapping::Submap*> insertion_submaps,
231 const auto& scan_data = trajectory_nodes_.at(node_id).constant_data;
233 matching_id.
trajectory_id, scan_data->time, pose, optimized_pose);
237 submap_data_.at(submap_id).node_ids.emplace(node_id);
243 options_.matcher_translation_weight(),
244 options_.matcher_rotation_weight()},
248 for (
int trajectory_id = 0; trajectory_id < submap_data_.num_trajectories();
250 for (
int submap_index = 0;
251 submap_index < submap_data_.num_indices(trajectory_id);
255 CHECK_EQ(submap_data_.at(submap_id).node_ids.count(node_id), 0);
261 if (finished_submap !=
nullptr) {
263 SubmapData& finished_submap_data = submap_data_.at(finished_submap_id);
270 constraint_builder_.NotifyEndOfScan();
271 ++num_scans_since_last_loop_closure_;
272 if (
options_.optimize_every_n_scans() > 0 &&
273 num_scans_since_last_loop_closure_ >
options_.optimize_every_n_scans()) {
274 CHECK(!run_loop_closure_);
275 run_loop_closure_ =
true;
277 if (scan_queue_ ==
nullptr) {
278 scan_queue_ = common::make_unique<std::deque<std::function<void()>>>();
285 constraint_builder_.WhenDone(
289 constraints_.insert(constraints_.end(), result.begin(), result.end());
294 num_scans_since_last_loop_closure_ = 0;
295 run_loop_closure_ =
false;
296 while (!run_loop_closure_) {
297 if (scan_queue_->empty()) {
298 LOG(INFO) <<
"We caught up. Hooray!";
302 scan_queue_->front()();
303 scan_queue_->pop_front();
311 bool notification =
false;
313 const int num_finished_scans_at_start =
314 constraint_builder_.GetNumFinishedScans();
315 while (!locker.AwaitWithTimeout(
317 return constraint_builder_.GetNumFinishedScans() ==
318 num_trajectory_nodes_;
321 std::ostringstream progress_info;
322 progress_info <<
"Optimizing: " << std::fixed << std::setprecision(1)
324 (constraint_builder_.GetNumFinishedScans() -
325 num_finished_scans_at_start) /
326 (num_trajectory_nodes_ - num_finished_scans_at_start)
328 std::cout <<
"\r\x1b[K" << progress_info.str() << std::flush;
330 std::cout <<
"\r\x1b[KOptimizing: Done. " << std::endl;
331 constraint_builder_.WhenDone(
332 [
this, ¬ification](
335 constraints_.insert(constraints_.end(), result.begin(), result.end());
338 locker.Await([¬ification]() {
return notification; });
342 std::unique_ptr<mapping::PoseGraphTrimmer> trimmer) {
353 options_.max_num_final_iterations());
356 options_.optimization_problem_options()
357 .ceres_solver_options()
358 .max_num_iterations());
369 for (
int trajectory_id = 0;
370 trajectory_id !=
static_cast<int>(node_data.size()); ++trajectory_id) {
372 const int num_nodes = trajectory_nodes_.num_indices(trajectory_id);
373 for (; node_index !=
static_cast<int>(node_data[trajectory_id].size());
377 node_data[trajectory_id][node_index].point_cloud_pose);
383 optimized_submap_transforms_, trajectory_id);
385 local_to_new_global * local_to_old_global.
inverse();
386 for (; node_index < num_nodes; ++node_index) {
388 trajectory_nodes_.at(node_id).pose =
389 old_global_to_new_global * trajectory_nodes_.at(node_id).pose;
402 for (
auto& trimmer : trimmers_) {
403 trimmer->Trim(&trimming_handle);
407 std::vector<std::vector<mapping::TrajectoryNode>>
410 return trajectory_nodes_.data();
419 const int trajectory_id) {
432 if (trajectory_id >= submap_data_.num_trajectories()) {
435 return submap_data_.num_indices(trajectory_id);
443 static_cast<int>(optimized_submap_transforms_.size()) &&
444 submap_id.
submap_index < static_cast<int>(optimized_submap_transforms_
455 submap_data_.at(submap_id).submap->local_pose();
459 const std::vector<std::vector<sparse_pose_graph::SubmapData>>&
461 const int trajectory_id)
const {
462 if (trajectory_id >= static_cast<int>(submap_transforms.size()) ||
463 submap_transforms.at(trajectory_id).empty()) {
468 static_cast<int>(submap_transforms.at(trajectory_id).size() - 1)};
471 submap_data_.at(last_optimized_submap_id)
472 .submap->local_pose()
480 const int trajectory_id)
const {
492 std::set<mapping::NodeId> nodes_to_retain;
494 if (constraint.
tag == Constraint::Tag::INTRA_SUBMAP &&
496 nodes_to_retain.insert(constraint.
node_id);
500 std::set<mapping::NodeId> nodes_to_remove;
505 if (constraint.
tag == Constraint::Tag::INTRA_SUBMAP &&
506 nodes_to_retain.count(constraint.
node_id) == 0) {
509 nodes_to_remove.insert(constraint.
node_id);
512 constraints.push_back(constraint);
515 parent_->constraints_ = std::move(constraints);
521 if (nodes_to_remove.count(constraint.
node_id) == 0) {
522 constraints.push_back(constraint);
525 parent_->constraints_ = std::move(constraints);
530 parent_->constraint_builder_.DeleteScanMatcher(submap_id);
536 CHECK(!
parent_->trajectory_nodes_.at(node_id).trimmed());
537 parent_->trajectory_nodes_.at(node_id).constant_data.reset();
void AddTrimmer(std::unique_ptr< mapping::PoseGraphTrimmer > trimmer) override
void AddSubmap(int trajectory_id, const transform::Rigid2d &submap_pose)
proto::RangeDataInserterOptions options_
transform::Rigid3d GetSubmapTransform(const mapping::SubmapId &submap_id) EXCLUDES(mutex_) override
void SetMaxNumIterations(int32 max_num_iterations)
void RunOptimization() EXCLUDES(mutex_)
void RunFinalOptimization() override
~SparsePoseGraph() override
void Solve(const std::vector< Constraint > &constraints)
const mapping_2d::ProbabilityGrid * finished_probability_grid() const
transform::Rigid2d ComputeSubmapPose(const mapping::Submap &submap)
UniversalTimeScaleClock::time_point Time
void AddImuData(int trajectory_id, common::Time time, const Eigen::Vector3d &linear_acceleration, const Eigen::Vector3d &angular_velocity)
SparsePoseGraph *const parent_
void AddImuData(int trajectory_id, common::Time time, const Eigen::Vector3d &linear_acceleration, const Eigen::Vector3d &angular_velocity)
void AddScan(common::Time time, const transform::Rigid3d &tracking_to_pose, const sensor::RangeData &range_data_in_pose, const transform::Rigid2d &pose, int trajectory_id, const mapping::Submap *matching_submap, const std::vector< const mapping::Submap * > &insertion_submaps) EXCLUDES(mutex_)
void GrowSubmapTransformsAsNeeded(const std::vector< const mapping::Submap * > &insertion_submaps) REQUIRES(mutex_)
const std::vector< std::vector< SubmapData > > & submap_data() const
std::vector< Constraint > Result
Duration FromSeconds(const double seconds)
transform::Rigid3d ComputeLocalToGlobalTransform(const std::vector< std::vector< sparse_pose_graph::SubmapData >> &submap_transforms, int trajectory_id) const REQUIRES(mutex_)
const std::vector< std::vector< NodeData > > & node_data() const
void ComputeConstraint(const mapping::NodeId &node_id, const mapping::SubmapId &submap_id) REQUIRES(mutex_)
std::vector< std::vector< int > > GetConnectedTrajectories() override
OptimizationProblem optimization_problem_
CompressedRangeData Compress(const RangeData &range_data)
TrimmingHandle(SparsePoseGraph *parent)
void WaitForAllComputations() EXCLUDES(mutex_)
int num_submaps(int trajectory_id) const override
const mapping::proto::SparsePoseGraphOptions options_
std::map< int, size_t > reverse_connected_components_
mapping::SubmapId GetSubmapId(const mapping::Submap *submap) const REQUIRES(mutex_)
void AddWorkItem(std::function< void()> work_item) REQUIRES(mutex_)
enum cartographer::mapping::SparsePoseGraph::Constraint::Tag tag
std::vector< std::vector< mapping::TrajectoryNode > > GetTrajectoryNodes() override EXCLUDES(mutex_)
void ComputeConstraintsForScan(const mapping::Submap *matching_submap, std::vector< const mapping::Submap * > insertion_submaps, const mapping::Submap *finished_submap, const transform::Rigid2d &pose) REQUIRES(mutex_)
std::vector< Constraint > constraints() override EXCLUDES(mutex_)
void HandleScanQueue() REQUIRES(mutex_)
Mutex::Locker MutexLocker
void MarkSubmapAsTrimmed(const mapping::SubmapId &submap_id) override
std::vector< std::vector< int > > connected_components_
sparse_pose_graph::OptimizationProblem optimization_problem_
void AddTrajectoryNode(int trajectory_id, common::Time time, const transform::Rigid2d &initial_point_cloud_pose, const transform::Rigid2d &point_cloud_pose)
int num_submaps(int trajectory_id) EXCLUDES(mutex_) override
void ComputeConstraintsForOldScans(const mapping::Submap *submap) REQUIRES(mutex_)
transform::Rigid3d GetLocalToGlobalTransform(int trajectory_id) EXCLUDES(mutex_) override