三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

从红外反射原理到PID循迹:自制灰度传感器全流程解析

从红外反射原理到PID循迹:自制灰度传感器全流程解析

这次我们来看一个关于循迹小车核心传感器——灰度传感器的自制项目。标题“你连灰度传感器都要淘宝买成品,还做个屁的循迹!”直接点出了很多电子竞赛、课程设计或机器人爱好者的痛点:过度依赖现成模块,却对底层原理和自制方法一无所知。这篇文章将彻底拆解灰度传感器,从原理图绘制、元器件选型、焊接调试,到与单片机(如STM32、C51)的集成和循迹算法(PID)编写,提供一个完整的、可落地的自制方案。

如果你正在准备电赛、做课程设计,或者单纯想深入理解自动控制与传感器技术,那么自己动手做一个灰度传感器,远比直接买成品模块收获大。本文将重点关注自制传感器的硬件门槛(成本极低)、核心原理(红外反射式)、电路设计细节、以及如何将其集成到循迹小车系统中并编写稳健的代码。我们将从“能不能自己做”讲起,再到“具体怎么做”,最后通过“效果如何验证”来完成整个闭环。

1. 核心能力速览

能力项说明
项目类型开源硬件DIY项目,核心是自制红外灰度传感器模块
核心功能检测地面反射率(黑白线),输出数字/模拟信号,用于循迹小车路径识别
硬件门槛极低。核心元件成本仅数元,常用元器件易于获取
主要器件TCRT5000红外对管、LM393比较器、电位器、电阻、LED、排针等
输出信号数字量(高低电平)和模拟量(ADC电压值)双输出,兼容性强
供电要求3.3V或5V,与主流单片机(STM32, Arduino, C51)直接兼容
调试方式通过电位器调节检测灵敏度,通过LED指示状态
集成难度中等。需要基础焊接技能和单片机编程能力
适合场景电子竞赛(电赛)、单片机课程设计、机器人教育、业余DIY

2. 适用场景与使用边界

自制灰度传感器最适合以下几类人群和场景:

  1. 电子竞赛参赛者:如全国大学生电子设计竞赛(电赛)中,循迹小车是常见赛题。自制传感器能让你透彻理解其工作原理,在调试和应对复杂赛道(如Z型弯、十字路口)时更有优势,也符合竞赛鼓励创新的精神。
  2. 高校学生:正在学习单片机、传感器原理、自动控制等课程,通过此项目能将理论付诸实践,完成一个完整的课程设计或毕业设计。
  3. 机器人爱好者:希望摆脱“黑盒”模块,从底层构建自己的机器人感知系统,实现更高程度的自定义和优化。
  4. 创客教育工作者:作为教学案例,引导学生理解从原理图到实物的全过程,培养硬件思维和解决问题能力。

使用边界与注意事项:

  • 环境光干扰:红外反射式传感器受强环境光(特别是日光)影响较大。自制时需考虑添加遮光结构或软件滤波。
  • 检测距离固定:TCRT5000等器件的检测距离较短(通常几毫米),适用于贴地巡线。无法用于远程或非接触式测距。
  • 地面材质影响:对不同颜色、材质的反射率响应不同,需要针对实际赛道进行灵敏度校准。
  • 非精密测量:主要用于定性判断(黑/白),而非高精度的灰度值测量。对于需要精确灰度等级识别的场景(如复杂图案识别),应考虑摄像头方案。
  • 安全合规:本项目为低压直流电路实验,操作时注意用电安全,焊接时注意通风。使用的红外光为不可见光,功率很低,对人体无害。

3. 环境准备与前置条件

在开始动手之前,请确保你具备以下软硬件条件:

