To be sure there is a recent loop closure constraint, you can query PoseGraphInterface::constraints(), loop over all constraints and check if there is a recent one of type INTER that spans some time.
A simpler solution is to subscribe to the global slam callback GlobalSlamOptimizationCallback by setting PoseGraphInterface::SetGlobalSlamOptimizationCallback. This will call you back after Cartographer has searched for loop closures. It does not tell you if loop closures were found, it mostly tells you if the background loop closure search is keeping up or falls behind.
if (FLAGS_is_handsome) FLAGS_is_handsome = false; std::cout << FLAGS_hobby << std::endl;
DEFINE_string(configuration_directory, "", "First directory in which configuration files are searched, " "second is always the Cartographer installation to allow " "including files from there.");
intmain(int argc, char** argv) { google::InitGoogleLogging(argv[0]); // INFO std::string str_info; // 文件名最后只能是 等级+下划线 str_info.append("/home/user/log/INFO_"); google::SetLogDestination(google::INFO, str_info.c_str()); LOG(INFO)<< "The is a info!"; // WARNING std::string str_warn; str_warn.append("/home/user/log/WARNING_"); google::SetLogDestination(google::WARNING, str_warn.c_str()); LOG(WARNING) << "The is a warning!";
structConstraint { structPose { transform::Rigid3d zbar_ij; double translation_weight; double rotation_weight; }; SubmapId submap_id; // 'i' in the paper. NodeId node_id; // 'j' in the paper. // Pose of the node 'j' relative to submap 'i'. Pose pose; // Differentiates between intra-submap (where node 'j' was inserted into // submap 'i') and inter-submap constraints (where node 'j' was not // inserted into submap 'i'). enumTag { INTRA_SUBMAP, INTER_SUBMAP } tag; };
for (size_t i = 0; i < insertion_submaps.size(); ++i) { const SubmapId submap_id = submap_ids[i]; // Even if this was the last node added to 'submap_id', the submap will // only be marked as finished in 'data_.submap_data' further below. CHECK( data_.submap_data.at(submap_id).state == SubmapState::kNoConstraintSearch ); data_.submap_data.at(submap_id).node_ids.emplace(node_id); // node_id的 scan pose 在子图中的 相对位置,就是后面的 intra constrait const transform::Rigid2d constraint_transform = constraints::ComputeSubmapPose(*insertion_submaps[i]).inverse() * local_pose_2d; /* 遍历matching结果的所有submap,其新增加的轨迹节点必定组成了其submap, 故其约束为 INTRA_SUBMAP 类型约束,可直接将相对位置加入约束队列中 */ data_.constraints.push_back( Constraint{ submap_id, node_id, { transform::Embed3D(constraint_transform), options_.matcher_translation_weight(), options_.matcher_rotation_weight()}, Constraint::INTRA_SUBMAP} ); }
// 新加入的节点与之前所有完成约束计算的子图,均计算一次约束 for (constauto& submap_id : finished_submap_ids) ComputeConstraint(node_id, submap_id); /* 每次新的子图完成,不再更新即不再添加新的轨迹节点时, 则需要计算此子图与所有优化位姿图node之间的约束 */ if (newly_finished_submap) { const SubmapId newly_finished_submap_id = submap_ids.front(); // We have a new completed submap, so we look into // adding constraints for old nodes for (constauto& node_id_data : optimization_problem_->node_data() ) { const NodeId& node_id = node_id_data.id; if (newly_finished_submap_node_ids.count(node_id) == 0) { ComputeConstraint(node_id, newly_finished_submap_id); } } }