元器件 · 传感器

红外反射传感器阵列

红外反射传感器阵列是循迹机器人看见线条的方式。本文讲反射式红外检测的原理、如何标定,以及它在哪些情况下会失效。

它是什么

红外反射传感器阵列是一排朝地的小红外传感器。每个传感器是红外 LED 往下打光加光敏三极管量弹回多少。深色线在浅地面上反射少——线上的传感器和地面上的读数不一样。整排读下来不只知道在不在线上,还知道线在车底哪。

几乎每台循迹车的眼睛,循迹是极好的第一个项目的原因:传感便宜直观,立竿见影。

红外反射阵列在黑线地面上的剖面。每通道向下发射红外;白地面反射强,黑线吸收,线上的通道读数低,其他通道高。
每通道发射红外量回波。地面反射,线吸收——读数低的位置就是线在阵列下的位置。 下载 SVG

工作原理

每通道发射接收一对。红外 LED 打不可见约 940 nm 光;回光越多光敏三极管导通越多。白或浅表面反射强(回波大);黑线吸收红外(回波小)。两种输出:

  • 模拟——每个通道给出一个正比于反射率的连续值。信息更丰富:你能算出线落在两个传感器之间的什么位置,从而得到给 PID 控制器用的平滑误差信号。
  • 数字——板上比较器每通道只报有线无线。好读,但粗。

阵列变转向信号靠加权平均看哪几个传感器见线。线偏到左边传感器下,平均左移,这个偏移就是控制环要修的误差。

什么时候用它

机器人要跟高对比路径就用反射阵列——白底黑线或深底白胶带。通道越多,位置分辨率越细,过弯和过缺口也更从容;五通道够学,八通道跑更快或更弯的路线更舒服。

测物体、测距、测离地东西别用它——那是超声或飞行时间的活。

标定与坑

  • **一定标定。**环境光、表面、离地高度全改读数。跑之前阵列在线和地面都扫一遍,每通道记最小最大,实时读数归一。不做是循迹这桌好使那桌跪的头号原因。
  • **高度要紧。**反射传感器的最佳范围很窄(几毫米)。阵列装得太高,对比度就会塌下来。
  • **环境红外就是噪声。**阳光和某些照明会往探测器里灌满红外。给传感器加遮光罩,或者在室内跑以获得一致的表现,并对信号做滤波——见驯服传感器噪声。
  • **表面反光骗人。**亮黑胶带错角度反得像白;哑光胶带配哑光地面才可靠。

接到 Arduino

模拟阵列每通道一只 ADC 脚,所以 8 通道阵列配 Uno(六模拟脚)别扭——Nano 八个(A0–A7)正好。

阵列脚 Arduino 说明
VCC 5 V 耗电的是发射管,不是接收管
GND GND
OUT1–OUT8 A0–A7 模拟通道,每传感器一只
LEDON / CTRL 任一数字脚 可选:开关发射管

LEDON 脚值得接,虽然大多数项目无视。8 通道阵列发射管一起100–200 mA持续,小电池上占预算显著——还能做环境光相减,见下。

标定:决定成败的代码

这不是可选项,也不是锦上添花的改进。没标定的阵列,是循迹车在厨房餐桌上跑得好、到了比赛场上却失败的头号原因。

const int N = 8;
const int PIN[N] = {A0, A1, A2, A3, A4, A5, A6, A7};
int lo[N], hi[N];

void calibrate() {
  for (int i = 0; i < N; i++) { lo[i] = 1023; hi[i] = 0; }

  // Sweep the array across the line and the floor for ~3 seconds.
  unsigned long start = millis();
  while (millis() - start < 3000) {
    for (int i = 0; i < N; i++) {
      int v = analogRead(PIN[i]);
      if (v < lo[i]) lo[i] = v;
      if (v > hi[i]) hi[i] = v;
    }
  }
}

// 0 = floor, 1000 = line, per channel, normalised against this run's own extremes.
int normalised(int i) {
  int span = hi[i] - lo[i];
  if (span < 50) return 0;                       // this channel never saw contrast
  return constrain(map(analogRead(PIN[i]), lo[i], hi[i], 0, 1000), 0, 1000);
}

注意 span < 50 这道保护。标定时没扫到的通道——扫描漏掉了它,或者它的发射管已经坏了——否则微小的噪声归一化后会产生巨大的数值,小车就会朝一个根本没在提供信息的传感器猛拐。

八个读数变一个转向数

加权平均是全部诀窍,产出连续位置而不是离散“3 号传感器见了”:

// Returns position in the same units as the weights: 0..7000 for an 8-channel array,
// or -1 if the line is not visible at all.
long linePosition() {
  long weighted = 0, total = 0;
  for (int i = 0; i < N; i++) {
    int v = normalised(i);
    if (v > 100) {                    // ignore channels that are clearly on floor
      weighted += (long)v * i * 1000;
      total    += v;
    }
  }
  if (total == 0) return -1;          // line lost
  return weighted / total;
}

// Error for the control loop: 0 when centred.
long error() {
  long pos = linePosition();
  if (pos < 0) return LAST_ERROR;     // hold the last known direction, do not zero it
  return pos - 3500;                  // centre of an 8-channel array
}

里面两个设计决策比算术重要:

低于阈值的通道无视,地面噪声不拖平均。没有它,八通道各读小非零,线在哪估计都往中间拽。

