1. 程式人生 > >Cartographer原始碼閱讀(7):軌跡推算和位姿推算的原理

Cartographer原始碼閱讀(7):軌跡推算和位姿推算的原理

其實也就是包括兩個方面的內容:類似於運動模型的位姿估計和掃描匹配,因為需要計算速度,所以時間就有必要了!

1. PoseExtrapolator解決了IMU資料、里程計和位姿資訊進行融合的問題。

該類定義了三個佇列。

1 std::deque<TimedPose> timed_pose_queue_;
2 std::deque<sensor::ImuData> imu_data_;
3 std::deque<sensor::OdometryData> odometry_data_;

定義了(a)通過位姿計算線速度和角速度物件

  Eigen::Vector3d linear_velocity_from_poses_ = Eigen::Vector3d::Zero();
  Eigen::Vector3d angular_velocity_from_poses_ 
= Eigen::Vector3d::Zero();

和(b)通過里程計計算線速度和角速度物件

1 Eigen::Vector3d linear_velocity_from_odometry_ = Eigen::Vector3d::Zero();
2 Eigen::Vector3d angular_velocity_from_odometry_ = Eigen::Vector3d::Zero();

 輪詢處理三類訊息 IMU訊息、里程計訊息,鐳射測距訊息。有如下情況:

1)不使用IMU和里程計

  只執行AddPose,注意12-15行的程式碼,$ time{\rm{ }} - timed\_pose\_queue\_\left[ 1 \right].time \ge pose\_queue\_duration\_ $,佇列中最前面的資料的時間,當距離當前時間超過一定間隔時執行,作用是將較早時間的資料剔除。接著,根據位姿計算運動速度。對齊IMU資料,里程計資料。

 1 void PoseExtrapolator::AddPose(const common::Time time,
 2                                const transform::Rigid3d& pose) {
 3   if (imu_tracker_ == nullptr) {
 4     common::Time tracker_start = time;
 5     if (!imu_data_.empty()) {
 6       tracker_start = std::min(tracker_start, imu_data_.front().time);
7 } 8 imu_tracker_ = 9 common::make_unique<ImuTracker>(gravity_time_constant_, tracker_start); 10 } 11 timed_pose_queue_.push_back(TimedPose{time, pose}); 12 while (timed_pose_queue_.size() > 2 && 13 timed_pose_queue_[1].time <= time - pose_queue_duration_) { 14 timed_pose_queue_.pop_front(); 15 } 16 UpdateVelocitiesFromPoses(); 17 AdvanceImuTracker(time, imu_tracker_.get()); 18 TrimImuData(); 19 TrimOdometryData(); 20 odometry_imu_tracker_ = common::make_unique<ImuTracker>(*imu_tracker_); 21 extrapolation_imu_tracker_ = common::make_unique<ImuTracker>(*imu_tracker_); 22 }

 第16行,更新了根據Pose計算的線速度和角速度。

 1 void PoseExtrapolator::UpdateVelocitiesFromPoses() 
 2 {
 3   if (timed_pose_queue_.size() < 2)
 4   {
 5     // We need two poses to estimate velocities.
 6     return;
 7   }
 8   CHECK(!timed_pose_queue_.empty());
 9   const TimedPose& newest_timed_pose = timed_pose_queue_.back();
10   const auto newest_time = newest_timed_pose.time;
11   const TimedPose& oldest_timed_pose = timed_pose_queue_.front();
12   const auto oldest_time = oldest_timed_pose.time;
13   const double queue_delta = common::ToSeconds(newest_time - oldest_time);
14   if (queue_delta < 0.001) {  // 1 ms
15     LOG(WARNING) << "Queue too short for velocity estimation. Queue duration: "
16                  << queue_delta << " ms";
17     return;
18   }
19   const transform::Rigid3d& newest_pose = newest_timed_pose.pose;
20   const transform::Rigid3d& oldest_pose = oldest_timed_pose.pose;
21   linear_velocity_from_poses_ =
22       (newest_pose.translation() - oldest_pose.translation()) / queue_delta;
23   angular_velocity_from_poses_ =
24       transform::RotationQuaternionToAngleAxisVector(
25           oldest_pose.rotation().inverse() * newest_pose.rotation()) /
26       queue_delta;
27 }
PoseExtrapolator::UpdateVelocitiesFromPoses()

