C++ Cartographer加载配置文件过程介绍

 更新时间:2023年03月17日 08:29:00   作者:虾眠不觉晓,  
这篇文章主要介绍了Cartographer加载配置文件过程,谷歌优秀的激光SLAM开源框架Cartographer算法简单,但是程序部分太多需要学习的地方了,不论是整体框架的结构,还是数据的使用,都是非常优美的

在node_main.cc文件中,有如下代码

  std::tie(node_options, trajectory_options) =
      LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);

std::tie作用是同时对多个变量赋值,但是只能个从元组tuple赋值,在node_options.cc中有如下定义:

std::tuple<NodeOptions, TrajectoryOptions> LoadOptions(
    const std::string& configuration_directory,
    const std::string& configuration_basename) {
  // 获取配置文件所在的目录
  auto file_resolver =
      absl::make_unique<cartographer::common::ConfigurationFileResolver>(std::vector<std::string>{configuration_directory});
  // 读取配置文件内容到code中
  const std::string code =
      file_resolver->GetFileContentOrDie(configuration_basename);
  // 根据给定的字符串, 生成一个lua字典
  cartographer::common::LuaParameterDictionary lua_parameter_dictionary(
      code, std::move(file_resolver));
  // 创建元组tuple,元组定义了一个有固定数目元素的容器, 其中的每个元素类型都可以不相同
  // 将配置文件的内容填充进NodeOptions与TrajectoryOptions, 并返回
  return std::make_tuple(CreateNodeOptions(&lua_parameter_dictionary),
                         CreateTrajectoryOptions(&lua_parameter_dictionary));
}

这返回值为元组tuple.

ps:vector初始化:

要注意“()”和“{}”这样的初始化情况,比如:

std::vector<int> nVec(10,1);    // 包含10个元素,且值为1

std::vector<int> nVec{10,1};    // 包含2个元素,值分别为10,1

CreateNodeOptions,是定义在node_options.h文件里的一个结构体,同理CreateTrajectoryOptions,里面的参数是由lua文件传入的.

trajectoryoptions只在开始轨迹的时候用了,见node_main.cc

在trajectory_options.cc中有如下定义

void CheckTrajectoryOptions(const TrajectoryOptions& options) {
  CHECK_GE(options.num_subdivisions_per_laser_scan, 1);
  CHECK_GE(options.num_laser_scans + options.num_multi_echo_laser_scans +
               options.num_point_clouds,
           1)
      << "Configuration error: 'num_laser_scans', "
         "'num_multi_echo_laser_scans' and 'num_point_clouds' are "
         "all zero, but at least one is required.";
}

这个说明是要至少一个激光,或者激光+超声雷达+点云的个数要>1才能运行程序

NodeOptions CreateNodeOptions(
    ::cartographer::common::LuaParameterDictionary* const
        lua_parameter_dictionary) {
  NodeOptions options;
  options.map_builder_options =
      ::cartographer::mapping::CreateMapBuilderOptions(
          lua_parameter_dictionary->GetDictionary("map_builder").get());
  options.map_frame = lua_parameter_dictionary->GetString("map_frame");
  options.lookup_transform_timeout_sec =
      lua_parameter_dictionary->GetDouble("lookup_transform_timeout_sec");
  options.submap_publish_period_sec =
      lua_parameter_dictionary->GetDouble("submap_publish_period_sec");
  options.pose_publish_period_sec =
      lua_parameter_dictionary->GetDouble("pose_publish_period_sec");
  options.trajectory_publish_period_sec =
      lua_parameter_dictionary->GetDouble("trajectory_publish_period_sec");
  if (lua_parameter_dictionary->HasKey("publish_to_tf")) {
    options.publish_to_tf =
        lua_parameter_dictionary->GetBool("publish_to_tf");
  }
  if (lua_parameter_dictionary->HasKey("publish_tracked_pose")) {
    options.publish_tracked_pose =
        lua_parameter_dictionary->GetBool("publish_tracked_pose");
  }
  if (lua_parameter_dictionary->HasKey("use_pose_extrapolator")) {
    options.use_pose_extrapolator =
        lua_parameter_dictionary->GetBool("use_pose_extrapolator");
  }
  return options;
}

上面的程序是根据lua字典中的参数, 生成protobuf的序列化数据结构, 结构体NodeOptions定义在头文件中,其中有个元素为::cartographer::mapping::proto::MapBuilderOptions map_builder_options;是proto类型,在上述程序中的第一个参数被赋值

在node_options.cc有个类ConfigurationFileResolver,定义在configuration_file_resolver.h中,公有继承来自FileResolver

class ConfigurationFileResolver : public FileResolver{
 public:
  // c++11: explicit关键字 的作用就是防止类构造函数的隐式自动转换
  explicit ConfigurationFileResolver(
      const std::vector<std::string>& configuration_files_directories);
  std::string GetFullPathOrDie(const std::string& basename) override;
  std::string GetFileContentOrDie(const std::string& basename) override;
 private:
  std::vector<std::string> configuration_files_directories_;
};