硬件准备清单:

  1. 核心传感器元件:TCRT5000红外反射传感器(发射管+接收管一体)。
  2. 信号处理芯片:LM393双电压比较器(常用,一片可处理两路传感器)。
  3. 无源元件
    • 电阻:10kΩ(上拉)、100Ω-1kΩ(限流)若干。
    • 电位器:10kΩ可调电阻,用于灵敏度调节。
    • 发光二极管(LED):用于电源和信号指示。
    • 电容:104(0.1uF)瓷片电容,用于电源滤波。
  4. 电路板与连接
    • 万用板(洞洞板)或自制PCB。
    • 排针(2.54mm间距),用于连接单片机。
    • 杜邦线(公对公、母对母)。
  5. 工具
    • 电烙铁、焊锡丝、松香/助焊剂。
    • 万用表(必备,用于调试电压)。
    • 镊子、剪线钳。
  6. 供电与主控
    • 3.3V/5V直流电源(可用单片机开发板供电)。
    • 单片机开发板:如STM32F103/F407、Arduino Uno、51单片机开发板等。
    • 示波器(非必需,但有助于深入分析信号)。

软件与知识准备:

  1. 电路设计软件:推荐使用立创EDA、KiCad或Altium Designer绘制原理图,理解电路连接关系。
  2. 单片机开发环境
    • STM32:Keil MDK-ARM 或 STM32CubeIDE,安装对应芯片支持包。
    • Arduino:Arduino IDE。
    • C51:Keil C51。
  3. 基础技能
    • 能读懂基本的模拟电路原理图。
    • 掌握基础的焊接技术。
    • 熟悉所用单片机的GPIO输入输出、ADC模数转换功能。
    • 了解基本的C语言编程。

4. 电路设计与原理分析

这是自制的核心。我们以最经典、最实用的单路灰度传感器电路为例进行详解。

4.1 核心原理:红外反射式检测

TCRT5000内部集成一个红外发射管和一个红外接收管。发射管持续发出红外光,照射到地面。地面反射红外光,接收管接收到反射光的强度。白色表面反射率高,接收到的光强;黑色表面反射率低,接收到的光弱。接收管将光强转换为电流变化,进而引起输出电压变化。

4.2 原理图拆解

一个完整的单路传感器模块通常包含以下部分:

  1. 红外发射部分

    • 红外发射管(TCRT5000的E极)串联一个限流电阻(如100Ω)连接到VCC。电阻值决定发射管电流,影响发射功率和检测距离。
  2. 红外接收与放大比较部分(核心)

    • 接收管(TCRT5000的C极)相当于一个光敏三极管,其集电极输出接到LM393比较器的反相输入端(IN-)。
    • LM393的同相输入端(IN+)连接到一个由电位器(如10kΩ)构成的分压电路,这个电压就是参考电压(阈值电压)
    • 调节电位器,即可改变阈值电压,从而调节传感器识别黑白的灵敏度。
    • LM393的输出端(OUT)通过一个上拉电阻(如10kΩ)连接到VCC,形成数字输出。同时,接收管的输出也可以直接引出作为模拟输出(AO)。
  3. 指示电路

    • 在数字输出(DO)后接一个LED和限流电阻到地,当输出低电平(检测到黑线)时LED点亮,提供直观的状态指示。

4.3 关键参数计算与选型建议

  • 发射管限流电阻:假设VCC=5V,红外管正向压降约1.2V,期望电流20mA,则电阻 R = (5V - 1.2V) / 0.02A ≈ 190Ω,可取标称值200Ω或220Ω。
  • 参考电压范围:通过10kΩ电位器,理论上可在0V至VCC间调节。实际调试中,将传感器分别置于黑线和白线上,测量接收管输出(AO)的电压,将阈值设于这两个电压值之间。
  • 上拉电阻:LM393是集电极开路输出,必须接上拉电阻(通常4.7kΩ-10kΩ)才能输出高电平。

单路灰度传感器简易原理图(文字描述):

