Adds accumulation of range data to 2D. (#408)
This mostly follows the implementation as done for 3D. Towards googlecartographer/cartographer_ros#212.master
parent
3ef680e791
commit
1bce14b7b5
|
@ -39,23 +39,8 @@ LocalTrajectoryBuilder::~LocalTrajectoryBuilder() {}
|
||||||
sensor::RangeData LocalTrajectoryBuilder::TransformAndFilterRangeData(
|
sensor::RangeData LocalTrajectoryBuilder::TransformAndFilterRangeData(
|
||||||
const transform::Rigid3f& tracking_to_tracking_2d,
|
const transform::Rigid3f& tracking_to_tracking_2d,
|
||||||
const sensor::RangeData& range_data) const {
|
const sensor::RangeData& range_data) const {
|
||||||
// Drop any returns below the minimum range and convert returns beyond the
|
|
||||||
// maximum range into misses.
|
|
||||||
sensor::RangeData returns_and_misses{range_data.origin, {}, {}};
|
|
||||||
for (const Eigen::Vector3f& hit : range_data.returns) {
|
|
||||||
const float range = (hit - range_data.origin).norm();
|
|
||||||
if (range >= options_.min_range()) {
|
|
||||||
if (range <= options_.max_range()) {
|
|
||||||
returns_and_misses.returns.push_back(hit);
|
|
||||||
} else {
|
|
||||||
returns_and_misses.misses.push_back(
|
|
||||||
range_data.origin + options_.missing_data_ray_length() *
|
|
||||||
(hit - range_data.origin).normalized());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const sensor::RangeData cropped = sensor::CropRangeData(
|
const sensor::RangeData cropped = sensor::CropRangeData(
|
||||||
sensor::TransformRangeData(returns_and_misses, tracking_to_tracking_2d),
|
sensor::TransformRangeData(range_data, tracking_to_tracking_2d),
|
||||||
options_.min_z(), options_.max_z());
|
options_.min_z(), options_.max_z());
|
||||||
return sensor::RangeData{
|
return sensor::RangeData{
|
||||||
cropped.origin,
|
cropped.origin,
|
||||||
|
@ -112,6 +97,45 @@ LocalTrajectoryBuilder::AddHorizontalRangeData(
|
||||||
}
|
}
|
||||||
|
|
||||||
Predict(time);
|
Predict(time);
|
||||||
|
if (num_accumulated_ == 0) {
|
||||||
|
first_pose_estimate_ = pose_estimate_.cast<float>();
|
||||||
|
accumulated_range_data_ =
|
||||||
|
sensor::RangeData{Eigen::Vector3f::Zero(), {}, {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
const transform::Rigid3f tracking_delta =
|
||||||
|
first_pose_estimate_.inverse() * pose_estimate_.cast<float>();
|
||||||
|
const sensor::RangeData range_data_in_first_tracking =
|
||||||
|
sensor::TransformRangeData(range_data, tracking_delta);
|
||||||
|
// Drop any returns below the minimum range and convert returns beyond the
|
||||||
|
// maximum range into misses.
|
||||||
|
for (const Eigen::Vector3f& hit : range_data_in_first_tracking.returns) {
|
||||||
|
const Eigen::Vector3f delta = hit - range_data_in_first_tracking.origin;
|
||||||
|
const float range = delta.norm();
|
||||||
|
if (range >= options_.min_range()) {
|
||||||
|
if (range <= options_.max_range()) {
|
||||||
|
accumulated_range_data_.returns.push_back(hit);
|
||||||
|
} else {
|
||||||
|
accumulated_range_data_.misses.push_back(
|
||||||
|
range_data_in_first_tracking.origin +
|
||||||
|
options_.missing_data_ray_length() / range * delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++num_accumulated_;
|
||||||
|
|
||||||
|
if (num_accumulated_ >= options_.scans_per_accumulation()) {
|
||||||
|
num_accumulated_ = 0;
|
||||||
|
return AddAccumulatedRangeData(
|
||||||
|
time, sensor::TransformRangeData(accumulated_range_data_,
|
||||||
|
tracking_delta.inverse()));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<LocalTrajectoryBuilder::InsertionResult>
|
||||||
|
LocalTrajectoryBuilder::AddAccumulatedRangeData(
|
||||||
|
const common::Time time, const sensor::RangeData& range_data) {
|
||||||
const transform::Rigid3d odometry_prediction =
|
const transform::Rigid3d odometry_prediction =
|
||||||
pose_estimate_ * odometry_correction_;
|
pose_estimate_ * odometry_correction_;
|
||||||
const transform::Rigid3d model_prediction = pose_estimate_;
|
const transform::Rigid3d model_prediction = pose_estimate_;
|
||||||
|
@ -192,7 +216,7 @@ LocalTrajectoryBuilder::AddHorizontalRangeData(
|
||||||
range_data_in_tracking_2d, pose_estimate_2d});
|
range_data_in_tracking_2d, pose_estimate_2d});
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapping::GlobalTrajectoryBuilderInterface::PoseEstimate&
|
const LocalTrajectoryBuilder::PoseEstimate&
|
||||||
LocalTrajectoryBuilder::pose_estimate() const {
|
LocalTrajectoryBuilder::pose_estimate() const {
|
||||||
return last_pose_estimate_;
|
return last_pose_estimate_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ namespace mapping_2d {
|
||||||
// closure.
|
// closure.
|
||||||
class LocalTrajectoryBuilder {
|
class LocalTrajectoryBuilder {
|
||||||
public:
|
public:
|
||||||
|
using PoseEstimate = mapping::GlobalTrajectoryBuilderInterface::PoseEstimate;
|
||||||
|
|
||||||
struct InsertionResult {
|
struct InsertionResult {
|
||||||
common::Time time;
|
common::Time time;
|
||||||
std::vector<std::shared_ptr<const Submap>> insertion_submaps;
|
std::vector<std::shared_ptr<const Submap>> insertion_submaps;
|
||||||
|
@ -53,8 +55,7 @@ class LocalTrajectoryBuilder {
|
||||||
LocalTrajectoryBuilder(const LocalTrajectoryBuilder&) = delete;
|
LocalTrajectoryBuilder(const LocalTrajectoryBuilder&) = delete;
|
||||||
LocalTrajectoryBuilder& operator=(const LocalTrajectoryBuilder&) = delete;
|
LocalTrajectoryBuilder& operator=(const LocalTrajectoryBuilder&) = delete;
|
||||||
|
|
||||||
const mapping::GlobalTrajectoryBuilderInterface::PoseEstimate& pose_estimate()
|
const PoseEstimate& pose_estimate() const;
|
||||||
const;
|
|
||||||
std::unique_ptr<InsertionResult> AddHorizontalRangeData(
|
std::unique_ptr<InsertionResult> AddHorizontalRangeData(
|
||||||
common::Time, const sensor::RangeData& range_data);
|
common::Time, const sensor::RangeData& range_data);
|
||||||
void AddImuData(common::Time time, const Eigen::Vector3d& linear_acceleration,
|
void AddImuData(common::Time time, const Eigen::Vector3d& linear_acceleration,
|
||||||
|
@ -62,6 +63,8 @@ class LocalTrajectoryBuilder {
|
||||||
void AddOdometerData(common::Time time, const transform::Rigid3d& pose);
|
void AddOdometerData(common::Time time, const transform::Rigid3d& pose);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::unique_ptr<InsertionResult> AddAccumulatedRangeData(
|
||||||
|
common::Time time, const sensor::RangeData& range_data);
|
||||||
sensor::RangeData TransformAndFilterRangeData(
|
sensor::RangeData TransformAndFilterRangeData(
|
||||||
const transform::Rigid3f& tracking_to_tracking_2d,
|
const transform::Rigid3f& tracking_to_tracking_2d,
|
||||||
const sensor::RangeData& range_data) const;
|
const sensor::RangeData& range_data) const;
|
||||||
|
@ -81,7 +84,8 @@ class LocalTrajectoryBuilder {
|
||||||
|
|
||||||
const proto::LocalTrajectoryBuilderOptions options_;
|
const proto::LocalTrajectoryBuilderOptions options_;
|
||||||
ActiveSubmaps active_submaps_;
|
ActiveSubmaps active_submaps_;
|
||||||
mapping::GlobalTrajectoryBuilderInterface::PoseEstimate last_pose_estimate_;
|
|
||||||
|
PoseEstimate last_pose_estimate_;
|
||||||
|
|
||||||
// Current 'pose_estimate_' and 'velocity_estimate_' at 'time_'.
|
// Current 'pose_estimate_' and 'velocity_estimate_' at 'time_'.
|
||||||
common::Time time_ = common::Time::min();
|
common::Time time_ = common::Time::min();
|
||||||
|
@ -100,6 +104,10 @@ class LocalTrajectoryBuilder {
|
||||||
|
|
||||||
std::unique_ptr<mapping::ImuTracker> imu_tracker_;
|
std::unique_ptr<mapping::ImuTracker> imu_tracker_;
|
||||||
mapping::OdometryStateTracker odometry_state_tracker_;
|
mapping::OdometryStateTracker odometry_state_tracker_;
|
||||||
|
|
||||||
|
int num_accumulated_ = 0;
|
||||||
|
transform::Rigid3f first_pose_estimate_ = transform::Rigid3f::Identity();
|
||||||
|
sensor::RangeData accumulated_range_data_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mapping_2d
|
} // namespace mapping_2d
|
||||||
|
|
|
@ -34,6 +34,8 @@ proto::LocalTrajectoryBuilderOptions CreateLocalTrajectoryBuilderOptions(
|
||||||
options.set_max_z(parameter_dictionary->GetDouble("max_z"));
|
options.set_max_z(parameter_dictionary->GetDouble("max_z"));
|
||||||
options.set_missing_data_ray_length(
|
options.set_missing_data_ray_length(
|
||||||
parameter_dictionary->GetDouble("missing_data_ray_length"));
|
parameter_dictionary->GetDouble("missing_data_ray_length"));
|
||||||
|
options.set_scans_per_accumulation(
|
||||||
|
parameter_dictionary->GetInt("scans_per_accumulation"));
|
||||||
options.set_voxel_filter_size(
|
options.set_voxel_filter_size(
|
||||||
parameter_dictionary->GetDouble("voxel_filter_size"));
|
parameter_dictionary->GetDouble("voxel_filter_size"));
|
||||||
options.set_use_online_correlative_scan_matching(
|
options.set_use_online_correlative_scan_matching(
|
||||||
|
|
|
@ -32,6 +32,10 @@ message LocalTrajectoryBuilderOptions {
|
||||||
// Points beyond 'max_range' will be inserted with this length as empty space.
|
// Points beyond 'max_range' will be inserted with this length as empty space.
|
||||||
optional float missing_data_ray_length = 16;
|
optional float missing_data_ray_length = 16;
|
||||||
|
|
||||||
|
// Number of scans to accumulate into one unwarped, combined scan to use for
|
||||||
|
// scan matching.
|
||||||
|
optional int32 scans_per_accumulation = 19;
|
||||||
|
|
||||||
// Voxel filter that gets applied to the range data immediately after
|
// Voxel filter that gets applied to the range data immediately after
|
||||||
// cropping.
|
// cropping.
|
||||||
optional float voxel_filter_size = 3;
|
optional float voxel_filter_size = 3;
|
||||||
|
|
|
@ -75,7 +75,7 @@ class LocalTrajectoryBuilder {
|
||||||
const transform::Rigid3d& pose_observation);
|
const transform::Rigid3d& pose_observation);
|
||||||
|
|
||||||
const proto::LocalTrajectoryBuilderOptions options_;
|
const proto::LocalTrajectoryBuilderOptions options_;
|
||||||
mapping_3d::ActiveSubmaps active_submaps_;
|
ActiveSubmaps active_submaps_;
|
||||||
|
|
||||||
PoseEstimate last_pose_estimate_;
|
PoseEstimate last_pose_estimate_;
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package cartographer.mapping_3d.proto;
|
||||||
|
|
||||||
import "cartographer/mapping_3d/proto/motion_filter_options.proto";
|
import "cartographer/mapping_3d/proto/motion_filter_options.proto";
|
||||||
import "cartographer/sensor/proto/adaptive_voxel_filter_options.proto";
|
import "cartographer/sensor/proto/adaptive_voxel_filter_options.proto";
|
||||||
import "cartographer/mapping_2d/scan_matching/proto/real_time_correlative_scan_matcher_options.proto";
|
import "cartographer/mapping_2d/scan_matching/proto/real_time_correlative_scan_matcher_options.proto";
|
||||||
import "cartographer/mapping_3d/proto/submaps_options.proto";
|
import "cartographer/mapping_3d/proto/submaps_options.proto";
|
||||||
import "cartographer/mapping_3d/scan_matching/proto/ceres_scan_matcher_options.proto";
|
import "cartographer/mapping_3d/scan_matching/proto/ceres_scan_matcher_options.proto";
|
||||||
|
|
||||||
package cartographer.mapping_3d.proto;
|
|
||||||
|
|
||||||
message LocalTrajectoryBuilderOptions {
|
message LocalTrajectoryBuilderOptions {
|
||||||
// Rangefinder points outside these ranges will be dropped.
|
// Rangefinder points outside these ranges will be dropped.
|
||||||
optional float min_range = 1;
|
optional float min_range = 1;
|
||||||
|
|
|
@ -19,6 +19,7 @@ TRAJECTORY_BUILDER_2D = {
|
||||||
min_z = -0.8,
|
min_z = -0.8,
|
||||||
max_z = 2.,
|
max_z = 2.,
|
||||||
missing_data_ray_length = 5.,
|
missing_data_ray_length = 5.,
|
||||||
|
scans_per_accumulation = 1,
|
||||||
voxel_filter_size = 0.025,
|
voxel_filter_size = 0.025,
|
||||||
|
|
||||||
adaptive_voxel_filter = {
|
adaptive_voxel_filter = {
|
||||||
|
|
Loading…
Reference in New Issue