cartographer源码分析(1)node_main.cc

node_main.cc作为cartographer的主函数,是整个cartographer的入口。C++基础太差,结合了很多不同文章的理解,对node_main.cc文件进行了简单的注释:


#include "absl/memory/memory.h"
#include "cartographer/mapping/map_builder.h"
#include "cartographer_ros/node.h"
#include "cartographer_ros/node_options.h"
#include "cartographer_ros/ros_log_sink.h"
#include "gflags/gflags.h"
#include "tf2_ros/transform_listener.h"
//设置命令参数变量
//gflags支持多种不同的数据类型,通过DEFINE_type形式的宏来体现。支持的数据类型有bool, 
//string, int32, int64, uint64, double等。 上面的代码片段中通过DEFINE_string和DEFINE_bool定义
//了string和bool类型的参数。这类的宏有三个参数,依次是运行参数名、缺省值、帮助信息。
DEFINE_bool(collect_metrics, false,
            "Activates the collection of runtime metrics. If activated, the "
            "metrics can be accessed via a ROS service.");
DEFINE_string(configuration_directory, "",
              "First directory in which configuration files are searched, "
              "second is always the Cartographer installation to allow "
              "including files from there.");
DEFINE_string(configuration_basename, "",
              "Basename, i.e. not containing any directory prefix, of the "
              "configuration file.");
DEFINE_string(load_state_filename, "",
              "If non-empty, filename of a .pbstream file to load, containing "
              "a saved SLAM state.");
DEFINE_bool(load_frozen_state, true,
            "Load the saved state as frozen (non-optimized) trajectories.");
DEFINE_bool(
    start_trajectory_with_default_topics, true,
    "Enable to immediately start the first trajectory with default topics.");
DEFINE_string(
    save_state_filename, "",
    "If non-empty, serialize state and write it to disk before shutting down.");
//当参数定义之后,就可以通过FLAGS_param_name的形式访问对应的参数了。比如刚刚在main函数中,
//通过FLAGS_configuration_directory获取配置文件所在的目录, FLAGS_configuration_basename记
//录了配置文件的名字。这里的参数对象的定义和使用都是在同一个源文件中的没有什么特殊的操作,
//但是如果需要在其他文件中使用这里的参数对象, 还需要先通过宏DECLARE_type来声明这些参数对象,
//再使用。
namespace cartographer_ros {
namespace {

void Run() {
  //使用tf2定义了ROS的坐标系统监听器,它用于监听ROS系统中发布的坐标变换(tf)消息,
  //并将之缓存在tf_buffer中。 kTfBufferCacheTimeInSeconds描述了缓存的时间长度。
  //tf是ROS系统中常用的坐标变换库,它通过订阅和发布坐标变换消息来维护系统的坐标系。
  //我们在机器人操作系统——Robot Operating System(ROS)系列文章中介绍过早期的tf广播者
  //和监听者的使用方式。目前ROS已经不推荐使用tf库了,它们在推广tf2的使用,但其基本思想都是一样的,
  //而且同一个系统中还是可以运行两种库的。
  constexpr double kTfBufferCacheTimeInSeconds = 10.;
  tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
  tf2_ros::TransformListener tf(tf_buffer);
  //接着函数Run调用定义在node_options.cc中的函数LoadOptions加载配置文件。对应main函数中判断的两个文件
  NodeOptions node_options;
  TrajectoryOptions trajectory_options;
  std::tie(node_options, trajectory_options) =
      LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
  //然后构建了建图器map_builder和ROS封装对象node。
  auto map_builder = absl::make_unique<cartographer::mapping::MapBuilder>(
      node_options.map_builder_options);
  Node node(node_options, std::move(map_builder), &tf_buffer,
            FLAGS_collect_metrics);
  //如果在运行cartographer_node的时候通过命令行参数load_state_filename指定了保存有SLAM状态的文件,
  //那么就加载该状态文件继续运行。参数start_trajectory_with_default_topics的作用,可能是使用默认的主题直接开始第一条轨迹的跟踪。
  if (!FLAGS_load_state_filename.empty()) {
    node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
  }

  if (FLAGS_start_trajectory_with_default_topics) {
    node.StartTrajectoryWithDefaultTopics(trajectory_options);
  }
  //消息循环回调
  ::ros::spin();
  //如果在ROS的逻辑循环过程中,触发了退出机制,Run函数就会接着执行如下的语句,完成最终的路径和地图的优化。
  node.FinishAllTrajectories();
  node.RunFinalOptimization();
  //最后如果运行参数要求保存系统状态,则将当前的系统状态存到参数save_state_filename所指定的文件中。
  if (!FLAGS_save_state_filename.empty()) {
    node.SerializeState(FLAGS_save_state_filename,
                        true /* include_unfinished_submaps */);
  }
}

}  // namespace
}  // namespace cartographer_ros

int main(int argc, char** argv) {
  //gflags作用:简化命令行参数的解析,作用同get_opt()类的操作。
  google::InitGoogleLogging(argv[0]);//初始化glog库,参数是第一个命令行参数即程序名
  google::ParseCommandLineFlags(&argc, &argv, true);//调用解析函数
  //对应于launch文件中的参数路径?应该是判断参数是否存在
  //检查是否在运行参数中指定了配置文件和目录,若没有程序会报错退出。
  CHECK(!FLAGS_configuration_directory.empty())
      << "-configuration_directory is missing.";
  CHECK(!FLAGS_configuration_basename.empty())
      << "-configuration_basename is missing.";
  //初始化ros,创建cartographer_node节点并运行
  ::ros::init(argc, argv, "cartographer_node");
  ::ros::start();
  //ros_log_sink作为一个局部变量定义在这里似乎没什么意义。暂时不知道
  cartographer_ros::ScopedRosLogSink ros_log_sink;
  cartographer_ros::Run();
  ::ros::shutdown();
}

其实主要参考的是下面的链接,感觉博主写的特别详细,有兴趣的可以细读:

https://gaoyichao.com/Xiaotu/

你可能感兴趣的:(cartographer)