zoukankan      html  css  js  c++  java
  • Cartographer源码阅读(6):LocalTrajectoryBuilder和PoseExtrapolator

    LocalTrajectoryBuilder意思是局部轨迹的构建,下面的类图中方法的参数没有画进去。

    注意其中的三个类:PoseExtrapolator类,RealTimeCorrelativeScanMatcher类和CeresScanMatcher类。

    (1)PoseExtrapolator类(如下图),Node类和LocalTrajectoryBuilder类都有用到PoseExtrapolator对象,好像两者之间并没有什么关系?

    LocalTrajectoryBuilder中的PoseExtrapolator对象类似于运动模型。

    (Node类中的可能是为了发布位姿信息用的,单独进行了位姿推算。先不管了。)

    PoseExtrapolator的构造函数 VS 通过IMU初始化InitializeWithImu方法。

    在LocalTrajectoryBuilder::InitializeExtrapolator中对其构造函数的调用:

     1 void LocalTrajectoryBuilder::InitializeExtrapolator(const common::Time time)
     2 {
     3   if (extrapolator_ != nullptr) {
     4     return;
     5   }
     6   // We derive velocities from poses which are at least 1 ms apart for numerical
     7   // stability. Usually poses known to the extrapolator will be further apart
     8   // in time and thus the last two are used.
     9   constexpr double kExtrapolationEstimationTimeSec = 0.001;
    10   // TODO(gaschler): Consider using InitializeWithImu as 3D does.
    11   extrapolator_ = common::make_unique<mapping::PoseExtrapolator>(
    12       ::cartographer::common::FromSeconds(kExtrapolationEstimationTimeSec),
    13       options_.imu_gravity_time_constant());
    14   extrapolator_->AddPose(time, transform::Rigid3d::Identity());
    15 }

    PoseExtrapolator::InitializeWithImu方法:

     1 std::unique_ptr<PoseExtrapolator> PoseExtrapolator::InitializeWithImu(
     2     const common::Duration pose_queue_duration,
     3     const double imu_gravity_time_constant, const sensor::ImuData& imu_data)
     4 {
     5   auto extrapolator = common::make_unique<PoseExtrapolator>(pose_queue_duration, imu_gravity_time_constant);
     6   extrapolator->AddImuData(imu_data);
     7   extrapolator->imu_tracker_ =common::make_unique<ImuTracker>(imu_gravity_time_constant, imu_data.time);
     8   extrapolator->imu_tracker_->AddImuLinearAccelerationObservation(
     9       imu_data.linear_acceleration);
    10   extrapolator->imu_tracker_->AddImuAngularVelocityObservation(
    11       imu_data.angular_velocity);
    12   extrapolator->imu_tracker_->Advance(imu_data.time);
    13   extrapolator->AddPose(imu_data.time,transform::Rigid3d::Rotation(extrapolator->imu_tracker_->orientation()));
    14   return extrapolator;
    15 }

     LocalTrajectoryBuilder的AddImuDataAddOdometryData方法不赘述。

     1 void LocalTrajectoryBuilder::AddImuData(const sensor::ImuData& imu_data) {
     2   CHECK(options_.use_imu_data()) << "An unexpected IMU packet was added.";
     3   InitializeExtrapolator(imu_data.time);
     4   extrapolator_->AddImuData(imu_data);
     5 }
     6 
     7 void LocalTrajectoryBuilder::AddOdometryData(
     8     const sensor::OdometryData& odometry_data) {
     9   if (extrapolator_ == nullptr) {
    10     // Until we've initialized the extrapolator we cannot add odometry data.
    11     LOG(INFO) << "Extrapolator not yet initialized.";
    12     return;
    13   }
    14   extrapolator_->AddOdometryData(odometry_data);
    15 }

    如下查看LocalTrajectoryBuilder::AddRangeData方法。如果使用IMU数据,直接进入10行,如果不是用进入7行。

     1 std::unique_ptr<LocalTrajectoryBuilder::MatchingResult>
     2 LocalTrajectoryBuilder::AddRangeData(const common::Time time,
     3                                      const sensor::TimedRangeData& range_data) 
     4 {
     5   // Initialize extrapolator now if we do not ever use an IMU.
     6   if (!options_.use_imu_data()) 
     7   {
     8     InitializeExtrapolator(time);
     9   }
    10   if (extrapolator_ == nullptr) 
    11   {
    12     // Until we've initialized the extrapolator with our first IMU message, we
    13     // cannot compute the orientation of the rangefinder.
    14     LOG(INFO) << "Extrapolator not yet initialized.";
    15     return nullptr;
    16   }
    17 
    18   CHECK(!range_data.returns.empty());
    19   CHECK_EQ(range_data.returns.back()[3], 0);
    20   const common::Time time_first_point =
    21       time + common::FromSeconds(range_data.returns.front()[3]);
    22   if (time_first_point < extrapolator_->GetLastPoseTime()) {
    23     LOG(INFO) << "Extrapolator is still initializing.";
    24     return nullptr;
    25   }
    26 
    27   std::vector<transform::Rigid3f> range_data_poses;
    28   range_data_poses.reserve(range_data.returns.size());
    29   for (const Eigen::Vector4f& hit : range_data.returns) {
    30     const common::Time time_point = time + common::FromSeconds(hit[3]);
    31     range_data_poses.push_back(
    32         extrapolator_->ExtrapolatePose(time_point).cast<float>());
    33   }
    34 
    35   if (num_accumulated_ == 0) {
    36     // 'accumulated_range_data_.origin' is uninitialized until the last
    37     // accumulation.
    38     accumulated_range_data_ = sensor::RangeData{{}, {}, {}};
    39   }
    40 
    41   // Drop any returns below the minimum range and convert returns beyond the
    42   // maximum range into misses.
    43   for (size_t i = 0; i < range_data.returns.size(); ++i) {
    44     const Eigen::Vector4f& hit = range_data.returns[i];
    45     const Eigen::Vector3f origin_in_local =
    46         range_data_poses[i] * range_data.origin;
    47     const Eigen::Vector3f hit_in_local = range_data_poses[i] * hit.head<3>();
    48     const Eigen::Vector3f delta = hit_in_local - origin_in_local;
    49     const float range = delta.norm();
    50     if (range >= options_.min_range()) {
    51       if (range <= options_.max_range()) {
    52         accumulated_range_data_.returns.push_back(hit_in_local);
    53       } else {
    54         accumulated_range_data_.misses.push_back(
    55             origin_in_local +
    56             options_.missing_data_ray_length() / range * delta);
    57       }
    58     }
    59   }
    60   ++num_accumulated_;
    61 
    62   if (num_accumulated_ >= options_.num_accumulated_range_data()) {
    63     num_accumulated_ = 0;
    64     const transform::Rigid3d gravity_alignment = transform::Rigid3d::Rotation(
    65         extrapolator_->EstimateGravityOrientation(time));
    66     accumulated_range_data_.origin =
    67         range_data_poses.back() * range_data.origin;
    68     return AddAccumulatedRangeData(
    69         time,
    70         TransformToGravityAlignedFrameAndFilter(
    71             gravity_alignment.cast<float>() * range_data_poses.back().inverse(),
    72             accumulated_range_data_),
    73         gravity_alignment);
    74   }
    75   return nullptr;
    76 }

     接着,LocalTrajectoryBuilder::AddAccumulatedRangeData代码如下,传入的参数为3个。

    const common::Time time,const sensor::RangeData& gravity_aligned_range_data, const transform::Rigid3d& gravity_alignment

    重力定向,定向后的深度数据和定向矩阵。

    注意下面21行代码执行了扫描匹配的ScanMatch方法,之后代码29行调用的extrapolator_->AddPose()方法:

    每次扫描匹配之后执行AddPose方法。

     1 std::unique_ptr<LocalTrajectoryBuilder::MatchingResult>
     2 LocalTrajectoryBuilder::AddAccumulatedRangeData(
     3     const common::Time time,
     4     const sensor::RangeData& gravity_aligned_range_data,
     5     const transform::Rigid3d& gravity_alignment) 
     6 {
     7   if (gravity_aligned_range_data.returns.empty())
     8   {
     9     LOG(WARNING) << "Dropped empty horizontal range data.";
    10     return nullptr;
    11   }
    12 
    13   // Computes a gravity aligned pose prediction.
    14   const transform::Rigid3d non_gravity_aligned_pose_prediction =
    15       extrapolator_->ExtrapolatePose(time);
    16   const transform::Rigid2d pose_prediction = transform::Project2D(
    17       non_gravity_aligned_pose_prediction * gravity_alignment.inverse());
    18 
    19   // local map frame <- gravity-aligned frame
    20   std::unique_ptr<transform::Rigid2d> pose_estimate_2d =
    21       ScanMatch(time, pose_prediction, gravity_aligned_range_data);
    22   if (pose_estimate_2d == nullptr) 
    23   {
    24     LOG(WARNING) << "Scan matching failed.";
    25     return nullptr;
    26   }
    27   const transform::Rigid3d pose_estimate =
    28       transform::Embed3D(*pose_estimate_2d) * gravity_alignment;
    29   extrapolator_->AddPose(time, pose_estimate);
    30 
    31   sensor::RangeData range_data_in_local =
    32       TransformRangeData(gravity_aligned_range_data,
    33                          transform::Embed3D(pose_estimate_2d->cast<float>()));
    34   std::unique_ptr<InsertionResult> insertion_result =
    35       InsertIntoSubmap(time, range_data_in_local, gravity_aligned_range_data,
    36                        pose_estimate, gravity_alignment.rotation());
    37   return common::make_unique<MatchingResult>(
    38       MatchingResult{time, pose_estimate, std::move(range_data_in_local),
    39                      std::move(insertion_result)});
    40 }
    41 
    42 std::unique_ptr<LocalTrajectoryBuilder::InsertionResult>
    43 LocalTrajectoryBuilder::InsertIntoSubmap(
    44     const common::Time time, const sensor::RangeData& range_data_in_local,
    45     const sensor::RangeData& gravity_aligned_range_data,
    46     const transform::Rigid3d& pose_estimate,
    47     const Eigen::Quaterniond& gravity_alignment) 
    48 {
    49   if (motion_filter_.IsSimilar(time, pose_estimate))
    50   {
    51     return nullptr;
    52   }
    53 
    54   // Querying the active submaps must be done here before calling
    55   // InsertRangeData() since the queried values are valid for next insertion.
    56   std::vector<std::shared_ptr<const Submap>> insertion_submaps;
    57   for (const std::shared_ptr<Submap>& submap : active_submaps_.submaps()) 
    58   {
    59     insertion_submaps.push_back(submap);
    60   }
    61   active_submaps_.InsertRangeData(range_data_in_local);
    62 
    63   sensor::AdaptiveVoxelFilter adaptive_voxel_filter(
    64       options_.loop_closure_adaptive_voxel_filter_options());
    65   const sensor::PointCloud filtered_gravity_aligned_point_cloud =
    66       adaptive_voxel_filter.Filter(gravity_aligned_range_data.returns);
    67 
    68   return common::make_unique<InsertionResult>(InsertionResult{
    69       std::make_shared<const mapping::TrajectoryNode::Data>(
    70           mapping::TrajectoryNode::Data{
    71               time,
    72               gravity_alignment,
    73               filtered_gravity_aligned_point_cloud,
    74               {},  // 'high_resolution_point_cloud' is only used in 3D.
    75               {},  // 'low_resolution_point_cloud' is only used in 3D.
    76               {},  // 'rotational_scan_matcher_histogram' is only used in 3D.
    77               pose_estimate}),
    78       std::move(insertion_submaps)});
    79 }
    LocalTrajectoryBuilder::AddAccumulatedRangeData

    (2)RealTimeCorrelativeScanMatcher类,实时的扫描匹配,用的相关分析方法。

  • 相关阅读:
    用css画三角形(提示框三角形)
    SpringMVC(2)之表单(非表单)参数绑定
    mvn jetty:run--编码GBK的不可映射字符
    Git命令及常见问题
    eclipse整合ssh框架基础
    css基础一(权重与position)
    sublime Text3下sass环境配置(windows)
    sublime Text3 设置多个浏览器预览
    初识iOS NSTimer 循环引用不释放问题
    ARC MARC 文件支持
  • 原文地址:https://www.cnblogs.com/yhlx125/p/8470181.html
Copyright © 2011-2022 走看看