zoukankan      html  css  js  c++  java
  • Cartographer源码阅读(5):PoseGraph位姿图

    PoseGraph位姿图

    mapping2D::PoseGraph类的注释:

    // Implements the loop closure method called Sparse Pose Adjustment (SPA) from
    // Konolige, Kurt, et al. "Efficient sparse pose adjustment for 2d mapping."
    // Intelligent Robots and Systems (IROS), 2010 IEEE/RSJ International Conference
    // on (pp. 22--29). IEEE, 2010.
    //
    // It is extended for submapping:
    // Each node has been matched against one or more submaps (adding a constraint
    // for each match), both poses of nodes and of submaps are to be optimized.
    // All constraints are between a submap i and a node j.

    1.继承关系mapping,mapping2D,mapping3D (以前叫sparse_pose_graph.h,目前名称被修改了

    类中一个很重要的类OptimizationProblem对象optimization_problem_,该类的注释是Implements the SPA loop closure method.即实现了SPA方法的闭环。

    类的主要成员变量和成员函数如类图所示,其中重要的方法PoseGraph::RunOptimization()。

    pose_graph::OptimizationProblem optimization_problem_;
    pose_graph::ConstraintBuilder constraint_builder_ GUARDED_BY(mutex_);
    std::vector<Constraint> constraints_ GUARDED_BY(mutex_);

    接上一篇在PoseGraph::AddNode方法中调用了 AddTrajectoryIfNeeded() 和 PoseGraph::ComputeConstraintsForNode()方法。

     1 void PoseGraph::ComputeConstraintsForNode(
     2     const mapping::NodeId& node_id,
     3     std::vector<std::shared_ptr<const Submap>> insertion_submaps,
     4     const bool newly_finished_submap) {
     5   const auto& constant_data = trajectory_nodes_.at(node_id).constant_data;
     6   const std::vector<mapping::SubmapId> submap_ids = InitializeGlobalSubmapPoses(
     7       node_id.trajectory_id, constant_data->time, insertion_submaps);
     8   CHECK_EQ(submap_ids.size(), insertion_submaps.size());
     9   const mapping::SubmapId matching_id = submap_ids.front();
    10   const transform::Rigid2d pose = transform::Project2D(
    11       constant_data->local_pose *
    12       transform::Rigid3d::Rotation(constant_data->gravity_alignment.inverse()));
    13   const transform::Rigid2d optimized_pose =
    14       optimization_problem_.submap_data().at(matching_id).global_pose *
    15       pose_graph::ComputeSubmapPose(*insertion_submaps.front()).inverse() *
    16       pose;
    17   optimization_problem_.AddTrajectoryNode(
    18       matching_id.trajectory_id, constant_data->time, pose, optimized_pose,
    19       constant_data->gravity_alignment);
    20   for (size_t i = 0; i < insertion_submaps.size(); ++i) {
    21     const mapping::SubmapId submap_id = submap_ids[i];
    22     // Even if this was the last node added to 'submap_id', the submap will only
    23     // be marked as finished in 'submap_data_' further below.
    24     CHECK(submap_data_.at(submap_id).state == SubmapState::kActive);
    25     submap_data_.at(submap_id).node_ids.emplace(node_id);
    26     const transform::Rigid2d constraint_transform =
    27         pose_graph::ComputeSubmapPose(*insertion_submaps[i]).inverse() * pose;
    28     constraints_.push_back(Constraint{submap_id,
    29                                       node_id,
    30                                       {transform::Embed3D(constraint_transform),
    31                                        options_.matcher_translation_weight(),
    32                                        options_.matcher_rotation_weight()},
    33                                       Constraint::INTRA_SUBMAP});
    34   }
    35 
    36   for (const auto& submap_id_data : submap_data_) {
    37     if (submap_id_data.data.state == SubmapState::kFinished) {
    38       CHECK_EQ(submap_id_data.data.node_ids.count(node_id), 0);
    39       ComputeConstraint(node_id, submap_id_data.id);
    40     }
    41   }
    42 
    43   if (newly_finished_submap) {
    44     const mapping::SubmapId finished_submap_id = submap_ids.front();
    45     SubmapData& finished_submap_data = submap_data_.at(finished_submap_id);
    46     CHECK(finished_submap_data.state == SubmapState::kActive);
    47     finished_submap_data.state = SubmapState::kFinished;
    48     // We have a new completed submap, so we look into adding constraints for
    49     // old nodes.
    50     ComputeConstraintsForOldNodes(finished_submap_id);
    51   }
    52   constraint_builder_.NotifyEndOfNode();
    53   ++num_nodes_since_last_loop_closure_;
    54   if (options_.optimize_every_n_nodes() > 0 &&
    55       num_nodes_since_last_loop_closure_ > options_.optimize_every_n_nodes()) {
    56     CHECK(!run_loop_closure_);
    57     run_loop_closure_ = true;
    58     // If there is a 'work_queue_' already, some other thread will take care.
    59     if (work_queue_ == nullptr) {
    60       work_queue_ = common::make_unique<std::deque<std::function<void()>>>();
    61       HandleWorkQueue();
    62     }
    63   }
    64 }

    可以看到对本类中ComputeConstraint、ComputeConstraintsForOldNodes、HandleWorkQueue方法的调用。这里有个pose_graph::ComputeSubmapPose方法在cartographer/mapping_2d/pose_graph/constraint_builder.h文件中。子图submap位姿?

    transform::Rigid2d ComputeSubmapPose(const Submap& submap)
    {
          return transform::Project2D(submap.local_pose());
    }

    注意HandleWorkQueue()方法中调用了RunOptimization方法。

     1 void PoseGraph::HandleWorkQueue() {
     2   constraint_builder_.WhenDone(
     3       [this](const pose_graph::ConstraintBuilder::Result& result) {
     4         {
     5           common::MutexLocker locker(&mutex_);
     6           constraints_.insert(constraints_.end(), result.begin(), result.end());
     7         }
     8         RunOptimization();
     9 
    10         common::MutexLocker locker(&mutex_);
    11         for (const Constraint& constraint : result) {
    12           UpdateTrajectoryConnectivity(constraint);
    13         }
    14         TrimmingHandle trimming_handle(this);
    15         for (auto& trimmer : trimmers_) {
    16           trimmer->Trim(&trimming_handle);
    17         }
    18         trimmers_.erase(
    19             std::remove_if(
    20                 trimmers_.begin(), trimmers_.end(),
    21                 [](std::unique_ptr<mapping::PoseGraphTrimmer>& trimmer) {
    22                   return trimmer->IsFinished();
    23                 }),
    24             trimmers_.end());
    25 
    26         num_nodes_since_last_loop_closure_ = 0;
    27         run_loop_closure_ = false;
    28         while (!run_loop_closure_) {
    29           if (work_queue_->empty()) {
    30             work_queue_.reset();
    31             return;
    32           }
    33           work_queue_->front()();
    34           work_queue_->pop_front();
    35         }
    36         LOG(INFO) << "Remaining work items in queue: " << work_queue_->size();
    37         // We have to optimize again.
    38         HandleWorkQueue();
    39       });
    40 }
    PoseGraph::HandleWorkQueue

    查看PoseGraph::RunOptimization方法, 

     1 void PoseGraph::RunOptimization()
     2 {
     3   if (optimization_problem_.submap_data().empty())
     4   {
     5     return;
     6   }
     7 
     8   // No other thread is accessing the optimization_problem_, constraints_ and
     9   // frozen_trajectories_ when executing the Solve. Solve is time consuming, so
    10   // not taking the mutex before Solve to avoid blocking foreground processing.
    11   optimization_problem_.Solve(constraints_, frozen_trajectories_);
    12   common::MutexLocker locker(&mutex_);
    13 
    14   const auto& submap_data = optimization_problem_.submap_data();
    15   const auto& node_data = optimization_problem_.node_data();
    16   for (const int trajectory_id : node_data.trajectory_ids())
    17   {
    18     for (const auto& node : node_data.trajectory(trajectory_id)) 
    19     {
    20       auto& mutable_trajectory_node = trajectory_nodes_.at(node.id);
    21       mutable_trajectory_node.global_pose =
    22           transform::Embed3D(node.data.pose) *
    23           transform::Rigid3d::Rotation(mutable_trajectory_node.constant_data->gravity_alignment);
    24     }
    25 
    26     // Extrapolate all point cloud poses that were not included in the
    27     // 'optimization_problem_' yet.
    28     const auto local_to_new_global =
    29         ComputeLocalToGlobalTransform(submap_data, trajectory_id);
    30     const auto local_to_old_global =
    31         ComputeLocalToGlobalTransform(global_submap_poses_, trajectory_id);
    32     const transform::Rigid3d old_global_to_new_global =
    33         local_to_new_global * local_to_old_global.inverse();
    34 
    35     const mapping::NodeId last_optimized_node_id =
    36         std::prev(node_data.EndOfTrajectory(trajectory_id))->id;
    37     auto node_it = std::next(trajectory_nodes_.find(last_optimized_node_id));
    38     for (; node_it != trajectory_nodes_.EndOfTrajectory(trajectory_id); ++node_it) 
    39     {
    40       auto& mutable_trajectory_node = trajectory_nodes_.at(node_it->id);
    41       mutable_trajectory_node.global_pose =
    42           old_global_to_new_global * mutable_trajectory_node.global_pose;
    43     }
    44   }
    45   global_submap_poses_ = submap_data;
    46 }

     查看Constraint 结构体,该结构体在PoseGraphInterface中定义。

     1   // A "constraint" as in the paper by Konolige, Kurt, et al. "Efficient sparse
     2   // pose adjustment for 2d mapping." Intelligent Robots and Systems (IROS),
     3   // 2010 IEEE/RSJ International Conference on (pp. 22--29). IEEE, 2010.
     4   struct Constraint {
     5     struct Pose {
     6       transform::Rigid3d zbar_ij;
     7       double translation_weight;
     8       double rotation_weight;
     9     };
    10 
    11     SubmapId submap_id;  // 'i' in the paper.
    12     NodeId node_id;      // 'j' in the paper.
    13 
    14     // Pose of the node 'j' relative to submap 'i'.
    15     Pose pose;
    16 
    17     // Differentiates between intra-submap (where node 'j' was inserted into
    18     // submap 'i') and inter-submap constraints (where node 'j' was not inserted
    19     // into submap 'i').
    20     enum Tag { INTRA_SUBMAP, INTER_SUBMAP } tag;
    21   };
  • 相关阅读:
    汉语-词语:心性
    CE-计算机系统:并行处理
    CE-操作系统:程序并发执行
    CE-计算机系统:单道批量处理系统
    CE-计算机系统:多道程序
    CE-计算机系统:并行性
    生活灵感汇总
    【剑指Offer】俯视50题之21
    Single Number II
    汉诺塔
  • 原文地址:https://www.cnblogs.com/yhlx125/p/8466479.html
Copyright © 2011-2022 走看看