VCC(5V) --- [200Ω] --- TCRT5000.E (发射管正极) --- GND | TCRT5000.C (接收管集电极) --- AO (模拟输出) --- 去单片机ADC | |--- [10kΩ电位器] --- 调节后电压 --- LM393.IN+ (同相端) | |--- LM393.IN- (反相端) | LM393.OUT --- [10kΩ上拉] --- VCC | |--- DO (数字输出) --- 去单片机IO | |--- [LED + 330Ω] --- GND

(注:TCRT5000的接收管发射极通常接地)

对于多路传感器(如5路、8路),只需将上述单路电路复制多份,共用电源和地。可以使用多路比较器芯片(如LM339,四路比较器)来节省空间。

5. PCB设计与焊接制作

5.1 设计要点

  1. 布局:将TCRT5000放置在板子边缘,并考虑安装方式(通常垂直向下)。比较器、电位器、指示灯等靠近放置。
  2. 走线:电源线(VCC、GND)适当加粗。模拟信号线(AO)尽量短,远离数字部分和发射管以减少干扰。
  3. 接口:统一使用排针引出VCC,GND,AO,DO。对于多路模块,建议将各路的DOAO分别集中排列,方便连接单片机。
  4. 安装孔:预留螺丝孔,便于固定在车体上。

5.2 焊接与组装步骤

  1. 焊接顺序:先焊接高度低的元件(电阻、IC座),再焊接较高的元件(电位器、排针、TCRT5000)。
  2. TCRT5000焊接:注意引脚顺序,焊接速度要快,避免过热损坏。可以在引脚上使用散热夹。
  3. 电位器调试:先将其旋到中间位置,上电后再精细调节。
  4. 通电前检查:务必用万用表蜂鸣档检查电源(VCC和GND)之间是否短路!

5.3 硬件调试

  1. 上电测试:接通5V电源,观察电源指示灯是否亮起。
  2. 发射管检查:用手机摄像头(大部分手机CMOS可感应红外光)对准TCRT5000发射端,应能看到紫色光点。
  3. 模拟输出(AO)测试
    • 将万用表拨到直流电压档,黑表笔接地,红表笔接AO引脚。
    • 将传感器对准白纸,记录电压值V_white
    • 将传感器对准黑线或黑胶带,记录电压值V_black
    • 正常情况下,V_white应显著高于V_black(例如,白纸3.0V,黑线0.5V)。
  4. 数字输出(DO)与阈值调节
    • 将万用表红表笔接DO引脚。
    • 传感器对准白纸,调节电位器,使DO输出为高电平(接近VCC电压),此时状态指示灯应熄灭。
    • 传感器对准黑线,DO输出应变为低电平(接近0V),状态指示灯点亮。
    • 反复在白与黑之间移动传感器,观察DO电平及LED能否可靠切换。

6. 与单片机系统集成

硬件制作完成后,需要将其接入循迹小车的主控系统。这里以常见的5路传感器、STM32F103C8T6(蓝色Pill板)为例。

6.1 硬件连接

假设我们自制了一个5路灰度传感器模块,其接口定义如下:

  • VCC:接单片机板5V3.3V(注意与传感器设计电压匹配)。
  • GND:接单片机板GND
  • D1~D5:5路数字输出,分别接单片机PA0~PA4(配置为上拉输入或浮空输入)。
  • A1~A5:5路模拟输出,分别接单片机PA0~PA4(配置为ADC输入,注意IO复用)。(通常数字和模拟输出二选一即可)

连接示意图:

传感器模块 STM32F103C8T6 VCC --- 5V GND --- GND D1 --- PA0 (GPIO_Input) D2 --- PA1 (GPIO_Input) D3 --- PA2 (GPIO_Input) D4 --- PA3 (GPIO_Input) D5 --- PA4 (GPIO_Input)

(若使用模拟输出,则A1~A5PA0~PA4,并将这些引脚配置为ADC模式)

6.2 数字信号读取(简单循迹)

使用数字接口时,程序逻辑简单,直接判断高低电平。

