30 #include "Eigen/Eigenvalues" 33 #include "cartographer/mapping/sparse_pose_graph/proto/constraint_builder_options.pb.h" 36 #include "glog/logging.h" 39 namespace mapping_3d {
42 const mapping::proto::SparsePoseGraphOptions& options,
46 sparse_pose_graph::OptimizationProblem::FixZ::kNo),
47 constraint_builder_(
options_.constraint_builder_options(), thread_pool) {}
52 CHECK(scan_queue_ ==
nullptr);
56 const std::vector<const 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;
83 trajectory_id, first_submap_pose *
84 insertion_submaps[0]->local_pose().inverse() *
85 insertion_submaps[1]->local_pose());
92 const Submap*
const matching_submap,
93 const std::vector<const Submap*>& insertion_submaps) {
98 trajectory_nodes_.Append(
101 std::make_shared<const mapping::TrajectoryNode::Data>(
107 ++num_trajectory_nodes_;
108 trajectory_connectivity_.Add(trajectory_id);
110 if (submap_ids_.count(insertion_submaps.back()) == 0) {
112 submap_data_.Append(trajectory_id,
SubmapData());
113 submap_ids_.emplace(insertion_submaps.back(), submap_id);
114 submap_data_.at(submap_id).submap = insertion_submaps.back();
116 const Submap*
const finished_submap = insertion_submaps.front()->
finished()
117 ? insertion_submaps.front()
121 if (!global_localization_samplers_[trajectory_id]) {
122 global_localization_samplers_[trajectory_id] =
123 common::make_unique<common::FixedRatioSampler>(
129 finished_submap, pose);
134 if (scan_queue_ ==
nullptr) {
137 scan_queue_->push_back(work_item);
142 const Eigen::Vector3d& linear_acceleration,
143 const Eigen::Vector3d& angular_velocity) {
167 std::vector<mapping::TrajectoryNode> submap_nodes;
169 submap_data_.at(submap_id).node_ids) {
172 inverse_submap_pose * trajectory_nodes_.at(submap_node_id).pose});
177 global_localization_samplers_[node_id.
trajectory_id]->Pulse()) {
190 constraint_builder_.MaybeAddGlobalConstraint(
191 submap_id, submap_data_.at(submap_id).submap, node_id,
192 &trajectory_nodes_.at(node_id).constant_data->range_data_3d.returns,
193 submap_nodes, initial_relative_pose.
rotation(),
194 &trajectory_connectivity_);
196 const bool scan_and_submap_trajectories_connected =
202 scan_and_submap_trajectories_connected) {
203 constraint_builder_.MaybeAddConstraint(
204 submap_id, submap_data_.at(submap_id).submap, node_id,
205 &trajectory_nodes_.at(node_id).constant_data->range_data_3d.returns,
206 submap_nodes, initial_relative_pose);
213 const auto& submap_data = submap_data_.at(submap_id);
216 for (
size_t trajectory_id = 0; trajectory_id != node_data.size();
218 for (
size_t node_index = 0; node_index != node_data[trajectory_id].size();
221 static_cast<int>(node_index)};
222 if (submap_data.node_ids.count(node_id) == 0) {
230 const Submap* matching_submap, std::vector<const Submap*> insertion_submaps,
248 const auto& scan_data = trajectory_nodes_.at(node_id).constant_data;
250 scan_data->time, optimized_pose);
251 for (
const Submap* submap : insertion_submaps) {
254 submap_data_.at(submap_id).node_ids.emplace(node_id);
257 constraints_.push_back(
260 {constraint_transform,
options_.matcher_translation_weight(),
261 options_.matcher_rotation_weight()},
265 for (
int trajectory_id = 0; trajectory_id < submap_data_.num_trajectories();
267 for (
int submap_index = 0;
268 submap_index < submap_data_.num_indices(trajectory_id);
272 CHECK_EQ(submap_data_.at(submap_id).node_ids.count(node_id), 0);
278 if (finished_submap !=
nullptr) {
280 SubmapData& finished_submap_data = submap_data_.at(finished_submap_id);
287 constraint_builder_.NotifyEndOfScan();
288 ++num_scans_since_last_loop_closure_;
289 if (
options_.optimize_every_n_scans() > 0 &&
290 num_scans_since_last_loop_closure_ >
options_.optimize_every_n_scans()) {
291 CHECK(!run_loop_closure_);
292 run_loop_closure_ =
true;
294 if (scan_queue_ ==
nullptr) {
295 scan_queue_ = common::make_unique<std::deque<std::function<void()>>>();
302 constraint_builder_.WhenDone(
306 constraints_.insert(constraints_.end(), result.begin(), result.end());
311 num_scans_since_last_loop_closure_ = 0;
312 run_loop_closure_ =
false;
313 while (!run_loop_closure_) {
314 if (scan_queue_->empty()) {
315 LOG(INFO) <<
"We caught up. Hooray!";
319 scan_queue_->front()();
320 scan_queue_->pop_front();
328 bool notification =
false;
330 const int num_finished_scans_at_start =
331 constraint_builder_.GetNumFinishedScans();
332 while (!locker.AwaitWithTimeout(
334 return constraint_builder_.GetNumFinishedScans() ==
335 num_trajectory_nodes_;
338 std::ostringstream progress_info;
339 progress_info <<
"Optimizing: " << std::fixed << std::setprecision(1)
341 (constraint_builder_.GetNumFinishedScans() -
342 num_finished_scans_at_start) /
343 (num_trajectory_nodes_ - num_finished_scans_at_start)
345 std::cout <<
"\r\x1b[K" << progress_info.str() << std::flush;
347 std::cout <<
"\r\x1b[KOptimizing: Done. " << std::endl;
348 constraint_builder_.WhenDone(
349 [
this, ¬ification](
352 constraints_.insert(constraints_.end(), result.begin(), result.end());
355 locker.Await([¬ification]() {
return notification; });
361 options_.max_num_final_iterations());
364 options_.optimization_problem_options()
365 .ceres_solver_options()
366 .max_num_iterations());
377 for (
int trajectory_id = 0;
378 trajectory_id !=
static_cast<int>(node_data.size()); ++trajectory_id) {
380 const int num_nodes = trajectory_nodes_.num_indices(trajectory_id);
381 for (; node_index !=
static_cast<int>(node_data[trajectory_id].size());
384 trajectory_nodes_.at(node_id).pose =
385 node_data[trajectory_id][node_index].point_cloud_pose;
391 optimized_submap_transforms_, trajectory_id);
393 local_to_new_global * local_to_old_global.
inverse();
394 for (; node_index < num_nodes; ++node_index) {
396 trajectory_nodes_.at(node_id).pose =
397 old_global_to_new_global * trajectory_nodes_.at(node_id).pose;
410 std::vector<std::vector<mapping::TrajectoryNode>>
413 return trajectory_nodes_.data();
422 const int trajectory_id) {
435 if (trajectory_id >= submap_data_.num_trajectories()) {
438 return submap_data_.num_indices(trajectory_id);
446 static_cast<int>(optimized_submap_transforms_.size()) &&
447 submap_id.
submap_index < static_cast<int>(optimized_submap_transforms_
450 return optimized_submap_transforms_.at(submap_id.
trajectory_id)
457 submap_data_.at(submap_id).submap->local_pose();
461 const std::vector<std::vector<sparse_pose_graph::SubmapData>>&
463 const int trajectory_id)
const {
464 if (trajectory_id >= static_cast<int>(submap_transforms.size()) ||
465 submap_transforms.at(trajectory_id).empty()) {
470 static_cast<int>(submap_transforms.at(trajectory_id).size() - 1)};
472 return submap_transforms.at(trajectory_id).back().pose *
473 submap_data_.at(last_optimized_submap_id)
474 .submap->local_pose()
void GrowSubmapTransformsAsNeeded(const std::vector< const Submap * > &insertion_submaps) REQUIRES(mutex_)
proto::RangeDataInserterOptions options_
void RunOptimization() EXCLUDES(mutex_)
const mapping::proto::SparsePoseGraphOptions options_
void AddWorkItem(std::function< void()> work_item) REQUIRES(mutex_)
void ComputeConstraintsForScan(const Submap *matching_submap, std::vector< const Submap * > insertion_submaps, const Submap *finished_submap, const transform::Rigid3d &pose) REQUIRES(mutex_)
std::vector< std::vector< mapping::TrajectoryNode > > GetTrajectoryNodes() override EXCLUDES(mutex_)
const std::vector< std::vector< NodeData > > & node_data() const
const std::vector< std::vector< SubmapData > > & submap_data() const
std::vector< Constraint > Result
std::shared_ptr< const Data > constant_data
std::vector< Constraint > constraints() override EXCLUDES(mutex_)
transform::Rigid3d local_pose() const
void ComputeConstraint(const mapping::NodeId &node_id, const mapping::SubmapId &submap_id) REQUIRES(mutex_)
void HandleScanQueue() REQUIRES(mutex_)
void AddImuData(int trajectory_id, common::Time time, const Eigen::Vector3d &linear_acceleration, const Eigen::Vector3d &angular_velocity)
void Solve(const std::vector< Constraint > &constraints)
std::map< int, size_t > reverse_connected_components_
UniversalTimeScaleClock::time_point Time
void AddSubmap(int trajectory_id, const transform::Rigid3d &submap_pose)
std::vector< std::vector< int > > connected_components_
void SetMaxNumIterations(int32 max_num_iterations)
~SparsePoseGraph() override
Duration FromSeconds(const double seconds)
transform::Rigid3d GetLocalToGlobalTransform(int trajectory_id) EXCLUDES(mutex_) override
void AddTrajectoryNode(int trajectory_id, common::Time time, const transform::Rigid3d &point_cloud_pose)
void AddImuData(int trajectory_id, common::Time time, const Eigen::Vector3d &linear_acceleration, const Eigen::Vector3d &angular_velocity)
OptimizationProblem optimization_problem_
void WaitForAllComputations() EXCLUDES(mutex_)
CompressedRangeData Compress(const RangeData &range_data)
transform::Rigid3d ComputeLocalToGlobalTransform(const std::vector< std::vector< sparse_pose_graph::SubmapData >> &submap_transforms, int trajectory_id) const REQUIRES(mutex_)
mapping::SubmapId GetSubmapId(const mapping::Submap *submap) const REQUIRES(mutex_)
transform::Rigid3d GetSubmapTransform(const mapping::SubmapId &submap_id) EXCLUDES(mutex_) override
const bool finished() const
void RunFinalOptimization() override
Mutex::Locker MutexLocker
void ComputeConstraintsForOldScans(const Submap *submap) REQUIRES(mutex_)
int num_submaps(int trajectory_id) EXCLUDES(mutex_) override
sparse_pose_graph::OptimizationProblem optimization_problem_
void AddScan(common::Time time, const sensor::RangeData &range_data_in_tracking, const transform::Rigid3d &pose, int trajectory_id, const Submap *matching_submap, const std::vector< const Submap * > &insertion_submaps) EXCLUDES(mutex_)
std::vector< std::vector< int > > GetConnectedTrajectories() override