丢线回上次误差——而不是零——急弯能回来的原因。零是“完美居中”,丢线归零的车全速直行,离刚丢的线而去。保持上次误差车继续往已转的方向转,线就往那边去的。

安装高度,以及为什么决定一切

反射传感器甜点窄。信号两边都掉得快:太高回波弱,太低发射锥没散开照不到接收视场。

离地高度 典型表现
1–3 mm 对比最好,但地面不平就蹭
3–8 mm 可用带——多数阵列标约 3 mm
8–15 mm 对比度下降;标定的量程收窄
> 15 mm 在大多数表面上基本等于瞎

两条实践后果。刚性安装——装在柔性支架上的阵列会随小车加速而改变高度,高度一变读数就变,而控制环会把这读成线在移动。装平,因为阵列一旦倾斜,每个通道的有效高度就各不相同,标定也就各不相同,表现出来就是小车在一个方向上跟得好、另一个方向上跟得差。

装轮子前面也重要:越靠前越早见弯,控制器提前量越多。太靠前几何放大误差成振荡。

打赢环境光

阳光里大量 940 nm 红外,到接收管看起来和反射一模一样。室内好使窗边跪的车几乎永远是这个。

发射管能开关,解法彻底,两读数的事:

int ambientSubtracted(int i) {
  digitalWrite(LEDON, LOW);   delayMicroseconds(200);
  int dark = analogRead(PIN[i]);      // ambient only
  digitalWrite(LEDON, HIGH);  delayMicroseconds(200);
  int lit  = analogRead(PIN[i]);      // ambient + our own emitter
  return lit - dark;                  // just our emitter
}

环境里恒定不变的东西会被精确抵消。代价是采样时间翻倍,在快速循迹车上这是实打实的开销——但它把一个不可靠的传感器变成可靠的传感器,商用阵列用的就是这个办法。

没有就给阵列加裙边,只看正下方地面。

故障排查

现象 可能原因 解决
这面好使那面跪 无标定或标定过期 每次跑实际面上重标定
车往一边拐 某通道的标定量程不对 查每个通道的 hi/lo;发射管坏了会表现为量程极小
急弯丢线 阵列离轮太近,或丢线归零 前移;保持上次误差别归零
直道振荡 阵列太靠前或增益太大 收提前量;重调控制器
窗边跪 环境红外 关发射相减,或罩住阵列
亮黑胶带上发疯 胶带镜面反射 哑光胶带配哑光地面才可靠
越跑读数飘 电池电压下垂,发射管变暗 发射管很吃电流;带载时查电源轨
全通道一样 阵列太高 降到 3–8 mm 重标定

选哪个阵列

通道 位置分辨率 适合
3 粗——基本左右中 只学概念
5 够 温柔赛道第一台循迹
8 舒服 快道急弯、线迷宫路口检测
12–16 细 高速竞赛车

**带控制环的场合,模拟胜过数字。**数字阵列的比较器只给你每个通道有无线,把位置量化成少数几个离散值,平滑的比例转向根本做不到。模拟输出的是连续误差信号,PID 控制器要的正是这个。

通道间距和数量一样重要:阵列要比线宽够多,两边永远至少一传感器在地面上,又不能宽到线卡两传感器之间看不见。标准 19 mm 电工胶带,8 mm 间距好。

线迷宫机器人还多一条要求:阵列必须宽到能看见路口。小车是靠最外侧的左端传感器变黑、而中间还压在线上,来判断出现了左转——如果阵列只比胶带宽一点点,这根本做不到。

探索关联图谱

用到它的搭建

包含 红外反射传感器阵列 的项目、学习路线和模拟器。

问题

红外反射传感器阵列 常见问题

什么是循迹传感器?

循迹传感器是一种红外反射传感器,机器人把它朝向地面,用来检测标出的线。每个通道向下照射红外光,并测量反射回来多少,因此深色的线(反射较少)与周围地面的读数不同。

循迹传感器是怎么工作的?

每个通道由一个红外 LED 和一个光敏三极管配对组成。浅色表面反射强,深色的线吸收红外,所以位于线上方的传感器读数低,其余传感器读数高。读取整排传感器,机器人就知道线在它身下的什么位置。

循迹机器人的红外传感器怎么标定?

每次跑之前,让阵列在线和裸露的地面上都扫过一遍,记录每个通道的最小和最大读数,然后把实时读数按这两个极限进行缩放。不做标定,是循迹车在一种表面上能跑、换一种表面就失败的头号原因。

循迹车里的 PID 是什么?

PID 是一种控制方法,它把传感器给出的位置误差转换成平滑的转向。比例项根据机器人偏离线多远作出反应,微分项抑制超调,积分项消除持续的漂移——于是机器人能沿线行驶而不左右摇摆。你可以在我们的 PID 模拟器里实时调参。

循迹机器人的主要部件有哪些?

一台基本的循迹机器人需要四样东西:用来看线的红外反射传感器阵列,运行控制环的单片机(例如 Arduino Uno),L298N 之类的电机驱动,以及两个带轮子的直流电机。再加上电池和底盘,整台车就完整了。

循迹传感器阵列还能用来做什么?

除了循迹机器人,反射阵列还用于边缘检测(在桌子边缘停下)、类似编码器的位置检测,以及自动化设备中简单的表面或对比度检测。凡是机器人需要对表面上的高对比标记作出反应的地方,反射阵列都是便宜又可靠的选择。

延伸阅读

参考资料