17行執行了PoseExtrapolator::AdvanceImuTracker方法,當不使用IMU資料時,將 angular_velocity_from_poses_ 或者 angular_velocity_from_odometry_ 資料傳入了imu_tracker.

 1 void PoseExtrapolator::AdvanceImuTracker(const common::Time time,
 2                                          ImuTracker* const imu_tracker) const 
 3 {
 4   CHECK_GE(time, imu_tracker->time());
 5   if (imu_data_.empty() || time < imu_data_.front().time) 
 6   {
 7     // There is no IMU data until 'time', so we advance the ImuTracker and use
 8     // the angular velocities from poses and fake gravity to help 2D stability.
 9     imu_tracker->Advance(time);
10     imu_tracker->AddImuLinearAccelerationObservation(Eigen::Vector3d::UnitZ());
11     imu_tracker->AddImuAngularVelocityObservation(
12         odometry_data_.size() < 2 ? angular_velocity_from_poses_
13                                   : angular_velocity_from_odometry_);
14     return;
15   }
16   if (imu_tracker->time() < imu_data_.front().time) {
17     // Advance to the beginning of 'imu_data_'.
18     imu_tracker->Advance(imu_data_.front().time);
19   }
20   auto it = std::lower_bound(
21       imu_data_.begin(), imu_data_.end(), imu_tracker->time(),
22       [](const sensor::ImuData& imu_data, const common::Time& time) {
23         return imu_data.time < time;
24       });
25   while (it != imu_data_.end() && it->time < time) {
26     imu_tracker->Advance(it->time);
27     imu_tracker->AddImuLinearAccelerationObservation(it->linear_acceleration);
28     imu_tracker->AddImuAngularVelocityObservation(it->angular_velocity);
29     ++it;
30   }
31   imu_tracker->Advance(time);
32 }

 在執行ExtrapolatePose(),推測某一時刻的位姿的時候,呼叫了 ExtrapolateTranslation 和 ExtrapolateRotation 方法。

 1 transform::Rigid3d PoseExtrapolator::ExtrapolatePose(const common::Time time) {
 2   const TimedPose& newest_timed_pose = timed_pose_queue_.back();
 3   CHECK_GE(time, newest_timed_pose.time);
 4   if (cached_extrapolated_pose_.time != time) {
 5     const Eigen::Vector3d translation =
 6         ExtrapolateTranslation(time) + newest_timed_pose.pose.translation();
 7     const Eigen::Quaterniond rotation =
 8         newest_timed_pose.pose.rotation() *
 9         ExtrapolateRotation(time, extrapolation_imu_tracker_.get());
10     cached_extrapolated_pose_ =
11         TimedPose{time, transform::Rigid3d{translation, rotation}};
12   }
13   return cached_extrapolated_pose_.pose;
14 }

可以看到使用的是:(1)旋轉,imu_tracker的方位角角的變化量;(2)平移,里程計或者位姿線速度計算的移動量。

 1 Eigen::Quaterniond PoseExtrapolator::ExtrapolateRotation(
 2     const common::Time time, ImuTracker* const imu_tracker) const {
 3   CHECK_GE(time, imu_tracker->time());
 4   AdvanceImuTracker(time, imu_tracker);
 5   const Eigen::Quaterniond last_orientation = imu_tracker_->orientation();
 6   return last_orientation.inverse() * imu_tracker->orientation();
 7 }
 8 
 9 Eigen::Vector3d PoseExtrapolator::ExtrapolateTranslation(common::Time time) {
10   const TimedPose& newest_timed_pose = timed_pose_queue_.back();
11   const double extrapolation_delta =
12       common::ToSeconds(time - newest_timed_pose.time);
13   if (odometry_data_.size() < 2) {
14     return extrapolation_delta * linear_velocity_from_poses_;
15   }
16   return extrapolation_delta * linear_velocity_from_odometry_;
17 }

 2)使用IMU和里程計

  IMU頻率最高,假設訊息進入的先後順序是IMU、里程計,最後是鐳射訊息。

2. RealTimeCorrelativeScanMatcher解決了Scan和子圖的掃描匹配的問題。

