cartographer学习之lua参数详解

lua文件是cartographer中用于参数配置的文件,熟悉lua文件可以让我们对cartographer有一个基础的认知,也可以更好的根据自己的设备进行产品的调试与使用,这里简单介绍一下自己的lua文件应该包含哪些内容。
看一个简单的lua文件:

-- Copyright 2016 The Cartographer Authors
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

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 = "base_link",                         -- 将所有传感器数据转换到这个坐标系下默认imu_link,在有IMU的情况下将其他数据转到IMU下,因为IMU频率高,转到其他坐标系下需要转换次数更多
  published_frame = "odom",                        -- tf: map -> odom  "footprint"
  odom_frame = "odom",                                  -- 里程计的坐标系名字
  provide_odom_frame = false,                            -- 是否提供odom的tf, 如果为true,则tf树为map->odom->footprint
  publish_frame_projected_to_2d = false,                -- 是否将坐标系投影到平面上
  --use_pose_extrapolator = false                       -- 发布tf时是否使用pose_extrapolator的结果。
  use_odometry = true,                                  -- 是否使用里程计,如果使用要求一定要有odom的tf
  use_nav_sat = false,                                  -- 是否使用gps
  use_landmarks = true,                                -- 是否使用landmark
  num_laser_scans = 1,                                  -- 是否使用单线激光数据
  num_multi_echo_laser_scans = 0,                       -- 是否使用multi_echo_laser_scans数据
                                                        -- 这两个还有下面的是否使用点云数据不能同时为0
  num_subdivisions_per_laser_scan = 1,                  -- 1帧数据被分成几次处理,一般为1
  num_point_clouds = 0,                                 -- 是否使用点云数据
  lookup_transform_timeout_sec = 0.2,                   -- 查找tf时的超时时间
  submap_publish_period_sec = 0.3,                      -- 发布数据的时间间隔
  pose_publish_period_sec = 5e-3,                       -- 发布pose的时间间隔,比如:5e-3频率是200Hz
  trajectory_publish_period_sec = 30e-3,                -- 发布轨迹标记的间隔,30e-3是科学记数法,表示的是30乘以10-3次方。也就是0.030秒,就是30毫秒。
  rangefinder_sampling_ratio = 1.,                      -- 传感器数据的采样频率,多少次数据采样一次,默认都是1。
  odometry_sampling_ratio = 1.,
  fixed_frame_pose_sampling_ratio = 1.,
  imu_sampling_ratio = 1.,
  landmarks_sampling_ratio = 1.,
}
 
MAP_BUILDER.use_trajectory_builder_2d = true
 
TRAJECTORY_BUILDER_2D.submaps.num_range_data = 35       -- 其含义应该应该是多少帧插入一次子图,算法中还有一个乘二操作。
--num_range_data设置的值与CPU有这样一种关系,值小(10),CPU使用率比较稳定,整体偏高,值大时,CPU短暂爆发使用(插入子图的时候),平时使用率低,呈现极大的波动状态。
TRAJECTORY_BUILDER_2D.min_range = 0.3                   --激光的最近有效距离
TRAJECTORY_BUILDER_2D.max_range = 8.                    --激光最远的有效距离
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 1.      --无效激光数据设置距离为该数值,滤波的时候使用
TRAJECTORY_BUILDER_2D.use_imu_data = false              --是否使用imu数据
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true     -- 选择是否先求解online scan matching,然后用correlative scan matcher为Ceres求解器产生一个好的初始解,为true时效果更好
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window = 0.1  -- 线距离搜索框,在这个框的大小内,搜索最佳scan匹配.
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight = 10.  --两个参数相当于最小化误差函数中的权重值,两者的比值,决定了更侧重与平移和旋转中的哪部分
TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight = 1e-1
 