FileResolver定义在lua_parameter_dictionary.h中:

class FileResolver {
 public:
  virtual ~FileResolver() {}
  virtual std::string GetFullPathOrDie(const std::string& basename) = 0;
  virtual std::string GetFileContentOrDie(const std::string& basename) = 0;
};

这个都是虚函数,只是个接口

cartographer经常有对接口类的继承

ConfigurationFileResolver的构造函数在configuration_file_resolver.cc里面

ConfigurationFileResolver::ConfigurationFileResolver(
    const std::vector<std::string>& configuration_files_directories)
    : configuration_files_directories_(configuration_files_directories) {
  configuration_files_directories_.push_back(kConfigurationFilesDirectory);
}

这个函数有个初始化列表,可以看到最终传入的参数是kConfigurationFilesDirectory,这个参数定义在config.h.这个文件里,这个文件是config.h.cmake编译生成的,如下内容

namespace cartographer {
namespace common {
constexpr char kConfigurationFilesDirectory[] =
    "@CARTOGRAPHER_CONFIGURATION_FILES_DIRECTORY@";
constexpr char kSourceDirectory[] = "@PROJECT_SOURCE_DIR@";
}  // namespace common
}  // namespace cartographer

一个是定义工程配置文件的文件夹,一个是工程地址的目录,在config.h中会生成匹配自己电脑的字符串地址.那么上面的ConfigurationFileResolver的构造函数就是为了传入自己电脑的某些目录地址..

GetFullPathOrDie:遍历整个文件夹文件名看看能不能找到相应文件,如不能就报错

GetFileContentOrDie的作用是看传入的地址变量是不是空的,然后通过GetFullPathOrDie暴力查找是否在当前目录中存在,然后读取配置文件转为string格式然后返回.

再回到node_options.cc中

接下来是读取配置文件到code中,然后从code和之前读取的file_resolver生成一个lua字典

lua是个类似cpp的程序语言,定义在lua_parameter_dictionary.cc中,不细说了

如果想自己通过lua文件写入一些配置和参数,步骤如下

在自己写的lua配置文件中写入自己的参数,如th=1.1,

在想一下这个th是属于node_options还是trajectory_options,如在node_options中,则在node_options.h中定义好自己的数据类型和初始值,如double th = 1.1;

然后在node_options.cc中写入

  if (lua_parameter_dictionary->HasKey("th")) {
    options.th =
        lua_parameter_dictionary->GetDouble("th");
  }

到此这篇关于C++ Cartographer加载配置文件过程介绍的文章就介绍到这了,更多相关C++ Cartographer 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • matlab鸟群算法求解车间调度问题详解及实现源码

    matlab鸟群算法求解车间调度问题详解及实现源码

    这篇文章主要为大家介绍了matlab鸟群算法求解车间调度的问题分析及实现源码,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • C语言 实现N阶乘的程序代码

    C语言 实现N阶乘的程序代码

    本篇文章是对c语言中实现N阶乘的程序代码进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Cocos2d-x人物动作类实例

    Cocos2d-x人物动作类实例

    这篇文章主要介绍了Cocos2d-x人物动作类实例,本文用大量代码和图片讲解Cocos2d-x中的动作,代码中同时包含大量注释说明,需要的朋友可以参考下
    2014-09-09
  • C语言实现循环链表

    C语言实现循环链表

    这篇文章主要为大家详细介绍了C语言实现循环链表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C++ Explicit关键字详细解析

    C++ Explicit关键字详细解析

    以下是对C++中Explicit关键字的用法进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2013-09-09
  • C语言头文件<string.h>函数详解

    C语言头文件<string.h>函数详解

    本文主要介绍了C语言头文件<string.h>函数详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • C++中volatile关键字的使用详解以及常见的误解

    C++中volatile关键字的使用详解以及常见的误解

    volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统,硬件或者其他线程等
    2020-01-01
  • C语言实现单词助手功能

    C语言实现单词助手功能

    这篇文章主要为大家详细介绍了C语言实现单词小助手,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • C++中4种管理数据内存的方式总结

    C++中4种管理数据内存的方式总结

    根据用于分配内存的方法,C++中有3中管理数据内存的方式:自动存储、静态存储和动态存储。在存在时间的长短方面,以这三种方式分配的数据对象各不相同。下面简要介绍这三种类型
    2022-09-09
  • C语言深入分析递归函数的实现

    C语言深入分析递归函数的实现

    递归(recursive)函数是“自己调用自己”的函数,无论是采用直接或间接调用方式。间接递归意味着函数调用另一个函数(然后可能又调用第三个函数等),最后又调用第一个函数。因为函数不可以一直不停地调用自己,所以递归函数一定具备结束条件
    2022-04-04

最新评论