// STM32 HAL库示例 - 读取5路数字传感器状态 #include "main.h" // 假设传感器连接在GPIOA的PIN0-4 #define SENSOR_1_PIN GPIO_PIN_0 #define SENSOR_2_PIN GPIO_PIN_1 #define SENSOR_3_PIN GPIO_PIN_2 #define SENSOR_4_PIN GPIO_PIN_3 #define SENSOR_5_PIN GPIO_PIN_4 #define SENSOR_ALL_PINS (SENSOR_1_PIN | SENSOR_2_PIN | SENSOR_3_PIN | SENSOR_4_PIN | SENSOR_5_PIN) // 读取传感器状态,返回一个5位的值,每一位代表一个传感器(1:白/悬空,0:黑线) uint8_t Read_Digital_Sensors(void) { uint8_t sensor_state = 0; GPIO_PinState pinState; pinState = HAL_GPIO_ReadPin(GPIOA, SENSOR_1_PIN); sensor_state |= (pinState == GPIO_PIN_RESET) ? 0 : (1 << 0); // 黑线为低电平,取反 pinState = HAL_GPIO_ReadPin(GPIOA, SENSOR_2_PIN); sensor_state |= (pinState == GPIO_PIN_RESET) ? 0 : (1 << 1); // ... 读取其他传感器,类似操作 return sensor_state; } // 在主循环中根据传感器状态控制电机 void Main_Loop(void) { uint8_t sensors = Read_Digital_Sensors(); switch(sensors) { case 0b00100: // 仅中间传感器检测到黑线 Go_Straight(); // 直行 break; case 0b00010: // 中间偏右检测到 Turn_Slight_Right(); break; case 0b01000: // 中间偏左检测到 Turn_Slight_Left(); break; case 0b00001: // 最右边检测到 Turn_Hard_Right(); break; case 0b10000: // 最左边检测到 Turn_Hard_Left(); break; case 0b00000: // 全部检测到黑线(可能到终点或十字) Stop_Or_Handle_Cross(); break; case 0b11111: // 全部悬空(可能脱线) Search_Line(); break; default: // 其他组合状态处理 break; } HAL_Delay(10); // 控制周期 }

6.3 模拟信号读取与PID循迹(进阶)

使用模拟接口可以获得更丰富的路面信息,实现更平滑、更快速的PID控制。

// STM32 HAL库示例 - ADC读取5路模拟传感器并计算偏差 #include "main.h" ADC_HandleTypeDef hadc1; uint32_t adc_values[5]; // 存储5路ADC值 float sensor_weight[5] = {-2.0f, -1.0f, 0.0f, 1.0f, 2.0f}; // 传感器位置权重,中间为0 void Start_ADC_Conversion(void) { HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_values, 5); // 使用DMA连续采集5路 } // 计算位置偏差,范围大约在[-2, 2]之间 float Calculate_Position_Error(void) { float weighted_sum = 0.0f; float value_sum = 0.0f; const float black_ref = 500.0f; // 黑线ADC参考值(需实测校准) const float white_ref = 3000.0f; // 白底ADC参考值(需实测校准) for (int i = 0; i < 5; i++) { // 将ADC值归一化到0-1之间(0代表全黑,1代表全白) float normalized = (float)(adc_values[i] - black_ref) / (white_ref - black_ref); // 限制在0~1 if (normalized < 0.0f) normalized = 0.0f; if (normalized > 1.0f) normalized = 1.0f; // 累加加权值 weighted_sum += sensor_weight[i] * normalized; value_sum += normalized; } if (value_sum < 0.1f) { // 所有传感器都接近黑色,可能脱线 return 999.0f; // 返回一个错误标志 } return weighted_sum / value_sum; // 加权平均得到位置偏差 } // 简单的PID控制器 void PID_Control(float error) { static float integral = 0; static float last_error = 0; float Kp = 20.0f; // 比例系数,需调试 float Ki = 0.05f; // 积分系数,需调试 float Kd = 15.0f; // 微分系数,需调试 if (error == 999.0f) { // 脱线处理:原地旋转寻线 Motor_Set_Speed(-100, 100); return; } integral += error; // 积分限幅,防止积分饱和 if (integral > 100) integral = 100; if (integral < -100) integral = -100; float derivative = error - last_error; last_error = error; float output = Kp * error + Ki * integral + Kd * derivative; // 根据输出值调整左右电机速度 int base_speed = 150; // 基础速度 int left_speed = base_speed - output; int right_speed = base_speed + output; // 速度限幅 Motor_Set_Speed(left_speed, right_speed); }