--POSE_GRAPH.optimization_problem.huber_scale = 1e2       --鲁棒核函数,去噪
--POSE_GRAPH.optimize_every_n_nodes = 35                  --后端优化节点
--POSE_GRAPH.constraint_builder.min_score = 0.65          --当匹配分数低于此值时,忽略该分数。感觉可能是用来检测是否匹配到回环的
 
return options

对于上述一个lua文件,主要分为以下几个部分:

1.头文件

这里引用了两个头文件:

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

它们是放在cartographer_detailed_comments_ws/src/cartographer/configuration_files路径下,这里虽然只include了两个,但是其中也引用了该目录下其他几个lua文件。这几个lua文件基本包含了cartographer的大部分参数。先看一下trajectory_builder.lua:

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

TRAJECTORY_BUILDER = {
  trajectory_builder_2d = TRAJECTORY_BUILDER_2D,
  trajectory_builder_3d = TRAJECTORY_BUILDER_3D,
--  pure_localization_trimmer = {
--    max_submaps_to_keep = 3,
--  },
  collate_fixed_frame = true, -- 是否将数据放入阻塞队列中
  collate_landmarks = false,  -- 是否将数据放入阻塞队列中
}

这个文件比较短,它包含了一个2d轨迹的lua以及一个3d轨迹的lua。
然后再看一下2d的参数文件:

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,
    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_rotation_weight = 1.,
      imu_acceleration_weight = 1.,
      imu_rotation_weight = 1.,
      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,
      },
    },
  },
}

这个文件还是比较长的,简单看一下。

前面第一个参数:

use_imu_data = true,            -- 是否使用imu数据

是否使用IMU,如果设置为true则需要有IMU,如果没有IMU,可以在前面的lua文件第三部分内容其他参数中添加一行:

TRAJECTORY_BUILDER_2D.use_imu_data = false              --是否使用imu数据

相当于对该参数进行了一次重映射。

  min_range = 0.,                 -- 雷达数据的最远最近滤波, 保存中间值
  max_range = 30.,

表示使用的雷达的最远最近距离。

  min_z = -0.8,                   -- 雷达数据的最高与最低的过滤, 保存中间值
  max_z = 2.,

雷达点云的最高与最低高度的滤波参数,超过这个范围的点会被过滤掉。

missing_data_ray_length = 5.,   -- 超过最大距离范围的数据点用这个距离代替

雷达数据中有一些超过测量范围的点,显示为NAN或者inf之类的,或者是超过上述设置的最远距离的值,这些东西就会用missing_data_ray_length的值代替。

num_accumulated_range_data = 1, -- 几帧有效的点云数据进行一次扫描匹配

几帧有效数据做一次扫描匹配,一般设置为1.

voxel_filter_size = 0.025,      -- 体素滤波的立方体的边长

cartographer会对点云进行体素滤波,这里设置了体素滤波的边长。

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

自适应体素滤波器的设置,cartographer会对点云进行多次的处理,设置这个后cartographer会将滤波后的点云数量限制在min_num_points范围内。

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

做闭环检测时候的体素滤波器参数。

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,
  },

这个参数的含义是是否在扫描匹配前面先进行一次位姿计算,如果设置为true会很大的提高计算量,如果使用单线雷达数据建图时建图效果不好,总是叠图的话可以打开这个参数,可以优化建图效果。但是会付出一定的计算量。

-- 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,
    },
  },

前端扫描匹配的一些参数设置,第一个代表点云与地图匹配的权重,第二个代表匹配的位姿与先验位姿的平移权重,第三个代表匹配的位姿与先验位姿的旋转权重。ceres_solver_options内部是ceres内部的一些参数。

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

像gmapping粒子滤波这种一般需要机器人运动超过一定距离才会进行一次计算与地图的插入,但是cartographer不一样,它会对每一帧数据进行计算。为了减少子图插入太多点云数据,可以通过这里的motion_filter进行过滤。

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

这个可以不用管,好像没有用到。

