Add trajectory trimming support to 3d (#559)
* Adds DeleteScanMatcher() to 3D constraint builder * Add possibility to remove submaps and scans from the 3D optimization problem. * Implements TrimmingHandle in SPA.master
parent
3c521eb573
commit
9c81a01608
|
@ -648,12 +648,68 @@ SparsePoseGraph::TrimmingHandle::TrimmingHandle(SparsePoseGraph* const parent)
|
||||||
|
|
||||||
int SparsePoseGraph::TrimmingHandle::num_submaps(
|
int SparsePoseGraph::TrimmingHandle::num_submaps(
|
||||||
const int trajectory_id) const {
|
const int trajectory_id) const {
|
||||||
LOG(FATAL) << "Not yet implemented for 3D.";
|
return parent_->optimization_problem_.submap_data().at(trajectory_id).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SparsePoseGraph::TrimmingHandle::MarkSubmapAsTrimmed(
|
void SparsePoseGraph::TrimmingHandle::MarkSubmapAsTrimmed(
|
||||||
const mapping::SubmapId& submap_id) {
|
const mapping::SubmapId& submap_id) {
|
||||||
LOG(FATAL) << "Not yet implemented for 3D.";
|
// TODO(hrapp): We have to make sure that the trajectory has been finished
|
||||||
|
// if we want to delete the last submaps.
|
||||||
|
CHECK(parent_->submap_data_.at(submap_id).state == SubmapState::kFinished);
|
||||||
|
|
||||||
|
// Compile all nodes that are still INTRA_SUBMAP constrained once the submap
|
||||||
|
// with 'submap_id' is gone.
|
||||||
|
std::set<mapping::NodeId> nodes_to_retain;
|
||||||
|
for (const Constraint& constraint : parent_->constraints_) {
|
||||||
|
if (constraint.tag == Constraint::Tag::INTRA_SUBMAP &&
|
||||||
|
constraint.submap_id != submap_id) {
|
||||||
|
nodes_to_retain.insert(constraint.node_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove all 'constraints_' related to 'submap_id'.
|
||||||
|
std::set<mapping::NodeId> nodes_to_remove;
|
||||||
|
{
|
||||||
|
std::vector<Constraint> constraints;
|
||||||
|
for (const Constraint& constraint : parent_->constraints_) {
|
||||||
|
if (constraint.submap_id == submap_id) {
|
||||||
|
if (constraint.tag == Constraint::Tag::INTRA_SUBMAP &&
|
||||||
|
nodes_to_retain.count(constraint.node_id) == 0) {
|
||||||
|
// This node will no longer be INTRA_SUBMAP contrained and has to be
|
||||||
|
// removed.
|
||||||
|
nodes_to_remove.insert(constraint.node_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constraints.push_back(constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent_->constraints_ = std::move(constraints);
|
||||||
|
}
|
||||||
|
// Remove all 'constraints_' related to 'nodes_to_remove'.
|
||||||
|
{
|
||||||
|
std::vector<Constraint> constraints;
|
||||||
|
for (const Constraint& constraint : parent_->constraints_) {
|
||||||
|
if (nodes_to_remove.count(constraint.node_id) == 0) {
|
||||||
|
constraints.push_back(constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent_->constraints_ = std::move(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the submap with 'submap_id' as trimmed and remove its data.
|
||||||
|
auto& submap_data = parent_->submap_data_.at(submap_id);
|
||||||
|
CHECK(submap_data.state == SubmapState::kFinished);
|
||||||
|
submap_data.state = SubmapState::kTrimmed;
|
||||||
|
CHECK(submap_data.submap != nullptr);
|
||||||
|
submap_data.submap.reset();
|
||||||
|
parent_->constraint_builder_.DeleteScanMatcher(submap_id);
|
||||||
|
parent_->optimization_problem_.TrimSubmap(submap_id);
|
||||||
|
|
||||||
|
// Mark the 'nodes_to_remove' as trimmed and remove their data.
|
||||||
|
for (const mapping::NodeId& node_id : nodes_to_remove) {
|
||||||
|
CHECK(!parent_->trajectory_nodes_.at(node_id).trimmed());
|
||||||
|
parent_->trajectory_nodes_.at(node_id).constant_data.reset();
|
||||||
|
parent_->optimization_problem_.TrimTrajectoryNode(node_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mapping_3d
|
} // namespace mapping_3d
|
||||||
|
|
|
@ -294,6 +294,12 @@ int ConstraintBuilder::GetNumFinishedScans() {
|
||||||
return pending_computations_.begin()->first;
|
return pending_computations_.begin()->first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConstraintBuilder::DeleteScanMatcher(const mapping::SubmapId& submap_id) {
|
||||||
|
common::MutexLocker locker(&mutex_);
|
||||||
|
CHECK(pending_computations_.empty());
|
||||||
|
submap_scan_matchers_.erase(submap_id);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sparse_pose_graph
|
} // namespace sparse_pose_graph
|
||||||
} // namespace mapping_3d
|
} // namespace mapping_3d
|
||||||
} // namespace cartographer
|
} // namespace cartographer
|
||||||
|
|
|
@ -105,6 +105,9 @@ class ConstraintBuilder {
|
||||||
// Returns the number of consecutive finished scans.
|
// Returns the number of consecutive finished scans.
|
||||||
int GetNumFinishedScans();
|
int GetNumFinishedScans();
|
||||||
|
|
||||||
|
// Delete data related to 'submap_id'.
|
||||||
|
void DeleteScanMatcher(const mapping::SubmapId& submap_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SubmapScanMatcher {
|
struct SubmapScanMatcher {
|
||||||
const HybridGrid* high_resolution_hybrid_grid;
|
const HybridGrid* high_resolution_hybrid_grid;
|
||||||
|
|
|
@ -93,6 +93,20 @@ void OptimizationProblem::AddTrajectoryNode(
|
||||||
++trajectory_data.next_node_index;
|
++trajectory_data.next_node_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptimizationProblem::TrimTrajectoryNode(const mapping::NodeId& node_id) {
|
||||||
|
auto& node_data = node_data_.at(node_id.trajectory_id);
|
||||||
|
CHECK(node_data.erase(node_id.node_index));
|
||||||
|
|
||||||
|
if (!node_data.empty() &&
|
||||||
|
node_id.trajectory_id < static_cast<int>(imu_data_.size())) {
|
||||||
|
const common::Time node_time = node_data.begin()->second.time;
|
||||||
|
auto& imu_data = imu_data_.at(node_id.trajectory_id);
|
||||||
|
while (imu_data.size() > 1 && imu_data[1].time <= node_time) {
|
||||||
|
imu_data.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OptimizationProblem::AddSubmap(const int trajectory_id,
|
void OptimizationProblem::AddSubmap(const int trajectory_id,
|
||||||
const transform::Rigid3d& submap_pose) {
|
const transform::Rigid3d& submap_pose) {
|
||||||
CHECK_GE(trajectory_id, 0);
|
CHECK_GE(trajectory_id, 0);
|
||||||
|
@ -106,6 +120,11 @@ void OptimizationProblem::AddSubmap(const int trajectory_id,
|
||||||
++trajectory_data.next_submap_index;
|
++trajectory_data.next_submap_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptimizationProblem::TrimSubmap(const mapping::SubmapId& submap_id) {
|
||||||
|
auto& submap_data = submap_data_.at(submap_id.trajectory_id);
|
||||||
|
CHECK(submap_data.erase(submap_id.submap_index));
|
||||||
|
}
|
||||||
|
|
||||||
void OptimizationProblem::SetMaxNumIterations(const int32 max_num_iterations) {
|
void OptimizationProblem::SetMaxNumIterations(const int32 max_num_iterations) {
|
||||||
options_.mutable_ceres_solver_options()->set_max_num_iterations(
|
options_.mutable_ceres_solver_options()->set_max_num_iterations(
|
||||||
max_num_iterations);
|
max_num_iterations);
|
||||||
|
|
|
@ -73,7 +73,9 @@ class OptimizationProblem {
|
||||||
void AddTrajectoryNode(int trajectory_id, common::Time time,
|
void AddTrajectoryNode(int trajectory_id, common::Time time,
|
||||||
const transform::Rigid3d& initial_pose,
|
const transform::Rigid3d& initial_pose,
|
||||||
const transform::Rigid3d& pose);
|
const transform::Rigid3d& pose);
|
||||||
|
void TrimTrajectoryNode(const mapping::NodeId& node_id);
|
||||||
void AddSubmap(int trajectory_id, const transform::Rigid3d& submap_pose);
|
void AddSubmap(int trajectory_id, const transform::Rigid3d& submap_pose);
|
||||||
|
void TrimSubmap(const mapping::SubmapId& submap_id);
|
||||||
|
|
||||||
void SetMaxNumIterations(int32 max_num_iterations);
|
void SetMaxNumIterations(int32 max_num_iterations);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue