传感器原理:激光雷达、IMU、轮式编码器与视觉传感器

做机器人导航,说白了就是回答三个问题:我在哪?我要去哪?怎么去?而传感器,就是回答第一个问题的眼睛和耳朵。这一章,我把最常用的四种传感器掰开揉碎讲清楚。

我个人习惯把传感器分成两类:外部传感器(感知环境)和内部传感器(感知自身状态)。激光雷达和视觉属于前者,IMU和轮式编码器属于后者。你想想看,如果只有眼睛没有平衡感,走路肯定摔跤;反过来只有平衡感没有眼睛,那就是盲人摸象。

激光雷达工作原理

激光雷达,简称LiDAR。它的核心原理其实很简单:发射激光,测量反射回来的时间。光速是已知的,时间差一算,距离就出来了。

核心公式:距离 = (光速 × 飞行时间) / 2

除以2是因为激光走了个来回。

我在项目中遇到过最坑的事——激光雷达在强阳光下直接罢工。为什么?因为太阳光里也有红外成分,会淹没激光信号。所以室外选型时,一定要看抗环境光能力这个参数。

市面上常见的激光雷达分两种:

类型 测距方式 典型距离 适用场景
三角测距 激光照射,CMOS接收偏移量 0.1m - 8m 室内扫地机、服务机器人
TOF(飞行时间) 直接测量脉冲往返时间 0.5m - 100m+ 室外AGV、自动驾驶

我的选型建议:室内导航用三角测距就够了,便宜且精度够用。室外项目别省这个钱,直接上TOF。我曾经为了省成本在室外用了三角测距,结果下午三点以后数据全是噪点,教训深刻。

激光雷达输出的数据叫点云。一帧点云包含几百到几十万个点,每个点有(x, y, z)坐标和反射强度。做SLAM时,我们就是靠这些点来匹配环境特征的。

// 激光雷达数据解析示例(伪代码)
struct LaserPoint {
    float angle;    // 角度(弧度)
    float distance; // 距离(米)
    float intensity; // 反射强度(0-255)
};

// 一帧数据通常包含 360° 或 270° 的扫描点
std::vector<LaserPoint> scan = lidar.getScan();

IMU惯性测量单元

IMU这东西,说白了就是机器人的内耳前庭。它告诉你:我现在是倾斜的、我在加速、我在旋转。

一个典型的IMU包含三个传感器:

  • 加速度计:测量三轴加速度(包含重力分量)
  • 陀螺仪:测量三轴角速度
  • 磁力计(可选):测量地磁场方向,辅助航向

嗯,这里要注意——IMU有个天生的毛病叫漂移。加速度计积分得到速度,速度积分得到位置,每一步都有误差,积分几次以后位置就飞到天边去了。

避坑指南:我曾经做过一个纯IMU定位的项目,开机前10秒还挺准,30秒后位置误差超过1米,2分钟后完全不可用。所以IMU不能单独用于定位,必须配合其他传感器做融合。

那IMU到底有什么用?两个核心场景:

  1. 短时高精度推算:激光雷达或视觉失效时(比如快速旋转、进入白墙区域),IMU能顶住1-2秒
  2. 姿态估计:机器人爬坡时,IMU能实时输出俯仰角和横滚角,这对导航决策至关重要
// IMU数据融合示例(互补滤波)
float complementaryFilter(float accAngle, float gyroRate, float dt) {
    const float alpha = 0.98;  // 权重系数
    static float angle = 0;
    angle = alpha * (angle + gyroRate * dt) + (1 - alpha) * accAngle;
    return angle;
}

轮式编码器

轮式编码器,我愿称之为最被低估的传感器。它装在电机轴上,每转一圈输出固定数量的脉冲。通过数脉冲,就能知道轮子转了多少圈,结合轮径就能算出走了多远。

编码器分两种:

类型 输出信号 精度 成本
增量式编码器 A/B两相脉冲(可判方向) 取决于线数 低
式编码器 直接输出角度值 高 高

关键公式:

位移 = (脉冲数 / 每转脉冲数) × 轮子周长

速度 = 位移 / 时间间隔

但轮式编码器有个致命缺陷——打滑。轮子空转的时候,编码器以为你走了1米,实际上你还在原地。我在做仓储AGV时就吃过这个亏,地面有点水渍,编码器里程计直接崩了,机器人以为自己到了货架前,实际上还差半米。

我的经验:编码器数据一定要做有效性校验。比如突然出现一个不可能的高速度,大概率是打滑了,这时候应该降低里程计的置信度,多依赖激光或视觉数据。

视觉传感器

视觉传感器,就是摄像头。但机器人用的摄像头和手机摄像头不太一样。我们更关心的是:能不能在弱光下工作?帧率够不够?有没有全局快门?

视觉传感器在导航中的典型用法:

  • 单目视觉:一个摄像头,通过运动恢复结构(SFM)估算深度
  • 双目视觉:两个摄像头,利用视差直接计算深度
  • RGB-D相机:直接输出深度图,比如Kinect、RealSense

我个人最常用的是双目视觉。为什么?单目需要运动才能算深度,静止时就是个瞎子;RGB-D在室外强光下基本废掉。双目虽然计算量大,但胜在稳定。

注意:视觉传感器对光照极其敏感。我在一个工厂项目里,白天窗户进来的阳光导致一半画面过曝,特征点全丢了。后来加了ND滤镜才解决。如果你做室内导航,记得考虑光照变化。

// 视觉特征提取示例(使用ORB特征)
cv::Ptr<cv::ORB> orb = cv::ORB::create(500);  // 提取500个特征点
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
orb->detectAndCompute(image, cv::noArray(), keypoints, descriptors);

传感器融合:为什么需要组合使用?

看到这里你应该明白了——没有完美的传感器。激光雷达怕强光、怕镜面反射;IMU会漂移;编码器会打滑;视觉怕光照变化。

所以实际工程中,我们做的是传感器融合。最常见的组合是:

  • 激光雷达 + IMU:室内导航标配,激光提供观测,IMU填补激光帧间的运动估计
  • 视觉 + IMU:VIO(视觉惯性里程计),手机AR和无人机常用
  • 激光 + 视觉 + IMU + 编码器:全冗余方案,用于自动驾驶等安全关键场景

下面这张图展示了多传感器融合的典型数据流:

多传感器融合导航数据流 激光雷达 IMU 轮式编码器 视觉传感器 点云预处理 零偏补偿 脉冲计数 特征提取 传感器融合引擎 (扩展卡尔曼滤波 / 图优化) 位姿估计输出 每个传感器都有弱点,融合的目的是取长补短,提高整体鲁棒性

核心原则:融合不是简单平均,而是根据每个传感器的置信度做加权。比如编码器打滑时置信度降低,激光雷达数据良好时权重提高。这就是卡尔曼滤波在做的事。