从玩具小车到智能台灯:用STM32和光敏电阻DIY自动追光系统
周末整理储物间时,翻出儿子淘汰的玩具小车底盘,看着那些还能转动的轮子和电机,突然想到可以用它做个会"追太阳"的智能小车。这个想法让我兴奋不已——用最基础的光敏电阻和常见的STM32开发板,就能实现一个能感知光线、自主移动的智能装置。更妙的是,同样的原理稍加改动,就能变成根据环境光自动调节亮度的智能台灯。
1. 项目构思与核心逻辑
去年参加创客展时,看到过一个能跟着手电筒光跑的机器人,当时就觉得特别酷。其实这类项目的核心逻辑出奇简单:用光敏电阻感知光线强弱变化,通过STM32处理信号,最后控制电机或LED做出响应。就像向日葵追着太阳转一样,我们的装置也会朝着光线更强的方向移动。
追光小车的控制逻辑:
- 在车头两侧各安装一个光敏电阻(左L右R)
- 当左侧光强>右侧时,右转电机加速
- 当右侧光强>左侧时,左转电机加速
- 两侧光强相近时直行
智能台灯的变体方案:
// 伪代码示例 if(环境光 < 阈值){ PWM输出 = 最大亮度 - (阈值 - 当前光强)*系数; }else{ PWM输出 = 最小亮度; }2. 硬件搭建实战指南
我用的是一块吃灰已久的STM32F103C8T6最小系统板(俗称蓝板),价格不到20元。光敏电阻在电子市场5毛钱一个,建议买GL5528这类常见型号。电机驱动模块选择了经典的L298N,能同时驱动两个直流电机。
关键硬件连接表:
| 模块 | 连接引脚 | 备注 |
|---|---|---|
| 左侧光敏电阻 | PA0 | 需接10KΩ分压电阻 |
| 右侧光敏电阻 | PA1 | 需接10KΩ分压电阻 |
| L298N ENB | PB0 (PWM) | 右电机调速 |
| L298N ENA | PB1 (PWM) | 左电机调速 |
| L298N IN1 | PB12 | 右电机方向 |
| L298N IN2 | PB13 | 右电机方向 |
| L298N IN3 | PB14 | 左电机方向 |
| L298N IN4 | PB15 | 左电机方向 |
注意:光敏电阻没有极性,但分压电阻的阻值需要根据实际光照范围调整。我在室内测试时10KΩ效果不错,户外强光环境下可能需要换成1KΩ。
焊接时有个小技巧:用热熔胶把光敏电阻固定在可旋转的小支架上,这样就能灵活调整探测角度。我在车头用乐高积木搭了个简易云台,效果出奇地好。
3. 软件设计中的精妙之处
初始化ADC时,我选择了双通道交替采样模式,这样能同时读取两个光敏电阻的值,避免因采样时间差导致的判断误差。STM32的定时器产生PWM波控制电机转速,通过改变占空比实现差速转向。
核心控制代码片段:
// 光强差值计算 int light_diff = left_light - right_light; // 转向控制逻辑 if(abs(light_diff) < 50){ // 死区阈值 Motor_Forward(80); // 直行速度80% }else if(light_diff > 0){ Motor_TurnRight(map(light_diff, 50, 500, 30, 100)); // 差值越大转向越急 }else{ Motor_TurnLeft(map(-light_diff, 50, 500, 30, 100)); }这里用到的map()函数是个非常实用的数值映射工具,能把光强差值线性转换为PWM占空比。我在实际调试中发现,加入非线性修正系数效果更好:
// 加入平方系数使小转角更平缓 pwm_out = base_speed * (1 + pow(light_diff/500.0, 2));4. 调试过程中的经验之谈
第一个版本的小车表现得像喝醉酒似的,总是来回摆动。后来发现是采样频率太高(100Hz),导致系统反应过度。通过示波器观察ADC波形后,把采样间隔调整为200ms,并加入5次移动平均滤波,动作立刻流畅多了。
常见问题排查清单:
- 小车原地转圈 → 检查光敏电阻是否对称安装
- 对弱光无反应 → 尝试减小分压电阻阻值
- 电机间歇性停转 → 检查电源是否供电不足
- ADC值跳动剧烈 → 增加软件滤波或并联电容
有个有趣的发现:当把台灯版本的光敏电阻用铝箔包裹成"小喇叭"形状时,方向性检测灵敏度提升了3倍。这原理类似单反相机的遮光罩,能减少环境杂散光干扰。
5. 项目升级与创意拓展
基础版本成功后,我又尝试了几个变种:
- 避光模式:修改判断逻辑,让小车逃离强光
- 光强记忆:加入EEPROM存储用户偏好的亮度设置
- 无线遥控:通过蓝牙模块用手机调节灵敏度
- 太阳能充电:加装光伏板实现能量自给
最实用的改进是给台灯版本增加人体感应模块(HC-SR501),实现"人来灯亮,人走灯灭"的智能场景。配合光敏检测,白天有人经过时只微微亮起,夜晚则全亮度照明。
// 智能台灯进阶逻辑 if(人体检测 && 环境光 < 夜间阈值){ LED亮度 = 最大亮度; }else if(人体检测 && 环境光 < 白天阈值){ LED亮度 = 50%亮度; }else{ LED亮度 = 0; }这个项目最让我惊喜的是,原本对电子不感兴趣的儿子,看到会追着手电跑的小车后,主动要求学习编程。我们现在正一起用3D打印机制作更专业的底盘,计划加入超声波避障功能。也许这就是创客项目最大的魅力——用简单的技术点燃创造的火花。