(02)Cartographer源码无死角解析-(06) 参数详解与备注→调参查阅使用

  • Post author:
  • Post category:其他


讲解关于slam一系列文章汇总链接:

史上最全slam从零开始

,针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下:


(02)Cartographer源码无死角解析- (00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/127350885




文末正下方中心提供了本人

联系方式,

点击本人照片即可显示

W

X

官方认证

{\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证}








文末正下方中心



提供了本人


联系方式,


点击本人照片即可显示


W


X









官方认证








一、前言

通过上篇博客,对 Cartographer 中常见的低级错误进行了介绍,接下来我们需要去深刻的理解一下 Cartographer 中的参数了,主要讲解的时如下几个文件:

src/cartographer_ros/cartographer_ros/configuration_files/lx_rs16_2d_outdoor.lua
src/cartographer/configuration_files/map_builder.lua
src/cartographer/configuration_files/trajectory_builder.lua
src/cartographer/configuration_files/trajectory_builder_2d.lua
src/cartographer/configuration_files/trajectory_builder_3d.lua
src/cartographer/configuration_files/pose_graph.lua

如果查看lx_rs16_2d_outdoor.lua文件,可以看到存在如下代码:

include "map_builder.lua"
include "trajectory_builder.lua"

其用法和c++可以做类比,就是把 map_builder.lua 与 trajectory_builder.lua 中的配置都都加载到 lx_rs16_2d_outdoor.lua 之中。

另外在 lx_rs16_2d_outdoor.lua 中还可以看到

options = {
	......
}

其内部的参数,一般来说都是新的,也就是不不被 map_builder.lua 与 trajectory_builder.lua 包括的。如果在 lx_rs16_2d_outdoor.lua 想要修改 map_builder.lua 或者 trajectory_builder.lua 中的参数,应该如何操作呢?其实比较建档,如 lx_rs16_2d_outdoor.lua 中的如下语句:

TRAJECTORY_BUILDER_2D.use_imu_data = true
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight = 1.

就是对 TRAJECTORY_BUILDER_2D 中文件的修改, trajectory_builder.lua 中包含了 trajectory_builder_2d.lua 与 trajectory_builder_3d.lua,trajectory_builder.lua 的内容十分简单如下:

include "trajectory_builder_2d.lua"
include "trajectory_builder_3d.lua"

TRAJECTORY_BUILDER = {
  trajectory_builder_2d = TRAJECTORY_BUILDER_2D,  --导入2D追踪配置
  trajectory_builder_3d = TRAJECTORY_BUILDER_3D,  --导入3D追踪配置
--  pure_localization_trimmer = {  
--    max_submaps_to_keep = 3,  //纯定位模式下,保存子地图的最大数量。
--  },
  collate_fixed_frame = true,  --是否将GPS数据放入阻塞队列中,按时间排序再进行分发
  collate_landmarks = false,  --是否将landmarks数据放入阻塞队列中,按时间排序再进行分发
}

下面对是常用的配置文件做的注释



二、lx_rs16_2d_outdoor.lua

改文件位于 src/cartographer_ros/cartographer_ros/configuration_files/lx_rs16_2d_outdoor.lua:

include "map_builder.lua"
include "trajectory_builder.lua"

options = {
  map_builder = MAP_BUILDER,                -- map_builder.lua的配置信息
  trajectory_builder = TRAJECTORY_BUILDER,  -- trajectory_builder.lua的配置信息
  
  map_frame = "map",                        -- 地图坐标系的名字
  tracking_frame = "imu_link",              -- 将所有传感器数据转换到这个坐标系下
  published_frame = "odom",                 -- tf: map -> footprint
  odom_frame = "odom",                      -- 里程计的坐标系名字
  provide_odom_frame = true,                -- 是否提供odom的tf, 如果为true,则tf树为map->odom->footprint
                                            -- 如果为false tf树为map->footprint
  publish_frame_projected_to_2d = false,    -- 是否将坐标系投影到平面上
  --use_pose_extrapolator = false,            -- 发布tf时是使用pose_extrapolator的位姿还是前端计算出来的位姿

  use_odometry = false,                     -- 是否使用里程计,如果使用要求一定要有odom的tf
  use_nav_sat = false,                      -- 是否使用gps
  use_landmarks = false,                    -- 是否使用landmark
  num_laser_scans = 0,                      -- 是否使用单线激光数据
  num_multi_echo_laser_scans = 0,           -- 是否使用multi_echo_laser_scans数据
  num_subdivisions_per_laser_scan = 1,      -- 1帧数据被分成几次处理,一般为1
  num_point_clouds = 1,                     -- 是否使用点云数据
  
  lookup_transform_timeout_sec = 0.2,       -- 查找tf时的超时时间
  submap_publish_period_sec = 0.3,          -- 发布数据的时间间隔
  pose_publish_period_sec = 5e-3,
  trajectory_publish_period_sec = 30e-3,

  --表示全采样,0.5表示没两次数据,只采样一次。如果设置为0则表示丢弃所有数据
  rangefinder_sampling_ratio = 1.,          -- 范围传感器(如单线雷达、多线雷达等)数据的采样频率
  odometry_sampling_ratio = 1.,             --里程计采样频率
  fixed_frame_pose_sampling_ratio = 1.,     --GPS采样频率
  imu_sampling_ratio = 1.,                  --IMU采样频率
  landmarks_sampling_ratio = 1.,            --landmarks采样频率
}

MAP_BUILDER.use_trajectory_builder_2d = true  --使用2D轨迹

TRAJECTORY_BUILDER_2D.use_imu_data = true --使用imu数据
TRAJECTORY_BUILDER_2D.min_range = 0.3 --雷达数据的最近滤波, 保存中间值
TRAJECTORY_BUILDER_2D.max_range = 100. --雷达数据的最远滤波, 保存中间值
TRAJECTORY_BUILDER_2D.min_z = 0.2 --雷达数据的最低与最高过滤, 保存中间值
--TRAJECTORY_BUILDER_2D.max_z = 1.4
--TRAJECTORY_BUILDER_2D.voxel_filter_size = 0.02

--TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.max_length = 0.5
--TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.min_num_points = 200.
--TRAJECTORY_BUILDER_2D.adaptive_voxel_filter.max_range = 50.

--TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.max_length = 0.9
--TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.min_num_points = 100
--TRAJECTORY_BUILDER_2D.loop_closure_adaptive_voxel_filter.max_range = 50.

TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = false --是否使用相关性暴力匹配
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.occupied_space_weight = 1. --ceres扫匹配中使用点云优化的残差权重
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight = 1. --ceres扫匹配中使用推断器推断的机器人位置作为优化目标,其残差项权重
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight = 1. --ceres扫描匹配中角度优化残差权重
--TRAJECTORY_BUILDER_2D.ceres_scan_matcher.ceres_solver_options.max_num_iterations = 12

--TRAJECTORY_BUILDER_2D.motion_filter.max_distance_meters = 0.1
--TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = 0.004
--TRAJECTORY_BUILDER_2D.imu_gravity_time_constant = 1. //重力时间常数

TRAJECTORY_BUILDER_2D.submaps.num_range_data = 80. 
TRAJECTORY_BUILDER_2D.submaps.grid_options_2d.resolution = 0.1

POSE_GRAPH.optimize_every_n_nodes = 160.
POSE_GRAPH.constraint_builder.sampling_ratio = 0.3
POSE_GRAPH.constraint_builder.max_constraint_distance = 15.
POSE_GRAPH.constraint_builder.min_score = 0.48
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.60

return options

不再 options 中的参数是一些可能经常需要修改的,写在这里是对前面进行覆盖,方便配置。



三、trajectory_builder_2d.lua

文件位于 src/cartographer/configuration_files/trajectory_builder_2d.lua

TRAJECTORY_BUILDER_2D = {
  use_imu_data = true,            -- 是否使用imu数据
  min_range = 0.,                 -- 雷达数据的最近滤波, 保存中间值
  max_range = 30.,                -- 雷达数据的最远滤波, 保存中间值
  min_z = -0.8,                   -- 雷达数据的最高与最低的过滤, 保存中间值
  max_z = 2.,
  missing_data_ray_length = 5.,   -- 超过最大距离范围的数据点用这个距离代替
  num_accumulated_range_data = 1, -- 几帧有效的点云数据进行一次扫描匹配
  voxel_filter_size = 0.025,      -- 体素滤波的立方体的边长

  -- 使用固定的voxel滤波之后, 再使用自适应体素滤波器
  -- 体素滤波器 用于生成稀疏点云 以进行 扫描匹配
  adaptive_voxel_filter = {
    max_length = 0.5,             -- 尝试确定最佳的立方体边长, 边长最大为0.5
    min_num_points = 200,         -- 如果存在 较多点 并且大于'min_num_points', 则减小体素长度以尝试获得该最小点数
    max_range = 50.,              -- 距远离原点超过max_range 的点被移除
  },

  -- 闭环检测的自适应体素滤波器, 用于生成稀疏点云 以进行 闭环检测
  loop_closure_adaptive_voxel_filter = {
    max_length = 0.9,
    min_num_points = 100,
    max_range = 50.,
  },

  -- 是否使用 real_time_correlative_scan_matcher 为ceres提供先验信息
  -- 计算复杂度高 , 但是很鲁棒 , 在odom或者imu不准时依然能达到很好的效果
  use_online_correlative_scan_matching = false,
  real_time_correlative_scan_matcher = {
    linear_search_window = 0.1,             -- 线性搜索窗口的大小
    angular_search_window = math.rad(20.),  -- 角度搜索窗口的大小
    translation_delta_cost_weight = 1e-1,   -- 用于计算各部分score的权重
    rotation_delta_cost_weight = 1e-1,
  },

  -- ceres匹配的一些配置参数
  ceres_scan_matcher = {
    occupied_space_weight = 1.,
    translation_weight = 10.,
    rotation_weight = 40.,
    ceres_solver_options = {
      use_nonmonotonic_steps = false,
      max_num_iterations = 20,
      num_threads = 1,
    },
  },

  -- 为了防止子图里插入太多数据, 在插入子图之前之前对数据进行过滤
  motion_filter = {
    max_time_seconds = 5.,
    max_distance_meters = 0.2,
    max_angle_radians = math.rad(1.),
  },

  -- TODO(schwoere,wohe): Remove this constant. This is only kept for ROS.
  imu_gravity_time_constant = 10.,

  -- 位姿预测器
  pose_extrapolator = {
    use_imu_based = false,   --是否使使用推断Imu
    constant_velocity = {
      imu_gravity_time_constant = 10., --重力时间常数
      pose_queue_duration = 0.001,  --队列存中最后一个数据与第一个数据的最大时间间隔
    },
    imu_based = {
      pose_queue_duration = 5., --队列存中最后一个数据与第一个数据的最大时间间隔
      gravity_constant = 9.806, --重力常量
      pose_translation_weight = 1., --pose位移权重
      pose_rotation_weight = 1., --pose旋转权重
      imu_acceleration_weight = 1., --IMU加速度权重
      imu_rotation_weight = 1., --IMU加速度权重
      odometry_translation_weight = 1., --里程计平移权重
      odometry_rotation_weight = 1., -里程计方向权重
      solver_options = {
        use_nonmonotonic_steps = false;
        max_num_iterations = 10;
        num_threads = 1;
      },
    },
  },

  -- 子图相关的一些配置
  submaps = {
    num_range_data = 90,          -- 一个子图里插入雷达数据的个数的一半
    grid_options_2d = {
      grid_type = "PROBABILITY_GRID", -- 地图的种类, 还可以是tsdf格式
      resolution = 0.05,
    },
    range_data_inserter = {
      range_data_inserter_type = "PROBABILITY_GRID_INSERTER_2D",
      -- 概率占用栅格地图的一些配置
      probability_grid_range_data_inserter = {
        insert_free_space = true,
        hit_probability = 0.55,
        miss_probability = 0.49,
      },
      -- tsdf地图的一些配置
      tsdf_range_data_inserter = {
        truncation_distance = 0.3,
        maximum_weight = 10.,
        update_free_space = false,
        normal_estimation_options = {
          num_normal_samples = 4,
          sample_radius = 0.5,
        },
        project_sdf_distance_to_scan_normal = true,
        update_weight_range_exponent = 0,
        update_weight_angle_scan_normal_to_ray_kernel_bandwidth = 0.5,
        update_weight_distance_cell_to_hit_kernel_bandwidth = 0.5,
      },
    },
  },
}



四、trajectory_builder_3d.lua

文件位于 src/cartographer/configuration_files/trajectory_builder_3d.lua

MAX_3D_RANGE = 60.
INTENSITY_THRESHOLD = 40

TRAJECTORY_BUILDER_3D = {
  min_range = 1.,
  max_range = MAX_3D_RANGE,
  num_accumulated_range_data = 1,  --累计几帧点云进行一次扫描匹配
  voxel_filter_size = 0.15,

  -- 在3d slam 时会有2个自适应体素滤波, 一个生成高分辨率点云, 一个生成低分辨率点云
  high_resolution_adaptive_voxel_filter = {
    max_length = 2.,
    min_num_points = 150,
    max_range = 15.,
  },

  low_resolution_adaptive_voxel_filter = {
    max_length = 4.,
    min_num_points = 200,
    max_range = MAX_3D_RANGE,
  },

  use_online_correlative_scan_matching = false,
  real_time_correlative_scan_matcher = {
    linear_search_window = 0.15,
    angular_search_window = math.rad(1.),
    translation_delta_cost_weight = 1e-1,
    rotation_delta_cost_weight = 1e-1,
  },

  ceres_scan_matcher = {
    -- 在3D中,occupied_space_weight_0和occupied_space_weight_1参数分别与高分辨率和低分辨率滤波点云相关
    occupied_space_weight_0 = 1.,
    occupied_space_weight_1 = 6.,
    intensity_cost_function_options_0 = {
        weight = 0.5,
        huber_scale = 0.3,
        intensity_threshold = INTENSITY_THRESHOLD,
    },
    translation_weight = 5.,
    rotation_weight = 4e2,
    only_optimize_yaw = false,
    ceres_solver_options = {
      use_nonmonotonic_steps = false,
      max_num_iterations = 12,
      num_threads = 1,
    },
  },

  motion_filter = {
    max_time_seconds = 0.5,
    max_distance_meters = 0.1,
    max_angle_radians = 0.004,
  },

  rotational_histogram_size = 120,

  -- TODO(schwoere,wohe): Remove this constant. This is only kept for ROS.
  imu_gravity_time_constant = 10.,
  pose_extrapolator = {
    use_imu_based = false, --是否使用Imu推断
    constant_velocity = { 
      imu_gravity_time_constant = 10., --重力时间常数
      pose_queue_duration = 0.001, --队列存中最后一个数据与第一个数据的最大时间间隔
    },
    -- TODO(wohe): Tune these parameters on the example datasets.
    imu_based = {
      pose_queue_duration = 5., --队列存中最后一个数据与第一个数据的最大时间间隔
      gravity_constant = 9.806, --重力常量
      pose_translation_weight = 1., --pose位移权重
      pose_rotation_weight = 1., --pose旋转权重
      imu_acceleration_weight = 1., --IMU加速度权重
      imu_rotation_weight = 1., --IMU方向(位姿)权重
      odometry_translation_weight = 1., --里程计平移权重
      odometry_rotation_weight = 1., --里程计方向权重
      solver_options = {
        use_nonmonotonic_steps = false;
        max_num_iterations = 10;
        num_threads = 1;
      },
    },
  },

  submaps = {
    -- 2种分辨率的地图
    high_resolution = 0.10,           -- 用于近距离测量的高分辨率hybrid网格 for local SLAM and loop closure, 用来与小尺寸voxel进行精匹配
    high_resolution_max_range = 20.,  -- 在插入 high_resolution map 之前过滤点云的最大范围
    low_resolution = 0.45,
    num_range_data = 160,             -- 用于远距离测量的低分辨率hybrid网格 for local SLAM only, 用来与大尺寸voxel进行粗匹配
    range_data_inserter = {
      hit_probability = 0.55,
      miss_probability = 0.49,
      num_free_space_voxels = 2,
      intensity_threshold = INTENSITY_THRESHOLD,
    },
  },

  -- When setting use_intensites to true, the intensity_cost_function_options_0
  -- parameter in ceres_scan_matcher has to be set up as well or otherwise
  -- CeresScanMatcher will CHECK-fail.
  use_intensities = false,
}



五、pose_graph.lua

该文件位于 src/cartographer/configuration_files/pose_graph.lua

POSE_GRAPH = {
  -- 每隔多少个节点执行一次后端优化
  optimize_every_n_nodes = 90,

  -- 约束构建的相关参数
  constraint_builder = {
    sampling_ratio = 0.3,                 -- 对局部子图进行回环检测时的计算频率, 数值越大, 计算次数越多
    max_constraint_distance = 15.,        -- 对局部子图进行回环检测时能成为约束的最大距离
    min_score = 0.55,                     -- 对局部子图进行回环检测时的最低分数阈值
    global_localization_min_score = 0.6,  -- 对整体子图进行回环检测时的最低分数阈值
    loop_closure_translation_weight = 1.1e4,
    loop_closure_rotation_weight = 1e5,
    log_matches = true,                   -- 打印约束计算的log
    
    -- 基于分支定界算法的2d粗匹配器
    fast_correlative_scan_matcher = {
      linear_search_window = 7.,
      angular_search_window = math.rad(30.),
      branch_and_bound_depth = 7,
    },

    -- 基于ceres的2d精匹配器
    ceres_scan_matcher = {
      occupied_space_weight = 20.,
      translation_weight = 10.,
      rotation_weight = 1.,
      ceres_solver_options = {
        use_nonmonotonic_steps = true,
        max_num_iterations = 10,
        num_threads = 1,
      },
    },

    -- 基于分支定界算法的3d粗匹配器
    fast_correlative_scan_matcher_3d = {
      branch_and_bound_depth = 8,
      full_resolution_depth = 3,
      min_rotational_score = 0.77,
      min_low_resolution_score = 0.55,
      linear_xy_search_window = 5.,
      linear_z_search_window = 1.,
      angular_search_window = math.rad(15.),
    },

    -- 基于ceres的3d精匹配器
    ceres_scan_matcher_3d = {
      occupied_space_weight_0 = 5.,
      occupied_space_weight_1 = 30.,
      translation_weight = 10.,
      rotation_weight = 1.,
      only_optimize_yaw = false,
      ceres_solver_options = {
        use_nonmonotonic_steps = false,
        max_num_iterations = 10,
        num_threads = 1,
      },
    },
  },

  matcher_translation_weight = 5e2,
  matcher_rotation_weight = 1.6e3,

  -- 优化残差方程的相关参数
  optimization_problem = {
    huber_scale = 1e1,                -- 值越大,(潜在)异常值的影响就越大
    acceleration_weight = 1.1e2,      -- 3d里imu的线加速度的权重
    rotation_weight = 1.6e4,          -- 3d里imu的旋转的权重
    
    -- 前端结果残差的权重
    local_slam_pose_translation_weight = 1e5,
    local_slam_pose_rotation_weight = 1e5,
    -- 里程计残差的权重
    odometry_translation_weight = 1e5,
    odometry_rotation_weight = 1e5,
    -- gps残差的权重
    fixed_frame_pose_translation_weight = 1e1,
    fixed_frame_pose_rotation_weight = 1e2,
    fixed_frame_pose_use_tolerant_loss = false,
    fixed_frame_pose_tolerant_loss_param_a = 1,
    fixed_frame_pose_tolerant_loss_param_b = 1,

    log_solver_summary = false,
    use_online_imu_extrinsics_in_3d = true,
    fix_z_in_3d = false,
    ceres_solver_options = {
      use_nonmonotonic_steps = false,
      max_num_iterations = 50,
      num_threads = 7,
    },
  },

  max_num_final_iterations = 200,   -- 在建图结束之后执行一次全局优化, 不要求实时性, 迭代次数多
  global_sampling_ratio = 0.003,    -- 纯定位时候查找回环的频率
  log_residual_histograms = true,
  global_constraint_search_after_n_seconds = 10., -- 纯定位时多少秒执行一次全子图的约束计算

  --  overlapping_submaps_trimmer_2d = {
  --    fresh_submaps_count = 1,
  --    min_covered_area = 2,
  --    min_added_submaps_count = 5,
  --  },
}



六、调参总结

待写



.

.

.

.

.

.

……






……






七、结语

暂时还没有对参数做很详细的介绍,在后续分析源码的过程中,会对该篇博客增加更多详细的介绍。另外,看了这些参数之后,一脸懵逼,完全不知道怎么回事,这是正常的,因为还没有分析源码,等分析源码之后,大家就明白具体是怎么回事了。



版权声明:本文为weixin_43013761原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。