cartographer源码解析(二)node_main.cc文件详解

描述

cartographer学习笔记(二)

这一篇主要分析node_main.cc的代码

主函数main()

  • 主函数
int main(int argc, char** argv) {
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  CHECK(!FLAGS_configuration_directory.empty())
      << "-configuration_directory is missing.";
  CHECK(!FLAGS_configuration_basename.empty())
      << "-configuration_basename is missing.";

  ::ros::init(argc, argv, "cartographer_node");
  ::ros::start();

  cartographer_ros::ScopedRosLogSink ros_log_sink;
  cartographer_ros::Run();
  ::ros::shutdown();
}
google::InitGoogleLogging(argv[0]); // 初始化 glog
google::ParseCommandLineFlags(&argc, &argv, true); // 初始化 gflags

都是google开发的glog的函数,两句话是初始化,用于输出log信息,标准的分级为:INFO, WARNING, ERROR, FATAL。不同级别的日志信息会输出到不同文件,同时高级别的日志也会写入到低级别中。

LOG(INFO) << "Hello, GOOGLE!";  // INFO 级别的日志
LOG(ERROR) << "ERROR, GOOGLE!";  // ERROR 级别的日志

gflags用于在shell里面设置gflags的值,通过命令行参数 -v 50 这样子来指定 VLOG 输出的级别,-v 50 意味着只有小于 50 以下的 VLOG 才会被输出(这里不会影响 LOG(INFO)这些)

LOG(INFO) << "Hello, GOOGLE!";
VLOG(100) << "VLOG INFO 100";
VLOG(50) << "VLOG INFO 50";
VLOG(10) << "VLOG INFO 10";

我在整个项目里搜索了一下,没有使用过VLOG(100)这种形式,也就是说cartographer是没有日志级别的

CHECK(!FLAGS_configuration_directory.empty())
    << "-configuration_directory is missing.";
CHECK(!FLAGS_configuration_basename.empty())
    << "-configuration_basename is missing.";

我没找到CHECK()函数的定义,简单分析,如果CHECK()里面是false,则打印输出,大概是这个意思

::ros::init(argc, argv, "cartographer_node");
::ros::start();

节点初始化,节点命名为cartographer_node
节点启动

cartographer_ros::ScopedRosLogSink ros_log_sink;
cartographer_ros::Run();

ScopedRosLogSink的定义在cartographer_ros/ros_log_sink.h文件中

namespace cartographer_ros {
// Makes Google logging use ROS logging for output while an instance of this
// class exists.
class ScopedRosLogSink : public ::google::LogSink {
 public:
  ScopedRosLogSink();
  ~ScopedRosLogSink() override;

  void send(::google::LogSeverity severity, const char* filename,
            const char* base_filename, int line, const struct std::tm* tm_time,
            const char* message, size_t message_len) override;

  void WaitTillSent() override;

 private:
  bool will_die_;
};
}  // namespace cartographer_ros

使谷歌日志记录(glog)使用ROS日志记录输出,这是一个实例类存在,暂时没有太仔细去看,因为我再一次没有在代码中找到ros_log_sink,也就是说,这个类根本没有使用。

::ros::shutdown();

关闭节点

Run()


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.");

namespace cartographer_ros {
namespace {

void Run() {
  constexpr double kTfBufferCacheTimeInSeconds = 10.;
  tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
  tf2_ros::TransformListener tf(tf_buffer);
  NodeOptions node_options;
  TrajectoryOptions trajectory_options;
  std::tie(node_options, trajectory_options) =
      LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);

  auto map_builder =
      cartographer::mapping::CreateMapBuilder(node_options.map_builder_options);
  Node node(node_options, std::move(map_builder), &tf_buffer,
            FLAGS_collect_metrics);
  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();

  node.FinishAllTrajectories();
  node.RunFinalOptimization();

  if (!FLAGS_save_state_filename.empty()) {
    node.SerializeState(FLAGS_save_state_filename,
                        true /* include_unfinished_submaps */);
  }
}

}  // namespace
}  // namespace cartographer_ros