-- 位姿预测器
  pose_extrapolator = {
    use_imu_based = false,
    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_rotation_weight = 1.,
      imu_acceleration_weight = 1.,
      imu_rotation_weight = 1.,
      odometry_translation_weight = 1.,
      odometry_rotation_weight = 1.,
      solver_options = {
        use_nonmonotonic_steps = false;
        max_num_iterations = 10;
        num_threads = 1;
      },
    },
  },

use_imu_based参数决定了是否使用imu_based内部参数。

-- 子图相关的一些配置
  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,
      },
    },
  },
}

这块是子图相关的参数设置,num_range_data代表一个子图会插入多少个点云数据的一半,为什么是一半,因为代码里这个参数会乘以2。grid_type为地图的格式,默认是概率栅格地图。resolution为地图的分辨率,如果要修改地图的分辨率就是修改的这里。

2d的参数大概就是这些,3d的类似,少数区别:
首先关于体素滤波这块,3d有两个体素滤波:

  --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,
  },

其次,3d的submap也有两种:

  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,
    },
  },

再看一下map_builder.lua:

include "pose_graph.lua"

MAP_BUILDER = {
  use_trajectory_builder_2d = false,
  use_trajectory_builder_3d = false,
  num_background_threads = 4,
  pose_graph = POSE_GRAPH,
  collate_by_trajectory = false,
}

这个文件也很短,注意

  use_trajectory_builder_2d = false,
  use_trajectory_builder_3d = false,

这两个参数有且仅有一个为true。默认两个都是false,所以在第三节配置参数中要将其中一个映射为true。num_background_threads为线程数量。pose_graph代表加载pose_graph.lua相关参数配置。

pose_graph用于设置后端优化参数:

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,
  --  },
}

首先:

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

代表了多少个节点进行一次优化,一般设置为num_range_data的两倍左右。

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,

回环检测时平移和旋转的权重。

    -- 基于分支定界算法的2d粗匹配器
    fast_correlative_scan_matcher = {
      linear_search_window = 7.,
      angular_search_window = math.rad(30.),
      branch_and_bound_depth = 7,
    },

分支定界算法的粗匹配器的参数。

-- 基于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,
      },
    },

ceres精匹配器的参数。

以及再往下是3d的两个匹配器参数:

 -- 基于分支定界算法的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,
      },
    },

然后是一些残差相关的值

-- 优化残差方程的相关参数
  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,   -- 在建图结束之后执行一次全局优化, 不要求实时性, 迭代次数多

cartographer在结束的时候会进行一次全局优化,这里是全局优化的迭代次数。

global_sampling_ratio = 0.003,    -- 纯定位时候查找回环的频率

纯定位模式下的查找回环的频率。

global_constraint_search_after_n_seconds = 10., -- 纯定位时多少秒执行一次全子图的约束计算

多少秒执行一次子图的约束

2.options参数

options中的参数是指上面lua文件中没有的参数,需要根据自己的设置。展开看一下这部分:
首先是前两行:

  map_builder = MAP_BUILDER,                            -- map_builder.lua的配置信息
  trajectory_builder = TRAJECTORY_BUILDER,              -- trajectory_builder.lua的配置信息

定义包含前两个头文件的配置信息,照着写不用管。

map_frame = "map",                                    -- 地图坐标系的名字

用于设置地图坐标系的名字,一般都用map。

tracking_frame = "base_link",                         -- 将所有传感器数据转换到这个坐标系下默认imu_link,在有IMU的情况下将其他数据转到IMU下,因为IMU频率高,转到其他坐标系下需要转换次数更多

cartographer在做数据处理的时候,会将所有的传感器数据都转换到该坐标系下进行处理。每个传感器的频率不一样,IMU一般频率最高,如果有IMU,则将IMU转换到其他坐标系下需要更多的转换计算量。没有IMU设置为base_link也可以。

published_frame = "odom",                        -- tf: map -> odom  "footprint"