7. 循迹算法调试与优化

7.1 基础调试流程

  1. 静态测试:将小车抬起,分别用黑线和白纸划过每个传感器下方,观察串口打印的ADC值或IO状态,确认每个传感器工作正常,阈值设置合理。
  2. 动态手动测试:手持小车,让传感器沿黑线缓慢移动,观察偏差计算是否连续、平滑。
  3. 低速闭环测试:将小车放在赛道上,设置很低的基础速度,让其自主循迹。观察其是否振荡、冲出赛道或响应迟钝。
  4. PID参数整定
    • 先调P(比例):增大Kp直到小车开始沿着线摆动但不过冲。此时响应快,但稳定性差。
    • 再调D(微分):增大Kd以抑制摆动,使小车运动更平滑。Kd能预测变化趋势,防止过冲。
    • 最后调I(积分):如果小车在直道上能循迹,但在弯道存在静态误差(始终偏离中心一点),则加入较小的Ki来消除稳态误差。Ki过大会引起振荡。
    • 口诀Kp发力,Kd刹车,Ki纠偏。

7.2 应对复杂赛道

  • 十字路口:当所有(或多路)传感器同时检测到黑线时,判定为十字路口。可以结合编码器或计时,执行“直行通过”或“转弯”的预设动作。
  • Z型弯/急弯:需要更快的控制周期和更强的微分(Kd)作用。也可以采用状态机,当检测到特定传感器组合(如最左和最右同时检测到线)时,进入“急弯模式”,临时修改PID参数或控制策略。
  • 起跑线/终点线:通常是一条较粗的黑线。可以通过检测“所有传感器同时看到黑线超过一定时间”来判断。
  • 虚线:需要加入“记忆”功能。当传感器短暂丢失黑线时,保持上一时刻的控制输出,并在一小段时间内继续按原方向运动寻线。

8. 常见问题与排查方法

问题现象可能原因排查方式解决方案
传感器无反应,LED不亮1. 电源接反或未接通
2. TCRT5000损坏或焊反
3. 比较器LM393损坏
1. 检查VCC/GND电压
2. 检查发射管:用手机摄像头看红外光
3. 测量比较器输入输出端电压
1. 纠正电源
2. 更换TCRT5000,注意引脚顺序
3. 更换LM393
数字输出(DO)电平不变化1. 电位器调节不当
2. 阈值电压设置不合理
3. 上拉电阻未接或虚焊
1. 测量比较器IN+(阈值)和IN-(信号)电压
2. 测量AO端电压在白/黑条件下的变化
3. 检查上拉电阻连接
1. 重新调节电位器,使阈值位于白/黑电压之间
2. 检查并焊接好上拉电阻
模拟输出(AO)电压变化范围小1. 发射管限流电阻过大,红外光弱
2. 传感器距地面太远
3. 环境光太强
1. 测量发射管电流
2. 调整安装高度(通常2-5mm)
3. 测量不同环境光下的AO电压
1. 减小限流电阻(如从220Ω换为100Ω)
2. 降低安装高度,增加遮光罩
单片机读到的值不稳定(抖动)1. 电源噪声
2. 传感器抖动
3. 软件未去抖
1. 用示波器观察AO或DO信号
2. 检查机械安装是否牢固
3. 检查代码采样频率
1. 在VCC和GND间加104滤波电容
2. 加固安装
3. 软件加入均值滤波或延时去抖
循迹小车左右摇摆(振荡)1. PID参数Kp过大
2. 传感器安装间距不合适
3. 控制周期太长
1. 观察偏差曲线
2. 测量传感器间距
1. 减小Kp,增加Kd
2. 优化传感器间距(通常1.5-2cm)
3. 提高控制频率(如从50Hz提到100Hz)
过弯时冲出赛道1. 弯道Kp不够或Kd太弱
2. 速度过快
3. 传感器数量少,预判不足
1. 分析过弯时的传感器数据
2. 测量过弯速度
1. 针对弯道增加KpKd(可分段PID)
2. 入弯前减速
3. 增加传感器路数(如8路)
十字路口误判1. 阈值设置过于敏感
2. 判断逻辑过于简单
1. 检查通过十字时各传感器数值
2. 模拟十字路口测试
1. 适当提高黑线判定阈值
2. 加入“持续一段时间”和“多传感器同时”的判断条件

