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)方法。
void CollatedTrajectoryBuilder::HandleCollatedSensorData( const std::string& sensor_id, std::unique_ptr<sensor::Data> data)
{
auto it = rate_timers_.find(sensor_id);
if (it == rate_timers_.end())
{
it = rate_timers_ .emplace(
std::piecewise_construct, std::forward_as_tuple(sensor_id),
std::forward_as_tuple(common::FromSeconds(kSensorDataRatesLoggingPeriodSeconds))) .first;
}
it->second.Pulse(data->GetTime()); if (std::chrono::steady_clock::now() - last_logging_time_ >
common::FromSeconds(kSensorDataRatesLoggingPeriodSeconds))
{
for (const auto& pair : rate_timers_)
{
LOG(INFO) << pair.first << " rate: " << pair.second.DebugString();
}
last_logging_time_ = std::chrono::steady_clock::now();
} data->AddToTrajectoryBuilder(wrapped_trajectory_builder_.get());
} }
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);
}
再看一下激光点云的数据
void AddSensorData( const std::string& sensor_id, const sensor::TimedPointCloudData& timed_point_cloud_data) override
{
std::unique_ptr<typename LocalTrajectoryBuilder::MatchingResult> matching_result =
local_trajectory_builder_.AddRangeData( timed_point_cloud_data.time,
sensor::TimedRangeData {timed_point_cloud_data.origin,
timed_point_cloud_data.ranges, {}}
);
if (matching_result == nullptr)
{
// The range data has not been fully accumulated yet.
return;
}
std::unique_ptr<mapping::NodeId> node_id;
if (matching_result->insertion_result != nullptr)
{
node_id = ::cartographer::common::make_unique<mapping::NodeId>(
pose_graph_->AddNode(matching_result->insertion_result->constant_data,
trajectory_id_, matching_result->insertion_result->insertion_submaps));
CHECK_EQ(node_id->trajectory_id, trajectory_id_);
}
if (local_slam_result_callback_)
{
local_slam_result_callback_( trajectory_id_, matching_result->time,
matching_result->local_pose,
std::move(matching_result->range_data_in_local), std::move(node_id));
}
}
这里有两个重要的步骤一个是local_trajectory_builder_.AddRangeData(xxx),一个是 pose_graph_->AddNode(xxx)方法。同时std::unique_ptr<typename LocalTrajectoryBuilder::MatchingResult> matching_result作为AddNode方法的参数。
mapping::NodeId PoseGraph::AddNode(
std::shared_ptr<const mapping::TrajectoryNode::Data> constant_data,
const int trajectory_id,
const std::vector<std::shared_ptr<const Submap>>& insertion_submaps) {
const transform::Rigid3d optimized_pose(
GetLocalToGlobalTransform(trajectory_id) * constant_data->local_pose); common::MutexLocker locker(&mutex_);
AddTrajectoryIfNeeded(trajectory_id);
const mapping::NodeId node_id = trajectory_nodes_.Append(
trajectory_id, mapping::TrajectoryNode{constant_data, optimized_pose});
++num_trajectory_nodes_; // Test if the 'insertion_submap.back()' is one we never saw before.
if (submap_data_.SizeOfTrajectoryOrZero(trajectory_id) == ||
std::prev(submap_data_.EndOfTrajectory(trajectory_id))->data.submap !=
insertion_submaps.back()) {
// We grow 'submap_data_' as needed. This code assumes that the first
// time we see a new submap is as 'insertion_submaps.back()'.
const mapping::SubmapId submap_id =
submap_data_.Append(trajectory_id, SubmapData());
submap_data_.at(submap_id).submap = insertion_submaps.back();
} // We have to check this here, because it might have changed by the time we
// execute the lambda.
const bool newly_finished_submap = insertion_submaps.front()->finished();
AddWorkItem([=]() REQUIRES(mutex_) {
ComputeConstraintsForNode(node_id, insertion_submaps,
newly_finished_submap);
});
return node_id;
}
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
Cartographer源码阅读(4):Node和MapBuilder对象2的更多相关文章
- Cartographer源码阅读(2):Node和MapBuilder对象
上文提到特别注意map_builder_bridge_.AddTrajectory(x,x),查看其中的代码.两点: 首先是map_builder_.AddTrajectoryBuilder(...) ...
- Cartographer源码阅读(1):程序入口
带着几个思考问题: (1)IMU数据的使用,如何融合,Kalman滤波? (2)图优化的具体实现,闭环检测的策略? (3)3D激光的接入和闭环策略? 1. 安装Kdevelop工具: http://b ...
- Cartographer源码阅读(6):LocalTrajectoryBuilder和PoseExtrapolator
LocalTrajectoryBuilder意思是局部轨迹的构建,下面的类图中方法的参数没有画进去. 注意其中的三个类:PoseExtrapolator类,RealTimeCorrelativeSca ...
- Cartographer源码阅读(5):PoseGraph位姿图
PoseGraph位姿图 mapping2D::PoseGraph类的注释: // Implements the loop closure method called Sparse Pose Adju ...
- Cartographer源码阅读(8):imu_tracker
IMU的输入为imu_linear_acceleration 和 imu_angular_velocity 线加速和角速度.最终作为属性输出的是方位四元数. Eigen::Quaterniond ...
- Cartographer源码阅读(9):图优化的前端——闭环检测
约束计算 闭环检测的策略:搜索闭环,通过匹配检测是否是闭环,采用了分支定界法. 前已经述及PoseGraph的内容,此处继续.位姿图类定义了pose_graph::ConstraintBuilder ...
- Cartographer源码阅读(3):程序逻辑结构
Cartographer早期的代码在进行3d制图的时候使用了UKF方法,查看现有的tag版本,可以转到0.1.0和0.2.0查看,包含kalman_filter文件夹. 文件夹中的pose_track ...
- Cartographer源码阅读(7):轨迹推算和位姿推算的原理
其实也就是包括两个方面的内容:类似于运动模型的位姿估计和扫描匹配,因为需要计算速度,所以时间就有必要了! 1. PoseExtrapolator解决了IMU数据.里程计和位姿信息进行融合的问题. 该类 ...
- koa源码阅读[0]
koa源码阅读[0] Node.js也是写了两三年的时间了,刚开始学习Node的时候,hello world就是创建一个HttpServer,后来在工作中也是经历过Express.Koa1.x.Koa ...
随机推荐
- 修改Egret引擎代码的方法
某些情况下,我们需要修改Egret引擎的源码,我们可以在源码目录(一般如下:xxx\Egret\engine\x.x.x\src\egret)下直接修改ts代码. 在对应的项目下打开CMD命令行,输入 ...
- Git秘钥生成以及Gitlab配置(附以下问题解决方法:Key is invalid Fingerprint cannot be generated)
在进行Git密钥配置时,总是提示: “The form contains the following errors:Key is invalidFingerprint cannot be genera ...
- ELK & ElasticSearch 5.1 基础概念及配置文件详解【转】
转自:https://blog.csdn.net/zxf_668899/article/details/54582849 配置文件 基本概念 接近实时NRT 集群cluster 索引index 文档d ...
- 【转载】基于rasa的对话系统搭建(上)
文章介绍使用rasa nlu和 rasa core 实现一个电信领域对话系统demo,实现简单的业务查询办理功能,更完善的实现需要进一步数据的收集.demo基于玩具数据集,可以达到下面的效果: Bot ...
- C++实现景区信息管理系统
景区信息管理系统 实现了: 1.1 建立主程序应用菜单选项 主程序应用菜单选项包含所实现的所有功能,并且对选项采用数字标识进行选择,对其他错误输入可以进行判别,提示输入错误. 1.2 导游线路图的创建 ...
- Django admin 自定义Choice_field
在使用Django Admin后台时,有时候想自定义某一字段的Choice_field,例如屏蔽某些选项,只显示某些指定的选项. 想象这样的应用场景,我有一个网站,导航栏是这样的: 点开“技术杂谈”后 ...
- Jmeter在非GUI环境下传递参数(命令行&Jenkins配置)
https://www.cnblogs.com/kill0001000/p/8078686.html 通过cmd运行 jmeter -? 可以得到所有命令行选项(本文最后) 其中可以看到下面 -J 的 ...
- PXE:终于成功启动 fedora live 了!
default menu.c32 timeout 1 label fedora29-live menu label fedora29-live from ftp kernel fedora29live ...
- 并发编程(CountDownLatch使用)
一.简介: Latch意思是:门闩的意思,形象的来说await就是拴上门闩,等到门闩释放后当前线程开始工作. 下面是来自简书上的解释: CountDownlatch是一个多功能的同步工具,可以被用于各 ...
- is not in the sudoers file解决方法
用sudo时提示"xxx is not in the sudoers file. This incident will be reported.其中XXX是你的用户名,也就是你的用户名没有权 ...