用于发布到map的TF变换的坐标系,有odom的话最好写odom,没有的话看自己的TF变换,取自己的TF树最上层的一个坐标系即可。

odom_frame = "odom",                                  -- 里程计的坐标系名字

里程计坐标系的名称,一般用的是odom。

provide_odom_frame = false,                            -- 是否提供odom的tf, 如果为true,则tf树为map->odom->footprint

是否提供一个虚拟的odom,在没有odom的情况下,如果这里设置为true,则cartographer会在运算过程中发布一个map->odom->“published_frame“的TF变换。如果设置为false,则算法会直接发布一个map->“published_frame“的TF变换。

publish_frame_projected_to_2d = false,                -- 是否将坐标系投影到平面上

是否将坐标系投影到平面上,没什么太大意义,设置为false即可。

--use_pose_extrapolator = false                       -- 发布tf时是否使用pose_extrapolator的结果。

这个参数的含义是发布TF时使用位姿推测器推测出来的位姿还是使用算法计算出来的位姿,那一般肯定是算法计算出来的更为准确。推测出来的会有误差。

  use_odometry = true,                                  -- 是否使用里程计,如果使用要求一定要有odom的tf
  use_nav_sat = false,                                  -- 是否使用gps
  use_landmarks = true,                                -- 是否使用landmark

是否存在这三种传感器数据,三者都是通过topic形式进行订阅,如果设置为true则会订阅对应的topic。注意这三者的topic是唯一的,它们分别只能订阅一个对应的topic数据。但是这三者可以同时订阅是没关系的。但是雷达是可以订阅多个的。

  num_laser_scans = 1,                                  -- 是否使用单线激光数据
  num_multi_echo_laser_scans = 0,                       -- 是否使用multi_echo_laser_scans数据
                                                        -- 这两个还有下面的是否使用点云数据不能同时为0
  num_point_clouds = 0,  

表示使用单线雷达还是多线雷达,或者也可以是点云数据。cartographer支持多雷达建图,但是据说效果不是很好,所以一般使用一个单线雷达或者一个多线雷达就可以了。

  num_subdivisions_per_laser_scan = 1,                  -- 1帧数据被分成几次处理,一般为1

一帧数据分为几次处理,一般设置为1即可。

lookup_transform_timeout_sec = 0.2,                   -- 查找tf时的超时时间

查找tf时的超时时间。

submap_publish_period_sec = 0.3,                      -- 发布数据的时间间隔

发布submap的频率,0.3s更新一次submap的发布。

pose_publish_period_sec = 5e-3,                       -- 发布pose的时间间隔,比如:5e-3频率是200Hz

姿态的发布频率,一般还是比较高的。

trajectory_publish_period_sec = 30e-3,                -- 发布轨迹标记的间隔,30e-3是科学记数法,表示的是30乘以10-3次方。也就是0.030秒,就是30毫秒。

运动轨迹的发布频率,同样很高。

  rangefinder_sampling_ratio = 1.,                      -- 传感器数据的采样频率,多少次数据采样一次,默认都是1。
  odometry_sampling_ratio = 1.,
  fixed_frame_pose_sampling_ratio = 1.,
  imu_sampling_ratio = 1.,
  landmarks_sampling_ratio = 1.,

几种传感器数据的处理频率,cartographer在处理传感器数据时并不是每一帧数据都会处理,而是设置了一个采样器,当采样器设置为1时才是每一帧数据都会进行处理,如果设置为小于1(例如0.5)则会每两帧数据才处理一次。这样子首先可以降低数据量,其次如果传感器数据不准的情况下可以降低它的使用频率。

3.其他参数

