4、传感器配置基础:传感器类型、参数标定与数据同步

做SLAM这么多年,我接触过的传感器种类少说也有几十种。说实话,每次拿到一个新传感器,第一件事不是看它的精度有多高,而是先搞清楚它的「脾气」——数据怎么读、频率稳不稳、标定参数对不对。这一章,我就把传感器配置这块的实战经验掰开揉碎了讲给你听。

4.1 传感器类型:各有各的「性格」

SLAM系统里常见的传感器就这四类:激光雷达、IMU、里程计、相机。它们各有各的强项,也各有各的短板。

4.1.1 激光雷达(LiDAR)

激光雷达说白了就是「用激光测距」。它发射激光束,打到物体上反射回来,通过时间差算出距离。我最早接触的是16线雷达,那时候觉得能扫出点云已经很神奇了。

常见的激光雷达类型:

  • 机械式:旋转扫描,360度视野。Velodyne、Hesai是代表。优点是视野广,缺点是机械结构容易坏。
  • 固态式:没有旋转部件,靠电子扫描。Livox、Ouster。体积小、寿命长,但视场角有限。
  • MEMS式:微振镜扫描,介于机械和固态之间。性价比不错。
我的经验: 室内场景用16线够用,但室外复杂环境至少32线起步。我有个项目在矿区做,16线雷达扫出来的点云稀疏得跟筛子似的,后来换了64线才搞定。

4.1.2 IMU(惯性测量单元)

IMU测量加速度和角速度。它不依赖外部信号,所以不会丢。但它的致命问题是——漂移。你想想看,加速度积分一次得速度,再积分一次得位置,误差会像滚雪球一样越滚越大。

IMU的关键参数:

  • 加速度计量程:±2g、±4g、±6g、±8g、±16g。选大了精度低,选小了容易饱和。
  • 陀螺仪量程:±125°/s、±250°/s、±500°/s、±1000°/s、±2000°/s。机器人一般用±500°/s够用。
  • 零偏稳定性:这个参数决定了IMU的「底子」好不好。消费级IMU的零偏稳定性在10°/h左右,工业级能做到1°/h以下。
注意: 千万别买太便宜的IMU。我曾经贪便宜买了个几十块的模块,静止状态下角速度读数都能飘出5°/s,这种数据根本没法用。

4.1.3 里程计(Odometry)

里程计通常指轮式编码器。它测量轮子转了多少圈,结合轮径算出移动距离。优点是简单可靠,缺点是轮子打滑就完蛋。

里程计的数据格式很简单:

// 典型的里程计消息
header: 
  seq: 1234
  stamp: 1623456789.123
  frame_id: "odom"
pose:
  position: [1.234, 0.567, 0.0]
  orientation: [0.0, 0.0, 0.382, 0.924]
twist:
  linear: [0.5, 0.0, 0.0]
  angular: [0.0, 0.0, 0.1]

4.1.4 相机(Camera)

相机提供最丰富的环境信息——颜色、纹理、形状。但它的弱点是受光照影响大,纯视觉SLAM在暗处或纹理缺失的地方容易崩。

相机类型:

  • 单目:一个镜头,无法直接获取深度。需要靠运动估计。
  • 双目:两个镜头,通过视差算深度。基线越长,测距越远。
  • RGB-D:直接输出深度图。Intel RealSense、Microsoft Kinect是代表。室内好用,室外受红外干扰。

4.2 传感器参数标定:别让「误差」毁了你的系统

传感器买回来,参数都是厂家给的。但说实话,厂家参数只能当参考。每个传感器都有个体差异,温度变化、安装应力都会让参数偏移。所以标定是必须的。

4.2.1 内参标定

内参是传感器自身的参数。比如相机的焦距、畸变系数,IMU的零偏、尺度因子。

相机内参标定:

我习惯用张正友标定法。打印一张棋盘格,拍20张不同角度的照片,用OpenCV跑一遍就出来了。

# 相机内参标定示例(Python + OpenCV)
import cv2
import numpy as np

# 棋盘格尺寸
pattern_size = (9, 6)  # 内角点数量
square_size = 0.025    # 每个格子边长(米)

# 准备标定板上的3D点
objp = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size

# 存储所有图像的点
objpoints = []  # 3D点
imgpoints = []  # 2D点

# 遍历所有标定图像
for fname in calibration_images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)

# 执行标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray.shape[::-1], None, None
)

print("相机内参矩阵:\n", mtx)
print("畸变系数:\n", dist)
关键点: 标定照片要覆盖整个视野,边缘和角落都要拍到。我见过有人只拍中间区域,结果边缘畸变校正得一塌糊涂。

