node_main.cc中的Run函数最后:1
2
3
4::ros::spin();
// 终止所有轨迹
node.FinishAllTrajectories();
node.RunFinalOptimization();
主要看FinishAllTrajectories1
2
3
4
5
6
7
8
9
10
11
12void Node::FinishAllTrajectories()
{
carto::common::MutexLocker lock(&mutex_);
for (auto& entry : is_active_trajectory_) {
const int trajectory_id = entry.first;
// 已经lock了,所以叫做 FinishTrajectoryUnderLock
if (entry.second) {
CHECK_EQ(FinishTrajectoryUnderLock(trajectory_id).code,
cartographer_ros_msgs::StatusCode::OK);
}
}
}offline_node.cc 中还调用了一个Node::FinishTrajectory(是这个函数唯一被调用的地方),还有就是finish_trajectory服务的回调函数,以上3个函数实际都调用FinishTrajectoryUnderLock
1 | cartographer_ros_msgs::StatusResponse Node::FinishTrajectoryUnderLock( |
StatusResponse不正常的code是INVALID_ARGUMENT, NOT_FOUND, RESOURCE_EXHAUSTED, 只有OK是正常的
其中的关键函数就是:1
2
3
4
5
6
7
8
9
10
11
12
13
14void MapBuilderBridge::FinishTrajectory(const int trajectory_id)
{
LOG(INFO) << "Finishing trajectory with ID '" << trajectory_id << "'...";
// Make sure there is a trajectory with 'trajectory_id'.
CHECK_EQ(sensor_bridges_.count(trajectory_id), 1);
map_builder_->FinishTrajectory(trajectory_id);
sensor_bridges_.erase(trajectory_id);
}
// 再看这个函数
void MapBuilder::FinishTrajectory(const int trajectory_id) {
sensor_collator_->FinishTrajectory(trajectory_id);
pose_graph_->FinishTrajectory(trajectory_id);
}sensor_collator_就是Collator::FinishTrajectory 或者 TrajectoryCollator::FinishTrajectory,不用关注。
重要的是后端的同名函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14void PoseGraph2D::FinishTrajectory(const int trajectory_id)
{
AddWorkItem([this, trajectory_id]() LOCKS_EXCLUDED(mutex_)
{
absl::MutexLock locker(&mutex_);
CHECK(!IsTrajectoryFinished(trajectory_id)); // 不能是已结束
data_.trajectories_state[trajectory_id].state = TrajectoryState::FINISHED;
for (const auto& submap : data_.submap_data.trajectory(trajectory_id)) {
data_.submap_data.at(submap.id).state = SubmapState::kFinished;
}
return WorkItem::Result::kRunOptimization;
});
}
这里又是全局优化的标志kRunOptimization,然后又去PoseGraph2D::HandleWorkQueue,也是一次优化过程了
