32位系统编译eigen库会出现问题
为了编译 Cartographer ROS 包,我们推荐使用wstool
和rosdep
。从提高编译速度来讲,我们也推荐使用Ninja
。
sudo apt-get update
sudo apt-get install -y python-wstool python-rosdep ninja-build
在’catkin_ws’中创建一个新的工作空间cartographer_ros
mkdir catkin_ws
cd catkin_ws
wstool init src
wstool merge -t src https://raw.githubusercontent.com/googlecartographer/cartographer_ros/master/cartographer_ros.rosinstall
wstool update -t src
安装cartographer_ros
依赖(proto3 和 deb 包)。如果你之前已经执行过sudo rosdep init
命令则这次执行会报错,因为你在安装 ROS 的时候已经执行过了,所以这个错误可以忽略。
src/cartographer/scripts/install_proto3.sh
sudo rosdep init
rosdep update
rosdep install --from-paths src --ignore-src --rosdistro=${ROS_DISTRO} -y
编译安装
catkin_make_isolated --install --use-ninja
安装好了 Cartographer 和 Cartographer 的 ROS 整合包,可以下载样例bag(比如,德意志博物馆的 2D 和 3D系列)到指定位置,在此教程我们下载到~/Downloads
,并使用roslaunch
来启动样例。
luanch文件会自动启动roscore
和rviz
。
注意:
当你运行cartographer_ros时,你可能需要先source一下你的 ROS 环境。运行如下命令
source install_isolated/setup.bash
(如果你用的 zsh shell 就把 bash 后缀替换成 zsh)
下载并运行 2D bag Demo:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag
roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag
下载并运行 2D bag Demo:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_3d/with_intensities/b3-2016-04-05-14-14-00.bag
roslaunch cartographer_ros demo_backpack_3d.launch bag_filename:=${HOME}/Downloads/b3-2016-04-05-14-14-00.bag
定位功能需要使用两个不同的bag。第一个用来生成地图,第二个用来运行定位。
下载 2D bag:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/b2-2016-04-05-14-44-52.bag
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/b2-2016-04-27-12-31-41.bag
生成地图(等到cartographer_offline_node
运行完毕)然后运行定位:
roslaunch cartographer_ros offline_backpack_2d.launch bag_filenames:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag
roslaunch cartographer_ros demo_backpack_2d_localization.launch \
load_state_filename:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag.pbstream \
bag_filename:=${HOME}/Downloads/b2-2016-04-27-12-31-41.bag
下载 3D bag:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_3d/b3-2016-04-05-13-54-42.bag
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_3d/b3-2016-04-05-15-52-20.bag
生成地图(等到cartographer_offline_node
运行完毕)然后运行定位:
roslaunch cartographer_ros offline_backpack_3d.launch bag_filenames:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag
roslaunch cartographer_ros demo_backpack_3d_localization.launch \
load_state_filename:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag.pbstream \
bag_filename:=${HOME}/Downloads/b3-2016-04-05-15-52-20.bag
# Download the landmarks example bag.
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/mir/landmarks_demo_uncalibrated.bag
# Launch the landmarks demo.
roslaunch cartographer_mir offline_mir_100_rviz.launch bag_filename:=${HOME}/Downloads/landmarks_demo_uncalibrated.bag
下载并运行使用便宜的 Revo 激光距离传感器捕获的样例bag:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/revo_lds/cartographer_paper_revo_lds.bag
roslaunch cartographer_ros demo_revo_lds.launch bag_filename:=${HOME}/Downloads/cartographer_paper_revo_lds.bag
下载并运行从 Willow Garage 研发的 PR2 类人机器人上捕获的bag:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/pr2/2011-09-15-08-32-46.bag
roslaunch cartographer_ros demo_pr2.launch bag_filename:=${HOME}/Downloads/2011-09-15-08-32-46.bag
下载并运行从 Taurob Tracker 遥控机器人上捕获的bag:
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/taurob_tracker/taurob_tracker_simulation.bag
roslaunch cartographer_ros demo_taurob_tracker.launch bag_filename:=${HOME}/Downloads/taurob_tracker_simulation.bag
你之前已经运行过几个样例bag了,现在可以直接继续将 Cartographer 运行在自己的数据上。找一个你想用来跑SLAM的一个.bag
文件来学习该入门教程。
注意:
当你运行cartographer_ros时,你可能需要先source一下你的 ROS 环境。运行如下命令
source install_isolated/setup.bash
(如果你用的 zsh shell 就把 bash 后缀替换成 zsh)
Cartographer ROS 提供了一个工具cartographer_rosbag_validate
,可以自动分析你的 bag 数据。在你跑自己的数据之前最好先用这个工具来检测一下你的数据,这样就可以避免在错误的数据上调试 Cartographer 。
这个工具得益于了 Cartographer 作者们的经历,可以帮你检查许多常见的错误。比如,如果检测到sensor_msgs/Imu
话题,那么 这个工具就会确认 IMU 测量数据中是否缺失了重力向量因为 Cartographer 会它用来检测地面的方向。
这个工具同样提供了帮你改善数据质量的一些小技巧。例如,使用 Velodyne 雷达时,推荐采用传感器每个 UDP 包都发送一次sensor_msgs/PointCloud2
信息而避免每次循环发送一次信息。使用这种粒度的消息控制, Cartographer 可以解包由机器人运动引起的点云变形,最终会获得更好的建图效果。
如果你已经 source 过你的 Cartographer ROS 环境,你便可以通过如下命令运行该工具:
cartographer_rosbag_validate -bag_filename your_bag.bag
Cartographer 很灵活,通过配置便可以用于不同的机器人。机器人配置从 Lua 脚本定义的options
数据结构读取。配置样例在src/cartographer_ros/cartographer_ros/configuration_files
中定义并且安装在install_isolated/share/cartographer_ros/configuration_files/
。
注意:
理想情况下,.lua 配置应该是针对机器人而不是针对 bag 的。
你可以先复制一个样例来尝试然后将其应用到自己需要的地方。如果你想用 3D SLAM:
cp install_isolated/share/cartographer_ros/configuration_files/backpack_3d.lua install_isolated/share/cartographer_ros/configuration_files/my_robot.lua
如果你想用 2D SLAM:
cp install_isolated/share/cartographer_ros/configuration_files/backpack_2d.lua install_isolated/share/cartographer_ros/configuration_files/my_robot.lua
接下来你可以编辑my_robot.lua
来满足自己机器人的要求。options
块中定义的值决定了 Cartographer ROS 的前端如何与你的 bag 对接。在options
块后面定义的值用来调整 Cartographer 的内部工作参数,现在我们暂且忽略这些。
另请参阅:
Cartographer ROS 配置参考文档 和 Cartographer 配置。
你可能需要提供你环境和机器人的 TF 坐标系 ID,所以需要提供这几个值map_frame
,tracking_frame
,published_frame
和odom_frame
。
注意:
你可以通过tf
话题来发布你的 TF 树或者在.urdf
文件里进行定义。
注意:
你应该相信你的位姿!你机器人跟 IMU 或者雷达之间连接杆上的一个小偏移就会导致建图不连续。Cartographer通常可以纠正一些小的位姿错误但并不意味着它会纠正所有错误。
其他需要定义的参数就是你的传感器数量跟类型相关的。
num_laser_scans
:使用的sensor_msgs/LaserScan
话题数量。num_multi_echo_laser_scans
:使用的sensor_msgs/MultiEchoLaserScan
话题数量。num_point_clouds
:使用的sensors_msgs/PointCloud2
话题数量。 你也可以通过设置use_landmarks
和use_nav_sat
来开启使用地标(landmarks)与 GPS 来作为额外的定位资源。剩下的options
块里的变量保持原样即可。
然而,有一个全局变量必须要根据你的 bag 来改一下,TraTRAJECTORY_BUILDER_3D.num_accumulated_range_data
或者 TRAJECTORY_BUILDER_2D.num_accumulated_range_data
。这个变量定义了构建一次完整扫描所需要的信息数量。如果你遵循了cartographer_rosbag_validate
的建议并且每次扫描使用100条 ROS 信息,你可以把这个变量值设为100。如果你一次使用两个测距传感器(比如两个雷达)来提供完整的扫描数据,你就应该把这个变量值设为2。
你可能注意到了前边章节的每个 demo 都要使用不同的 roslaunch 命令来运行。确实推荐针对不同的机器人和 SLAM 类型使用不同的.launch
文件。.launch
文件的样例在src/cartographer_ros/cartographer_ros/launch
中定义,并安装在install_isolated/share/cartographer_ros/launch/
。
通过复制任意一个样例来开始我们的例程吧:
cp install_isolated/share/cartographer_ros/launch/backpack_3d.launch install_isolated/share/cartographer_ros/launch/my_robot.launch
cp install_isolated/share/cartographer_ros/launch/demo_backpack_3d.launch install_isolated/share/cartographer_ros/launch/demo_my_robot.launch
cp install_isolated/share/cartographer_ros/launch/offline_backpack_3d.launch install_isolated/share/cartographer_ros/launch/offline_my_robot.launch
cp install_isolated/share/cartographer_ros/launch/demo_backpack_3d_localization.launch install_isolated/share/cartographer_ros/launch/demo_my_robot_localization.launch
cp install_isolated/share/cartographer_ros/launch/assets_writer_backpack_3d.launch install_isolated/share/cartographer_ros/launch/assets_writer_my_robot.launch
my_robot.launch
用来让机器人根究传感器数据执行在线(实时)SLAM。demo_my_robot.launch
用在开发机器上,并且需要指定bag_filename
参数来重放记录的数据。同样该 launch 文件会打开一个配置好的 rviz 窗口来显示 Cartographer 的状态。offline_my_robot.launch
这个文件跟demo_my_robot.launch
非常类似,但是这个文件会尝试尽可能快的执行 SLAM。这样可以大大加快地图的构建速度。同样,他也可以通过指定bag_filenames
参数来使用多个 bag 文件。demo_my_robot_localization.launch
这个文件也类似于demo_my_robot.launch
,但是需要指定load_state_filename
参数指向一个之前 Cartographer 执行的.pbstream
记录,之前的记录将作为一个预计地图然后 Cartographer 将只在这个地图中进行定位。assets_writer_my_robot.launch
用来从之前 Cartographer 执行的.pstream
记录中提取数据。同样,需要调整这些文件中的一些参数来适应你的机器人。
-configuration_basename
参数都应该指向my_robot.lua
。.urdf
文件来描述你的机器人,你应该将你的描述文件放到install_isolated/share/cartographer_ros/urdf
并将robot_description
参数指向你的文件名。/tf
信息,你可以删除robot_description
参数、robot_state_publisher
节点和以-urdf
开头的那些行。
标签来对你的话题进行重定向。Cartographer ROS 期望的话题名字取决于你使用的测距设备类型。注意:
sensor_msgs/LaserScan
话题,就命名为scan
,如果你有多个话题,那就命名为scan_1
,scan_2
等等……sensor_msgs/MultiEchoLaserScan
话题,就命名为echoes
,如果多个话题,就命名为echoes_
,echoes_2
等等……sensor_msgs/PointCloud2
话题,就命名为points2
,如果多个话题,就命名为points2_1
,points2_2
等等……至此基本上所有环节都配置好了,来运行你的 Cartographer:
roslaunch cartographer_ros my_robot.launch bag_filename:=/path/to/your_bag.bag
如果你足够幸运,一切都会像预期的那样。然而,你也有可能会遇到一些问题,还需要做一些调整。
Cartographer 是一个负责的系统所以它的调优需要对它的内部工作有一个很好的理解。这一章试图给出 Cartographer 使用的不同子系统及其配置值的直观的概览。如果你对 Cartographer 感兴趣,你可以参考 Cartographer 的论文。它仅描述了 2D SLAM 但是严格定义了大部分在此提到了概念。这些概念亦可以应用到 3D SLAM 中。
W. Hess, D. Kohler, H. Rapp, and D. Andor, Real-Time Loop Closure in 2D LIDAR SLAM, in Robotics and Automation (ICRA), 2016 IEEE International Conference on. IEEE, 2016. pp. 1271–1278
Cartographer 可以被分为相关的两个子系统。第一个
是local SLAM(有时候也称为前端或者局部轨迹构建器)他负责构建一系列子地图(submaps)。每个子地图是局部一致的但是我们同样接受随着时间 local SLAM 会发生漂移。大部分 local SLAM 选项可以查看 2D install_isolated/share/cartographer/configuration_files/trajectory_builder_2d.lua
或者 3D install_isolated/share/cartographer/configuration_files/trajectory_builder_3d.lua
另一个子系统 global SLAM (有时也叫做后台)。它在后台的线程中运行,主要负责寻找闭环约束。这个工作是通过对子地图的扫描匹配(scan-matching)扫描数据(节点收集的)来完成的。同样它也结合其它传感器数据来获取更高水平视图并确认最一致的全局方案。在 3D 建图中,它也尝试去确认重力的方向。大部分选项可以查看install_isolated/share/cartographer/configuration_files/pose_graph.lua
从更高层次的抽象来看, local SLAM 的任务是产生好的子地图(submaps),而 global SLAM 负责将子地图尽可能一致地联系起来。
指定传感器(如雷达)有效范围
TRAJECTORY_BUILDER_nD.min_range
TRAJECTORY_BUILDER_nD.max_range
注意:
在 2D 建图中,Cartographer 通过设定TRAJECTORY_BUILDER_2D.missing_data_ray_length
来代替比max_range
更远的范围。同时提供了max_z
和min_z
数值来将 3D 点云过滤成 2D 切片。
注意:
在 Cartographer 配置文件里,所有的距离单位均为米。
推荐通过 scan 提供尽可能多的距离数据
TRAJECTORY_BUILDER_nD.num_accumulated_range_data
为了避免远近距离点云密度不一致,我们使用体过滤器将原始点云下采样为一个固定大小的正方体,然后每个正方体只取质心一个点。如果立方体规模太小还是会导致数据秘籍,导致太多的计算量,如果规模太大则会导致数据丢失但是计算速率提高了。
TRAJECTORY_BUILDER_nD.voxel_filter_size
应用固定体过滤器之后, Cartographer 也提供了一个自适应体过滤器,通过max_length
设定体最大值,并根据目标点的数量来决定体的大小。在 3D 建图中,使用了 2 个自适应体过滤器分别用来生成高分辨率与低分辨率点云,具体用法可以查看 Local SLAM(应用固定体过滤器之后, Cartographer 也提供了一个自适应体过滤器,通过max_length
设定体最大值,并根据目标点的数量来决定体的大小。在 3D 建图中,使用了 2 个自适应体过滤器分别用来生成高分辨率与低分辨率点云,具体用法可以查看 Local SLAM。
TRAJECTORY_BUILDER_nD.*adaptive_voxel_filter.max_length
TRAJECTORY_BUILDER_nD.*adaptive_voxel_filter.min_num_points
IMU(Inertial Measurement Unit,惯性测量单元)是 SLAM 的有用信息来源,因为它可以提供精确的重力方向,还提供虽然有噪声但是整体表明了机器人的旋转。为了过滤 IMU 噪声,将会观测重力一段时间。如果你使用 2D SLAM,距离数据可以被实时处理而不需要额外的信息来源,所以你可以自由地选择 Cartographer 是否使用 IMU 信息。在 3D SLAM 中,你需要提供 IMU 信息,因为 IMU 信息用来估计扫描数据的初始方向,可以大大减少扫描数据匹配的复杂度。
TRAJECTORY_BUILDER_2D.use_imu_data
TRAJECTORY_BUILDER_nD.imu_gravity_time_constant
注意:
在 Cartographer 的配置文件中,所有时间的单位都是秒
等到扫描数据组装完、多个距离传感器数据过滤完,就要开始跑 local SLAM 算法了。Local SLAM 通过扫描匹配(scan matching)将一个新的扫描数据插入到当前的子地图构建中,其中扫描匹配使用来自位姿外推器(pose extrapolator)的初始位姿估计。位姿外推器的意图是使用出了距离传感器之外的其它传感器数据来预测下一个扫描数据应该插入到子地图的什么地方。
可以使用两种不同的扫描匹配(scan matching)策略:
CeresScanMatcher
将初始估计(intial guess)作为参考来寻找扫描匹配适合子地图的最佳点。这是通过子地图插值和扫描数据的子像素对齐来实现的。这个过程虽然快,但是不能修复比子地图分辨率明显大的错误。如果你的传感器配置和定时合理,仅仅使用CeresScanMatcher
通常是最好的选择。RealTimeCorrelativeScanMatcher
选项。它使用了与扫描数据在闭环中匹配子地图(后边会有讲解)类似的方法,但是实际上它匹配的是当前的子地图。最佳匹配接下来会用作CeresScanMatcher
的参照。这个扫描匹配器非常昂贵,它将会覆盖除了距离传感器之外的其它所有的传感器信号,但是在特征丰富的环境中它的鲁棒性很好。不管哪种策略,CeresScanMatcher
可以给它的每个输入一个指定的权重。权重表征的是对数据的信任程度,这也可以被看作是静态协方差。权重参数的单位是无量纲的所以不能与其他的权重互相比较。数据源的权重越大,Cartographer 在扫描匹配的时候会给予更多的重视。数据源包括空间占用(扫描数据中的点)、位姿外推器(或RealTimeCorrelativeScanMatcher
)的平移和旋转。
TRAJECTORY_BUILDER_3D.ceres_scan_matcher.occupied_space_weight
TRAJECTORY_BUILDER_3D.ceres_scan_matcher.occupied_space_weight_0
TRAJECTORY_BUILDER_3D.ceres_scan_matcher.occupied_space_weight_1
TRAJECTORY_BUILDER_3D.ceres_scan_matcher.translation_weight
TRAJECTORY_BUILDER_3D.ceres_scan_matcher.rotation_weight
注意:
在 3D SLAM 中,occupied_space_weight_0
和occupied_space_weight_1
参数是相关的,分别指向高分辨率和低分辨率过滤点云。
CeresScanMatcher
的名字来源于 Ceres Solver,一个谷歌开发的用来解非线性最小二乘问题的库。扫描匹配问题被建模为这样一个最小化的问题,两个扫描之间的运动(一个变换矩阵)是需要确定的一个参数。Ceres 使用给定迭代次数的下降算法来对运动做出优化。Ceres 可以根据你的需要来调整收敛速度。
TRAJECTORY_BUILDER_nD.ceres_scan_matcher.ceres_solver_options.use_nonmonotonic_steps
TRAJECTORY_BUILDER_nD.ceres_solver_options.max_num_iterations
TRAJECTORY_BUILDER_nD.ceres_scan_matcher.ceres_solver_options.num_threads
RealTimeCorrelativeScanMatcher
参数可以根据你是否信任你的数据来开关它。它的工作机理是从搜索窗口(search window)中搜索相似的扫描数据,其中搜索窗口通过最大距离半径和最小角度半径来定义。当使用搜索窗口中的扫描数据进行扫描匹配时,可以针对平移与旋转分量选择不同的权重。你可以调整这些权重,比如你知道你的机器人压根就没发生旋转。
TRAJECTORY_BUILDER_nD.use_online_correlative_scan_matching
TRAJECTORY_BUILDER_nD.real_time_correlative_scan_matcher.linear_search_window
TRAJECTORY_BUILDER_nD.real_time_correlative_scan_matcher.angular_search_window
TRAJECTORY_BUILDER_nD.real_time_correlative_scan_matcher.translation_delta_cost_weight
TRAJECTORY_BUILDER_nD.real_time_correlative_scan_matcher.rotation_delta_cost_weight
为了避免每个子地图插入太多的扫描数据,一旦扫描匹配器找到了两个扫描数据之间的运动关系,就会转到运动过滤器。如果本次扫描的运动被认为不够重要,那么本次扫描会被丢弃。一次扫描能够被插入当前子地图的前提是它的运动超过了一定的距离、角度或者时间阈值。
TRAJECTORY_BUILDER_nD.motion_filter.max_time_seconds
TRAJECTORY_BUILDER_nD.motion_filter.max_distance_meters
TRAJECTORY_BUILDER_nD.motion_filter.max_angle_radians
当 local SLAM 接收到给定数量的距离数据时就认为一片子地图构建完成了。Local SLAM 随着时间会发生漂移,而 global SLAM 则用来修复漂移。子地图必须足够的小以保证其中的漂移低于分辨率,所以它们可以被局部修正。另一方面,它们又应该足够大,这样才能将它们区分出来,闭环检测才能工作正常。
TRAJECTORY_BUILDER_nD.submaps.num_range_data
子地图可以用几张不同的数据结构来存储范围数据:最常用的便是方法叫做概率网格。然而,在 2D SLAM 中,你也可以选择则用 TSDF(Truncated Signed Distance Fields)。
TRAJECTORY_BUILDER_2D.submaps.grid_options_2d.grid_type
概率网格将空间划分为 2D 或 3D 表格,其中每个单元格有固定的大小并且包含一个是否被阻塞的概率。这个概率根据“hits”(测量范围数据)和“misses”(传感器和测量点之间的自由空间)进行更新。hits 和 misses 可以在占用概率计算的时候设定不同的权重来给予占据或者自由空间测量或多或少的信任。
TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.hit_probability
TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.miss_probability
TRAJECTORY_BUILDER_3D.submaps.range_data_inserter.hit_probability
TRAJECTORY_BUILDER_3D.submaps.range_data_inserter.miss_probability
在 2D SLAM 中,每个子地图仅存储一个概率网格。在 3D 中,由于扫描匹配执行的原因,使用两个 hybrid(混合)概率网格。(“hybrid”仅仅表示一种内部树状数据表示且对用户来说是抽象的)
扫描匹配首先将低分辨率点云的远距离点与低分辨率混合网格对齐,然后通过将高分辨率的近距离点与高分辨率混合网格对齐来细化位姿。
TRAJECTORY_BUILDER_2D.submaps.grid_options_2d.resolution
TRAJECTORY_BUILDER_3D.submaps.high_resolution
TRAJECTORY_BUILDER_3D.submaps.low_resolution
TRAJECTORY_BUILDER_3D.high_resolution_adaptive_voxel_filter.max_range
TRAJECTORY_BUILDER_3D.low_resolution_adaptive_voxel_filter.max_range
注意:
Cartographer ROS 提供了一个 RViz 插件来显示子地图,你可以通过编号来选择你想看的子地图。在 3D 中,RViz 只显示 3D 混合概率网格的 2D 投影(灰度图)。RViz 的左面板中可以在低和高分辨率混合概率网格显示中切换。
当 local SLAM 生成连续子地图的时候,全局优化(通常称为“优化问题”或者“稀疏姿态调整”)任务就在后台运行了。它的作用是重新安排彼此之间的子地图,以形成一个连贯的全局地图。比如,这个优化负责修改当前建好的轨迹以根据闭环正确地对齐子地图。
等到一定数量的轨迹节点插入了,优化过程就开始批量的运行了。你可以根据你需要的运行频率来调整批次的大小。
POSE_GRAPH.optimize_every_n_nodes
注意:
设置POSE_GRAPH.optimize_every_n_nodes
为 0 是一种禁用 global SLAM 的便捷方式,这样就可以将注意力放在 local SLAM 上了。通常这是 Cartographer 调优首先要做的事。
global SLAM 是一种 “GraphSLAM(图 SLAM)” ,它本质上是一种位姿优化,通过在节点和子图建立约束然后优化得到的约束图来工作。可以直观地将约束视为把所有节点捆绑在一起的小绳索。稀疏位姿调整将这些小绳索完全捆绑在一起。生成的网络叫做“位姿图”。
注意:
约束可以在 RViz 中可视化,这可以非常方便的用来调优 global SLAM。你也可以开关POSE_GRAPH.constraint_builder.log_matches
来获取格式化为直方图的约束生成器的常规报告。
POSE_GRAPH.constraint_builder.max_constraint_distance
POSE_GRAPH.fast_correlative_scan_matcher.linear_search_window
POSE_GRAPH.fast_correlative_scan_matcher_3d.linear_xy_search_window
POSE_GRAPH.fast_correlative_scan_matcher_3d.linear_z_search_window
POSE_GRAPH.fast_correlative_scan_matcher*.angular_search_window
注意:
在实际中,全局约束不仅可以在单个轨迹上寻找闭环,也可以对齐多个机器人记录的不同的轨迹但是在此文档中我们不讨论这个用法和与“全局定位”参数有关的内容。
为了限制约束(和计算)的数量,Cartographer 只考虑构建约束的所有关闭节点的子采样集。这是通过一个采样率常熟控制的。采样太少节点可能导致错过约束和无效的闭环,采样太多节点又容易拖慢 global SLAM 的速度且不能实时闭环。
POSE_GRAPH.constraint_builder.sampling_ratio
当用节点和子地图构建约束时,它们先经过第一个扫描匹配器FastCorrelativeScanMatcher
。这个扫描匹配器是专门为 Cartographer 设计的,可以实现实时闭环扫描匹配。FastCorrelativeScanMatcher
依靠“Branch and bound(分支和边界)”机制来在不同网格分辨率下工作并有效地消除不正确的匹配。这种机制在本文之前提到的 Cartographer 论文中有很多地介绍,它工作在深度可控的搜索树上。
POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher.branch_and_bound_depth
POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher_3d.branch_and_bound_depth
POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher_3d.full_resolution_depth
一旦FastCorrelativeScanMatcher
具有好的足够好的提议(超过最小匹配分数),它就会被送入 Ceres 扫描匹配器进行位姿细化。
POSE_GRAPH.constraint_builder.min_score
POSE_GRAPH.constraint_builder.ceres_scan_matcher_3d
POSE_GRAPH.constraint_builder.ceres_scan_matcher
当 Cartographer 运行优化问题时,Ceres 用来根据多个残差重新排列子图。残差是使用加权代价函数计算的。全局优化使用代价函数来考虑许多数据源:全局(闭环)约束、非全局(匹配器)约束,IMU 加速和旋转测量、local SLAM 位姿粗估计、里程计源或者固定坐标系(如 GPS 系统)。权重和 Ceres 选项可以按照 Local SLAM 一节中介绍的配置。
POSE_GRAPH.constraint_builder.loop_closure_translation_weight
POSE_GRAPH.constraint_builder.loop_closure_rotation_weight
POSE_GRAPH.matcher_translation_weight
POSE_GRAPH.matcher_rotation_weight
POSE_GRAPH.optimization_problem.*_weight
POSE_GRAPH.optimization_problem.ceres_solver_options
注意:
你可以打开POSE_GRAPH.max_num_final_iterations
来寻找关于优化问题中使用的残差的有用信息。
作为其 IMU 残差的一部分,优化问题为 IMU 位姿提供了一些灵活性,默认情况下, Ceres 可以自由地优化 IMU 和跟踪坐标系之间的外部校准。如果你不信任你 IMU 的位姿,可以记录 Ceres 的全局结果然后用来提高你的外部校准。如果 Ceres 没有正确地优化你的 IMU 位姿并且你走狗相信你的外部校准,那么你可以不改变这个位姿。
POSE_GRAPH.optimization_problem.log_solver_summary
POSE_GRAPH.optimization_problem.use_online_imu_extrinsics_in_3d
在残差中,异常值的影响是由配置了某个 Huber 尺度(scale)的 Huber 损失函数来处理的。 Huber 尺度越大,(潜在)异常值的影响越大。
POSE_GRAPH.optimization_problem.huber_scale
等轨迹生成完成,Cartographer 运行一个新的全局优化,通常比之前的全局优化迭代次数要多。这个过程用来完善 Cartographer 的最终结果,且通常不必是实时的,所以经常选择一个很大的迭代次数。
POSE_GRAPH.max_num_final_iterations