DEFINE_boolDEFINE_string没什么可说的,google的api,功能是读取shell命令的参数

constexpr double kTfBufferCacheTimeInSeconds = 10.;里的constexpr关键字是C++11/14编译规则,简单来说就是让编译器在编译时就编译成字面值
具体的可以自行去学习,

tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};

使用tf2消息的大部分工作通过tf2_ros::Buffer类完成,其通过tf2_ros::TransformListener完成对tf2_ros::Buffer类的初始化和构造,并订阅相应tf消息,后续操作都是用的tf2_ros::Buffer类的成员函数完成:

整句话的意思是,tf变换的历史要保存10秒

tf2_ros::TransformListener tf(tf_buffer);
负责tf数据接收

节点参数和轨迹参数

NodeOptions node_options;
TrajectoryOptions trajectory_options;

定义在文件cartographer_ros/node_options.h

namespace cartographer_ros {

// 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

定义在文件cartographer_ros/trajectory_options.h

namespace cartographer_ros {

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

加载参数

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

std::tie把node_options和trajectory_options整合成一个std::tuple,从而实现批量赋值(node_options和 trajectory_options一起赋值)

建图指针

auto map_builder =
      cartographer::mapping::CreateMapBuilder(node_options.map_builder_options);

::cartographer::mapping::proto::MapBuilderOptions map_builder_options定义在cartographer/cartographer/mapping/map_builder_interface.h

cartographer::mapping::CreateMapBuilder定义在cartographer/cartographer/mapping/map_builder.h中,构造函数就只有一个输入变量,就是map_builder_options

Node node(node_options, std::move(map_builder), &tf_buffer,
            FLAGS_collect_metrics);

Node定义在cartographer_ros/node.h

  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();

  node.FinishAllTrajectories();
  node.RunFinalOptimization();

  if (!FLAGS_save_state_filename.empty()) {
    node.SerializeState(FLAGS_save_state_filename,
                        true /* include_unfinished_submaps */);
  }

如果node.LoadStatenode.StartTrajectoryWithDefaultTopicsnode.FinishAllTrajectoriesnode.RunFinalOptimizationnode.SerializeState的定义都在cartographer_ros/node.h

FAILED: CMakeFiles/cartographer.transform.timestamped_transform_test.dir/cartographer/transform/timestamped_transform_test.cc.o /usr/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_IOSTREAMS_DYN_LINK -DGFLAGS_IS_A_DLL=0 -I../cartographer -I. -I../ -isystem /usr/include/eigen3 -isystem /usr/include/lua5.2 -O3 -DNDEBUG -pthread -fPIC -Wall -Wpedantic -Werror=format-security -Werror=missing-braces -Werror=reorder -Werror=return-type -Werror=switch -Werror=uninitialized -O3 -DNDEBUG -pthread -fPIC -Wall -Wpedantic -Werror=format-security -Werror=missing-braces -Werror=reorder -Werror=return-type -Werror=switch -Werror=uninitialized -O3 -DNDEBUG -std=gnu++11 -MD -MT CMakeFiles/cartographer.transform.timestamped_transform_test.dir/cartographer/transform/timestamped_transform_test.cc.o -MF CMakeFiles/cartographer.transform.timestamped_transform_test.dir/cartographer/transform/timestamped_transform_test.cc.o.d -o CMakeFiles/cartographer.transform.timestamped_transform_test.dir/cartographer/transform/timestamped_transform_test.cc.o -c ../cartographer/transform/timestamped_transform_test.cc In file included from ../cartographer/transform/timestamped_transform_test.cc:17: ../cartographer/transform/timestamped_transform.h:21:10: fatal error: cartographer/transform/proto/timestamped_transform.pb.h: No such file or directory 21 | #include "cartographer/transform/proto/timestamped_transform.pb.h" | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated. [44/380] Building CXX object CMakeFiles/cartographer.sensor.internal.voxel_filter_test.dir/cartographer/sensor/internal/voxel_filter_test.cc.o
07-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值