9. 最佳实践与进阶建议

  1. 从单路开始:先制作并调试好一个单路传感器,彻底理解其工作原理和调试方法,再扩展到多路。
  2. 善用ADC:即使使用数字输出,也强烈建议将模拟输出(AO)接到单片机的ADC引脚。在调试时,通过串口打印ADC值,可以直观看到传感器对黑白的响应曲线,便于精确设置数字阈值。
  3. 模块化设计:将传感器模块、电机驱动模块、主控板分开设计,用排线或接插件连接。这样便于调试、更换和复用。
  4. 加入状态指示:每个传感器模块上最好有独立的电源灯和信号灯,在系统调试时能提供巨大的便利。
  5. 软件滤波:在读取传感器数据时,加入简单的软件滤波,如中值滤波或移动平均滤波,可以有效消除偶然干扰。
    // 简单的移动平均滤波示例 #define FILTER_SIZE 5 uint32_t adc_filter_buffer[5][FILTER_SIZE] = {0}; uint8_t filter_index = 0; uint32_t Get_Filtered_ADC_Value(uint8_t ch) { uint32_t sum = 0; for(int i=0; i<FILTER_SIZE; i++) { sum += adc_filter_buffer[ch][i]; } return sum / FILTER_SIZE; }
  6. 参数可配置:将PID参数、速度、传感器阈值等关键参数定义为变量,并通过串口命令或蓝牙APP在线修改,避免反复烧录程序。
  7. 记录与回放:在调试PID时,可以将偏差error、输出output等数据通过串口实时发送到电脑,用串口绘图工具(如Serial Plotter)可视化,这是调参的神器。
  8. 考虑扩展性:在设计电路和代码时,考虑未来可能增加的功能,如蓝牙遥控、OLED显示、多模式切换(循迹、避障、遥控)等,预留接口和资源。

10. 总结

自己动手制作灰度传感器,远不止是省下十几块钱的模块费用。这个过程迫使你深入理解红外反射原理、运算放大器比较器的应用、模拟与数字信号的转换、以及如何将物理信号转化为可靠的逻辑控制。当你亲手调校的传感器,驱动着小车稳稳地跑完复杂的赛道时,那种成就感是直接使用成品模块无法比拟的。

这个项目的核心价值在于“打通任督二脉”:从电路原理图到PCB焊接,从单片机IO操作到ADC采样,从简单的if-else逻辑到PID控制算法。它串联了电子、硬件、嵌入式软件和自动控制多个知识点。建议你按照文章步骤,从画原理图开始,一步步实践。遇到问题时,回头仔细检查硬件连接、测量关键点电压、分析软件逻辑。调试PID时,耐心一点,遵循“先P后D再I”的原则,多观察、多记录。

最终,你将获得一个完全受自己控制的、性能可优化的循迹感知系统。在此基础上,你可以进一步探索更复杂的传感器融合(如结合摄像头)、更高级的控制算法,这才是参加电赛、钻研技术的正确路径。

← 返回列表