Use multi-res scan matching for loop closures too. (#374)
Improves loop closure scan matcher refinement.master
parent
955e190166
commit
f765e55ea9
|
@ -55,6 +55,16 @@ proto::ConstraintBuilderOptions CreateConstraintBuilderOptions(
|
||||||
parameter_dictionary
|
parameter_dictionary
|
||||||
->GetDictionary("fast_correlative_scan_matcher_3d")
|
->GetDictionary("fast_correlative_scan_matcher_3d")
|
||||||
.get());
|
.get());
|
||||||
|
*options.mutable_high_resolution_adaptive_voxel_filter_options() =
|
||||||
|
sensor::CreateAdaptiveVoxelFilterOptions(
|
||||||
|
parameter_dictionary
|
||||||
|
->GetDictionary("high_resolution_adaptive_voxel_filter")
|
||||||
|
.get());
|
||||||
|
*options.mutable_low_resolution_adaptive_voxel_filter_options() =
|
||||||
|
sensor::CreateAdaptiveVoxelFilterOptions(
|
||||||
|
parameter_dictionary
|
||||||
|
->GetDictionary("low_resolution_adaptive_voxel_filter")
|
||||||
|
.get());
|
||||||
*options.mutable_ceres_scan_matcher_options_3d() =
|
*options.mutable_ceres_scan_matcher_options_3d() =
|
||||||
mapping_3d::scan_matching::CreateCeresScanMatcherOptions(
|
mapping_3d::scan_matching::CreateCeresScanMatcherOptions(
|
||||||
parameter_dictionary->GetDictionary("ceres_scan_matcher_3d").get());
|
parameter_dictionary->GetDictionary("ceres_scan_matcher_3d").get());
|
||||||
|
|
|
@ -59,6 +59,15 @@ message ConstraintBuilderOptions {
|
||||||
ceres_scan_matcher_options = 11;
|
ceres_scan_matcher_options = 11;
|
||||||
optional mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions
|
optional mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions
|
||||||
fast_correlative_scan_matcher_options_3d = 10;
|
fast_correlative_scan_matcher_options_3d = 10;
|
||||||
|
|
||||||
|
// Voxel filter used for high resolution, 3D loop closure refinement.
|
||||||
|
optional sensor.proto.AdaptiveVoxelFilterOptions
|
||||||
|
high_resolution_adaptive_voxel_filter_options = 15;
|
||||||
|
|
||||||
|
// Voxel filter used for low resolution, 3D loop closure refinement.
|
||||||
|
optional sensor.proto.AdaptiveVoxelFilterOptions
|
||||||
|
low_resolution_adaptive_voxel_filter_options = 16;
|
||||||
|
|
||||||
optional mapping_3d.scan_matching.proto.CeresScanMatcherOptions
|
optional mapping_3d.scan_matching.proto.CeresScanMatcherOptions
|
||||||
ceres_scan_matcher_options_3d = 12;
|
ceres_scan_matcher_options_3d = 12;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,16 @@ class SparsePoseGraphTest : public ::testing::Test {
|
||||||
linear_z_search_window = 4.,
|
linear_z_search_window = 4.,
|
||||||
angular_search_window = 0.1,
|
angular_search_window = 0.1,
|
||||||
},
|
},
|
||||||
|
high_resolution_adaptive_voxel_filter = {
|
||||||
|
max_length = 2.,
|
||||||
|
min_num_points = 150,
|
||||||
|
max_range = 15.,
|
||||||
|
},
|
||||||
|
low_resolution_adaptive_voxel_filter = {
|
||||||
|
max_length = 4.,
|
||||||
|
min_num_points = 200,
|
||||||
|
max_range = 60.,
|
||||||
|
},
|
||||||
ceres_scan_matcher_3d = {
|
ceres_scan_matcher_3d = {
|
||||||
occupied_space_weight_0 = 20.,
|
occupied_space_weight_0 = 20.,
|
||||||
translation_weight = 10.,
|
translation_weight = 10.,
|
||||||
|
|
|
@ -72,7 +72,7 @@ void ConstraintBuilder::MaybeAddConstraint(
|
||||||
++pending_computations_[current_computation_];
|
++pending_computations_[current_computation_];
|
||||||
const int current_computation = current_computation_;
|
const int current_computation = current_computation_;
|
||||||
ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
||||||
submap_id, submap_nodes, &submap->high_resolution_hybrid_grid(),
|
submap_id, submap_nodes, submap,
|
||||||
[=]() EXCLUDES(mutex_) {
|
[=]() EXCLUDES(mutex_) {
|
||||||
ComputeConstraint(submap_id, submap, node_id,
|
ComputeConstraint(submap_id, submap, node_id,
|
||||||
false, /* match_full_submap */
|
false, /* match_full_submap */
|
||||||
|
@ -96,7 +96,7 @@ void ConstraintBuilder::MaybeAddGlobalConstraint(
|
||||||
++pending_computations_[current_computation_];
|
++pending_computations_[current_computation_];
|
||||||
const int current_computation = current_computation_;
|
const int current_computation = current_computation_;
|
||||||
ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
||||||
submap_id, submap_nodes, &submap->high_resolution_hybrid_grid(),
|
submap_id, submap_nodes, submap,
|
||||||
[=]() EXCLUDES(mutex_) {
|
[=]() EXCLUDES(mutex_) {
|
||||||
ComputeConstraint(
|
ComputeConstraint(
|
||||||
submap_id, submap, node_id, true, /* match_full_submap */
|
submap_id, submap, node_id, true, /* match_full_submap */
|
||||||
|
@ -126,7 +126,7 @@ void ConstraintBuilder::WhenDone(
|
||||||
void ConstraintBuilder::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
void ConstraintBuilder::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
||||||
const mapping::SubmapId& submap_id,
|
const mapping::SubmapId& submap_id,
|
||||||
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
||||||
const HybridGrid* const submap, const std::function<void()> work_item) {
|
const Submap* const submap, const std::function<void()> work_item) {
|
||||||
if (submap_scan_matchers_[submap_id].fast_correlative_scan_matcher !=
|
if (submap_scan_matchers_[submap_id].fast_correlative_scan_matcher !=
|
||||||
nullptr) {
|
nullptr) {
|
||||||
thread_pool_->Schedule(work_item);
|
thread_pool_->Schedule(work_item);
|
||||||
|
@ -143,13 +143,15 @@ void ConstraintBuilder::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
||||||
void ConstraintBuilder::ConstructSubmapScanMatcher(
|
void ConstraintBuilder::ConstructSubmapScanMatcher(
|
||||||
const mapping::SubmapId& submap_id,
|
const mapping::SubmapId& submap_id,
|
||||||
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
||||||
const HybridGrid* const submap) {
|
const Submap* const submap) {
|
||||||
auto submap_scan_matcher =
|
auto submap_scan_matcher =
|
||||||
common::make_unique<scan_matching::FastCorrelativeScanMatcher>(
|
common::make_unique<scan_matching::FastCorrelativeScanMatcher>(
|
||||||
*submap, submap_nodes,
|
submap->high_resolution_hybrid_grid(), submap_nodes,
|
||||||
options_.fast_correlative_scan_matcher_options_3d());
|
options_.fast_correlative_scan_matcher_options_3d());
|
||||||
common::MutexLocker locker(&mutex_);
|
common::MutexLocker locker(&mutex_);
|
||||||
submap_scan_matchers_[submap_id] = {submap, std::move(submap_scan_matcher)};
|
submap_scan_matchers_[submap_id] = {&submap->high_resolution_hybrid_grid(),
|
||||||
|
&submap->low_resolution_hybrid_grid(),
|
||||||
|
std::move(submap_scan_matcher)};
|
||||||
for (const std::function<void()>& work_item :
|
for (const std::function<void()>& work_item :
|
||||||
submap_queued_work_items_[submap_id]) {
|
submap_queued_work_items_[submap_id]) {
|
||||||
thread_pool_->Schedule(work_item);
|
thread_pool_->Schedule(work_item);
|
||||||
|
@ -219,11 +221,23 @@ void ConstraintBuilder::ComputeConstraint(
|
||||||
// Use the CSM estimate as both the initial and previous pose. This has the
|
// Use the CSM estimate as both the initial and previous pose. This has the
|
||||||
// effect that, in the absence of better information, we prefer the original
|
// effect that, in the absence of better information, we prefer the original
|
||||||
// CSM estimate.
|
// CSM estimate.
|
||||||
|
sensor::AdaptiveVoxelFilter adaptive_voxel_filter(
|
||||||
|
options_.high_resolution_adaptive_voxel_filter_options());
|
||||||
|
const sensor::PointCloud high_resolution_point_cloud =
|
||||||
|
adaptive_voxel_filter.Filter(point_cloud);
|
||||||
|
sensor::AdaptiveVoxelFilter low_resolution_adaptive_voxel_filter(
|
||||||
|
options_.low_resolution_adaptive_voxel_filter_options());
|
||||||
|
const sensor::PointCloud low_resolution_point_cloud =
|
||||||
|
low_resolution_adaptive_voxel_filter.Filter(point_cloud);
|
||||||
|
|
||||||
ceres::Solver::Summary unused_summary;
|
ceres::Solver::Summary unused_summary;
|
||||||
transform::Rigid3d constraint_transform;
|
transform::Rigid3d constraint_transform;
|
||||||
ceres_scan_matcher_.Match(
|
ceres_scan_matcher_.Match(
|
||||||
pose_estimate, pose_estimate,
|
pose_estimate, pose_estimate,
|
||||||
{{&filtered_point_cloud, submap_scan_matcher->hybrid_grid}},
|
{{&high_resolution_point_cloud,
|
||||||
|
submap_scan_matcher->high_resolution_hybrid_grid},
|
||||||
|
{&low_resolution_point_cloud,
|
||||||
|
submap_scan_matcher->low_resolution_hybrid_grid}},
|
||||||
&constraint_transform, &unused_summary);
|
&constraint_transform, &unused_summary);
|
||||||
|
|
||||||
constraint->reset(new OptimizationProblem::Constraint{
|
constraint->reset(new OptimizationProblem::Constraint{
|
||||||
|
|
|
@ -110,7 +110,8 @@ class ConstraintBuilder {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SubmapScanMatcher {
|
struct SubmapScanMatcher {
|
||||||
const HybridGrid* hybrid_grid;
|
const HybridGrid* high_resolution_hybrid_grid;
|
||||||
|
const HybridGrid* low_resolution_hybrid_grid;
|
||||||
std::unique_ptr<scan_matching::FastCorrelativeScanMatcher>
|
std::unique_ptr<scan_matching::FastCorrelativeScanMatcher>
|
||||||
fast_correlative_scan_matcher;
|
fast_correlative_scan_matcher;
|
||||||
};
|
};
|
||||||
|
@ -120,14 +121,14 @@ class ConstraintBuilder {
|
||||||
void ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
void ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
|
||||||
const mapping::SubmapId& submap_id,
|
const mapping::SubmapId& submap_id,
|
||||||
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
||||||
const HybridGrid* submap, std::function<void()> work_item)
|
const Submap* submap, std::function<void()> work_item)
|
||||||
REQUIRES(mutex_);
|
REQUIRES(mutex_);
|
||||||
|
|
||||||
// Constructs the scan matcher for a 'submap', then schedules its work items.
|
// Constructs the scan matcher for a 'submap', then schedules its work items.
|
||||||
void ConstructSubmapScanMatcher(
|
void ConstructSubmapScanMatcher(
|
||||||
const mapping::SubmapId& submap_id,
|
const mapping::SubmapId& submap_id,
|
||||||
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
const std::vector<mapping::TrajectoryNode>& submap_nodes,
|
||||||
const HybridGrid* submap) EXCLUDES(mutex_);
|
const Submap* submap) EXCLUDES(mutex_);
|
||||||
|
|
||||||
// Returns the scan matcher for a submap, which has to exist.
|
// Returns the scan matcher for a submap, which has to exist.
|
||||||
const SubmapScanMatcher* GetSubmapScanMatcher(
|
const SubmapScanMatcher* GetSubmapScanMatcher(
|
||||||
|
|
|
@ -47,12 +47,23 @@ SPARSE_POSE_GRAPH = {
|
||||||
full_resolution_depth = 3,
|
full_resolution_depth = 3,
|
||||||
rotational_histogram_size = 120,
|
rotational_histogram_size = 120,
|
||||||
min_rotational_score = 0.77,
|
min_rotational_score = 0.77,
|
||||||
linear_xy_search_window = 4.,
|
linear_xy_search_window = 5.,
|
||||||
linear_z_search_window = 1.,
|
linear_z_search_window = 1.,
|
||||||
angular_search_window = math.rad(15.),
|
angular_search_window = math.rad(15.),
|
||||||
},
|
},
|
||||||
|
high_resolution_adaptive_voxel_filter = {
|
||||||
|
max_length = 2.,
|
||||||
|
min_num_points = 150,
|
||||||
|
max_range = 15.,
|
||||||
|
},
|
||||||
|
low_resolution_adaptive_voxel_filter = {
|
||||||
|
max_length = 4.,
|
||||||
|
min_num_points = 200,
|
||||||
|
max_range = 60.,
|
||||||
|
},
|
||||||
ceres_scan_matcher_3d = {
|
ceres_scan_matcher_3d = {
|
||||||
occupied_space_weight_0 = 20.,
|
occupied_space_weight_0 = 5.,
|
||||||
|
occupied_space_weight_1 = 30.,
|
||||||
translation_weight = 10.,
|
translation_weight = 10.,
|
||||||
rotation_weight = 1.,
|
rotation_weight = 1.,
|
||||||
only_optimize_yaw = false,
|
only_optimize_yaw = false,
|
||||||
|
|
|
@ -149,6 +149,12 @@ cartographer.mapping_2d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_m
|
||||||
cartographer.mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options_3d
|
cartographer.mapping_3d.scan_matching.proto.FastCorrelativeScanMatcherOptions fast_correlative_scan_matcher_options_3d
|
||||||
Not yet documented.
|
Not yet documented.
|
||||||
|
|
||||||
|
cartographer.sensor.proto.AdaptiveVoxelFilterOptions high_resolution_adaptive_voxel_filter_options
|
||||||
|
Voxel filter used for high resolution, 3D loop closure refinement.
|
||||||
|
|
||||||
|
cartographer.sensor.proto.AdaptiveVoxelFilterOptions low_resolution_adaptive_voxel_filter_options
|
||||||
|
Voxel filter used for low resolution, 3D loop closure refinement.
|
||||||
|
|
||||||
cartographer.mapping_3d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options_3d
|
cartographer.mapping_3d.scan_matching.proto.CeresScanMatcherOptions ceres_scan_matcher_options_3d
|
||||||
Not yet documented.
|
Not yet documented.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue