voidPoseGraph2D::RunOptimization() { if (optimization_problem_->submap_data().empty() ) return; // std::unique_ptr<optimization::OptimizationProblem2D> optimization_problem_; // No other thread is accessing the optimization_problem_, // data_.constraints, data_.frozen_trajectories and data_.landmark_nodes // when executing Solve. // 调用优化,Ceres在这里面,由于耗时间,故没加锁,防止阻塞其他线程 optimization_problem_->Solve(data_.constraints, GetTrajectoryStates(), data_.landmark_nodes);
// Extrapolate all point cloud poses that were not included in the // 'optimization_problem_' yet. 注意是已经加入tarjectory但是还没有进行优化的新Node // 由于使用采样器建立约束,有的node没有建立约束,其pose就不会被优化 // 因此,要通过已经优化的位姿转换关系来修正所有的node
我的理解是,求inter约束也是一个 scan to map 的过程,找到和点云最相似的不同时间的子图,也就是找回环。其实是和lidar_localization的后端用NDT找关键帧的匹配是类似的,但是cartographer是点云和栅格地图匹配,不像点云匹配那样直观,分支定界的score就像NDT匹配的score,不过前者越大越好,后者越小越好。
// Use the CSM estimate as both the initial and previous pose. // This has the effect that, in the absence of better information, // we prefer the original CSM estimate. ceres::Solver::Summary unused_summary; // ceres更新pose_estimate,获得节点在local map中的最优位姿 ceres_scan_matcher_.Match(pose_estimate.translation(), pose_estimate, constant_data->filtered_gravity_aligned_point_cloud, *submap_scan_matcher.grid, &pose_estimate, &unused_summary); // 计算得到node相对子图的位姿 const transform::Rigid2d constraint_transform = ComputeSubmapPose(*submap).inverse() * pose_estimate; constraint->reset(new Constraint{submap_id, node_id, { transform::Embed3D(constraint_transform), options_.loop_closure_translation_weight(), options_.loop_closure_rotation_weight() }, Constraint::INTER_SUBMAP} );
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.");
Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作类似。 每个级别的日志除了输出到对应日志文件中,还输出到每个低级别日志文件中。默认ERROR和FATAL消息除了输出到日志文件中之外,还会输出到标准错误中 每个级别都对应有相应的日志文件,文件默认存放在临时文件中,Linux是 /tmp。运行cartographer之后,可以在/tmp里看到
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!";