IMU内参标定:

IMU标定主要是确定零偏、尺度因子和轴间对齐误差。我常用的工具是imu_utils(ROS包)。把IMU静止放置2小时以上,采集数据后跑一遍标定程序。

# 使用imu_utils标定IMU
rosrun imu_utils imu_an.py --bagname imu_static.bag --imu_topic /imu/data

4.2.2 外参标定

外参是传感器之间的相对位姿。比如激光雷达和相机之间的旋转平移矩阵。这个标定做不好,融合出来的数据就是「两张皮」。

我常用的外参标定方法:

  • 手动标定:找几个特征点,手动对齐。精度一般,但快。
  • 自动标定:用标定板或自然特征,跑优化算法。精度高,但需要写代码。
  • 在线标定:系统运行过程中自动估计外参。适合长期运行的机器人。
我的建议: 如果条件允许,用自动标定。我早期做项目时用手动标定,结果外参误差导致地图拼接出现重影,排查了三天才发现是外参偏了0.5度。

4.3 传感器数据帧率与同步:时间就是一切

SLAM系统里,时间同步比数据精度更重要。你想想看,如果激光雷达的数据是10Hz,IMU是200Hz,相机是30Hz,它们的时间戳对不上,融合出来的位姿就是错的。

4.3.1 帧率匹配

不同传感器的帧率差异很大。常见的帧率:

传感器类型 典型帧率 说明
激光雷达 10-20 Hz 机械式一般10Hz,固态可以到20Hz
IMU 100-1000 Hz 消费级200Hz,工业级400Hz以上
里程计 50-200 Hz 取决于编码器采样频率
相机 15-60 Hz 视觉SLAM常用30Hz

帧率不匹配怎么办?插值。比如IMU数据比激光雷达快,就把IMU数据插值到激光雷达的时间戳上。

// IMU数据插值到激光雷达时间戳
// 伪代码示例
IMUData interpolateIMU(IMUData imu1, IMUData imu2, double target_time) {
    double dt = (target_time - imu1.timestamp) / (imu2.timestamp - imu1.timestamp);
    IMUData result;
    result.acc = imu1.acc + (imu2.acc - imu1.acc) * dt;
    result.gyro = imu1.gyro + (imu2.gyro - imu1.gyro) * dt;
    result.timestamp = target_time;
    return result;
}

4.3.2 硬件同步 vs 软件同步

硬件同步:用一根PPS(秒脉冲)信号线把所有传感器的时间基准统一。精度可以达到微秒级。但需要硬件支持,布线也麻烦。

软件同步:各传感器各自记录时间戳,然后在算法层做对齐。精度取决于系统时钟的稳定性。Linux系统用clock_gettime()可以做到毫秒级。

避坑指南: 我曾经在一个项目里只用软件同步,结果系统跑了半小时后,激光雷达和IMU的时间戳差了200多毫秒。后来发现是系统时钟漂移了。从那以后,我只要条件允许,一定上硬件同步。

4.3.3 时间戳管理

时间戳是传感器数据的「身份证」。管理好时间戳,后面融合就省心一半。

我的时间戳管理原则:

  1. 统一时基:所有传感器用同一个时钟源。ROS里就是/clock话题。
  2. 记录触发时间:不是接收时间,而是传感器实际采集的时间。很多相机驱动默认给的是接收时间,这个坑我踩过。
  3. 处理延迟:传感器数据从采集到到达CPU有延迟。IMU延迟最小(微秒级),相机延迟最大(几毫秒到几十毫秒)。

4.4 知识体系总览

下面这张图是我自己整理的传感器配置知识体系,你可以把它当作一个检查清单。每次搭建新系统时,对着这张图过一遍,基本不会漏东西。

传感器配置知识体系 传感器类型 激光雷达(LiDAR) IMU(惯性测量单元) 里程计(轮式编码器) 相机(单目/双目/RGB-D) 参数标定 内参标定(相机/IMU) 外参标定(传感器间位姿) 手动标定 / 自动标定 在线标定 / 离线标定 数据同步 帧率匹配与插值 硬件同步(PPS) 软件同步(时间戳对齐) 延迟补偿 核心原则:选对传感器 → 标定好参数 → 同步好时间 → 融合出好结果

嗯,传感器配置这块内容其实挺杂的。但只要你把「类型选择→参数标定→时间同步」这条主线抓住,剩下的都是细节问题。我在实际项目中,每次搭建新系统都会花至少半天时间专门做标定和同步测试——这个时间省不得。

一句话总结: 传感器配置做得好,SLAM系统就成功了一半。另一半?那是算法的事,咱们下回再聊。

可可精品资料库