options后面的一些参数是指在头文件中已经存在的参数,这些参数已经有默认值,如果不想使用默认值可以写在这里重定义它的值。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: Cartographer 是一个开源的地图制图工具,主要用于构建和绘制室内和室外环境的三维地图。它是以Lua语言作为脚本编写和扩展的。 首先,Lua是一种轻量级高级编程语言,被广泛应用于嵌入式系统、游戏开发、脚本编写等领域。Cartographer选择使用Lua作为其脚本编写语言,是因为Lua拥有简洁的语法和高度可扩展性,使得用户可以轻松地编写和修改Cartographer的功能。 使用Lua作为Cartographer的脚本语言,使得开发人员可以根据特定需求自定义各种功能和算法。他们可以通过编写Lua脚本来改变地图的生成方式、路径规划算法、环境感知等内容。这种灵活性使得Cartographer能够适应各种特定的应用场景和需求。 同时,Lua也是一个功能强大的脚本语言,拥有很多有用的函数库和模块,例如字符串处理、JSON解析、网络通信等。这些功能可以被利用来扩展Cartographer的能力,使得它具备更多的功能。例如,用户可以使用内置的JSON库来处理来自传感器的数据,然后将其集成到Cartographer的地图生成过程中。 总之,Cartographer中使用Lua作为脚本编写语言,给开发人员提供了一种灵活且可扩展的方式来定制和扩展地图生成和绘制的功能。通过编写Lua脚本,用户可以根据自己的需求来改变Cartographer的行为和输出,使其更好地适应各种应用场景。 ### 回答2: 在游戏开发中,cartographer(制图师)是一个很重要的角色,而Lua则是常用于游戏制作的脚本语言。Lua提供了简单、高效和可嵌入的特性,使得在游戏中实现制图功能变得更加容易。 制图师的工作是创建和设计游戏中的地图。他们使用图形工具来绘制地图的外貌,并使用Lua脚本来定义地图的行为、布局和特性。 使用Lua的主要好处之一是它的灵活性。制图师可以根据需要编写自定义脚本来控制地图元素的交互逻辑。例如,他们可以编写脚本来定义角色在地图上的移动、碰撞检测和触发事件等。这样可以为游戏增加更多的互动性和挑战性。 此外,Lua还提供了强大的扩展性。制图师可以利用Lua的扩展功能来添加自定义的地图特性,如随机生成地形、动态添加/移除地图元素等。这样可以使游戏的地图更加多样化和有趣。 另一个使用Lua的好处是它的易学性。相对于其他编程语言,Lua语法简洁明了,并且具有良好的文档和丰富的教程资源。制图师即使没有深厚的编程知识,也可以迅速上手并编写简单的脚本来完成地图设计。 总的来说,cartographer中的Lua在游戏开发中扮演着非常重要的角色。它为制图师提供了强大和灵活的工具,使他们能够轻松创建和定制游戏的地图。无论是添加互动性、扩展地图特性,还是实现复杂的游戏逻辑,Lua都是一个理想的选择。 ### 回答3: cartographer是一个用于构建并绘制地图的开源库,而lua是一种脚本语言,常用于嵌入式系统和游戏开发中。在cartographer中,可以使用lua来编写自定义的功能和逻辑。 使用lua可以为cartographer添加一些自定义的功能。比如,可以利用lua脚本来编写一些特定的算法,从而优化地图的构建和绘制过程。也可以通过lua脚本来实现特定的地图渲染效果,如灯光效果、阴影等。 此外,使用lua还可以在运行时动态加载和修改地图配置。通过编写lua脚本,可以实现在地图运行时根据特定条件对地图进行修改,例如动态生成障碍物、修改地图尺寸、添加额外的特征等。这使得cartographer在适应不同应用领域和需求时更加灵活。 同时,cartographer还提供了一些接口和函数来与lua进行交互。这些接口和函数可以让lua脚本获取和修改地图、传递数据给其他系统、控制执行流程等。通过这些交互方式,我们可以实现cartographer与其他部分的集成,或者将cartographer作为其他系统的一部分,以满足更具体的需求。 综上所述,cartographer中的lua提供了一种扩展和定制地图构建和绘制功能的方法,能够使cartographer更加灵活和适应不同的应用场景和需求。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶执念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值