Cartographer源碼閱讀(4):Node和MapBuilder對象2


  MapBuilder的成員變量sensor::Collator sensor_collator_;

  再次閱讀MapBuilder::AddTrajectoryBuilder方法。首先構造了mapping::GlobalTrajectoryBuilder實例,接着作為參數構造了CollatedTrajectoryBuilder實例。

trajectory_builders_.push_back(
common::make_unique<CollatedTrajectoryBuilder>(
&sensor_collator_, trajectory_id, expected_sensor_ids,
common::make_unique<mapping::GlobalTrajectoryBuilder<mapping_2d::LocalTrajectoryBuilder,mapping_2d::proto::LocalTrajectoryBuilderOptions,mapping_2d::PoseGraph>>
(trajectory_options.trajectory_builder_2d_options(),trajectory_id, pose_graph_2d_.get(),local_slam_result_callback)
)
);

  這里sensor_collator_作為參數傳入,參與CollatedTrajectoryBuilder構造。查看構造函數:

CollatedTrajectoryBuilder::CollatedTrajectoryBuilder(sensor::Collator* const sensor_collator, const int trajectory_id, const std::unordered_set<std::string>& expected_sensor_ids,   std::unique_ptr<TrajectoryBuilderInterface> wrapped_trajectory_builder)
    : sensor_collator_(sensor_collator)
    , trajectory_id_(trajectory_id)
    , wrapped_trajectory_builder_(std::move(wrapped_trajectory_builder))
    , last_logging_time_(std::chrono::steady_clock::now()) 
{
     sensor_collator_->AddTrajectory(trajectory_id, expected_sensor_ids,
      [this](const std::string& sensor_id, std::unique_ptr<sensor::Data> data)
      {
        HandleCollatedSensorData(sensor_id, std::move(data));
      }
      );
}

  這里是回調函數,std::unique_ptr是表示參數為智能指針。

 [this](const std::string& sensor_id, std::unique_ptr<sensor::Data> data)
 {
        HandleCollatedSensorData(sensor_id, std::move(data));
  }

  (1)查看sensor::Collator的AddTrajectory方法:

void Collator::AddTrajectory( const int trajectory_id, const std::unordered_set<std::string>& expected_sensor_ids, const Callback& callback) 
{
   for (const auto& sensor_id : expected_sensor_ids)
  {
      const auto queue_key = QueueKey{trajectory_id, sensor_id};
      queue_.AddQueue(queue_key, [callback, sensor_id](std::unique_ptr<Data> data)
                    {
                      callback(sensor_id, std::move(data));
                    });
       queue_keys_[trajectory_id].push_back(queue_key);
  }
}

  for (const auto& sensor_id : expected_sensor_ids)用到了C++11的auto新特性。

  (2)查看HandleCollatedSensorData方法。調用了data->AddToTrajectoryBuilder(wrapped_trajectory_builder_.get());這里wrapped_trajectory_builder_是在CollatedTrajectoryBuilder構造函數中賦值的。為GlobalTrajectoryBuilder對象。因而查看sensor::Data的AddToTrajectoryBuilder() 方法。

  virtual void AddToTrajectoryBuilder(mapping::TrajectoryBuilderInterface *trajectory_builder) = 0;是sensor::Data類的一個虛方法。內部執行了trajectory_builder->AddSensorData(sensor_id_, data_);

最后調用的是GlobalTrajectoryBuilder對象的AddSensorData(xx)方法。

 1 void CollatedTrajectoryBuilder::HandleCollatedSensorData( const std::string& sensor_id, std::unique_ptr<sensor::Data> data)
 2 {
 3   auto it = rate_timers_.find(sensor_id);
 4   if (it == rate_timers_.end())
 5   {
 6       it = rate_timers_ .emplace(
 7                  std::piecewise_construct, std::forward_as_tuple(sensor_id),
 8                  std::forward_as_tuple(common::FromSeconds(kSensorDataRatesLoggingPeriodSeconds))) .first;
 9   }
10   it->second.Pulse(data->GetTime());
11 
12   if (std::chrono::steady_clock::now() - last_logging_time_ >
13       common::FromSeconds(kSensorDataRatesLoggingPeriodSeconds)) 
14   {
15        for (const auto& pair : rate_timers_) 
16       {
17         LOG(INFO) << pair.first << " rate: " << pair.second.DebugString();
18       }
19       last_logging_time_ = std::chrono::steady_clock::now();
20   }
21 
22    data->AddToTrajectoryBuilder(wrapped_trajectory_builder_.get());
23   }
24 
25 } 
CollatedTrajectoryBuilder::HandleCollatedSensorData

 

