零知派——STM32智能小车系列教程(三):红外双目跟随模块原理与调试
引言:智能小车要实现的功能很多——避障、跟随、贴边、灭火、直线行驶,每一个模块单独调试起来都有自己的难点。如果一开始就把所有模块塞进一个工程里联调,出了问题很难分清到底是传感器硬件的问题、电平极性的问题,还是上层控制算法的问题所以这一系列教程的思路是:先把每个功能模块单独拎出来,配一个不依赖其他硬件的最小测试程序,把模块本身调通调透,再回头看它在完整项目里是怎么被使用的
目录
一、引言
二、红外对射传感器硬件原理
2.2 原理图讲解三、硬件接线说明
3.1 红外跟随模块引脚定义3.2 接线方案表3.3 连接示意图四、独立测试程序
五、调试流程演示
5.1 测试流程5.2 演示视频六、项目跟随功能实现
6.1 IRSensor底层感知层6.2 FollowBehavior跟随状态机6.3 系统流程图七、常见问题解答(FAQ)
Q1:传感器接好了,跟随时小车原地转但不追目标,是什么问题?Q2:红外传感器在阳光下失效怎么办?
一、引言
在前两篇教程里,我们把循迹传感器和超声波云台都调通了,这一篇讲红外双目跟随——用两个固定在车头左右两侧的红外对射传感器,让小车识别目标方向,像影子一样跟在目标后面走,相比超声波云台,双目红外跟随的优势在:
[*]响应速度极快:毫秒级,无需舵机扫描等待
[*]电路简单、成本极低:只需读两个GPIO电平
劣势是探测距离短(2~30cm可调)、无法测量具体距离、对高反射率目标(白色物体)更灵敏。正是因为这个特性,在本项目里这两个模块同时承担了两个角色:跟随模式(G命令)用于追踪目标,避障模式(B命令)的辅助IR用于检测45°斜前方近距离障碍
这篇教程会把传感器原理、模块电路、跟随算法设计、调试过程和遇到的坑都完整梳理一遍,包括项目里这个模块走弯路的调试历程
这个系列教程拆成以下几篇:
篇次内容
第一篇(已完成) 五路循迹模块(TCRT5000 + LM393/LM339)
第二篇(已完成)HC-SR04 超声波测距 + SG90 舵机云台三模式应用
第三篇(本文)红外双目跟随模块(红外避障对管)
第四篇霍尔编码器测速与直线行驶 PID(含 PID 自整定)
第五篇DHT11 温湿度、火焰传感器、风扇灭火模块
第六篇蓝牙/串口双通道通信协议设计
终篇整车项目架构总览,把前面六篇串起来讲整体设计思路
二、红外对射传感器硬件原理 红外双目跟随模块使用的是主动式红外避障传感器,每个传感器内部集成了一个红外发射管(发射红外光)和一个红外接收管(接收反射回来的红外光)
2.1 红外发射+光电接收
红外跟随模块红外发射器与光电三极管集成在一起,适用于近接检测和反射传感
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3tqAPcD6AAAr9DhC5Co693.png
[*]红外发射管是由红外发光二极管组成发光体,用红外辐射效率高的材料(常用砷化镓)制成 PN 结,正向偏压向 PN 结注入电流激发红外光
[*]红外接收管则是将红外线光信号变成电信号的半导体器件,其核心部件是一个特殊材料的 PN 结,随着红外光强度的增加,电流也随之增大
①核心检测原理
① 发射管持续发出 940nm 红外脉冲光 → ② 目标物体反射红外光(反射率与目标材质、颜色相关) → ③ 接收管检测反射光强度 → LM393 比较器将模拟信号转为数字电平输出
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3uOAOc1CAAbK9gUFHWE640.png不同表面对红外光的反射特性:
表面特性红外反射接收管状态输出电平
浅色/光滑表面 强反射导通 LOW(检测到物体)
深色/粗糙表面弱反射/吸收 截止HIGH(未检测到)
黑色物体几乎吸收截止HIGH(未检测到)
②输出电平与检测状态
当探测到障碍物在检测范围内时,模块会输出低电平(LOW)。该模块检测距离为 2~30cm,检测角度 35°,距离可通过电位器调节
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3uyAFi-cAAID1inDCME880.png注意:不同厂家、不同批次的模块,输出电平与检测状态的对应关系可能相反。本项目实测确认:检测到物体 → 输出 LOW(0),无物体 → 输出 HIGH(1)
③LM393 比较器
LM393 是一款双差分比较器 IC,内部包含两个独立的运算放大器(比较器)。比较器对两路输入电压进行比较,判断哪路更大,然后给出输出
https://file1.elecfans.com/web3/M00/67/F3/wKgZPGpB3vWAf2MNAABifWvF_FI985.png比较电压工作原理
[*]当同相输入端(+) 电压高于反相输入端(-)电压时,比较器输出高电平。
[*]当同相输入端(+)电压低于反相输入端(-)电压时,比较器输出低电平
比较器内部电路解析
晶体管Q1、Q2(绿色)构成同相输入端的输入级。反相输入端的输入级由晶体管Q3、Q4(黄色)组成。晶体管Q5、Q6(灰色)用作电流镜。晶体管Q7、Q8(红色)为开关级
https://file1.elecfans.com/web3/M00/67/F3/wKgZPGpB3v-AaGU6AAkdarPJLLk192.png
[*]各级晶体管均由恒流源供电、一旦同相输入端(+)的输入电压高于反相输入端(-)的电压,比较器输出端的晶体管(Q8)就会截止
[*]若通过电阻(RL)为输出端提供5伏电压,即可引出高电平脉冲、同相输入端电压等于或低于反相输入端电压,输出端晶体管导通,比较器输出端向电源负电位侧切换,此时可引出低电平脉冲
电压变化发生在反相输入端还是同相输入端,对开关功能没有影响。唯一关键的因素是两个输入端之间的电压差值。各类开关示例中,将不同的电压变化情况(蓝色箭头)分开展示:
(1)同相输入端电压上升
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3wuARuIqAAciC46bH7c180.png同相输入端电压升高会使输出端电压随之升高
(2)同相输入端的电压降低
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3xaAWlAlAAgtvJjj9ls569.png同相输入端产生电压降会使输出端出现电压降
(3)反相输入端电压上升
https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB3y-AKY8jAAgvIcei8bw335.png反相输入端电压升高会使输出端电压降低
(4)反相输入端的电压降低
https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB30KAdggoAAcimFFH3ZQ425.png同相输入端产生电压压降时,输出端也会出现电压压降
④电位器调节
模块上那颗 蓝色方形可调3362电位器,本质上是 可调分压器——旋转旋钮改变分压比例,从而改变送入 LM393 比较器的参考电压(阈值)
调节效果:
调节方向参考电压变化检测距离变化
顺时针旋转 阈值降低 检测距离增大(更灵敏)
逆时针旋转阈值升高检测距离减小(更不灵敏)
实际调试方法:
[*]将模块正对目标物体(如手掌),距离约 10~15cm
[*]慢慢旋转电位器,观察模块上的状态指示灯
[*]找到指示灯刚好点亮(或熄灭)的临界点
[*]再往灵敏方向回调一点点
两个模块需要分别调节,因为每个模块的电位器是独立的,灵敏度和检测距离不会自动一致
2.2 原理图讲解①单路 红外跟随电路
典型的 IR333 + PT333 + LM393 红外避障模块单路原理图
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB3zuAAg8WAAw-Q0GirVU950.png
元件作用
100Ω限流电阻R3限制 IR333发射管电流,通常 100Ω ~ 200Ω
10KΩ上拉电阻R5LM393 集电极开路输出需要上拉到 VCC,通常 10kΩ
10kΩ电位器R2调节比较器参考阈值电压,通常 10kΩ 3362型
②探测逻辑
两个红外传感器在车头两侧呈八字形安装:
左传感器检测到目标意味着目标在左侧,小车应该左转对准;右传感器检测到目标意味着目标在右侧,小车应该右转对准
左传感器右传感器判断结果执行动作
检测到(LOW)未检测(HIGH)目标在左侧左转
未检测(HIGH) 检测到(LOW) 目标在右侧 右转
检测到(LOW)检测到(LOW)目标在正前方停车(目标已近)
未检测(HIGH)未检测(HIGH)目标丢失原地旋转搜索
如果方向反了,小车会朝着远离目标的方向转,永远跟不住
三、硬件接线说明3.1 红外跟随模块引脚定义本项目跟随模块的引脚定义(与 pinsdefine.h 一致)
传感器位置引脚号代码定义
左侧IR模块 21ServoPWM3
右侧IR模块24ServoPWM4
注意:这两个引脚虽然命名为 ServoPWM3/4,但在本项目中被复用为红外传感器的信号输入引脚
3.2 接线方案表每个红外跟随模块有 3个引脚:
模块引脚零知派迷你板引脚说明
左红外传感器 VCC 5V电源正极
左红外传感器GNDGND电源地
左红外传感器OUTD21(ServoPWM3) 信号输出
右红外传感器VCC5V电源正极
右红外传感器GNDGND电源地
右红外传感器OUTD24(ServoPWM4)信号输出
3.3 连接示意图https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB316ATvDTAAcuWz2Ad4c333.png左侧传感器(直插小车扩展板——舵机接口 PWM3)和右侧传感器(直插小车扩展板——舵机接口 PWM4)接反后,代码里 lIR 和 rIR 含义会颠倒,导致目标在右侧时车向左转。如果跟随方向错误,第一步先用独立测试程序确认左右传感器方向是否正确,再排查代码
四、独立测试程序下面这个程序只依赖两个红外传感器,不需要电机、超声波等其他模块,在接入整车工程之前,先用这个程序独立验证传感器的方向和灵敏度/**************************************************************************************
* 文件: IR_Follow_Standalone_Test.ino
* 作者:零知实验室(深圳市在芯间科技有限公司)
* 功能:红外双目跟随模块 独立测试程序
* 引脚定义与主项目 pinsdefine.h 完全一致
*
* 使用方法:
* 1. 烧录本程序到零知派迷你板
* 2. 打开串口监视器,波特率115200
* 3. 用手或物体在左右传感器前方移动
* 4. 观察串口输出的检测状态变化
* 5. 通过电位器调节每个传感器的检测距离
**************************************************************************************/
#define IR_LEFT_PIN 21 // ServoPWM3
#define IR_RIGHT_PIN24 // ServoPWM4
void setup()
{
Serial.begin(115200);
delay(200);
pinMode(IR_LEFT_PIN, INPUT_PULLUP);
pinMode(IR_RIGHT_PIN, INPUT_PULLUP);
Serial.println(F("========================================"));
Serial.println(F(" 红外双目跟随模块 独立测试程序"));
Serial.println(F("========================================"));
Serial.println(F("L=1 表示左传感器检测到物体"));
Serial.println(F("R=1 表示右传感器检测到物体"));
Serial.println(F(""));
Serial.println(F("状态说明:"));
Serial.println(F("L=0 R=0→ 目标丢失"));
Serial.println(F("L=1 R=0→ 目标在左侧 → 左转"));
Serial.println(F("L=0 R=1→ 目标在右侧 → 右转"));
Serial.println(F("L=1 R=1→ 目标在正前方 → 停车"));
Serial.println(F(""));
}
void loop()
{
int leftVal= digitalRead(IR_LEFT_PIN);
int rightVal = digitalRead(IR_RIGHT_PIN);
// 传感器检测到物体输出 LOW,取反后 1 表示检测到
bool leftDetected= (leftVal == LOW);
bool rightDetected = (rightVal == LOW);
Serial.print(F("L="));
Serial.print(leftDetected ? 1 : 0);
Serial.print(F(" R="));
Serial.print(rightDetected ? 1 : 0);
// 状态判断
if (leftDetected && rightDetected) {
Serial.println(F("→ 停车(目标居中且已近)"));
} else if (leftDetected && !rightDetected) {
Serial.println(F("→ 左转(目标偏左)"));
} else if (!leftDetected && rightDetected) {
Serial.println(F("→ 右转(目标偏右)"));
} else {
Serial.println(F("→ 搜索(目标丢失)"));
}
delay(100);
}
五、调试流程演示5.1 测试流程①灵敏度测试
https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB33OASSzuABlES8QTfEM441.png 上电,传感器前无遮挡、串口显示 L=0 R=0 → 搜索(目标丢失)、如有误检测,调节电位器降低灵敏度
②遮挡测试
https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB33mALI0SABO7JE4zU1U111.png 用手掌挡住左传感器,串口显示 L=1 R=0 → 左转(目标偏左)、用手掌挡住右传感器,串口显示 L=0 R=1 → 右转(目标偏右)、用手掌同时挡住两个传感器,串口显示 L=1 R=1 → 停车(目标居中且已近)
③跟随模式测试
https://file1.elecfans.com/web3/M00/67/F2/wKgZO2pB34KAERhcABNQWLP5c40434.png 发送命令"G",手掌从左侧移到右侧,状态从左转、停车到右转状态依次变化,确认状态切换平滑
5.2 演示视频零知派迷你板智能小车-红外双目跟随模块调试
https://live.csdn.net/v/532922?spm=1001.2014.3001.5501
展示独立测试程序在串口监视器上的实时输出,用手在不同位置遮挡两个传感器,对应串口输出的状态变化;演示灵敏度调节——用螺丝刀旋转电位器,观察触发距离的变化;展示整车跟随效果
六、项目跟随功能实现确认模块本身没问题之后,再看完整项目里跟随功能是怎么组织的。这部分代码分布在两个文件里:
文件职责
sc_perception.h/.cpp IRSensor::read() ——底层读取两个 GPIO 电平,转换为布尔值
sc_behaviors.h/.cppFollowBehavior::update() ——上层跟随状态机
6.1 IRSensor底层感知层// sc_perception.cppIRSensor::IRSensor(){ // INPUT_PULLUP:无物体时保持HIGH,避免悬空导致误触发 pinMode(ServoPWM3, INPUT_PULLUP); pinMode(ServoPWM4, INPUT_PULLUP);}void IRSensor::read(bool *isLeft, bool *isRight){ // 检测到物体 → LOW → isLeft/isRight = true // 无物体 → HIGH → false *isLeft= (digitalRead(ServoPWM3) == LOW); *isRight = (digitalRead(ServoPWM4) == LOW);}
6.2 FollowBehavior跟随状态机最终版本状态机
FOLLOW(跟随状态)
lIR && rIR → stop()(双触发=正对且近,停止)
lIR && !rIR → 左转对准(-FOLLOW_TURN, FOLLOW_TURN)
!lIR && rIR → 右转对准(FOLLOW_TURN, -FOLLOW_TURN)
连续 5 帧无触发(_lostFrames >= LOST_THRESH)
切换回 SEARCH_CWvoid FollowBehavior::update()
{
bool lIR = false, rIR = false;
g_ir.read(&lIR, &rIR);
// 调试输出(正式发布可屏蔽)
Serial.print(F(" L=")); Serial.print(lIR);
Serial.print(F(" R=")); Serial.println(rIR);
// ── 有目标:进入跟随 ─────────────────────────────────────────
if (lIR || rIR) {
_lostFrames = 0;
if (_st != FOLLOW) {
_st = FOLLOW;
Serial.println(F(" 发现目标,进入跟随"));
BTSerial.println(F(" Target found"));
}
if (lIR && rIR) {
// 双触发:目标正对且已非常近,停止
g_motor.stop();
} else if (lIR && !rIR) {
// 左侧触发:目标在左侧 → 左转对准
g_motor.motorRun(-FOLLOW_TURN, FOLLOW_TURN);
} else {
// 右侧触发:目标在右侧 → 右转对准
g_motor.motorRun(FOLLOW_TURN, -FOLLOW_TURN);
}
return;
}
// ── 无目标:消抖后进入搜索 ───────────────────────────────────
if (_st == FOLLOW) {
_lostFrames++;
if (_lostFrames < LOST_THRESH) {
g_motor.stop(); // 消抖期间保持停止
return;
}
_st = SEARCH_CW; _ts = millis(); _phase = 0; _lostFrames = 0;
g_motor.stop();
Serial.println(F(" 目标丢失,开始搜索"));
BTSerial.println(F(" Lost, searching"));
return;
}
// ── 搜索阶段 ─────────────────────────────────────────────────
unsigned long elapsed = millis() - _ts;
switch (_phase) {
case 0: g_motor.motorRun(SEARCH_SPEED, -SEARCH_SPEED);
if (elapsed >= SPIN_MS) { g_motor.stop(); _phase = 1; _ts = millis(); }
break;
case 1: if (elapsed >= PAUSE_MS) { _phase = 2; _ts = millis(); } break;
case 2: g_motor.motorRun(-SEARCH_SPEED, SEARCH_SPEED);
if (elapsed >= SPIN_MS * 2) { g_motor.stop(); _phase = 3; _ts = millis(); }
break;
case 3: if (elapsed >= PAUSE_MS) { _phase = 0; _ts = millis(); } break;
default: _phase = 0; _ts = millis(); break;
}
}
调试历程功能迭代内容
卡死不动最初 onEnter() 进入搜索状态旋转,IR引脚没有接线,读到的是拉高的 HIGH
跟随逻辑方向反了motorRun(-FOLLOW_TURN, FOLLOW_TURN) 实际上是转向弄反
跟随效果不稳定,抖动明显 降低搜索和跟随转速,加入丢失目标消抖(连续5帧确认丢失才切换)
6.3 系统流程图https://file1.elecfans.com/web3/M00/67/F4/wKgZPGpB4VSAPCaCAA7IPlFD1gI274.png①参数调优指南
问题现象可能原因调整方案
搜索时转速过快,找到目标有明显顿挫 SEARCH_SPEED 太大 降低到 50~65
对准时过冲,来回抖动FOLLOW_TURN 太大降低到 45~55
目标稍微晃动就进入搜索LOST_THRESH 太小增加到 8~10
丢失目标后反应太慢才开始搜索LOST_THRESH 太大减小到 3~5
双触发区间太窄,小车总在左右摆两传感器间距太大缩小传感器间距
传感器始终触发(误触发)灵敏度太高逆时针调电位器降低灵敏度
②与避障模式(B命令)的功能共用说明
同一对 IR 传感器在两种模式下复用,逻辑完全不同:
对比项跟随模式(G)避障辅助(B)
传感器安装推荐角度 正前方,偏内 ±15°斜前方 45°/135°
触发含义目标在那一侧,应转向靠近那一侧有障碍,应转向远离
转向决策转向触发侧(左触发→左转) 转离触发侧(左触发→右转)
速度控制慢速跟随,双触发停车紧急规避,直接全速转向
这也是代码里两个模块功能共用同一套硬件的典型案例,上层算法完全不同,但底层 IRSensor::read() 接口是相同的,体现了感知层与行为层分离的设计价值
七、常见问题解答(FAQ)Q1:传感器接好了,跟随时小车原地转但不追目标,是什么问题? A:首先用独立测试程序检查:把手放在左侧传感器前,串口显示的是 L=1 还是 R=1。如果显示 R=1,说明左右信号线接反了,换线即可。如果双侧都是0,检查供电和电位器
Q2:红外传感器在阳光下失效怎么办?
A:该模块对环境光有一定的适应性,但在强阳光直射的情况下,阳光中的红外分量会干扰接收管,导致误触发。解决方法:逆时针调小电位器降低灵敏度,同时给传感器加装遮光外壳(可用黑色热缩管套住模块两侧)
资料整合
LM393 数据手册(TI): lm393.pdf
LM393 应用电路: 差分比较器应用电路
红外跟随和红外避障虽然用了同样的硬件,但控制逻辑完全不同。避障只需要二值判断(有/没有障碍),而跟随需要正确理解“目标在左还是在右”并执行对应的转向动作——方向一旦搞反,整个功能就完全失效了
页:
[1]