欢迎访问我的博客首页。
cartographer
1. 编译
cartographer 可以作为 gRPC 服务器,也可以作为 plain cmake package 被 cartographer_ros 中的 catkin package 调用。文档1介绍了系统要求及怎样安装 cartographer 依赖。cartographer ros 使用 ROS1,而 ROS1 最高支持到 Ubuntu 20.04,所以不能安装更高版本的 Ubuntu,否则无法安装 python3-rosdep。
文档2详细介绍了使用 ros 时,下载源码、编译、运行 cartographer 的详细步骤。下面我们详细介绍。
1.1 安装基础依赖
ubunut 20.04 使用下面的命令安装 ros 工具包和编译工具。ros 工具包用于创建工作空间,拉取源码。
sudo apt-get update
sudo apt-get install -y python3-wstool python3-rosdep ninja-build stow
上面的命令不建议添加 -y 选项。因为 -y 选项会默认同意安装过程中的所有询问,这会使我们发现不了错误。比如可能会提示 “匹配到 python3-rosdep2,而不是 python3-rosdep”。ubuntu20 必须安装 python3-rosdep,否则会出现依赖错误。如果出现该错误,请更换 ROS 源。
1.2 获取源码
使用下面的命令获取源码。第 3 行命令会在 catkin_ws 下创建文件夹 src,并在 src 中添加文件 .rosinstall。第 4 行命令会在 src 中添加文件 .rosinstall.bak。第 5 行命令会在 src 下创建非空文件夹 cartographer 和 cartographer_ros。至此,我们已获取所有源码。
mkdir catkin_ws
cd catkin_ws
wstool init src
wstool merge -t src https://raw.githubusercontent.com/cartographer-project/cartographer_ros/master/cartographer_ros.rosinstall
wstool update -t src
在 src 文件夹中搜索 package.xml 会有 4 个搜索结果,分别属于 4 个 ROS 包。cartographer 文件夹是一个包,cartographer_ros 中有 cartographer_ros、cartographer_ros_msgs 和 cartographer_rviz 三个包。
访问 raw.githubusercontent.com 可能会超时,请多试几次,可以切换手机热点。或更换 DNS 服务器:使用 sudo gedit /etc/hosts 命令打开 /etc/hosts 并添加:
199.232.68.133 raw.githubusercontent.com
185.199.108.133 raw.githubusercontent.com
185.199.109.133 raw.githubusercontent.com
185.199.110.133 raw.githubusercontent.com
185.199.111.133 raw.githubusercontent.com
1.3 安装源码依赖
第一步安装的是基本依赖,现在安装其它依赖。rosdep 命令会解析并安装 ros 包的 package.xml 文件指定的依赖。
sudo rosdep init
rosdep update
rosdep install --from-paths src --ignore-src --rosdistro=${ROS_DISTRO} -y
执行上面第 3 行命令可能出现 2 个错误。
错误1:报错如下
WARNING: ROS_PYTHON_VERSION is unset. Defaulting to 3
ERROR: the following packages/stacks could not have their rosdep keys resolved
to system dependencies:
cartographer: [libabsl-dev] defined as “not available” for OS version [focal]
cartographer_ros_msgs: Cannot locate rosdep definition for [std_msgs]
cartographer_ros: Cannot locate rosdep definition for [rosunit]
cartographer_rviz: Cannot locate rosdep definition for [rviz]
首先考虑是不是安装了 python3-rosdep2 而不是 python3-rosdep。有些教程说把上面等号后面使用花括号表示的变量换成你的 ubuntu 对于的 ROS 版本,如 ubuntu 20.04 对应的 noetic。安装了 python3-rosdep2 还可能出现下面的错误:
executing command [sudo -H apt-get install -y ros-noetic-message-generation]
[sudo] xxx 的密码:
正在读取软件包列表… 完成
正在分析软件包的依赖关系树
正在读取状态信息… 完成
E: 无法定位软件包 ros-noetic-message-generation
ERROR: the following rosdeps failed to install
apt: command [sudo -H apt-get install -y ros-noetic-message-generation] failed
错误2:报错如下
ERROR: the following packages/stacks could not have their rosdep keys resolved
to system dependencies:
cartographer: [libabsl-dev] defined as “not available” for OS version [focal]
把 src/cartographer/package.xml 第 46 行的 libabsl-dev 注释掉。
命令 rosdep init 从 ros 官方服务器上下载一个 20-default.list 文件。重复执行该命令会出现以下错误,忽略即可:
# 超时
ERROR: cannot download default sources list from:
https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sources.list.d/20-default.list
Website may be down.
# 第一次成功
Wrote /etc/ros/rosdep/sources.list.d/20-default.list
Recommended: please run
rosdep update
# 成功后再次执行
ERROR: default sources list file already exists:
/etc/ros/rosdep/sources.list.d/20-default.list
Please delete if you wish to re-initialize
命令 rosdep update 也会访问 raw.githubusercontent.com,这个命令很难顺利完成。如果已在第 2 步更换 DNS 服务器,该命令仍不能成功,请使用代理。或者在 /usr/lib/python3/dist-packages 中按下表更换 gitee 源,其中路径中的 python3 视自己的情况而定。
文件 | 变量 | 路径 |
---|---|---|
rosdep2/sources_list.py | DEFAULT_SOURCES_LIST_URL | https://gitee.com/ssonic/rosdistro/raw/master/rosdep/sources.list.d/20-default.list |
rosdep2/gbpdistro_support.py | FUERTE_GBPDISTRO_URL | https://gitee.com/ssonic/rosdistro/raw/master/releases/fuerte.yaml |
rosdep2/rep3.py | REP3_TARGETS_URL | https://gitee.com/ssonic/rosdistro/raw/master/releases/targets.yaml |
rosdistro/__init__.py | DEFAULT_INDEX_URL | https://gitee.com/ssonic/rosdistro/raw/master/index-v4.yaml |
1.4 编译
在 catkin_ws 文件夹内执行下面的命令。
catkin_make_isolated --install --use-ninja
2. 数据集与运行
本节参考 Running Cartographer ROS on a demo bag、Cartographer Public Data。
首先我们从 cartographer_ros/node_constants.h 中可以看到 cartographer 订阅四类话题:
// 1.1 Range Data。
constexpr char kLaserScanTopic[] = "scan"; // 激光雷达。
constexpr char kMultiEchoLaserScanTopic[] = "echoes"; // 多回波激光雷达。
constexpr char kPointCloud2Topic[] = "points2"; // 点云。
// 1.2 IMU Data。
constexpr char kImuTopic[] = "imu";
// 1.3 Odometry Pose。
constexpr char kOdometryTopic[] = "odom";
// 1.4 Fixed Frame Pose。
constexpr char kNavSatFixTopic[] = "fix";
constexpr char kLandmarkTopic[] = "landmark";
2.1 德意志博物馆
先下载德意志博物馆数据集,再在 catkin_ws 文件夹内执行 source 命令,最后执行 launch 命令。
# 2D
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag
source install_isolated/setup.bash
roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag
# 3D
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_3d/with_intensities/b3-2016-04-05-14-14-00.bag
source install_isolated/setup.bash
roslaunch cartographer_ros demo_backpack_3d.launch bag_filename:=${HOME}/Downloads/b3-2016-04-05-14-14-00.bag
无论二维数据集还是三维数据集,每个数据集中都包含 IMU 数据、水平激光雷达数据和竖直激光雷达数据。使用命令 rosbag info cartographer_paper_deutsches_museum.bag 查看二维数据集,其话题有
topics: horizontal_laser_2d 70358 msgs : sensor_msgs/MultiEchoLaserScan
imu 478244 msgs : sensor_msgs/Imu
vertical_laser_2d 69363 msgs : sensor_msgs/MultiEchoLaserScan
文件 cartographer_ros/launch/backpack_2d.launch 中的话题映射为
<remap from="echoes" to="horizontal_laser_2d" />
因此,cartographer 会订阅该数据集的 horizontal_laser_2d(echoes) 和 imu 话题。
2.2 静态路标 MiR
该数据集有 MiR100 机器人采集。特征点检测(landmark detection) 由固定在其顶部的 Logitech Webcam C930e Full HD camera 负责。
在 src 文件夹内执行下面的命令以获取 mir 包,然后重新编译。mir 包即 Cartographer ROS for Mobile Industrial Robots Platforms,用于移动工业机器人平台的 cartographer ros。
git clone https://github.com/googlecartographer/cartographer_mir.git
编译时如果出现下面的错误,请使用 sudo apt install libgmock-dev 安装 gmock。
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
GMOCK_LIBRARY (ADVANCED)
linked by target “time_conversion_test” in directory /home/xxx/workspace/cartographer/cartographer_ws/src/cartographer_ros/cartographer_ros
linked by target “configuration_files_test” in directory /home/xxx/workspace/cartographer/cartographer_ws/src/cartographer_ros/cartographer_ros
linked by target “msg_conversion_test” in directory /home/xxx/workspace/cartographer/cartographer_ws/src/cartographer_ros/cartographer_ros
linked by target “metrics_test” in directory /home/xxx/workspace/cartographer/cartographer_ws/src/cartographer_ros/cartographer_ros
然后使用下面的命令下载数据集并运行。
# Download the landmarks example bag.
wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/mir/landmarks_demo_uncalibrated.bag
# source
source install_isolated/setup.bash
# Launch the landmarks demo.
roslaunch cartographer_mir offline_mir_100_rviz.launch bag_filename:=${HOME}/Downloads/landmarks_demo_uncalibrated.bag
注意第三个命令中是 bag_filenames,没有 s 会报错。
RLException: [/home/xxx/workspace/cartographer/cartographer_ws/install_isolated/share/cartographer_mir/launch/offline_mir_100_rviz.launch] requires the ‘bag_filenames’ arg to be set
使用命令 rosbag info landmarks_demo_uncalibrated.bag 查看数据集,其话题有
topics: /b_scan 4558 msgs : sensor_msgs/LaserScan
/clock 9330 msgs : rosgraph_msgs/Clock
/f_scan 4546 msgs : sensor_msgs/LaserScan
/imu_data 17923 msgs : sensor_msgs/Imu
/landmark 1355 msgs : cartographer_ros_msgs/LandmarkList
/odom_enc 14853 msgs : nav_msgs/Odometry
/rosout 16 msgs : rosgraph_msgs/Log (3 connections)
/rosout_agg 8 msgs : rosgraph_msgs/Log
/tf 21489 msgs : tf2_msgs/TFMessage
/tf_static 1 msg : tf2_msgs/TFMessage
文件 cartographer_mir/launch/offline_mir_100_rviz.launch 中的话题映射为
<remap from="scan_1" to="f_scan" />
<remap from="scan_2" to="b_scan" />
<remap from="imu" to="imu_data" />
<remap from="ignore_odom" to="odom" />
<remap from="odom" to="odom_enc" />
因此,cartographer 会订阅该数据集的 f_scan(scan_1)、b_scan(scan_2)、imu_data(imu) 和 odom_enc(odom) 话题。
3. ImuTracker
IMU 由加速度计和陀螺仪组成。加速度计能测量三个正交方向的加速度,陀螺仪能测量三个正交方向的角速度。
使用 IMU 跟踪时,方向指位姿中的旋转,即从当前坐标系 n 到世界坐标系 0 的旋转 o 0 n o_{0n} o0n。静止时的重力向量表示 IMU 的倾斜情况。如图 2.1,蓝色向上箭头表示 IMU 水平静止放置时的重力向量 g ⃗ n − 1 = [ 0 , 0 , 1 ] \vec g_{n-1} = [0, 0, 1] gn−1=[0,0,1];当 IMU 有旋转 q ( n − 1 ) n q_{(n-1)n} q(n−1)n 时,重力向量 g ⃗ n = q ( n − 1 ) n − 1 ⋅ g ⃗ n − 1 \vec g_n = q^{-1}_{(n-1)n} \cdot \vec g_{n-1} gn=q(n−1)n−1⋅gn−1。
图 2.1 是 cartographer 中的 ImuTracker。传感器作缓慢运动时,角速度不变,加速度为重力加速度。
前进到时刻 n:我们可以由时刻 n-1 时的角速度 ω \omega ω 得到时刻 n 到时刻 n-1 的旋转 q ( n − 1 ) n q_{(n-1)n} q(n−1)n。方向和重力向量的旋转始终是一致的,因此利用 q ( n − 1 ) n q_{(n-1)n} q(n−1)n 可以更新这两个量。
观测到线性加速度 a:缓慢运动时线性加速度 a 就是陀螺仪测得的重力方向的反向。使用指数移动平均值更新重力向量。重力向量的变化量 q ( n − 1 ) n q_{(n-1)n} q(n−1)n 表示传感器坐标系的旋转,可以用于更新方向。图中的函数 f ( a , b ) f(a, b) f(a,b) 代表 Eigen::Quaterniond::FromTwoVectors(a, b),表示从向量 a 到向量 b 的旋转。
4. 参考
- cartographer 论文,sci-hub,2016。
- cartographer 源码,github。
- cartographer 文档。
- cartographer 源码阅读,知乎专栏,2018-2021。
- cartographer 思想解读,CSDN,2020。位姿图讲解较详细。
- protobuf 教程,CSDN,2022。
- cartographer 源码阅读,高乙超。
- 视频,B 站,2021。这 5 个视频很好地讲解了数据处理流水线、激光数据处理和外推器。
- 激光SLAM的发展和应用趋势,B 站 深蓝学院 曾书格,2021。
- Cartographer代码详解专题五:算法主线程讲解, B 站,2021。
- 论文讲解,B 站,2022。
- ROS零基础入门教程百日谈合集第9期: SLAM同步定位与建图之Google Cartographer ,B 站,2021。