void Run() {
constexpr double kTfBufferCacheTimeInSeconds = 10.;
//构建tf_buffer
tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
tf2_ros::TransformListener tf(tf_buffer); //坐标系之间的关系
//读取node和trajectory参数
NodeOptions node_options;
TrajectoryOptions trajectory_options;
std::tie(node_options, trajectory_options) =
LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
//构造map_builder
auto map_builder =
cartographer::mapping::CreateMapBuilder(node_options.map_builder_options);//创建地图构建器,实参map_builder
//构造node
Node node(node_options, std::move(map_builder), &tf_buffer,
FLAGS_collect_metrics);//创建节点node,节点里有地图构建器
//从proto中加载之前离线保存的state(pbstream文件)
if (!FLAGS_load_state_filename.empty()) {
node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
}
//用默认参数开启trajectory
if (FLAGS_start_trajectory_with_default_topics) {
node.StartTrajectoryWithDefaultTopics(trajectory_options);
}
::ros::spin();//不断进入订阅函数callback(传感器)
//在node结束时执行的任务
//1:finish trajectory
node.FinishAllTrajectories();//停止node后将所有轨迹停止
//2:最终优化(最后一次)
node.RunFinalOptimization();
//3:可选:如果指定保存最终的状态,则将PoseGraph保存下来
if (!FLAGS_save_state_filename.empty()) {
node.SerializeState(FLAGS_save_state_filename,
true /* include_unfinished_submaps */);
}
}
} // namespace
} // namespace cartographer_ros
1、node执行之前,读取参数,构造Node(同时构造map_builder和tf);
2、执行node,开启任务:Start Trajectory With Default Topics(使用默认topic名称)和LoadState(定位时用);
3、在node任务结束时,执行3个任务:finish trajectory、最后一次优化和保存PoseGraph(可选)。
class Node {
public:
//构造函数
Node(const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* tf_buffer, bool collect_metrics);
~Node();
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// Finishes all yet active trajectories.
void FinishAllTrajectories();
// Finishes a single given trajectory. Returns false if the trajectory did not
// exist or was already finished.
bool FinishTrajectory(int trajectory_id);
// Runs final optimization. All trajectories have to be finished when calling.
void RunFinalOptimization();
// Starts the first trajectory with the default topics.
void StartTrajectoryWithDefaultTopics(const TrajectoryOptions& options);
// Returns unique SensorIds for multiple input bag files based on
// their TrajectoryOptions.
// 'SensorId::id' is the expected ROS topic name.
std::vector<
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId>>
ComputeDefaultSensorIdsForMultipleBags(
const std::vector<TrajectoryOptions>& bags_options) const;
// Adds a trajectory for offline processing, i.e. not listening to topics.
int AddOfflineTrajectory(
const std::set<
cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& options);
// The following functions handle adding sensor data to a trajectory.
void HandleOdometryMessage(int trajectory_id, const std::string& sensor_id,
const nav_msgs::Odometry::ConstPtr& msg);
void HandleNavSatFixMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::NavSatFix::ConstPtr& msg);
void HandleLandmarkMessage(
int trajectory_id, const std::string& sensor_id,
const cartographer_ros_msgs::LandmarkList::ConstPtr& msg);
void HandleImuMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::Imu::ConstPtr& msg);
void HandleLaserScanMessage(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::LaserScan::ConstPtr& msg);
void HandleMultiEchoLaserScanMessage(
int trajectory_id, const std::string& sensor_id,
const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg);
void HandlePointCloud2Message(int trajectory_id, const std::string& sensor_id,
const sensor_msgs::PointCloud2::ConstPtr& msg);
// Serializes the complete Node state.序列化
void SerializeState(const std::string& filename,
const bool include_unfinished_submaps);
// Loads a serialized SLAM state from a .pbstream file.
void LoadState(const std::string& state_filename, bool load_frozen_state);
//这是什么?句柄
::ros::NodeHandle* node_handle();
private:
struct Subscriber {
::ros::Subscriber subscriber;
// ::ros::Subscriber::getTopic() does not necessarily return the same
// std::string
// it was given in its constructor. Since we rely on the topic name as the
// unique identifier of a subscriber, we remember it ourselves.
std::string topic;
};
//处理cartographer的一些service
bool HandleSubmapQuery(
cartographer_ros_msgs::SubmapQuery::Request& request,
cartographer_ros_msgs::SubmapQuery::Response& response);
bool HandleTrajectoryQuery(
::cartographer_ros_msgs::TrajectoryQuery::Request& request,
::cartographer_ros_msgs::TrajectoryQuery::Response& response);
bool HandleStartTrajectory(
cartographer_ros_msgs::StartTrajectory::Request& request,
cartographer_ros_msgs::StartTrajectory::Response& response);
bool HandleFinishTrajectory(
cartographer_ros_msgs::FinishTrajectory::Request& request,
cartographer_ros_msgs::FinishTrajectory::Response& response);
bool HandleWriteState(cartographer_ros_msgs::WriteState::Request& request,
cartographer_ros_msgs::WriteState::Response& response);
bool HandleGetTrajectoryStates(
::cartographer_ros_msgs::GetTrajectoryStates::Request& request,
::cartographer_ros_msgs::GetTrajectoryStates::Response& response);
bool HandleReadMetrics(
cartographer_ros_msgs::ReadMetrics::Request& request,
cartographer_ros_msgs::ReadMetrics::Response& response);
// Returns the set of SensorIds expected for a trajectory.
// 'SensorId::id' is the expected ROS topic name.
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId>
ComputeExpectedSensorIds(const TrajectoryOptions& options) const;
// 添加轨迹
int AddTrajectory(const TrajectoryOptions& options);
// 轨迹订阅消息的处理函数
void LaunchSubscribers(const TrajectoryOptions& options, int trajectory_id);
// 为轨迹添加外推器,注意:该外推器和前端的外推器没有关系,该外推器是为了发布trajectory state
// 即函数:PublishTrajectoryStates。该外推器同样会接收轮速计和IMU数据
void AddExtrapolator(int trajectory_id, const TrajectoryOptions& options);
// 为轨迹添加接收数据的计数器(传感器采样)
void AddSensorSamplers(int trajectory_id, const TrajectoryOptions& options);
//发布相关消息
void PublishSubmapList(const ::ros::WallTimerEvent& timer_event);
void PublishLocalTrajectoryData(const ::ros::TimerEvent& timer_event);
void PublishTrajectoryNodeList(const ::ros::WallTimerEvent& timer_event);
void PublishLandmarkPosesList(const ::ros::WallTimerEvent& timer_event);
void PublishConstraintList(const ::ros::WallTimerEvent& timer_event);
bool ValidateTrajectoryOptions(const TrajectoryOptions& options);
bool ValidateTopicNames(const TrajectoryOptions& options);
cartographer_ros_msgs::StatusResponse FinishTrajectoryUnderLock(
int trajectory_id) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void MaybeWarnAboutTopicMismatch(const ::ros::WallTimerEvent&);
// Helper function for service handlers that need to check trajectory states.
cartographer_ros_msgs::StatusResponse TrajectoryStateToStatus(
int trajectory_id,
const std::set<
cartographer::mapping::PoseGraphInterface::TrajectoryState>&
valid_states);
const NodeOptions node_options_;
tf2_ros::TransformBroadcaster tf_broadcaster_;
absl::Mutex mutex_;
std::unique_ptr<cartographer_ros::metrics::FamilyFactory> metrics_registry_;
MapBuilderBridge map_builder_bridge_ GUARDED_BY(mutex_);//Node成员变量map_builder_bridge_,其类型为MapBuilderBridge
// 发布相关消息
::ros::NodeHandle node_handle_;
::ros::Publisher submap_list_publisher_;
::ros::Publisher trajectory_node_list_publisher_;
::ros::Publisher landmark_poses_list_publisher_;
::ros::Publisher constraint_list_publisher_;
::ros::Publisher tracked_pose_publisher_;
::ros::Publisher scan_matched_point_cloud_publisher_;
// These ros::ServiceServers need to live for the lifetime of the node.
std::vector<::ros::ServiceServer> service_servers_;
struct TrajectorySensorSamplers {
TrajectorySensorSamplers(const double rangefinder_sampling_ratio,
const double odometry_sampling_ratio,
const double fixed_frame_pose_sampling_ratio,
const double imu_sampling_ratio,
const double landmark_sampling_ratio)
: rangefinder_sampler(rangefinder_sampling_ratio),
odometry_sampler(odometry_sampling_ratio),
fixed_frame_pose_sampler(fixed_frame_pose_sampling_ratio),
imu_sampler(imu_sampling_ratio),
landmark_sampler(landmark_sampling_ratio) {}
::cartographer::common::FixedRatioSampler rangefinder_sampler;
::cartographer::common::FixedRatioSampler odometry_sampler;
::cartographer::common::FixedRatioSampler fixed_frame_pose_sampler;
::cartographer::common::FixedRatioSampler imu_sampler;
::cartographer::common::FixedRatioSampler landmark_sampler;
};
// These are keyed with 'trajectory_id'.
// 每个轨迹对应一个外推器
std::map<int, ::cartographer::mapping::PoseExtrapolator> extrapolators_;
std::map<int, ::ros::Time> last_published_tf_stamps_;
// 轨迹接收数据的计数器
std::unordered_map<int, TrajectorySensorSamplers> sensor_samplers_;
// 订阅消息
std::unordered_map<int, std::vector<Subscriber>> subscribers_;
std::unordered_set<std::string> subscribed_topics_;
std::unordered_set<int> trajectories_scheduled_for_finish_;
// We have to keep the timer handles of ::ros::WallTimers around, otherwise
// they do not fire.
std::vector<::ros::WallTimer> wall_timers_;
// The timer for publishing local trajectory data (i.e. pose transforms and
// range data point clouds) is a regular timer which is not triggered when
// simulation time is standing still. This prevents overflowing the transform
// listener buffer by publishing the same transforms over and over again.
::ros::Timer publish_local_trajectory_data_timer_;
};
1、管理轨迹:添加轨迹、finish 轨迹(某条或所有)、添加离线轨迹(不再listening topics)、优化所有轨迹(node结束时调用);
2、接收sensor消息:IMU、Odometry、Landmark、LaserScan、PointCloud、MultiEchoLaserScan、NavSatFix。并对Sensor消息进行处理:降频(sensor_samplers_的作用)、传给node的外推器(extrapolators的作用)进行位姿推算、传给相应的trajectory,进行SLAM过程;
3、发布相关信息:TrajectoryStates、TrajectoryNodeList、LandmarkPosesList、ConstraintList、SubmapList、scan_matched_point_cloud。
4、处理相关service:SubmapQuery、StartTrajectory、FinishTrajectory、WriteState
5、测试相关:添加离线轨迹、验证TrajectoryOptions和TopicNames。
Node::Node(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* const tf_buffer, const bool collect_metrics)
: node_options_(node_options),
map_builder_bridge_(node_options_, std::move(map_builder), tf_buffer) {}
//Node::Node(node_options配置文件中读参,地图构建器,坐标系:初始化列表,将map_builder给到map_builder_bridge_)
void Node::StartTrajectoryWithDefaultTopics(const TrajectoryOptions& options) {
absl::MutexLock lock(&mutex_);
//验证trajectoryOptions是否有异常参数
CHECK(ValidateTrajectoryOptions(options));
//若无,这开启一个新的Node::AddTrajectory()函数
AddTrajectory(options);
}
//传入数据TrajectoryOptions在trajectory_options.h;
//另:DefaultSensorTopics(默认传感器topic在node_constants.h中定义)
bool Node::ValidateTrajectoryOptions(const TrajectoryOptions& options) {
//2D
if (node_options_.map_builder_options.use_trajectory_builder_2d()) {
return options.trajectory_builder_options
.has_trajectory_builder_2d_options();
}
//3D
if (node_options_.map_builder_options.use_trajectory_builder_3d()) {
return options.trajectory_builder_options
.has_trajectory_builder_3d_options();
}
return false;
}
int Node::AddTrajectory(const TrajectoryOptions& options) {
// 获取轨迹所需的topics名称
const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
expected_sensor_ids = ComputeExpectedSensorIds(options);
// 获取轨迹的trajectory_id
const int trajectory_id =
map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);//让map_builder_bridge_添加轨迹
// 为该条轨迹添加位姿外推器
AddExtrapolator(trajectory_id, options);
// 添加计数器
AddSensorSamplers(trajectory_id, options);
// 为该条轨迹开启回调函数
LaunchSubscribers(options, trajectory_id);
wall_timers_.push_back(node_handle_.createWallTimer(
::ros::WallDuration(kTopicMismatchCheckDelaySec),
&Node::MaybeWarnAboutTopicMismatch, this, /*oneshot=*/true));
for (const auto& sensor_id : expected_sensor_ids) {
subscribed_topics_.insert(sensor_id.id);
}
return trajectory_id;
}
std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
Node::ComputeExpectedSensorIds(const TrajectoryOptions& options) const {
using SensorId = cartographer::mapping::TrajectoryBuilderInterface::SensorId;
using SensorType = SensorId::SensorType;
std::set<SensorId> expected_topics;
// Subscribe to all laser scan, multi echo laser scan, and point cloud topics.
for (const std::string& topic :
ComputeRepeatedTopicNames(kLaserScanTopic, options.num_laser_scans)) {
expected_topics.insert(SensorId{SensorType::RANGE, topic});
}
for (const std::string& topic : ComputeRepeatedTopicNames(
kMultiEchoLaserScanTopic, options.num_multi_echo_laser_scans)) {
expected_topics.insert(SensorId{SensorType::RANGE, topic});
}
for (const std::string& topic :
ComputeRepeatedTopicNames(kPointCloud2Topic, options.num_point_clouds)) {
expected_topics.insert(SensorId{SensorType::RANGE, topic});
}
// For 2D SLAM, subscribe to the IMU if we expect it. For 3D SLAM, the IMU is
// required.
if (node_options_.map_builder_options.use_trajectory_builder_3d() ||
(node_options_.map_builder_options.use_trajectory_builder_2d() &&
options.trajectory_builder_options.trajectory_builder_2d_options()
.use_imu_data())) {
expected_topics.insert(SensorId{SensorType::IMU, kImuTopic});
}
// Odometry is optional.
if (options.use_odometry) {
expected_topics.insert(SensorId{SensorType::ODOMETRY, kOdometryTopic});
}
// NavSatFix is optional.
if (options.use_nav_sat) {
expected_topics.insert(
SensorId{SensorType::FIXED_FRAME_POSE, kNavSatFixTopic});
}
// Landmark is optional.
if (options.use_landmarks) {
expected_topics.insert(SensorId{SensorType::LANDMARK, kLandmarkTopic});
}
return expected_topics;
}
int MapBuilderBridge::AddTrajectory(
const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options) {
//激光传感器数据id,this是λ表达式
const int trajectory_id = map_builder_->AddTrajectoryBuilder(
expected_sensor_ids, trajectory_options.trajectory_builder_options,
[this](const int trajectory_id, const ::cartographer::common::Time time,
const Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local,
const std::unique_ptr<
const ::cartographer::mapping::TrajectoryBuilderInterface::
InsertionResult>) {
OnLocalSlamResult(trajectory_id, time, local_pose, range_data_in_local);
});
LOG(INFO) << "Added trajectory with ID '" << trajectory_id << "'.";
// Make sure there is no trajectory with 'trajectory_id' yet.
CHECK_EQ(sensor_bridges_.count(trajectory_id), 0);
sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>(
trajectory_options.num_subdivisions_per_laser_scan,
trajectory_options.tracking_frame,
node_options_.lookup_transform_timeout_sec, tf_buffer_,
map_builder_->GetTrajectoryBuilder(trajectory_id));//sensor_bridges_获取了map_builder_的GetTrajectoryBuilder
auto emplace_result =
trajectory_options_.emplace(trajectory_id, trajectory_options);
CHECK(emplace_result.second == true);
return trajectory_id;
}
void Node::AddExtrapolator(const int trajectory_id,
const TrajectoryOptions& options) {
constexpr double kExtrapolationEstimationTimeSec = 0.001; // 1 ms
CHECK(extrapolators_.count(trajectory_id) == 0);
const double gravity_time_constant =
node_options_.map_builder_options.use_trajectory_builder_3d()
? options.trajectory_builder_options.trajectory_builder_3d_options()
.imu_gravity_time_constant()
: options.trajectory_builder_options.trajectory_builder_2d_options()
.imu_gravity_time_constant();
extrapolators_.emplace(
std::piecewise_construct, std::forward_as_tuple(trajectory_id),
std::forward_as_tuple(
::cartographer::common::FromSeconds(kExtrapolationEstimationTimeSec),
gravity_time_constant));
}
void Node::AddSensorSamplers(const int trajectory_id,
const TrajectoryOptions& options) {
CHECK(sensor_samplers_.count(trajectory_id) == 0);
sensor_samplers_.emplace(
std::piecewise_construct, std::forward_as_tuple(trajectory_id),
std::forward_as_tuple(
options.rangefinder_sampling_ratio, options.odometry_sampling_ratio,
options.fixed_frame_pose_sampling_ratio, options.imu_sampling_ratio,
options.landmarks_sampling_ratio));
}
void Node::LaunchSubscribers(const TrajectoryOptions& options,
const int trajectory_id) {
for (const std::string& topic :
ComputeRepeatedTopicNames(kLaserScanTopic, options.num_laser_scans)) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::LaserScan>(
&Node::HandleLaserScanMessage, trajectory_id, topic, &node_handle_,
this),
topic});
}
for (const std::string& topic : ComputeRepeatedTopicNames(
kMultiEchoLaserScanTopic, options.num_multi_echo_laser_scans)) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::MultiEchoLaserScan>(
&Node::HandleMultiEchoLaserScanMessage, trajectory_id, topic,
&node_handle_, this),
topic});
}
for (const std::string& topic :
ComputeRepeatedTopicNames(kPointCloud2Topic, options.num_point_clouds)) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::PointCloud2>(
&Node::HandlePointCloud2Message, trajectory_id, topic,
&node_handle_, this),
topic});
}
// For 2D SLAM, subscribe to the IMU if we expect it. For 3D SLAM, the IMU is
// required.
if (node_options_.map_builder_options.use_trajectory_builder_3d() ||
(node_options_.map_builder_options.use_trajectory_builder_2d() &&
options.trajectory_builder_options.trajectory_builder_2d_options()
.use_imu_data())) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::Imu>(&Node::HandleImuMessage,
trajectory_id, kImuTopic,
&node_handle_, this),
kImuTopic});
}
if (options.use_odometry) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<nav_msgs::Odometry>(&Node::HandleOdometryMessage,
trajectory_id, kOdometryTopic,
&node_handle_, this),
kOdometryTopic});
}
if (options.use_nav_sat) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::NavSatFix>(
&Node::HandleNavSatFixMessage, trajectory_id, kNavSatFixTopic,
&node_handle_, this),
kNavSatFixTopic});
}
if (options.use_landmarks) {
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<cartographer_ros_msgs::LandmarkList>(
&Node::HandleLandmarkMessage, trajectory_id, kLandmarkTopic,
&node_handle_, this),
kLandmarkTopic});
}
}
namespace cartographer_ros {
class MapBuilderBridge {
public:
// 前端解算完位姿后,生成TrajectoryState,用于发送定位信息
struct LocalTrajectoryData {
// Contains the trajectory data received from local SLAM, after
// it had processed accumulated 'range_data_in_local' and estimated
// current 'local_pose' at 'time'.
struct LocalSlamData {
//激光帧时间戳
::cartographer::common::Time time;
//该帧在Local SLAM坐标系下的位姿
::cartographer::transform::Rigid3d local_pose;
//在Local SLAM坐标系下的该帧点运输局
::cartographer::sensor::RangeData range_data_in_local;
};
std::shared_ptr<const LocalSlamData> local_slam_data;
//Local SLAM到Global SLAM坐标系的转换
cartographer::transform::Rigid3d local_to_map;
//发布坐标系到tracking坐标系的转换
std::unique_ptr<cartographer::transform::Rigid3d> published_to_tracking;
//加载轨迹参数
TrajectoryOptions trajectory_options;
};
//构造函数
MapBuilderBridge(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* tf_buffer);
MapBuilderBridge(const MapBuilderBridge&) = delete;
MapBuilderBridge& operator=(const MapBuilderBridge&) = delete;
//从proto加载state
void LoadState(const std::string& state_filename, bool load_frozen_state);
//添加轨迹
int AddTrajectory(
const std::set<
::cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options);
//结束轨迹
void FinishTrajectory(int trajectory_id);
//执行最后一次优化
void RunFinalOptimization();
//将State写入proto
bool SerializeState(const std::string& filename,
const bool include_unfinished_submaps);
// service : node::HandleSubmapQuery函数调用该函数
void HandleSubmapQuery(
cartographer_ros_msgs::SubmapQuery::Request& request,
cartographer_ros_msgs::SubmapQuery::Response& response);
void HandleTrajectoryQuery(
cartographer_ros_msgs::TrajectoryQuery::Request& request,
cartographer_ros_msgs::TrajectoryQuery::Response& response);
std::map<int /* trajectory_id */,
::cartographer::mapping::PoseGraphInterface::TrajectoryState>
GetTrajectoryStates();
// node publish 相关函数调用的函数
cartographer_ros_msgs::SubmapList GetSubmapList();
std::unordered_map<int, LocalTrajectoryData> GetLocalTrajectoryData()
LOCKS_EXCLUDED(mutex_);
visualization_msgs::MarkerArray GetTrajectoryNodeList();
visualization_msgs::MarkerArray GetLandmarkPosesList();
visualization_msgs::MarkerArray GetConstraintList();
//获取某个轨迹的sensor_bridge
SensorBridge* sensor_bridge(int trajectory_id);
private:
//前端localSLAM的回调函数
void OnLocalSlamResult(const int trajectory_id,
const ::cartographer::common::Time time,
const ::cartographer::transform::Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local)
LOCKS_EXCLUDED(mutex_);
// 锁
absl::Mutex mutex_;
const NodeOptions node_options_;
// 轨迹State
std::unordered_map<int,
std::shared_ptr<const LocalTrajectoryData::LocalSlamData>>
local_slam_data_ GUARDED_BY(mutex_);
// MapBuilderBridge的成员变量map_builder_
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder_;
// tf
tf2_ros::Buffer* const tf_buffer_;
// landmark相关
std::unordered_map<std::string /* landmark ID */, int> landmark_to_index_;
// These are keyed with 'trajectory_id'.
// 存放每个轨迹参数
std::unordered_map<int, TrajectoryOptions> trajectory_options_;
// 每个轨迹对应一个SensorBridge
std::unordered_map<int, std::unique_ptr<SensorBridge>> sensor_bridges_;
// landmark相关
std::unordered_map<int, size_t> trajectory_to_highest_marker_id_;
};
} // namespace cartographer_ros
int MapBuilderBridge::AddTrajectory(
const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options) {
// 激光传感器数据id,this是λ表达式
// 调用MapBuilder的AddTrajectoryBuilder函数添加轨迹
const int trajectory_id = map_builder_->AddTrajectoryBuilder(
expected_sensor_ids, trajectory_options.trajectory_builder_options,
[this](const int trajectory_id, const ::cartographer::common::Time time,
const Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local,
const std::unique_ptr<
const ::cartographer::mapping::TrajectoryBuilderInterface::
InsertionResult>) {
OnLocalSlamResult(trajectory_id, time, local_pose, range_data_in_local);
});
LOG(INFO) << "Added trajectory with ID '" << trajectory_id << "'.";
// Make sure there is no trajectory with 'trajectory_id' yet.
CHECK_EQ(sensor_bridges_.count(trajectory_id), 0);
// 为该条轨迹添加SensorBridge
sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>(
trajectory_options.num_subdivisions_per_laser_scan,
trajectory_options.tracking_frame,
node_options_.lookup_transform_timeout_sec, tf_buffer_,
map_builder_->GetTrajectoryBuilder(trajectory_id));//sensor_bridges_获取了map_builder_的GetTrajectoryBuilder
auto emplace_result =
trajectory_options_.emplace(trajectory_id, trajectory_options);
CHECK(emplace_result.second == true);
return trajectory_id;
}
1、MapBuilderBridge类中的成员变量map_builder_是由map_builder和tf构造而成;
2、在构造SensorBridge时,又将Node的tf传给了SensorBridge,将map_builder中的TrajectoryBuilder传给了SensorBridge。在SensorBridge中,该条轨迹的数据在SensorBridge中处理后,传递给了其对应的轨迹TrajectoryBuilder
3、注意:定义的map_builder是std::unique_ptrcartographer::mapping::MapBuilderInterface类型的,是cartographer文件下的MapBuilderInterface类,但定义的名称是map_builder,而MapBuilder是MapBuilderInterface的一个子类,可转到cartographer中查看具体信息
class MapBuilder : public MapBuilderInterface {
public:
explicit MapBuilder(const proto::MapBuilderOptions &options);
~MapBuilder() override {}
MapBuilder(const MapBuilder &) = delete;
MapBuilder &operator=(const MapBuilder &) = delete;
int AddTrajectoryBuilder(
const std::set<SensorId> &expected_sensor_ids,
const proto::TrajectoryBuilderOptions &trajectory_options,
LocalSlamResultCallback local_slam_result_callback) override;
int AddTrajectoryForDeserialization(
const proto::TrajectoryBuilderOptionsWithSensorIds
&options_with_sensor_ids_proto) override;
void FinishTrajectory(int trajectory_id) override;
std::string SubmapToProto(const SubmapId &submap_id,
proto::SubmapQuery::Response *response) override;
void SerializeState(bool include_unfinished_submaps,
io::ProtoStreamWriterInterface *writer) override;
bool SerializeStateToFile(bool include_unfinished_submaps,
const std::string &filename) override;
std::map<int, int> LoadState(io::ProtoStreamReaderInterface *reader,
bool load_frozen_state) override;
std::map<int, int> LoadStateFromFile(const std::string &filename,
const bool load_frozen_state) override;
mapping::PoseGraphInterface *pose_graph() override {
return pose_graph_.get();
}
int num_trajectory_builders() const override {
return trajectory_builders_.size();
}
mapping::TrajectoryBuilderInterface *GetTrajectoryBuilder(
int trajectory_id) const override {
return trajectory_builders_.at(trajectory_id).get();
}
const std::vector<proto::TrajectoryBuilderOptionsWithSensorIds>
&GetAllTrajectoryBuilderOptions() const override {
return all_trajectory_builder_options_;
}
private:
const proto::MapBuilderOptions options_;
// 线程池
common::ThreadPool thread_pool_;
// 一个后端的pose_graph_
std::unique_ptr<PoseGraph> pose_graph_;
//数据分发器
std::unique_ptr<sensor::CollatorInterface> sensor_collator_;
// 多条轨迹的前端
std::vector<std::unique_ptr<mapping::TrajectoryBuilderInterface>>
trajectory_builders_;
std::vector<proto::TrajectoryBuilderOptionsWithSensorIds>
all_trajectory_builder_options_;
};
int MapBuilder::AddTrajectoryBuilder(
const std::set<SensorId>& expected_sensor_ids,
const proto::TrajectoryBuilderOptions& trajectory_options,
LocalSlamResultCallback local_slam_result_callback) {
// 返回待创建的Trajectory的id
const int trajectory_id = trajectory_builders_.size();
absl::optional<MotionFilter> pose_graph_odometry_motion_filter;
if (trajectory_options.has_pose_graph_odometry_motion_filter()) {
LOG(INFO) << "Using a motion filter for adding odometry to the pose graph.";
pose_graph_odometry_motion_filter.emplace(
MotionFilter(trajectory_options.pose_graph_odometry_motion_filter()));
}
// 3Dslam
if (options_.use_trajectory_builder_3d()) {
// 3D前端
std::unique_ptr<LocalTrajectoryBuilder3D> local_trajectory_builder;
if (trajectory_options.has_trajectory_builder_3d_options()) {
local_trajectory_builder = absl::make_unique<LocalTrajectoryBuilder3D>(
trajectory_options.trajectory_builder_3d_options(),
SelectRangeSensorIds(expected_sensor_ids));
}
// 3D后端
// sensor_collator_ 数据分发器
// MapBuilder里的TrajectoryBuilder是CollatedBuilder,
// 而该CollatedBuilder又是由数据分发器和GlobalTrajectoryBuilder构成,
// 且此GlobalTrajectoryBuilder又是由前端LocalTrajectoryBuilder3D和后端PoseGraph3D构造而成
DCHECK(dynamic_cast<PoseGraph3D*>(pose_graph_.get()));
trajectory_builders_.push_back(absl::make_unique<CollatedTrajectoryBuilder>(
trajectory_options, sensor_collator_.get(), trajectory_id,
expected_sensor_ids,
CreateGlobalTrajectoryBuilder3D(
std::move(local_trajectory_builder), trajectory_id,
static_cast<PoseGraph3D*>(pose_graph_.get()),
local_slam_result_callback, pose_graph_odometry_motion_filter)));
} else {
// 2D SLAM
// 2D前端
std::unique_ptr<LocalTrajectoryBuilder2D> local_trajectory_builder;
if (trajectory_options.has_trajectory_builder_2d_options()) {
local_trajectory_builder = absl::make_unique<LocalTrajectoryBuilder2D>(
trajectory_options.trajectory_builder_2d_options(),
SelectRangeSensorIds(expected_sensor_ids));
}
// 和3D一样
DCHECK(dynamic_cast<PoseGraph2D*>(pose_graph_.get()));
trajectory_builders_.push_back(absl::make_unique<CollatedTrajectoryBuilder>(
trajectory_options, sensor_collator_.get(), trajectory_id,
expected_sensor_ids,
CreateGlobalTrajectoryBuilder2D(
std::move(local_trajectory_builder), trajectory_id,
static_cast<PoseGraph2D*>(pose_graph_.get()),
local_slam_result_callback, pose_graph_odometry_motion_filter)));
}
MaybeAddPureLocalizationTrimmer(trajectory_id, trajectory_options,
pose_graph_.get());
// 轨迹的初始位姿
if (trajectory_options.has_initial_trajectory_pose()) {
const auto& initial_trajectory_pose =
trajectory_options.initial_trajectory_pose();
pose_graph_->SetInitialTrajectoryPose(
trajectory_id, initial_trajectory_pose.to_trajectory_id(),
transform::ToRigid3(initial_trajectory_pose.relative_pose()),
common::FromUniversal(initial_trajectory_pose.timestamp()));
}
proto::TrajectoryBuilderOptionsWithSensorIds options_with_sensor_ids_proto;
for (const auto& sensor_id : expected_sensor_ids) {
*options_with_sensor_ids_proto.add_sensor_id() = ToProto(sensor_id);
}
*options_with_sensor_ids_proto.mutable_trajectory_builder_options() =
trajectory_options;
all_trajectory_builder_options_.push_back(options_with_sensor_ids_proto);
CHECK_EQ(trajectory_builders_.size(), all_trajectory_builder_options_.size());
return trajectory_id;
}
// 3D后端
// sensor_collator_ 数据分发器
// MapBuilder里的TrajectoryBuilder是CollatedBuilder,
// 而该CollatedBuilder又是由数据分发器sensor_collator_.get()和GlobalTrajectoryBuilder构成,
// 且此GlobalTrajectoryBuilder又是由前端LocalTrajectoryBuilder3D和后端PoseGraph3D构造而成
DCHECK(dynamic_cast<PoseGraph3D*>(pose_graph_.get()));
trajectory_builders_.push_back(absl::make_unique<CollatedTrajectoryBuilder>(
trajectory_options, sensor_collator_.get(), trajectory_id,
expected_sensor_ids,
CreateGlobalTrajectoryBuilder3D(
std::move(local_trajectory_builder), trajectory_id,
static_cast<PoseGraph3D*>(pose_graph_.get()),
local_slam_result_callback, pose_graph_odometry_motion_filter)));
class CollatedTrajectoryBuilder : public TrajectoryBuilderInterface {
public:
using SensorId = TrajectoryBuilderInterface::SensorId;
// 构造函数,由MapBuilder的数据分发器sensor_collator和global_trajectory_builder构造
// wrapped_trajectory_builder就是global_trajectory_builder其数据类型都一样std::unique_ptr
CollatedTrajectoryBuilder(
const proto::TrajectoryBuilderOptions& trajectory_options,
sensor::CollatorInterface* sensor_collator, int trajectory_id,
const std::set<SensorId>& expected_sensor_ids,
std::unique_ptr<TrajectoryBuilderInterface> wrapped_trajectory_builder);
~CollatedTrajectoryBuilder() override {}
CollatedTrajectoryBuilder(const CollatedTrajectoryBuilder&) = delete;
CollatedTrajectoryBuilder& operator=(const CollatedTrajectoryBuilder&) =
delete;
// 由sensor_bridge的HandleRangefinder函数调用,将sensor_bridge中处理好的激光数据传给CollatedTrajectoryBuilder
void AddSensorData(
const std::string& sensor_id,
const sensor::TimedPointCloudData& timed_point_cloud_data) override {
AddData(sensor::MakeDispatchable(sensor_id, timed_point_cloud_data));
}
void AddSensorData(const std::string& sensor_id,
const sensor::ImuData& imu_data) override {
AddData(sensor::MakeDispatchable(sensor_id, imu_data));
}
// 由sensor_bridge的HandleOdometryMessage函数调用,将sensor_bridge中处理好的轮速计数据传给CollatedTrajectoryBuilder
void AddSensorData(const std::string& sensor_id,
const sensor::OdometryData& odometry_data) override {
AddData(sensor::MakeDispatchable(sensor_id, odometry_data));
}
void AddSensorData(
const std::string& sensor_id,
const sensor::FixedFramePoseData& fixed_frame_pose_data) override {
if (collate_fixed_frame_) {
AddData(sensor::MakeDispatchable(sensor_id, fixed_frame_pose_data));
return;
}
wrapped_trajectory_builder_->AddSensorData(sensor_id,
fixed_frame_pose_data);
}
void AddSensorData(const std::string& sensor_id,
const sensor::LandmarkData& landmark_data) override {
if (collate_landmarks_) {
AddData(sensor::MakeDispatchable(sensor_id, landmark_data));//分发数据
return;
}
wrapped_trajectory_builder_->AddSensorData(sensor_id, landmark_data);
}
void AddLocalSlamResultData(std::unique_ptr<mapping::LocalSlamResultData>
local_slam_result_data) override {
AddData(std::move(local_slam_result_data));
}
private:
void AddData(std::unique_ptr<sensor::Data> data);
void HandleCollatedSensorData(const std::string& sensor_id,
std::unique_ptr<sensor::Data> data);
// 数据分发器,由MapBuilder的sensor_collator_构造,该sensor_collator_的类型:
// sensor::Collator或sensor::TrajectoryCollator。一般情况下为sensor::Collator
sensor::CollatorInterface* const sensor_collator_;
const bool collate_landmarks_;
const bool collate_fixed_frame_;
const int trajectory_id_;
// 该wrapped_trajectory_builder_是GlobalTrajectoryBuilder
std::unique_ptr<TrajectoryBuilderInterface> wrapped_trajectory_builder_;
// Time at which we last logged the rates of incoming sensor data.
std::chrono::steady_clock::time_point last_logging_time_;
std::map<std::string, common::RateTimer<>> rate_timers_;
};
} // namespace mapping
} // namespace cartographer
CollatedTrajectoryBuilder::CollatedTrajectoryBuilder(
const proto::TrajectoryBuilderOptions& trajectory_options,
sensor::CollatorInterface* const sensor_collator, const int trajectory_id,
const std::set<SensorId>& expected_sensor_ids,
std::unique_ptr<TrajectoryBuilderInterface> wrapped_trajectory_builder)
: sensor_collator_(sensor_collator),
collate_landmarks_(trajectory_options.collate_landmarks()),
collate_fixed_frame_(trajectory_options.collate_fixed_frame()),
trajectory_id_(trajectory_id),
wrapped_trajectory_builder_(std::move(wrapped_trajectory_builder)),
last_logging_time_(std::chrono::steady_clock::now()) {
absl::flat_hash_set<std::string> expected_sensor_id_strings;
for (const auto& sensor_id : expected_sensor_ids) {
if (sensor_id.type == SensorId::SensorType::LANDMARK &&
!collate_landmarks_) {
continue;
}
if (sensor_id.type == SensorId::SensorType::FIXED_FRAME_POSE &&
!collate_fixed_frame_) {
continue;
}
expected_sensor_id_strings.insert(sensor_id.id);
}
// 通过lambda(λ)表达式将该轨迹不同sensor_id的数据通过HandleCollatedSensorData
//传给数据分发器sensor_collator_(来自MapBuilder),需要注意是传进去的是一个回调函数callback,
//在该回调函数中,将数据传给MapBuilder中构造的GlobalTrajectoryBuilder,数据分发器接收到数据后,
//又将数据传给了GlobalTrajectoryBuilder
sensor_collator_->AddTrajectory(
trajectory_id, expected_sensor_id_strings,
[this](const std::string& sensor_id, std::unique_ptr<sensor::Data> data) {
HandleCollatedSensorData(sensor_id, std::move(data));
});
}
void CollatedTrajectoryBuilder::AddData(std::unique_ptr<sensor::Data> data) {
// 轮速计数据等通过该函数统一将数据送入数据分发器中
sensor_collator_->AddSensorData(trajectory_id_, std::move(data));
}
// 回调函数
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();
}
// 在该callback函数中将数据传给MapBuilder中构造的GlobalTrajectoryBuilder
data->AddToTrajectoryBuilder(wrapped_trajectory_builder_.get());
}
} // namespace mapping
} // namespace cartographer
至此:轨迹添加部分完结
参考链接: https://blog.csdn.net/yeluohanchan/article/details/108672133.