简述
本次主要针对node_options.h
,node_options.cc
,trajectory_options.h
和trajectory_options.cc
文件进行讲解,这两个文件主要完成了从配置文件目录下的基础文件名所指定的文件中读取配置的功能。
node_options.h
这里主要完成了对NodeOptions
结构体,创建NodeOptions
函数以及使用配置文件目录和基础配置文件名获取配置的对外接口的声明
// Top-level options of Cartographer's ROS integration.
struct NodeOptions {
::cartographer::mapping::proto::MapBuilderOptions map_builder_options;
std::string map_frame;
double lookup_transform_timeout_sec;
double submap_publish_period_sec;
double pose_publish_period_sec;
double trajectory_publish_period_sec;
bool publish_to_tf = true;
bool publish_tracked_pose = false;
bool use_pose_extrapolator = true;
};
NodeOptions CreateNodeOptions(
::cartographer::common::LuaParameterDictionary* lua_parameter_dictionary);
std::tuple<NodeOptions, TrajectoryOptions> LoadOptions(
const std::string& configuration_directory,
const std::string& configuration_basename);
} // namespace cartographer_ros
这里的NodeOptions
中主要包含了后端优化位姿图优化的相关配置以及cartographer_ros
集成中所用到的一些顶层配置。
node_options.cc
首先是对外的根据配置文件目录和基础配置文件名读取配置的接口函数
/**
* @brief 加载lua配置文件中的参数
*
* @param[in] configuration_directory 配置文件所在目录
* @param[in] configuration_basename 配置文件的名字
* @return std::tuple<NodeOptions, TrajectoryOptions> 返回节点的配置与轨迹的配置
*/
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));
}
} // namespace cartographer_ros
其中主要完成了以下的步骤:
- 使用配置文件夹目录创建了配置文件解析器
其中的
cartographer::common::ConfigurationFileResolver
的官方注释为:
为“LuaParameterDictionary”设计的为从磁盘读取文件的“FileResolver”。它搜索“configuration_files_directories”以找到请求的文件名。 最后搜索的地方总是与 Cartographer 一起安装的“configuration_files/”目录。 它包含各种 Cartographer 组件的合理配置,这为新平台的适配提供良好的开端。
- 使用配置文件解析器从配置文件目录下的以基础文件名命名的文件中读取数据,并返回配置文件的数据流
- 使用数据流生成一个lua字典
- 使用lua字典创建
NodeOptions
和TrajectoryOptions
接下来,接下来就是这个源文件中最关键的从lua中创建NodeOptions
的函数
NodeOptions CreateNodeOptions(
::cartographer::common::LuaParameterDictionary* const
lua_parameter_dictionary) {
NodeOptions options;
// 根据lua字典中的参数, 生成protobuf的序列化数据结构 proto::MapBuilderOptions
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;
}
trajectory_options.h
这里主要完成了对TrajectoryOptions
结构体和创建TrajectoryOptions
的函数的声明
// 一条轨迹的基础参数配置
struct TrajectoryOptions {
::cartographer::mapping::proto::TrajectoryBuilderOptions
trajectory_builder_options;
std::string tracking_frame;
std::string published_frame;
std::string odom_frame;
bool provide_odom_frame;
bool use_odometry;
bool use_nav_sat;
bool use_landmarks;
bool publish_frame_projected_to_2d;
int num_laser_scans;
int num_multi_echo_laser_scans;
int num_subdivisions_per_laser_scan;
int num_point_clouds;
double rangefinder_sampling_ratio;
double odometry_sampling_ratio;
double fixed_frame_pose_sampling_ratio;
double imu_sampling_ratio;
double landmarks_sampling_ratio;
};
TrajectoryOptions CreateTrajectoryOptions(
::cartographer::common::LuaParameterDictionary* lua_parameter_dictionary);
} // namespace cartographer_ros
这里的TrajectoryOptions
中主要包含了前端配准的相关配置。
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.";
}
这里的检查主要是为了确保
num_subdivisions_per_laser_scan
大于等于1,这非常容易理解,一次扫描在cartographer
的使用中可以被拆分成多次扫描来发送,以提高鲁棒性,但是不可能被拆分为少于一次。options.num_laser_scans + options.num_multi_echo_laser_scans + options.num_point_clouds
大于等于1,由于cartographer
是基于激光雷达的SLAM
,那么一定要接受至少一个激光雷达传感器的信息。
接下来就是这个源文件中最关键的从lua中创建TrajectoryOptions
的函数
/**
* @brief 读取lua文件内容, 将lua文件的内容赋值给TrajectoryOptions
*
* @param[in] lua_parameter_dictionary lua字典
* @return TrajectoryOptions
*/
TrajectoryOptions CreateTrajectoryOptions(
::cartographer::common::LuaParameterDictionary* const
lua_parameter_dictionary) {
TrajectoryOptions options;
options.trajectory_builder_options =
::cartographer::mapping::CreateTrajectoryBuilderOptions(
lua_parameter_dictionary->GetDictionary("trajectory_builder").get());
options.tracking_frame =
lua_parameter_dictionary->GetString("tracking_frame");
options.published_frame =
lua_parameter_dictionary->GetString("published_frame");
options.odom_frame = lua_parameter_dictionary->GetString("odom_frame");
options.provide_odom_frame =
lua_parameter_dictionary->GetBool("provide_odom_frame");
options.use_odometry = lua_parameter_dictionary->GetBool("use_odometry");
options.use_nav_sat = lua_parameter_dictionary->GetBool("use_nav_sat");
options.use_landmarks = lua_parameter_dictionary->GetBool("use_landmarks");
options.publish_frame_projected_to_2d =
lua_parameter_dictionary->GetBool("publish_frame_projected_to_2d");
options.num_laser_scans =
lua_parameter_dictionary->GetNonNegativeInt("num_laser_scans");
options.num_multi_echo_laser_scans =
lua_parameter_dictionary->GetNonNegativeInt("num_multi_echo_laser_scans");
options.num_subdivisions_per_laser_scan =
lua_parameter_dictionary->GetNonNegativeInt(
"num_subdivisions_per_laser_scan");
options.num_point_clouds =
lua_parameter_dictionary->GetNonNegativeInt("num_point_clouds");
options.rangefinder_sampling_ratio =
lua_parameter_dictionary->GetDouble("rangefinder_sampling_ratio");
options.odometry_sampling_ratio =
lua_parameter_dictionary->GetDouble("odometry_sampling_ratio");
options.fixed_frame_pose_sampling_ratio =
lua_parameter_dictionary->GetDouble("fixed_frame_pose_sampling_ratio");
options.imu_sampling_ratio =
lua_parameter_dictionary->GetDouble("imu_sampling_ratio");
options.landmarks_sampling_ratio =
lua_parameter_dictionary->GetDouble("landmarks_sampling_ratio");
CheckTrajectoryOptions(options);
return options;
}