在参数读取上中,我们说到了,lua的配置参数最后会通过std::tie传到两个变量中,分别是
- 类为NodeOptions的变量 node_options
- 类为TrajectoryOptions的变量trajectory_options
下面我们具体分析参数的读取过程
即从node_main.cc的
1 2
| std::tie(node_options, trajectory_options) = LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
|
LoadOptions
开始,下面是LoadOption的具体内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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}); const std::string code = file_resolver->GetFileContentOrDie(configuration_basename);
cartographer::common::LuaParameterDictionary lua_parameter_dictionary( code, std::move(file_resolver));
return std::make_tuple(CreateNodeOptions(&lua_parameter_dictionary), CreateTrajectoryOptions(&lua_parameter_dictionary)); }
|
在参数配置上中,我们简单说明了参数的返回,和加载结果。下面首先看一下如何获取配置文件所在的目录
构造ConfigurationFileResolver对象
1 2 3
| auto file_resolver = absl::make_unique<cartographer::common::ConfigurationFileResolver>( std::vector<std::string>{configuration_directory});
|
file_resolver是一个指向ConfigurationFileResolver类的只能指针,传入的参数是配置文件的目录,将其包装为一个vector,即只含有这一个目录的vector
1 2 3 4 5 6 7 8 9 10 11
| class ConfigurationFileResolver : public FileResolver { public: 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_; };
|
ConfigurationFileResolver继承于FileResolver类,FileResolver是一个接口(见下小节),需要实现GetFullPathOrDie和GetFileContentOrDie两个方法,在这里有一个构造函数,explicit,可以防止隐式转换?还有一个私有变量来存储configuration_files_directories。
FileResolver
1 2 3 4 5 6
| class FileResolver { public: virtual ~FileResolver() {} virtual std::string GetFullPathOrDie(const std::string& basename) = 0; virtual std::string GetFileContentOrDie(const std::string& basename) = 0; };
|
此FIleResolver是一个文件处理的接口,有两个纯虚函数
- GetFullPathOrDie: 获取路径
- GetFileContentOrDie:获取文件内容
构造函数ConfigurationFileResolver
1 2 3 4 5
| ConfigurationFileResolver::ConfigurationFileResolver( const std::vector<std::string>& configuration_files_directories) : configuration_files_directories_(configuration_files_directories) { configuration_files_directories_.push_back(kConfigurationFilesDirectory); }
|
构造函数中,一共两步骤
- 入参configurationfiles_directories传递给私有变量configuration_files_directories
- 把参数kConfigurationFilesDirectory加入到配置文件目录里面,即编译后的cartographer自己的配置文件的目录。因此每一次更改了lua文件之后,都需要重新编译才可以
因此其实私有成员变量configurationfiles_directories里面有两个目录地址
- 自己在launch文件里面指定的目录地址
- cartographer在编译之后的项目配置文件地址
kConfigurationFilesDirectory
注意,此参数是所在的文件目录在build_isolated/cartographer/common/config.h
,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #ifndef CARTOGRAPHER_COMMON_CONFIG_H_ #define CARTOGRAPHER_COMMON_CONFIG_H_
namespace cartographer { namespace common {
constexpr char kConfigurationFilesDirectory[] = "/home/kong/lixiang_carto/cartographer_detailed_comments_ws/install_isolated/share/cartographer/configuration_files"; constexpr char kSourceDirectory[] = "/home/kong/lixiang_carto/cartographer_detailed_comments_ws/src/cartographer";
} }
#endif
|
他是经过编译之后才有的文件,此文件是由src/cartographer/cartographer/common/config.h.cmake
文件生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
namespace cartographer { namespace common {
constexpr char kConfigurationFilesDirectory[] = "@CARTOGRAPHER_CONFIGURATION_FILES_DIRECTORY@"; constexpr char kSourceDirectory[] = "@PROJECT_SOURCE_DIR@";
} // namespace common } // namespace cartographer
|
在这里配置了两个参数,一个是CARTOGRAPHER_CONFIGURATION_FILES_DIRECTORY
,他表示编译之后cartographer配置文件的目录所在位置,因此每一次更改了lua文件之后,都需要重新编译才可以
下面的PROJECT_SOURCE_DIR
表示项目的源代码目录位置
获取文件内容GetFileContentOrDie
1 2 3
| const std::string code = file_resolver->GetFileContentOrDie(configuration_basename);
|
file_resolver是上一节中的ConfigurationFileResolver对象,在此调用GetFileContentOrDie来获得文件内容
1 2 3 4 5 6 7 8 9 10 11 12
| std::string ConfigurationFileResolver::GetFileContentOrDie( const std::string& basename) { CHECK(!basename.empty()) << "File basename cannot be empty." << basename;
const std::string filename = GetFullPathOrDie(basename); std::ifstream stream(filename.c_str());
return std::string((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>()); }
|
首先通过函数GetFullPathOrDie来获得文件basename所在的路径,然后读取完整路径下的文件内容。
GetFullPathOrDie
首先通过函数GetFullPathOrDie来获得文件basename所在的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| std::string ConfigurationFileResolver::GetFullPathOrDie( const std::string& basename) { for (const auto& path : configuration_files_directories_) { const std::string filename = path + "/" + basename; std::ifstream stream(filename.c_str()); if (stream.good()) { LOG(INFO) << "Found '" << filename << "' for '" << basename << "'."; return filename; } } LOG(FATAL) << "File '" << basename << "' was not found."; }
|
通过对两个配置路径(launch文件指定的以及cartographer自己的编译后的配置文件路径)进行for循环一个目录一个目录查看有没有这个文件,如果找到,就返回组合后的配置文件全路径
生成lua字典LuaParameterDictionary
1 2 3
| cartographer::common::LuaParameterDictionary lua_parameter_dictionary( code, std::move(file_resolver));
|
构造函数 LuaParameterDictionary
1 2 3 4 5 6 7 8 9 10
|
LuaParameterDictionary::LuaParameterDictionary( const std::string& code, std::unique_ptr<FileResolver> file_resolver) : LuaParameterDictionary(code, ReferenceCount::YES, std::move(file_resolver)) {}
|
这里传入的是字符串类型的配置文件,一个指向FileResolver的unique_ptr,下面是调用了另外一个构造函数,对lua文件进行解析,因为下面的内容需要对lua文件进行操作,就不再深究。实际自己书写的时候,只要搞一下yaml就可以了
创建结点CreateNodeOptions
1 2 3 4
|
return std::make_tuple(CreateNodeOptions(&lua_parameter_dictionary), CreateTrajectoryOptions(&lua_parameter_dictionary));
|
最后是把参数分别赋值给两个参数类中,在上一节中已经说明
添加自己的参数
- lua文件里面的options中添加变量
- 判断自己的变量应该是属于NodeOptions还是TrajectoryOptions(一条轨迹的基础参数配置)
- 在相应的Create*Options函数里,添加对应的Option.xx = xxx
这样就可以完成新参数的读取了