template <typename DataType>
class Dispatchable : public Data 
{
 public:
  Dispatchable(const std::string &sensor_id, const DataType &data): Data(sensor_id), data_(data) {}

  common::Time GetTime() const override { return data_.time; }

  void AddToTrajectoryBuilder( mapping::TrajectoryBuilderInterface *const trajectory_builder) override 
 {
    trajectory_builder->AddSensorData(sensor_id_, data_);
  }

 private:
  const DataType data_;
};

  再以IMU數據為例,GlobalTrajectoryBuilder類的AddSensorData(xx):

void AddSensorData(const std::string& sensor_id,  const sensor::ImuData& imu_data) override 
{
      local_trajectory_builder_.AddImuData(imu_data);
      pose_graph_->AddImuData(trajectory_id_, imu_data);
}

  再看一下激光點雲的數據

 1 void AddSensorData( const std::string& sensor_id, const sensor::TimedPointCloudData& timed_point_cloud_data) override
 2  {
 3     std::unique_ptr<typename LocalTrajectoryBuilder::MatchingResult>  matching_result = 
 4        local_trajectory_builder_.AddRangeData( timed_point_cloud_data.time, 
 5                                                sensor::TimedRangeData {timed_point_cloud_data.origin, 
 6                                                timed_point_cloud_data.ranges, {}}
 7        );
 8     if (matching_result == nullptr) 
 9     {
10         // The range data has not been fully accumulated yet.
11         return;
12     }
13     std::unique_ptr<mapping::NodeId> node_id;
14     if (matching_result->insertion_result != nullptr) 
15     {
16           node_id = ::cartographer::common::make_unique<mapping::NodeId>(
17           pose_graph_->AddNode(matching_result->insertion_result->constant_data, 
18 trajectory_id_, matching_result->insertion_result->insertion_submaps));
19           CHECK_EQ(node_id->trajectory_id, trajectory_id_);
20     }
21     if (local_slam_result_callback_) 
22     {
23       local_slam_result_callback_( trajectory_id_, matching_result->time, 
24              matching_result->local_pose,
25           std::move(matching_result->range_data_in_local), std::move(node_id));
26      }
27   }

  這里有兩個重要的步驟一個是local_trajectory_builder_.AddRangeData(xxx),一個是 pose_graph_->AddNode(xxx)方法。同時std::unique_ptr<typename LocalTrajectoryBuilder::MatchingResult> matching_result作為AddNode方法的參數。

 1 mapping::NodeId PoseGraph::AddNode(
 2     std::shared_ptr<const mapping::TrajectoryNode::Data> constant_data,
 3     const int trajectory_id,
 4     const std::vector<std::shared_ptr<const Submap>>& insertion_submaps) {
 5   const transform::Rigid3d optimized_pose(
 6       GetLocalToGlobalTransform(trajectory_id) * constant_data->local_pose);
 7 
 8   common::MutexLocker locker(&mutex_);
 9   AddTrajectoryIfNeeded(trajectory_id);
10   const mapping::NodeId node_id = trajectory_nodes_.Append(
11       trajectory_id, mapping::TrajectoryNode{constant_data, optimized_pose});
12   ++num_trajectory_nodes_;
13 
14   // Test if the 'insertion_submap.back()' is one we never saw before.
15   if (submap_data_.SizeOfTrajectoryOrZero(trajectory_id) == 0 ||
16       std::prev(submap_data_.EndOfTrajectory(trajectory_id))->data.submap !=
17           insertion_submaps.back()) {
18     // We grow 'submap_data_' as needed. This code assumes that the first
19     // time we see a new submap is as 'insertion_submaps.back()'.
20     const mapping::SubmapId submap_id =
21         submap_data_.Append(trajectory_id, SubmapData());
22     submap_data_.at(submap_id).submap = insertion_submaps.back();
23   }
24 
25   // We have to check this here, because it might have changed by the time we
26   // execute the lambda.
27   const bool newly_finished_submap = insertion_submaps.front()->finished();
28   AddWorkItem([=]() REQUIRES(mutex_) {
29     ComputeConstraintsForNode(node_id, insertion_submaps,
30                               newly_finished_submap);
31   });
32   return node_id;
33 }
PoseGraph::AddNode

  PoseGraph::AddNode方法很重要,分析節點和子圖的關系。

  此處強調一下GlobalTrajectoryBuilder的兩個關鍵對象local_trajectory_builder_和pose_graph_。

  PoseGraph* const pose_graph_;
  LocalTrajectoryBuilder local_trajectory_builder_;

  接下來按照准備安裝ROS消息發布和處理的流程進行分析,即數據流。


 

參考資料:

http://blog.csdn.net/datase/article/details/78665862

http://blog.csdn.net/learnmoreonce/article/category/6989560


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM