Cartographer SLAM 系统架构与算法框架(1)
单个机器人的完整运动历史,由时序排列的Nodes组成。// 轨迹唯一标识 (支持多机器人)// 时间戳// IMU 重力对齐// 滤波后点云// 局部坐标系位姿支持多轨迹并行 (Multi-robot SLAM)每个 Node 存储压缩后的点云数据 (用于闭环验证)Cartographer 的架构设计体现了分层解耦前端: 保证实时性和局部精度 (Scan-to-Submap)后端: 保证全局一致性
Cartographer SLAM 系统架构与算法框架
0. 扫地机器人 SLAM 背景
0.1 扫地机器人 SLAM 的特殊挑战
在扫地机器人导航系统中,SLAM (Simultaneous Localization and Mapping) 是核心技术模块。与其他移动机器人相比,扫地机器人面临独特的技术挑战:
硬件约束:
- 成本敏感: 消费级产品价格限制 (< $500),传感器选择受限
- 算力受限: 嵌入式 ARM 处理器 (如 RK3588, Jetson Nano),CPU < 4 核
- 功耗约束: 电池续航要求 SLAM 算法功耗 < 5W
- 传感器配置: 单线 LiDAR (360° 扫描) + 低成本 IMU + 轮式编码器
环境挑战:
| 挑战 | 描述 | 对 SLAM 的影响 |
|---|---|---|
| 家居环境复杂 | 桌椅、沙发、杂物密集 | 动态物体干扰多 |
| 重复结构 | 对称房间、长走廊 | 闭环误检风险高 |
| 地面材质 | 地毯、瓷砖、木地板 | 轮式里程计打滑严重 |
| 低矮障碍物 | 门槛、电线、玩具 | 2D LiDAR 易漏检 |
| 镜面/玻璃 | 落地窗、镜子 | LiDAR 虚假反射 |
| 光照变化 | 视觉 SLAM 失效 | 需要 LiDAR-based |
性能要求:
- 实时性: 位姿更新频率 > 10Hz (控制回路需求)
- 精度: 长期漂移 < 1% 轨迹长度 (保证覆盖率)
- 鲁棒性: 连续运行 2-3 小时不崩溃
- 启动速度: 冷启动建图 < 5 秒
0.2 为什么 Cartographer 是扫地机器人 SLAM 的首选
Cartographer 在扫地机器人领域的核心优势:
1. 硬件适配性强
| 需求 | Cartographer 支持 | 其他方案对比 |
|---|---|---|
| 低成本 LiDAR | ✅ 原生支持单线 2D LiDAR | ORB-SLAM 需要相机 |
| 嵌入式平台 | ✅ 可配置计算负载 (sampling_ratio) | LeGO-LOAM 需要 GPU |
| 无 IMU 降级 | ✅ 可纯 LiDAR 运行 (虽不推荐) | LOAM 必须 IMU |
| 编码器融合 | ✅ 原生支持 Odometry | Hector SLAM 不支持 |
关键代码示例:
-- 扫地机器人典型配置
TRAJECTORY_BUILDER_2D = {
use_imu_data = false, -- 低成本方案无 IMU
voxel_filter_size = 0.05, -- 适应嵌入式算力
submaps.num_range_data = 45, -- 减半降低内存
}
2. 强闭环能力 (核心优势)
问题: 扫地机器人在重复清扫时必须识别已访问区域,避免重复劳动。
Cartographer 解决方案:
传统方案 (Gmapping):
粒子滤波 → 重复房间 → 粒子退化 → 闭环失败 → 地图错乱
❌ 成功率: ~60% (在对称房间)
Cartographer:
Branch-and-Bound → 全局搜索 → 必然找到闭环 → 图优化消除误差
✅ 成功率: ~95% (相同场景)
实测数据 (某扫地机厂商):
- 测试环境: 100㎡ 三室一厅 (对称结构)
- 清扫路径: 8 字形 (必然闭环)
| SLAM 方案 | 闭环成功率 | 地图一致性误差 | CPU 占用 |
|---|---|---|---|
| Gmapping | 62% | ±15cm | 80% |
| Hector | 45% | ±25cm | 60% |
| Cartographer | 94% | ±3cm | 120% |
结论: Cartographer 以 1.5× CPU 代价换取 50% 闭环成功率提升。
3. 长时间运行稳定性
问题: 扫地机需连续工作 2-3 小时,累积误差会导致地图崩溃。
Cartographer 后端优化:
Gmapping (纯前端):
t=0min: 误差 0cm ✅
t=30min: 误差 50cm ⚠️
t=60min: 误差 1.5m ❌ 地图不可用
Cartographer (前端 + 后端):
t=0min: 误差 0cm ✅
t=30min: 误差 30cm ⚠️ (前端累积)
t=31min: 误差 2cm ✅ (后端闭环修正)
t=120min: 误差 5cm ✅ (多次闭环)
关键机制:
- 定期优化: 每 90 个 Node 触发全局优化
- 累积误差重置: 闭环检测后误差清零
- 内存管理: 纯定位模式仅保留 3 个 Submap
4. 工业级鲁棒性
Google 内部验证场景:
- Google 办公楼导航机器人 (2014-2016)
- 仓库物流 AGV (2016-至今)
- 消费级扫地机 (通过 OEM 授权)
已知商用扫地机使用 Cartographer 的品牌:
- 科沃斯 (Ecovacs): 部分高端型号 (T8 系列)
- 石头科技 (Roborock): S7/S8 系列 (改进版)
- 追觅 (Dreame): L10 Pro 系列
- iRobot: 部分 Roomba 型号 (间接参考)
注: 商业产品通常对 Cartographer 进行定制优化,如:
- 简化后端 (sampling_ratio = 0.1)
- 混合导航 (Cartographer 建图 + A* 路径规划)
- 云端地图服务 (离线优化)
0.3 Cartographer 在扫地机 SLAM 中的地位
为什么说 Cartographer 是"不能绕过的框架"?
1. 学术界基准 (Benchmark Standard)
在 SLAM 论文中,Cartographer 是标准对比基线:
论文标题 对比方法
──────────────────────────── ──────────────────────
"Improved LiDAR SLAM for..." vs Cartographer + Gmapping
"Deep Learning-based SLAM" baseline: Cartographer
"Multi-robot Cooperative..." extend Cartographer
Google Scholar 引用量 (截至 2025):
- Cartographer 原始论文: 2,400+ 次引用
- 扫地机相关引用: ~600 次
2. 开源社区活跃度
| 指标 | Cartographer | Gmapping | Hector SLAM |
|---|---|---|---|
| GitHub Stars | 7.2k | 1.1k (ROS pkg) | 800 |
| Issues (已解决) | 1,500+ | 200+ | 150+ |
| Contributors | 120+ | 30+ | 15+ |
| 最后更新 | 2024-12 | 2019-06 | 2018-03 |
活跃维护: Cartographer 仍在持续更新,支持最新 ROS2 Humble/Iron。
3. 技术演进路径
扫地机 SLAM 技术发展史:
2010-2014: Gmapping 时代
→ 基于粒子滤波
→ 问题: 大场景崩溃、闭环弱
2014-2018: Cartographer 兴起
→ Google 开源 (2016)
→ 解决大场景 + 强闭环
→ 成为工业标准
2018-现在: 深度学习增强
→ Cartographer + CNN (动态物体过滤)
→ Cartographer + PointNet (特征增强)
→ 但核心框架仍是 Cartographer
关键节点:
- 2016.10: Google 开源 Cartographer
- 2017.03: 首个商业扫地机集成 (未公开型号)
- 2019: ROS 社区默认推荐方案
- 2021: 扫地机行业事实标准
4. 竞争方案对比
当前扫地机 SLAM 技术栈:
| 方案 | 市场占有率 | 代表产品 | 核心缺陷 |
|---|---|---|---|
| Gmapping | 15% | 低端扫地机 | 大房间失效 |
| Hector SLAM | 5% | 无编码器方案 | 长期漂移 |
| Cartographer | 60% | 中高端产品 | CPU 负载高 |
| 自研方案 | 15% | iRobot, Dyson | 闭环算法类似 Cartographer |
| 视觉 SLAM | 5% | 实验性产品 | 光照依赖强 |
结论: Cartographer 占据 60% 市场份额,是扫地机器人 SLAM 的事实标准。
0.4 学习 Cartographer 的必要性
对于扫地机器人算法工程师:
- 必备技能:
- 理解 Cartographer 原理是行业基础要求
- 面试高频考点: Branch-and-Bound, Submap 机制, SPA 优化
- 技术债务:
- 不懂 Cartographer = 无法调试线上问题
- 无法优化性能 (70% CPU 瓶颈在闭环检测)
- 创新基础:
- 所有改进方案都基于 Cartographer 框架
- 如: 动态物体过滤、语义增强、多楼层建图
本系列文档目标:
从系统架构到数学理论,从源码实现到工程调优,全方位掌握 Cartographer,使读者能够:
- 独立部署并调优 Cartographer (生产环境)
- 诊断并解决线上 SLAM 问题 (闭环失败、地图扭曲等)
- 基于 Cartographer 进行算法创新 (添加新传感器、改进闭环检测)
1. 设计哲学
1.1 核心思想
Cartographer 采用 图优化 (Graph-based SLAM) 范式,区别于传统的滤波方法 (如 EKF-SLAM):
| 特性 | 图优化 (Cartographer) | 滤波方法 (Gmapping) |
|---|---|---|
| 状态估计 | 批量优化所有历史位姿 | 递推更新当前状态 |
| 误差处理 | 可全局消除累积误差 | 误差不可逆 |
| 计算复杂度 | 后端开销大 (需定期优化) | 实时性好但精度受限 |
| 闭环能力 | 强 (全局搜索 + 约束优化) | 弱 (依赖粒子多样性) |
关键设计决策:
- Submap 分层机制: 将全局问题分解为局部子问题
- 前后端解耦: Local SLAM 负责实时性,Global SLAM 负责精度
- 多传感器融合: 原生支持 LiDAR + IMU + Odometry
2. 系统宏观架构
2.1 模块层次结构
┌─────────────────────────────────────────────────────────────┐
│ Sensor Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LiDAR │ │ IMU │ │ Odometry │ │ Other │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
└───────┼─────────────┼─────────────┼─────────────┼──────────┘
│ │ │ │
└─────────────┴─────────────┴─────────────┘
│
┌─────────────▼─────────────────┐
│ Sensor Bridge │
│ - Timestamp Alignment │
│ - Coordinate Transformation │
└─────────────┬─────────────────┘
│
┌─────────────▼─────────────────┐
│ Collator │
│ - Multi-sensor Fusion │
│ - Ordered Data Dispatch │
└─────────────┬─────────────────┘
│
┌─────────────▼─────────────────┐
│ Map Builder │
│ - Trajectory Management │
│ - Multi-robot Support │
└──────┬──────────────────┬─────┘
│ │
┌─────────▼─────────┐ ┌────▼──────────────────┐
│ Local Trajectory │ │ Pose Graph │
│ Builder (Front) │ │ (Back-end) │
│ │ │ │
│ ┌───────────────┐ │ │ ┌──────────────────┐ │
│ │ Scan Matching │ │ │ │ Constraint │ │
│ │ - CSM │ │ │ │ Builder │ │
│ │ - Ceres │ │ │ │ - Loop Closure │ │
│ └───────────────┘ │ │ └──────────────────┘ │
│ │ │ │
│ ┌───────────────┐ │ │ ┌──────────────────┐ │
│ │ Submap │ │ │ │ Optimization │ │
│ │ Insertion │ │ │ │ Problem (SPA) │ │
│ └───────────────┘ │ │ └──────────────────┘ │
│ │ │ │
│ ┌───────────────┐ │ │ ┌──────────────────┐ │
│ │ Motion Filter │ │ │ │ Global Map │ │
│ └───────────────┘ │ │ │ Assembly │ │
└───────────────────┘ │ └──────────────────┘ │
└───────────────────────┘
│
┌─────────▼─────────┐
│ Output Layer │
│ - Pose Stream │
│ - Occupancy Grid │
│ - Point Cloud │
└───────────────────┘
2.2 数据流详解
阶段 1: 数据采集与预处理
// sensor/collator.cc
Collator::AddSensorData(sensor_id, data) {
// 1. 接收多源数据
// - Range Data: 点云 + 时间戳
// - IMU Data: 加速度 + 角速度
// - Odometry Data: 位姿 + 协方差
// 2. 时间戳对齐 (关键: 处理传感器时钟漂移)
common::Time synchronized_time =
time_conversion_.ToUniversalTime(data.time);
// 3. 按时间顺序排队
sensor_queue_[sensor_id].Push(synchronized_time, data);
// 4. 多传感器融合调度
DispatchQueuedData(); // 按时间戳从小到大分发
}
阶段 2: 前端位姿估计
// mapping/internal/2d/local_trajectory_builder_2d.cc
LocalTrajectoryBuilder2D::AddRangeData(range_data) {
// 1. 点云预处理
RangeData filtered = VoxelFilter(range_data);
// 2. 扫描匹配 (核心算法)
std::unique_ptr<InsertionResult> result =
ScanMatch(filtered, pose_prediction);
// 3. 更新 Submap
InsertIntoSubmap(result->range_data, result->pose);
// 4. 运动过滤
if (MotionFilter::IsSimilar(last_pose, result->pose)) {
return nullptr; // 跳过插入 Node
}
// 5. 创建新 Node
return std::make_unique<InsertionResult>{
.time = range_data.time,
.pose = result->pose,
.range_data = std::move(filtered)
};
}
阶段 3: 后端全局优化
// mapping/internal/pose_graph.cc
PoseGraph::HandleWorkQueue() {
// 1. 监听前端输出
while (HasWork()) {
WorkItem item = work_queue_.Pop();
// 2. 添加新 Node/Submap 到图中
if (item.type == kAddNode) {
AddNodeToGraph(item.node);
// 3. 触发闭环检测
constraint_builder_.MaybeAddConstraint(
item.node, finished_submaps_);
}
// 4. 执行全局优化
if (ShouldRunOptimization()) {
RunOptimization();
// 5. 更新所有位姿
UpdateTrajectoryStates();
}
}
}
3. 核心概念定义
3.1 Trajectory (轨迹)
定义: 单个机器人的完整运动历史,由时序排列的 Nodes 组成。
数据结构:
// mapping/id.h
struct TrajectoryId {
int trajectory_id; // 轨迹唯一标识 (支持多机器人)
};
// mapping/trajectory_node.h
struct TrajectoryNode {
struct Data {
common::Time time; // 时间戳
Eigen::Quaterniond gravity_alignment; // IMU 重力对齐
sensor::RangeData filtered_range_data; // 滤波后点云
transform::Rigid3d local_pose; // 局部坐标系位姿
};
common::Time time() const;
const Data& constant_data() const;
};
关键特性:
- 支持多轨迹并行 (Multi-robot SLAM)
- 每个 Node 存储压缩后的点云数据 (用于闭环验证)
3.2 Submap (子图)
定义: 短期地图单元,包含 N 次连续扫描 (典型 45-90 次)。
设计目的:
- 限定匹配区域: 防止扫描匹配在全局地图上漂移
- 分层优化: 前端优化 Scan-to-Submap,后端优化 Submap-to-Submap
- 内存管理: 旧 Submap 可卸载到磁盘
状态机:
// mapping/submaps.h
enum class SubmapState {
kActive, // 正在接收新扫描
kFinished // 已冻结,可参与全局优化
};
class Submap {
public:
int num_range_data() const; // 包含的扫描数
bool insertion_finished() const;
// 状态转换条件
void SetInsertionFinished() {
CHECK_EQ(state_, kActive);
state_ = kFinished;
}
private:
SubmapState state_ = kActive;
int num_range_data_ = 0;
};
2D Submap 实现:
// mapping/2d/submap_2d.h
class Submap2D : public Submap {
public:
// 核心数据: 占用概率栅格
const Grid2D& grid() const { return *grid_; }
// 插入新扫描
void InsertRangeData(
const sensor::RangeData& range_data,
const RangeDataInserterInterface& inserter);
private:
std::unique_ptr<Grid2D> grid_; // ProbabilityGrid or TSDF
ValueConversionTables conversion_tables_;
};
3.3 Node (位姿节点)
定义: Pose Graph 的顶点,代表某次扫描时的机器人位姿。
分类:
- Intra-submap Node (子图内节点):
- 连接: 同一 Submap 内的连续 Nodes
- 约束来源: Local SLAM 的扫描匹配结果
- 特点: 高权重 (高可信度)
- Inter-submap Node (子图间节点):
- 连接: 不同 Submap 的 Nodes
- 约束来源: Loop Closure 检测
- 特点: 低权重但消除累积误差
约束表示:
// mapping/pose_graph_interface.h
struct Constraint {
enum Tag {
INTRA_SUBMAP, // 局部约束
INTER_SUBMAP // 闭环约束
};
SubmapId submap_id; // 子图 ID
NodeId node_id; // 节点 ID
struct Pose {
transform::Rigid3d zbar_ij; // 观测到的相对位姿
double translation_weight; // 平移约束权重
double rotation_weight; // 旋转约束权重
} pose;
Tag tag;
};
3.4 Sparse Pose Graph (稀疏位姿图)
定义: 后端优化的核心数据结构。
图结构:
- 顶点 (Vertices): Submaps + Nodes
- 边 (Edges): Constraints (Intra + Inter)
数学表达:
G = ( V , E ) \mathcal{G} = (\mathcal{V}, \mathcal{E}) G=(V,E)
其中:
- V = T ∗ s i ∗ i = 1 N s ∪ T ∗ n j ∗ j = 1 N n \mathcal{V} = \mathbf{T}*s^i*{i=1}^{N_s} \cup \mathbf{T}*n^j*{j=1}^{N_n} V=T∗si∗i=1Ns∪T∗nj∗j=1Nn (Submap 位姿 + Node 位姿)
- E = ( T ∗ i j , Σ ∗ i j ) \mathcal{E} = (\mathbf{T}*{ij}, \Sigma*{ij}) E=(T∗ij,Σ∗ij) (相对位姿约束 + 协方差)
优化目标:
KaTeX parse error: Invalid delimiter type 'font'
稀疏性来源:
- 不是所有 Node 对都有约束 (仅局部连续 + 闭环)
- 稀疏矩阵求解器 (Ceres SPARSE_NORMAL_CHOLESKY) 加速优化
4. 模块职责划分
4.1 Sensor Bridge
职责:
- 传感器数据类型转换 (ROS msg → Cartographer 内部格式)
- 坐标系变换 (sensor frame → tracking frame)
- 数据有效性检查
关键代码:
// sensor/internal/trajectory_collator.cc
void SensorBridge::HandleRangeMessage(
const sensor_msgs::LaserScan& msg) {
// 1. 转换为内部格式
sensor::PointCloud point_cloud = ToPointCloud(msg);
// 2. 坐标变换
if (!tf_buffer_.CanTransform(tracking_frame_, msg.header.frame_id)) {
LOG(ERROR) << "Cannot transform from " << msg.header.frame_id;
return;
}
transform::Rigid3d sensor_to_tracking =
LookupTransform(msg.header.frame_id, tracking_frame_);
// 3. 分发给 Map Builder
map_builder_->AddRangeData(
trajectory_id_,
TransformPointCloud(point_cloud, sensor_to_tracking));
}
4.2 Map Builder
职责:
- 管理多个 Trajectory (多机器人场景)
- 分发数据到对应的 Local Trajectory Builder
- 触发 Pose Graph 优化
接口设计:
// mapping/map_builder_interface.h
class MapBuilderInterface {
public:
virtual int AddTrajectoryBuilder(
const std::set<SensorId>& sensor_ids,
const proto::TrajectoryBuilderOptions& options) = 0;
virtual void FinishTrajectory(int trajectory_id) = 0;
virtual void AddSensorData(
const std::string& sensor_id,
const sensor::Data& data) = 0;
virtual PoseGraphInterface* pose_graph() = 0;
};
4.3 Local Trajectory Builder (前端)
职责:
- 实时位姿跟踪 (Scan Matching)
- Submap 构建与更新
- 输出 Node 给后端
输入/输出:
Input: RangeData + Pose Prediction (来自 Odometry/IMU)
Output: InsertionResult {
pose: 优化后的位姿
range_data: 滤波后点云
insertion_submaps: 涉及的 Submaps
}
4.4 Pose Graph (后端)
职责:
- 维护全局位姿图
- 闭环检测 (Constraint Builder)
- 全局优化 (SPA)
- 输出全局一致的轨迹
线程模型:
// mapping/internal/pose_graph.cc
class PoseGraph {
private:
// 工作队列 (接收前端输出)
std::deque<WorkItem> work_queue_ GUARDED_BY(work_queue_mutex_);
// 后台线程
void WorkQueueRunner() {
while (!shutdown_) {
HandleWorkQueue(); // 处理 Node 插入、闭环检测、优化
}
}
std::thread work_thread_;
};
5. 配置参数层级
Cartographer 使用 Lua 脚本管理参数:
-- configuration_files/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,
},
}
参数层级结构:
TRAJECTORY_BUILDER
├── trajectory_builder_2d
│ ├── use_imu_data
│ ├── submaps
│ │ ├── num_range_data
│ │ └── grid_options_2d
│ ├── ceres_scan_matcher
│ └── motion_filter
│
└── trajectory_builder_3d
└── ...
POSE_GRAPH
├── optimize_every_n_nodes
├── constraint_builder
│ ├── sampling_ratio
│ ├── min_score
│ └── fast_correlative_scan_matcher_3d
│
└── optimization_problem
├── huber_scale
└── odometry_translation_weight
6. 关键设计权衡
| 设计选择 | 优势 | 代价 |
|---|---|---|
| Submap 分层 | 局部匹配精度高,内存可控 | 需要管理 Submap 状态机 |
| 前后端解耦 | 前端实时性好,后端精度高 | 数据同步复杂度增加 |
| 稀疏位姿图 | 计算复杂度低 (vs 稠密滤波) | 需要设计闭环检测策略 |
| Ceres 求解器 | 鲁棒性强,易扩展 Cost Function | 引入第三方依赖 |
| 多分辨率地图 | 加速闭环搜索 | 内存占用增加 30% |
7. 与其他 SLAM 系统对比
7.1 vs ORB-SLAM (视觉 SLAM)
| 维度 | Cartographer | ORB-SLAM |
|---|---|---|
| 传感器 | LiDAR + IMU | 单/双目相机 |
| 特征提取 | 无 (直接点云匹配) | ORB 特征点 |
| 闭环检测 | Fast CSM (几何) | Bag-of-Words (语义) |
| 动态环境 | 弱 (需额外滤波) | 强 (特征筛选) |
| 纹理依赖 | 无 | 强 (无纹理场景失效) |
7.2 vs LeGO-LOAM (LiDAR SLAM)
| 维度 | Cartographer | LeGO-LOAM |
|---|---|---|
| 优化方法 | Graph-based | LM 优化 |
| 地图表示 | Occupancy Grid | Point Cloud |
| 实时性 | 中 (70% CPU 给后端) | 高 (10Hz) |
| 大场景 | 强 (Submap 机制) | 中 (累积误差问题) |
| 地面约束 | 无 | 有 (地面分割) |
8. 总结
Cartographer 的架构设计体现了 分层解耦 的工程哲学:
- 前端: 保证实时性和局部精度 (Scan-to-Submap)
- 后端: 保证全局一致性 (Submap-to-Submap)
- 接口: 通过 WorkQueue 解耦前后端,支持异步优化
核心优势:
- 强闭环能力 (Branch-and-Bound 算法)
- 可扩展性 (易添加新传感器/Cost Function)
- 工业级鲁棒性 (Google 内部验证)
适用场景:
- ✅ 扫地机器人 (最佳应用场景)
- ✅ 室内机器人导航
- ✅ 仓库物流 AGV
- ✅ 大范围建图 (商场、工厂)
不适用场景:
- ❌ 快速运动 (如无人机,IMU 漂移严重)
- ❌ 高动态环境 (人群密集区域)
- ❌ 纯视觉 SLAM (需改造传感器模块)
9. 扫地机器人 SLAM 实战要点
9.1 典型硬件配置
主流扫地机器人传感器配置 (2024):
| 价位 | LiDAR | IMU | 编码器 | 其他传感器 | SLAM 方案 |
|---|---|---|---|---|---|
| 低端 (< ¥1000) | 无 | 无 | ✅ | 碰撞传感器 | 随机清扫 |
| 中端 (¥1000-3000) | 单线 2D | ❌ | ✅ | 红外、超声 | Cartographer (简化版) |
| 高端 (> ¥3000) | 单线 2D | ✅ | ✅ | ToF、视觉 | Cartographer (完整版) |
推荐配置 (成本优化):
- 必选: 单线 LiDAR (360°, 5-10Hz, 如 RPLIDAR A1)
- 强烈推荐: 轮式编码器 (分辨率 > 1000 pulses/rev)
- 可选: 低成本 IMU (如 MPU6050, 仅用于快速旋转场景)
9.2 扫地机专用优化
基于 Cartographer 的扫地机定制方案:
1. 降低计算负载 (适应嵌入式平台)
-- vacuum_cleaner_optimized.lua
TRAJECTORY_BUILDER_2D = {
-- 点云下采样: 激进策略
voxel_filter_size = 0.08, -- 默认 0.025, 增大 3 倍
-- 禁用实时 CSM (仅依赖 Ceres)
use_online_correlative_scan_matching = false,
-- Submap 缩小 (减少内存)
submaps.num_range_data = 30, -- 默认 90, 减少 66%
}
POSE_GRAPH = {
-- 闭环检测: 极低采样率
constraint_builder.sampling_ratio = 0.05, -- 默认 0.3, 降低 83%
-- 优化频率降低
optimize_every_n_nodes = 150, -- 默认 90
}
-- 性能提升:
-- CPU: 150% → 60% (降低 60%)
-- 内存: 500MB → 150MB (降低 70%)
-- 代价: 闭环成功率 95% → 85%
2. 动态物体过滤 (家居环境必备)
// 扫地机专用: 过滤人腿、宠物、移动家具
sensor::PointCloud FilterDynamicObjects(
const sensor::PointCloud& cloud,
const ProbabilityGrid& static_map) {
sensor::PointCloud static_cloud;
for (const auto& point : cloud) {
// 1. 查询静态地图
const float map_probability = static_map.GetProbability(point);
// 2. 策略: 如果点云落在地图的自由空间 → 可能是动态物体
if (map_probability < 0.3) {
// 额外验证: 欧式聚类判断是否为人腿
if (!IsLegCluster(point, cloud)) {
static_cloud.push_back(point);
}
} else {
static_cloud.push_back(point); // 静态障碍物
}
}
return static_cloud;
}
3. 地图持久化与重定位
需求: 扫地机需要保存家庭地图,下次启动时快速重定位。
# 首次建图
roslaunch cartographer_ros vacuum_mapping.launch
# 保存地图
rosservice call /finish_trajectory 0
rosservice call /write_state "{filename: '/data/home_map.pbstream'}"
# 下次启动 (纯定位模式)
roslaunch cartographer_ros vacuum_localization.launch \
load_state_filename:=/data/home_map.pbstream
重定位优化:
-- localization.lua
TRAJECTORY_BUILDER.pure_localization = true
TRAJECTORY_BUILDER.pure_localization_trimmer = {
max_submaps_to_keep = 3,
}
-- 初始位姿不确定性处理
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7
9.3 扫地机特有问题处理
问题 1: 镜面反射 (落地窗、镜子)
现象: LiDAR 虚假测量导致地图出现"幽灵墙"。
解决方案:
// 基于强度的镜面检测
sensor::PointCloud FilterMirrorReflections(
const sensor::PointCloud& cloud) {
sensor::PointCloud filtered;
for (const auto& point : cloud) {
// 镜面反射特征:
// 1. 强度异常低 (反射率低)
// 2. 距离异常远 (双倍距离)
if (point.intensity > kMinIntensity &&
point.position.norm() < kMaxReliableRange) {
filtered.push_back(point);
}
}
return filtered;
}
问题 2: 地毯打滑 (编码器失效)
现象: 在厚地毯上,轮式编码器严重偏差。
解决方案:
-- 降低里程计权重
POSE_GRAPH.optimization_problem.odometry_translation_weight = 1e3 -- 默认 1e5
-- 增大 Ceres 搜索窗口 (补偿里程计误差)
TRAJECTORY_BUILDER_2D.ceres_scan_matcher.linear_search_window = 0.2
问题 3: 多楼层建图
需求: 复式住宅需要分层地图。
解决方案:
// 基于高度检测楼层切换
class FloorDetector {
public:
int DetectFloor(const sensor::ImuData& imu) {
// 方法 1: IMU 高度积分
height_ += imu.linear_acceleration.z() * dt * dt / 2;
// 方法 2: 气压计 (如果有)
// height_ = barometer.GetAltitude();
// 楼层判定: 每 3m 为一层
return static_cast<int>(height_ / 3.0);
}
void OnFloorChange(int new_floor) {
// 结束当前轨迹
map_builder_->FinishTrajectory(current_trajectory_id_);
// 启动新轨迹
current_trajectory_id_ = map_builder_->AddTrajectoryBuilder(...);
}
private:
double height_ = 0.0;
};
9.4 工业部署最佳实践
石头科技 S7 扫地机 SLAM 架构 (推测):
硬件层:
LiDAR: RPLIDAR S2 (2D, 15Hz)
IMU: 6-axis (200Hz)
编码器: 左右轮 (1024 pulses/rev)
处理器: Allwinner R818 (4× ARM A53 @ 1.6GHz)
软件栈:
├─ Cartographer (定制版)
│ ├─ sampling_ratio = 0.1 (节省 CPU)
│ ├─ num_range_data = 30 (节省内存)
│ └─ 禁用 3D 模块
│
├─ 动态物体过滤 (自研)
│
├─ 多楼层管理 (气压计)
│
└─ 云端地图服务
├─ 离线全局优化 (手机 App)
└─ 地图分享 (多设备同步)
性能指标:
- 建图速度: 100㎡ 约 15 分钟
- 重定位时间: < 3 秒
- CPU 占用: 平均 60%, 峰值 90%
- 内存占用: 120 MB
9.5 开发者资源
官方资源:
- GitHub: https://github.com/cartographer-project/cartographer
- 论文: “Real-Time Loop Closure in 2D LIDAR SLAM” (ICRA 2016)
- 文档: https://google-cartographer.readthedocs.io
社区资源:
- ROS Answers: https://answers.ros.org/questions/tags:cartographer
- 中文教程: 古月居 Cartographer 专栏
- 视频教程: B站 “Cartographer 源码解析”
行业交流:
- 扫地机器人开发者论坛
- ROS China 用户组
- SLAM 技术研讨会 (每年 6 月,深圳)
10. 总结
10.1 Cartographer 在扫地机 SLAM 的不可替代性
技术层面:
- 唯一能工业化的开源图优化 SLAM (ORB-SLAM3 过于复杂)
- Branch-and-Bound 算法 是闭环检测的金标准
- Submap 机制 完美适配扫地机的房间-走廊拓扑结构
商业层面:
- 许可证友好: Apache 2.0 (允许商用闭源)
- 生态成熟: ROS 完整支持,第三方工具丰富
- 人才储备: 大量算法工程师熟悉 Cartographer
演进趋势:
- 2024-2025: Cartographer + Transformer (闭环特征学习)
- 2025-2026: 端到端神经网络 SLAM (仍基于 Cartographer 框架)
- 长期: 多模态融合 (LiDAR + 视觉 + 毫米波雷达)
10.2 后续文档导航
本系列文档架构:
[01] 系统架构 ← 当前文档
↓
[02] 前端 Local SLAM
├─ 数据预处理
├─ CSM 暴力搜索
└─ Ceres 非线性优化
↓
[03] 后端 Global SLAM
├─ 闭环检测
├─ Fast CSM (Branch-and-Bound)
└─ SPA 位姿图优化
↓
[04] 概率地图理论基础
├─ 贝叶斯滤波
└─ Log-Odds 表示
↓
[05] 参数调优 (扫地机专项)
├─ 室内环境配置
├─ 性能优化
└─ 故障诊断
↓
[06] 地图源码剖析
└─ SIMD/GPU 加速
↓
[07] 分支定界算法 (核心)
└─ 361× 加速原理
↓
[08] 数学理论推导
└─ 定理证明
推荐学习路径 (扫地机工程师):
快速入门: 01 → 05 → 02
深度掌握: 01 → 02 → 03 → 07
理论研究: 04 → 08 → 07 → 03
Cartographer 是扫地机器人 SLAM 领域的基石框架,掌握它不仅是技术需求,更是职业发展的必经之路。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)