diff --git a/cartographer/mapping_2d/sparse_pose_graph.cc b/cartographer/mapping_2d/sparse_pose_graph.cc index d153264..b0c70d6 100644 --- a/cartographer/mapping_2d/sparse_pose_graph.cc +++ b/cartographer/mapping_2d/sparse_pose_graph.cc @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/cartographer/mapping_2d/sparse_pose_graph.h b/cartographer/mapping_2d/sparse_pose_graph.h index 732e99e..6995993 100644 --- a/cartographer/mapping_2d/sparse_pose_graph.h +++ b/cartographer/mapping_2d/sparse_pose_graph.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -166,7 +167,7 @@ class SparsePoseGraph : public mapping::SparsePoseGraph { common::Mutex mutex_; // If it exists, further scans must be added to this queue, and will be - // considered later + // considered later. std::unique_ptr>> scan_queue_ GUARDED_BY(mutex_); diff --git a/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.cc b/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.cc index d5233a4..a159139 100644 --- a/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.cc +++ b/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.cc @@ -161,12 +161,16 @@ void OptimizationProblem::Solve(const std::vector& constraints, } for (size_t trajectory_id = 0; trajectory_id != node_data_.size(); ++trajectory_id) { + const bool frozen = frozen_trajectories.count(trajectory_id); // Reserve guarantees that data does not move, so the pointers for Ceres // stay valid. C_nodes[trajectory_id].reserve(node_data_[trajectory_id].size()); for (const NodeData& node_data : node_data_[trajectory_id]) { C_nodes[trajectory_id].push_back(FromPose(node_data.point_cloud_pose)); problem.AddParameterBlock(C_nodes[trajectory_id].back().data(), 3); + if (frozen) { + problem.SetParameterBlockConstant(C_nodes[trajectory_id].back().data()); + } } } diff --git a/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.h b/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.h index 47aaf68..209308b 100644 --- a/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.h +++ b/cartographer/mapping_2d/sparse_pose_graph/optimization_problem.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "Eigen/Core" diff --git a/cartographer/mapping_3d/sparse_pose_graph.cc b/cartographer/mapping_3d/sparse_pose_graph.cc index a8f4eeb..e1a0ca7 100644 --- a/cartographer/mapping_3d/sparse_pose_graph.cc +++ b/cartographer/mapping_3d/sparse_pose_graph.cc @@ -368,6 +368,23 @@ void SparsePoseGraph::WaitForAllComputations() { locker.Await([¬ification]() { return notification; }); } +void SparsePoseGraph::FreezeTrajectory(const int trajectory_id) { + common::MutexLocker locker(&mutex_); + AddWorkItem([this, trajectory_id]() REQUIRES(mutex_) { + CHECK_EQ(frozen_trajectories_.count(trajectory_id), 0); + frozen_trajectories_.insert(trajectory_id); + }); +} + +void SparsePoseGraph::AddTrimmer( + std::unique_ptr trimmer) { + common::MutexLocker locker(&mutex_); + // C++11 does not allow us to move a unique_ptr into a lambda. + mapping::PoseGraphTrimmer* const trimmer_ptr = trimmer.release(); + AddWorkItem([this, trimmer_ptr]() + REQUIRES(mutex_) { trimmers_.emplace_back(trimmer_ptr); }); +} + void SparsePoseGraph::RunFinalOptimization() { WaitForAllComputations(); optimization_problem_.SetMaxNumIterations( @@ -383,7 +400,7 @@ void SparsePoseGraph::RunOptimization() { if (optimization_problem_.submap_data().empty()) { return; } - optimization_problem_.Solve(constraints_); + optimization_problem_.Solve(constraints_, frozen_trajectories_); common::MutexLocker locker(&mutex_); const auto& node_data = optimization_problem_.node_data(); @@ -418,6 +435,11 @@ void SparsePoseGraph::RunOptimization() { reverse_connected_components_.emplace(trajectory_id, i); } } + + TrimmingHandle trimming_handle(this); + for (auto& trimmer : trimmers_) { + trimmer->Trim(&trimming_handle); + } } std::vector> @@ -513,5 +535,18 @@ mapping::SparsePoseGraph::SubmapData SparsePoseGraph::GetSubmapDataUnderLock( submap->local_pose()}; } +SparsePoseGraph::TrimmingHandle::TrimmingHandle(SparsePoseGraph* const parent) + : parent_(parent) {} + +int SparsePoseGraph::TrimmingHandle::num_submaps( + const int trajectory_id) const { + LOG(FATAL) << "Not yet implemented for 3D."; +} + +void SparsePoseGraph::TrimmingHandle::MarkSubmapAsTrimmed( + const mapping::SubmapId& submap_id) { + LOG(FATAL) << "Not yet implemented for 3D."; +} + } // namespace mapping_3d } // namespace cartographer diff --git a/cartographer/mapping_3d/sparse_pose_graph.h b/cartographer/mapping_3d/sparse_pose_graph.h index 6e459b6..b0c4a30 100644 --- a/cartographer/mapping_3d/sparse_pose_graph.h +++ b/cartographer/mapping_3d/sparse_pose_graph.h @@ -31,6 +31,7 @@ #include "cartographer/common/mutex.h" #include "cartographer/common/thread_pool.h" #include "cartographer/common/time.h" +#include "cartographer/mapping/pose_graph_trimmer.h" #include "cartographer/mapping/sparse_pose_graph.h" #include "cartographer/mapping/trajectory_connectivity.h" #include "cartographer/mapping_3d/sparse_pose_graph/constraint_builder.h" @@ -77,17 +78,13 @@ class SparsePoseGraph : public mapping::SparsePoseGraph { const Eigen::Vector3d& linear_acceleration, const Eigen::Vector3d& angular_velocity); - void FreezeTrajectory(const int trajectory_id) override { - LOG(FATAL) << "Not yet implemented for 3D."; - } - void AddSubmapFromProto(const int trajectory_id, + void FreezeTrajectory(int trajectory_id) override; + void AddSubmapFromProto(int trajectory_id, const transform::Rigid3d& initial_pose, const mapping::proto::Submap& submap) override { LOG(FATAL) << "Not yet implemented for 3D"; } - void AddTrimmer(std::unique_ptr trimmer) override { - LOG(FATAL) << "Not yet implemented for 3D."; - } + void AddTrimmer(std::unique_ptr trimmer) override; void RunFinalOptimization() override; std::vector> GetConnectedTrajectories() override; int num_submaps(int trajectory_id) EXCLUDES(mutex_) override; @@ -208,6 +205,27 @@ class SparsePoseGraph : public mapping::SparsePoseGraph { // Current submap transforms used for displaying data. std::vector> optimized_submap_transforms_ GUARDED_BY(mutex_); + + // List of all trimmers to consult when optimizations finish. + std::vector> trimmers_ + GUARDED_BY(mutex_); + + // Set of all frozen trajectories not being optimized. + std::set frozen_trajectories_ GUARDED_BY(mutex_); + + // Allows querying and manipulating the pose graph by the 'trimmers_'. The + // 'mutex_' of the pose graph is held while this class is used. + class TrimmingHandle : public mapping::Trimmable { + public: + TrimmingHandle(SparsePoseGraph* parent); + ~TrimmingHandle() override {} + + int num_submaps(int trajectory_id) const override; + void MarkSubmapAsTrimmed(const mapping::SubmapId& submap_id) override; + + private: + SparsePoseGraph* const parent_; + }; }; } // namespace mapping_3d diff --git a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.cc b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.cc index efbce1b..97fc6f6 100644 --- a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.cc +++ b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.cc @@ -112,7 +112,8 @@ void OptimizationProblem::SetMaxNumIterations(const int32 max_num_iterations) { max_num_iterations); } -void OptimizationProblem::Solve(const std::vector& constraints) { +void OptimizationProblem::Solve(const std::vector& constraints, + const std::set& frozen_trajectories) { if (node_data_.empty()) { // Nothing to optimize. return; @@ -137,6 +138,7 @@ void OptimizationProblem::Solve(const std::vector& constraints) { std::vector> C_nodes(node_data_.size()); for (size_t trajectory_id = 0; trajectory_id != submap_data_.size(); ++trajectory_id) { + const bool frozen = frozen_trajectories.count(trajectory_id); for (size_t submap_index = 0; submap_index != submap_data_[trajectory_id].size(); ++submap_index) { if (trajectory_id == 0 && submap_index == 0) { @@ -154,16 +156,29 @@ void OptimizationProblem::Solve(const std::vector& constraints) { translation_parameterization(), common::make_unique(), &problem); } + if (frozen) { + problem.SetParameterBlockConstant( + C_submaps[trajectory_id].back().rotation()); + problem.SetParameterBlockConstant( + C_submaps[trajectory_id].back().translation()); + } } } for (size_t trajectory_id = 0; trajectory_id != node_data_.size(); ++trajectory_id) { + const bool frozen = frozen_trajectories.count(trajectory_id); for (size_t node_index = 0; node_index != node_data_[trajectory_id].size(); ++node_index) { C_nodes[trajectory_id].emplace_back( node_data_[trajectory_id][node_index].point_cloud_pose, translation_parameterization(), common::make_unique(), &problem); + if (frozen) { + problem.SetParameterBlockConstant( + C_nodes[trajectory_id].back().rotation()); + problem.SetParameterBlockConstant( + C_nodes[trajectory_id].back().translation()); + } } } diff --git a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.h b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.h index 355be78..403c1c4 100644 --- a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.h +++ b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "Eigen/Core" @@ -69,7 +70,8 @@ class OptimizationProblem { void SetMaxNumIterations(int32 max_num_iterations); // Computes the optimized poses. - void Solve(const std::vector& constraints); + void Solve(const std::vector& constraints, + const std::set& frozen_trajectories); const std::vector>& node_data() const; const std::vector>& submap_data() const; diff --git a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem_test.cc b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem_test.cc index 336cc99..56426be 100644 --- a/cartographer/mapping_3d/sparse_pose_graph/optimization_problem_test.cc +++ b/cartographer/mapping_3d/sparse_pose_graph/optimization_problem_test.cc @@ -167,7 +167,8 @@ TEST_F(OptimizationProblemTest, ReducesNoise) { optimization_problem_.AddSubmap(kTrajectoryId, kSubmap0Transform); optimization_problem_.AddSubmap(kTrajectoryId, kSubmap0Transform); optimization_problem_.AddSubmap(kTrajectoryId, kSubmap2Transform); - optimization_problem_.Solve(constraints); + const std::set kFrozen; + optimization_problem_.Solve(constraints, kFrozen); double translation_error_after = 0.; double rotation_error_after = 0.;