打开cartographer_ros下的node_main.cc
main函数
首先看一下main函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| int main(int argc, char** argv) {
// note: 初始化glog库 google::InitGoogleLogging(argv[0]); // 使用gflags进行参数的初始化. 其中第三个参数为remove_flag // 如果为true, gflags会移除parse过的参数, 否则gflags就会保留这些参数, 但可能会对参数顺序进行调整. // 开始解析参数 google::ParseCommandLineFlags(&argc, &argv, true);
/** * @brief glog里提供的CHECK系列的宏, 检测某个表达式是否为真 * 检测expression如果不为真, 则打印后面的description和栈上的信息 * 然后退出程序, 出错后的处理过程和FATAL比较像. */ CHECK(!FLAGS_configuration_directory.empty()) << "-configuration_directory is missing."; CHECK(!FLAGS_configuration_basename.empty()) << "-configuration_basename is missing.";
// ros节点的初始化 ::ros::init(argc, argv, "cartographer_node");
// 一般不需要在自己的代码中显式调用 // 但是若想在创建任何NodeHandle实例之前启动ROS相关的线程, 网络等, 可以显式调用该函数. ::ros::start();
// 使用ROS_INFO进行glog消息的输出 cartographer_ros::ScopedRosLogSink ros_log_sink;
// 开始运行cartographer_ros cartographer_ros::Run();
// 结束ROS相关的线程, 网络等 ::ros::shutdown(); }
|
如果不进行初始化,那么就无法使用glog库
1 2
| // note: 初始化glog库 google::InitGoogleLogging(argv[0]);
|
这里开始解析参数,即就是DEFINE_bool这里的参数,前面加上FALGS的操作
1 2 3 4
| // 使用gflags进行参数的初始化. 其中第三个参数为remove_flag // 如果为true, gflags会移除parse过的参数, 否则gflags就会保留这些参数, 但可能会对参数顺序进行调整. // 开始解析参数 google::ParseCommandLineFlags(&argc, &argv, true);
|
对ros结点进行初始化,并且命名为cartographer_node,定义自己的log系统
1 2 3 4 5 6 7 8 9
| // ros节点的初始化 ::ros::init(argc, argv, "cartographer_node");
// 一般不需要在自己的代码中显式调用 // 但是若想在创建任何NodeHandle实例之前启动ROS相关的线程, 网络等, 可以显式调用该函数. ::ros::start();
// 使用ROS_INFO进行glog消息的输出 cartographer_ros::ScopedRosLogSink ros_log_sink;
|
最后开始运行cartographer_ros
1
| cartographer_ros::Run();
|
Run函数
开启监听tf的独立线程,开启监听tf独立的线程
1 2 3
| tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)}; // 开启监听tf的独立线程,开启监听tf独立的线程 tf2_ros::TransformListener tf(tf_buffer);
|
根据Lua配置文件中的内容, 为node_options, trajectory_options 赋值
1 2
| std::tie(node_options, trajectory_options) = LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
|
建立 map_builder类,map_build类是一个完整的slam, 包括前端和后端.auto的变量必须要赋值。
1 2
| auto map_builder = cartographer::mapping::CreateMapBuilder(node_options.map_builder_options);
|
对Node类进行初始化,将ROS的topic传入SLAM, 也就是MapBuilder
1 2
| Node node(node_options, std::move(map_builder), &tf_buffer, FLAGS_collect_metrics);
|
加载pbstream
1 2 3 4
| // 如果加载了pbstream文件, 就执行这个函数 if (!FLAGS_load_state_filename.empty()) { node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state); }
|
最后结束的时候还会有一次全局优化
1 2
| // 当所有的轨迹结束时, 再执行一次全局优化 node.RunFinalOptimization();
|
std::tie
这个函数的作用就和Python的多个变量赋值一样,但是他只接受元祖作为赋值
1 2
| std::tie(node_options, trajectory_options) = LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
|
在这里,LoadOptions的返回值为std::tuple,注意return,是通过make_tuple生成的tuple
1 2 3 4 5 6 7 8
| std::tuple<NodeOptions, TrajectoryOptions> LoadOptions( const std::string& configuration_directory, const std::string& configuration_basename) { ... return std::make_tuple(CreateNodeOptions(&lua_parameter_dictionary), CreateTrajectoryOptions(&lua_parameter_dictionary)); }
|