元器件 · 传感器
红外反射传感器阵列
红外反射传感器阵列是循迹机器人看见线条的方式。本文讲反射式红外检测的原理、如何标定,以及它在哪些情况下会失效。
它是什么
红外反射传感器阵列是一排朝地的小红外传感器。每个传感器是红外 LED 往下打光加光敏三极管量弹回多少。深色线在浅地面上反射少——线上的传感器和地面上的读数不一样。整排读下来不只知道在不在线上,还知道线在车底哪。
几乎每台循迹车的眼睛,循迹是极好的第一个项目的原因:传感便宜直观,立竿见影。
工作原理
每通道发射接收一对。红外 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 之类的电机驱动,以及两个带轮子的直流电机。再加上电池和底盘,整台车就完整了。
循迹传感器阵列还能用来做什么?
除了循迹机器人,反射阵列还用于边缘检测(在桌子边缘停下)、类似编码器的位置检测,以及自动化设备中简单的表面或对比度检测。凡是机器人需要对表面上的高对比标记作出反应的地方,反射阵列都是便宜又可靠的选择。
延伸阅读