通過 real_time_correlative_scan_matcher_ 和 ceres_scan_matcher_ 實現的

 1 std::unique_ptr<transform::Rigid2d> LocalTrajectoryBuilder::ScanMatch(
 2     const common::Time time, const transform::Rigid2d& pose_prediction,
 3     const sensor::RangeData& gravity_aligned_range_data) 
 4 {
 5   std::shared_ptr<const Submap> matching_submap =
 6       active_submaps_.submaps().front();
 7   // The online correlative scan matcher will refine the initial estimate for
 8   // the Ceres scan matcher.
 9   transform::Rigid2d initial_ceres_pose = pose_prediction;
10   sensor::AdaptiveVoxelFilter adaptive_voxel_filter(
11       options_.adaptive_voxel_filter_options());
12   const sensor::PointCloud filtered_gravity_aligned_point_cloud =
13       adaptive_voxel_filter.Filter(gravity_aligned_range_data.returns);
14   if (filtered_gravity_aligned_point_cloud.empty())
15   {
16     return nullptr;
17   }
18   if (options_.use_online_correlative_scan_matching()) 
19   {
20     real_time_correlative_scan_matcher_.Match(
21         pose_prediction, filtered_gravity_aligned_point_cloud,
22         matching_submap->probability_grid(), &initial_ceres_pose);
23   }
24 
25   auto pose_observation = common::make_unique<transform::Rigid2d>();
26   ceres::Solver::Summary summary;
27   ceres_scan_matcher_.Match(pose_prediction.translation(), initial_ceres_pose,
28                             filtered_gravity_aligned_point_cloud,
29                             matching_submap->probability_grid(),
30                             pose_observation.get(), &summary);
31   return pose_observation;
32 }

相關推薦

Cartographer原始碼閱讀(7)軌跡推算姿推算原理

其實也就是包括兩個方面的內容:類似於運動模型的位姿估計和掃描匹配,因為需要計算速度,所以時間就有必要了! 1. PoseExtrapolator解決了IMU資料、里程計和位姿資訊進行融合的問題。 該類定義了三個佇列。 1 std::deque<TimedPose> timed_pose_

Cartographer原始碼閱讀(2)NodeMapBuilder物件

  上文提到特別注意map_builder_bridge_.AddTrajectory(x,x),檢視其中的程式碼。兩點:   首先是map_builder_.AddTrajectoryBuilder(...),呼叫了map_builder_物件的方法。其次是sensor_bridges_鍵值對的賦值。

Cartographer原始碼閱讀(4)NodeMapBuilder物件2

  MapBuilder的成員變數sensor::Collator sensor_collator_;   再次閱讀MapBuilder::AddTrajectoryBuilder方法。首先構造了mapping::GlobalTrajectoryBuilder例項,接著作為引數構造了CollatedTraj

Cartographer原始碼閱讀(6)LocalTrajectoryBuilderPoseExtrapolator

LocalTrajectoryBuilder意思是區域性軌跡的構建,下面的類圖中方法的引數沒有畫進去。 注意其中的三個類:PoseExtrapolator類,RealTimeCorrelativeScanMatcher類和CeresScanMatcher類。 (1)PoseExtrapolator類(

Cartographer原始碼閱讀(8)imu_tracker

1 /* 2 * Copyright 2016 The Cartographer Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use

Cartographer原始碼閱讀(1)程式入口

1 [email protected]:~$ sudo apt-get install kdevelop 2 [sudo] password for yhexie: 3 Reading package lists... Done 4 Building dependency

Cartographer原始碼閱讀(5)PoseGraph姿

PoseGraph位姿圖 mapping2D::PoseGraph類的註釋: // Implements the loop closure method called Sparse Pose Adjustment (SPA) from// Konolige, Kurt, et al. "E

Ethzasl MSF原始碼閱讀(1)程式入口主題訂閱

Ethz的Stephen Weiss的工作,是一個IMU鬆耦合的方法。 1.程式入口:ethzasl_msf\msf_updates\src\pose_msf\main.cpp 1 #include "pose_sensormanager.h" 2 3 int main(int argc,

Cartographer原始碼閱讀(3)程式邏輯結構

Cartographer早期的程式碼在進行3d製圖的時候使用了UKF方法,檢視現有的tag版本,可以轉到0.1.0和0.2.0檢視,包含kalman_filter資料夾。 資料夾中的pose_tracker類檔案在mapping_3d的檔案加下有kalman_local_trajectory_builder

Cartographer原始碼閱讀(9)圖優化的前端——閉環檢測

約束計算 閉環檢測的策略:搜尋閉環,通過匹配檢測是否是閉環,採用了分支定界法。 前已經述及PoseGraph的內容,此處繼續。位姿圖類定義了pose_graph::ConstraintBuilder constraint_builder_物件。 1.ConstraintBuilder類圖 定義了S

Ethzasl MSF原始碼閱讀(3)MSF_CorePoseMeasurement

1.MSF_Core的三個函式:ProcessIMU、ProcessExternallyPropagatedState和AddMeasurement MSF_Core維護了狀態佇列和觀測值佇列,這裡需要結合論文思考這個狀態佇列的作用。 ProcessIMU方法: 1 template<

mysql5.7mysql安裝基於SSL加密的主從復制(詳細剖析)

mysql ssl db 數據 加密傳輸 小生博客:http://xsboke.blog.51cto.com 小生 Q Q:1770058260 -------謝謝您的參考,如有疑問,歡迎交流目錄:--------my

Ethzasl MSF源碼閱讀(1)程序入口主題訂閱

turn war lB void true matrix emp ati spin 1.程序入口:ethzasl_msf\msf_updates\src\pose_msf\main.cpp 1 #include "pose_sensormanager.h" 2

7靜態屬性靜態方法

在屬性或方法前面加 static 修飾,即可稱為靜態屬性/方法 普通屬性例項化之後放在例項物件上,靜態屬性則是放在類上; 可以不例項化類而直接訪問,不能通過一個類已例項化的物件訪問,直接使用類訪問:類名::$屬性名; 靜態屬性只能被初始化為直接量,不能使用表示式,不能

Direct3D 11 Tutorial 7:Texture Mapping and Constant Buffers_Direct3D 11 教程7紋理對映常量緩衝區

概述 在上一個教程中,我們為專案引入了照明。 現在我們將通過向我們的立方體新增紋理來構建它。 此外,我們將介紹常量緩衝區的概念,並解釋如何使用緩衝區通過最小化頻寬使用來加速處理。 本教程的目的是修改中心立方體以將紋理對映到其上。   資源目錄 (SDK root)\Samples\C++\

LDAP基礎7使用ldapmodifyldapdelete進行修改或刪除

這篇文章主要介紹一下如何使用ldapmodify和ldapdelete進行資訊的修改或者刪除,並在前面新增的資料的基礎上進行一些簡單的例子的操作。 操作方式 執行場所 對LDAP進行操作,場所不限,LDAP伺服器上進行操作,也可以在可以連線LDAP服務的客戶端進行 使用命

Caffe原始碼理解2SyncedMemory CPUGPU間的資料同步

目錄 寫在前面 成員變數的含義及作用 構造與析構 記憶體同步管理 參考 部落格:blog.shinelee.me | 部落格園 | CSDN 寫在前面 在Caffe原始碼理解1中介紹了Blob類,其中的資料成員有 shared_ptr<SyncedMemory>

Java虛擬機器7記憶體溢位記憶體洩露、並行併發、Minor GCFull GC、Client模式Server模式的區別

記憶體溢位和記憶體洩露的區別 1、記憶體溢位 記憶體溢位指的是程式在申請記憶體的時候,沒有足夠大的空間可以分配了。 2、記憶體洩露 記憶體洩露指的是程式在申請記憶體之後,沒有辦法釋放掉已經申請到記憶體,它始終佔用著記憶體,即被分配的物件可達但無用。記憶體洩露一般都是因

Caffe原始碼解析7Pooling_Layer

Pooling 層一般在網路中是跟在Conv卷積層之後,做取樣操作,其實是為了進一步縮小feature map,同時也能增大神經元的視野。在Caffe中,pooling層屬於vision_layer的一部分,其相關的定義也在vision_layer.hpp的標頭檔案中。Pooling層的相關操作比較少,在C

Spring4.3.12原始碼閱讀系列1-環境搭建

學習任務 近期想增加部分原始碼閱讀經驗,提高自己在造輪子方面的實力,增長些在設計模式應用方面的編碼能力,以及懷著向大佬們膜拜的心情,開始有計劃地閱讀Spring原始碼 前期準備 以下幾項準備事項,算是基本的日常開發環境,就算沒有,也是動動手很快安