1. 项目概述与核心思路最近在整理工作室的零件盒翻出来一块Adafruit的Circuit Playground Express开发板和几个闲置的微伺服电机。看着窗外刺眼的阳光我忽然想到能不能用这些手头的“边角料”做个实用的小玩意儿于是就有了这个“自动调光眼镜”的原型。它的核心逻辑非常简单直接利用开发板上集成的光传感器实时监测环境亮度当光线过强时控制一个微伺服电机将墨镜片或者任何遮光片降下来当环境变暗时再将镜片升上去。这本质上是一个经典的“传感器-控制器-执行器”闭环控制系统在智能家居的自动窗帘、根据光线调节亮度的台灯等场景里都能看到它的影子。这个项目特别适合刚接触嵌入式开发和物联网的朋友上手。它没有复杂的电路不需要焊接当然你想焊也行核心硬件就是一块Circuit Playground Express和一个微伺服。代码部分我提供了图形化的MakeCode和文本式的CircuitPython两种实现无论你是喜欢拖拽积木的初学者还是想练习Python编程的爱好者都能找到适合自己的路径。最终成品虽然看起来有点“极客风”不那么时尚但制作过程能让你透彻理解数据采集、阈值判断和电机控制这几个嵌入式开发中最基础也最重要的环节。下面我就把从零件准备、结构搭建到代码调试的完整过程以及我踩过的几个坑详细拆解一遍。2. 硬件选型与物料清单解析2.1 核心控制器为什么是Circuit Playground Express选择Circuit Playground Express后面简称CPX作为大脑是让这个项目变得简单的关键。市面上开发板很多比如经典的Arduino Uno但对于这个可穿戴项目CPX有几点不可替代的优势高度集成开箱即用CPX板载了我们需要的光传感器光电晶体管、10个可编程RGB LEDNeoPixels、多个触摸感应引脚甚至还有运动传感器和温度传感器。这意味着我们不需要额外购买和连接光敏电阻模块省去了电路搭建和分压计算的麻烦极大降低了入门门槛。供电灵活它可以通过USB口供电也支持连接3.7V的锂电池。对于需要戴在头上的眼镜来说一块小巧的锂电池是必须的CPX板载的JST PH电池接口让连接变得非常方便。编程友好同时支持MakeCode基于Blocks的图形编程和CircuitPython基于Python 3对新手和有一定基础的开发者都非常友好。特别是其“U盘拖拽式”编程用于CircuitPython无需安装复杂的IDE体验流畅。注意市面上有“Circuit Playground Classic”和“Express”两个版本。务必选择“Express”版本因为只有它原生支持CircuitPython和更强大的MakeCode功能光传感器的API调用也更简单。2.2 执行机构微伺服电机的选择与考量执行机构负责将电信号转化为机械运动这里我们选择微伺服电机。为什么是伺服电机而不是步进电机或普通直流电机精准的角度控制伺服电机可以通过脉冲信号精确控制旋转角度通常是0-180度。我们只需要它停在“镜片升起”如90度和“镜片降下”如0度两个位置伺服是天然适合的。集成度高伺服内部包含了电机、减速齿轮组和控制电路我们只需要提供电源和一根控制信号线无需额外的电机驱动板如L298N。扭矩保持到达指定角度后伺服会尽力保持位置这对于托住镜片至关重要。微伺服型号选择推荐使用SG90或MG90S这类常见的9克微伺服。它们价格便宜扭矩通常1.2-1.8 kg/cm足够带动一个小型墨镜片。购买时注意接口通常是三根线的杜邦线棕色/黑色-地线GND红色-电源VCC橙色/黄色-信号线Signal。需要确认其工作电压。大多数微伺服标称电压在4.8V-6V但在5V下可以稳定工作。我们的CPX逻辑电平是3.3V但控制伺服信号是没问题的伺服电源则需要单独从电池取电后面接线会讲。2.3 供电方案锂电池的选型与安全可穿戴设备必须考虑移动供电。我们选用一块3.7V、500mAh的锂聚合物电池。容量计算CPX待机和工作电流不大微伺服在动作瞬间电流可能达到200-300mA。500mAh的电池假设平均工作电流100mA理论上可连续工作约5小时。对于原型演示和间歇性使用完全足够。电压匹配锂电池满电电压约4.2V标称电压3.7V放电截止电压约3.0V。CPX的电池输入端口有保护电路可以安全地接3.7V锂电池。关键点在于伺服电机的电源不能直接从CPX的3.3V输出取电因为电流不够会导致CPX重启或伺服无法工作。正确做法是电池同时给CPX和伺服供电但信号线由CPX控制。充电与保护务必使用专用的锂电池充电器如USB接口的LiPo充电器切勿过充过放。CPX板载的USB口可以充电但充电时最好断开伺服避免意外动作。2.4 其他材料与工具清单类别物品说明/替代方案主体结构旧眼镜/太阳镜框架一副建议用塑料或轻质金属框架的便宜太阳镜方便改造。需要能拆卸镜片或本身是“翻盖”式。遮光片原装墨镜片或深色亚克力片如果原镜片不可拆卸可以寻找大小相近的深色塑料片用胶水粘在伺服舵盘上。连接线鳄鱼夹转杜邦公头跳线若干强烈推荐初期使用。无需焊接可快速连接和修改电路。固定材料热熔胶枪及胶棒固定伺服和CPX到眼镜框的主要工具。快速、牢固且有一定弹性。双面泡沫胶/纳米胶用于粘贴电池或辅助固定比热熔胶更易拆卸。强力胶如401胶水用于粘合伺服舵盘等需要高强度、小面积粘接的部位。工具小螺丝刀套装可能需要拆卸眼镜螺丝。剪刀、尖嘴钳、美工刀用于修剪材料、剪断扎带等。可选电烙铁、焊锡、助焊剂如果你想做一个更整洁、永久的版本焊接是必要的。3. 机械结构设计与组装实战3.1 眼镜框的预处理与伺服安装规划首先你需要仔细观察你的眼镜框。我们的目标是将伺服电机固定在眼镜框的中央顶部鼻梁上方让它的旋转轴朝前这样舵盘连接臂的旋转就能带动镜片上下翻动。确定安装位将伺服电机临时放在眼镜框顶部目测其旋转轴心位置。确保舵盘在旋转到水平位置作为镜片的初始“升起”状态时不会碰到你的额头或眉毛。同时舵盘降到垂直位置“降下”状态时连接的镜片能恰好覆盖你的视线区域。处理镜片如果是翻盖太阳镜这是最理想的情况。通常可以拆下原装的翻盖组件将伺服舵盘直接粘在翻盖的转轴部位。如果是普通太阳镜你可能需要小心地取出镜片有些是卡扣式然后制作一个连接臂一端粘在镜片顶部另一端粘在伺服舵盘上。或者干脆用一块独立的深色亚克力板作为遮光片。延长舵臂标准伺服附带的塑料舵臂舵盘通常很短。为了有足够的力臂带动镜片并且让镜片在升起时能完全移出视线范围我们需要延长它。一个简单可靠的方法是用强力胶将两个舵臂首尾粘接在一起。粘接前用砂纸轻轻打磨粘接面增加接触面积和胶水附着力。等待胶水完全固化通常24小时达到最大强度。3.2 伺服电机的固定技巧伺服电机本身的固定是个挑战因为眼镜框形状不规则。这里提供几种思路方法一热熔胶直接固定最常用。在伺服电机底部和侧面大量涂抹热熔胶然后迅速按压到眼镜框顶部预定位置。热熔胶冷却快有调整余地。技巧先点少量胶初步定位确认位置无误后再大量堆胶加固。可以在伺服和眼镜框之间垫一小块硬纸板或塑料片增加粘接面积。方法二利用伺服安装耳。很多伺服电机两侧有小的安装耳带孔。你可以用细扎带穿过这些孔然后紧紧绑在眼镜框上。如果眼镜框是金属的且较细甚至可以尝试将框体直接卡进伺服外壳的固定槽里如果尺寸巧合的话。方法三3D打印定制支架。如果你有3D打印机可以设计一个“眼镜框转伺服底座”的支架这是最完美、最牢固的方案。实操心得在最终固定伺服前务必先临时接通电源和信号线用一段测试代码让伺服在0度和90度之间来回运动几次。观察其运动轨迹确保镜片连接件在旋转过程中不会刮擦眼镜框或打到你的脸。这是避免返工的关键一步。3.3 Circuit Playground Express与电池的安装CPX和电池需要安装在眼镜的“后脑勺”位置即伺服电机的后方以达到前后重量的基本平衡避免眼镜整体前倾。固定CPX同样使用热熔胶将CPX的背面粘在伺服电机的后壳上。注意避开伺服电机轴和CPX的复位按钮、电源开关等。确保CPX正面的光传感器没有被遮挡能正常感知前方环境光。固定电池将500mAh锂电池用双面泡沫胶贴在CPX的背面。双面胶的好处是便于日后更换电池。确保电池的JST插头能轻松连接到CPX的电池端口。理线与收纳用一小段扎带或电工胶布将连接伺服的三根线以及可能用到的其他飞线捆扎在一起沿着眼镜腿向后固定让整体看起来更整洁也防止线缆被意外拉扯。4. 电路连接详解与安全要点电路连接是本项目的“任督二脉”接错了轻则不工作重则烧毁元件。请对照下图和文字说明仔细操作。[逻辑连接示意图] 锂电池 () ---- CPX BAT端口 () 锂电池 (-) ---- CPX GND端口 (-) | |----- 伺服电机 VCC (红线) |----- 伺服电机 GND (棕线/黑线) CPX 3.3V/GPIO A1 ---- 伺服电机 Signal (橙线/黄线)具体接线步骤与安全警告断开所有电源确保电池未连接USB线未插入。连接电池到CPX将锂电池的JST插头插入CPX板上的“BAT”端口。注意正负极通常红线为正黑线为负JST插头有防呆设计一般不会插反。连接伺服电机电源这是最容易出错的地方。切勿将伺服的VCC红线接到CPX的3.3V或5V输出口CPX板载稳压器无法提供伺服动作时所需的大电流峰值可达500mA以上。正确做法是将伺服的红线VCC和棕线GND与锂电池的正负极并联。你可以使用面包板或分线板将电池正极引到面包板正极总线负极到负极总线。然后CPX的BAT和伺服VCC都接正极总线CPX的GND和伺服GND都接负极总线。焊接或使用鳄鱼夹可以将伺服的红线与电池正极线在插头后端拧在一起并用焊锡固定同样处理黑线。或者用鳄鱼夹同时夹住电池线和伺服线。连接伺服控制信号将伺服的信号线橙线/黄线连接到CPX的A1引脚。A1是CPX上支持PWM脉冲宽度调制输出的引脚之一这是控制伺服角度所必需的。使用杜邦线或鳄鱼夹连接即可。最终检查对照示意图再次确认电池同时给CPX和伺服供电。伺服信号线接到了CPX的A1。所有连接牢固无短路风险特别是正负极金属部分不能相碰。5. 代码实现MakeCode图形化编程对于完全没有编程经验的朋友微软的MakeCode for Adafruit是绝佳的起点。它通过拖拽彩色代码块的方式编程直观易懂。5.1 初始化设置与伺服校准访问 https://makecode.adafruit.com/ 新建一个项目。在代码块分类中找到“高级”点击以展开更多类别。我们需要添加伺服扩展。点击“扩展”在搜索框中输入“servo”然后添加“servo”扩展包。添加后左侧会出现新的“Servo”类别。开始编程从“输入”类别中拖出当开机时积木。从“灯光”类别中拖出更多-设置亮度为 0积木放入当开机时下面。这会将NeoPixel亮度设为0关闭避免开机时灯光刺眼。从“Servo”类别中拖出伺服 写入引脚 P0 到 90 °积木。将P0改为A1。这个积木的作用是让伺服电机在上电后立即转到90度的位置我们定义为“镜片升起”状态。将90度改为你实际测试后确定的“升起”角度。5.2 主循环逻辑与阈值调试核心逻辑在一个无限循环中读取光线值 - 判断 - 控制灯光和伺服。从“循环”类别中拖出无限循环积木。读取光线在“输入”类别中找到光线级别积木它模拟了一个从0-255的值0最暗255最亮。拖入循环内。条件判断与控制我们需要两个“如果...那么...”的判断。判断黑暗开LED从“逻辑”类别拖出如果 true 那么积木。将光线级别积木拖入true的位置点击下拉菜单选择并在后面输入一个值比如10。这个值就是“黑暗阈值”。在“那么”里面从“灯光”类别拖入设置所有像素颜色为 红 255 绿 255 蓝 255这将点亮所有NeoPixel作为“手电筒”功能。你可以调整RGB值如200,200,200来改变亮度和色温。否则关闭LED点击如果积木上的号添加否则部分。在里面放入设置所有像素颜色为 红 0 绿 0 蓝 0来关闭灯光。再判断明亮降下镜片在第一个如果积木下方再拖入一个如果 true 那么积木。条件设置为光线级别 200这是“明亮阈值”。在“那么”里面放入伺服 写入引脚 A1 到 0 °“镜片降下”位置。否则升起镜片同样添加否则里面放入伺服 写入引脚 A1 到 90 °。添加延迟在循环末尾从“循环”类别拖入暂停ms 100积木将100改为250。这表示每250毫秒0.25秒检查一次光线。延迟太短会频繁动作耗电且机械磨损快延迟太长则反应迟钝。250ms是一个不错的平衡点。5.3 完整MakeCode代码块参考与调试技巧你的完整代码块应该类似这样当开机时 设置亮度为 0 伺服 写入引脚 A1 到 90 ° 无限循环 如果 光线级别 10 那么 设置所有像素颜色为 红 200 绿 200 蓝 200 否则 设置所有像素颜色为 红 0 绿 0 蓝 0 如果 光线级别 200 那么 伺服 写入引脚 A1 到 0 ° 否则 伺服 写入引脚 A1 到 90 ° 暂停ms 250调试技巧阈值校准代码中的10和200是示例阈值。你需要根据实际环境测试。在MakeCode编辑器中点击左下角的“...”菜单选择“设备控制台”。将程序下载到CPX后控制台会实时显示光线级别的数值。用手电筒照和用手遮住传感器观察数值变化范围从而确定适合你环境的“黑暗”和“明亮”阈值。伺服角度校准代码中的0°和90°是理论值。实际中由于安装的机械偏差可能需要微调。例如你可能需要将“降下”改为5°“升起”改为85°才能让镜片到达理想位置。6. 代码实现CircuitPython文本编程对于希望更灵活控制、学习真正编程语言的开发者CircuitPython是更好的选择。它语法简洁接近标准Python。6.1 开发环境搭建与库安装刷入CircuitPython固件如果你的CPX还不是CircuitPython状态需要先刷机。访问 https://circuitpython.org/board/circuitplayground_express/ 下载最新的.uf2固件文件。按住CPX上的复位按钮然后用USB线连接电脑直到出现一个名为CPLAYBOOT的U盘。将下载的.uf2文件拖入该U盘它会自动刷机并重启之后会出现一个名为CIRCUITPY的U盘。安装必要的库CircuitPython的核心库已内置但控制伺服需要额外的库。访问 https://circuitpython.org/libraries 下载适用于你CircuitPython版本的“适配包”Bundle。解压后找到以下文件或文件夹复制到CIRCUITPYU盘的根目录下的lib文件夹里如果没有就新建一个adafruit_motor(文件夹)adafruit_circuitplayground(文件夹) - 通常已经在适配包里它包含了控制板载所有传感器的简便方法。6.2 代码逐行解析与编写在CIRCUITPYU盘根目录下用任何文本编辑器推荐Mu Editor或VS Code打开或新建一个名为code.py的文件。设备启动时会自动运行这个文件。# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries # SPDX-License-Identifier: MIT Circuit Playground Express 自动调光眼镜/手电筒 基于环境光线自动控制镜片升降和LED开关 import time # 导入时间模块用于延时 import board # 导入板级定义模块用于指定引脚 import pwmio # 导入PWM模块用于产生控制伺服的脉冲信号 from adafruit_circuitplayground.express import cpx # 导入CPX专用库简化操作 from adafruit_motor import servo # 导入伺服电机库 # 1. 初始化PWM输出用于控制伺服 # 在A1引脚上创建一个PWM对象频率设为50Hz标准伺服控制频率 pwm pwmio.PWMOut(board.A1, duty_cycle2**15, frequency50) # 2. 创建伺服对象关联到上面的PWM输出 my_servo servo.Servo(pwm) # 3. 初始化状态关闭所有NeoPixel LED cpx.pixels.fill((0, 0, 0)) # 4. 初始化伺服位置将镜片升起设为90度 my_servo.angle 90 # 主循环 while True: # 5. 读取当前环境光强度范围大致0-255但实际可能更高 light_level cpx.light # 6. 判断光线并控制LED手电筒功能 if light_level 10: # 如果非常暗 cpx.pixels.fill((200, 200, 200)) # 点亮所有LED为白色中等亮度 else: # 否则 cpx.pixels.fill((0, 0, 0)) # 关闭所有LED # 7. 判断光线并控制伺服调光镜片功能 if light_level 200: # 如果非常亮 my_servo.angle 0 # 降下镜片0度位置 else: # 否则包括中等亮度和黑暗情况 my_servo.angle 90 # 升起镜片90度位置 # 8. 等待0.25秒后再次循环避免过于频繁的检测和动作 time.sleep(0.25)6.3 代码优化与高级功能拓展上面的代码是基础版本。在实际使用中我们可以进行优化和扩展防止频繁动作滞后在明暗阈值附近如果光线稍有波动伺服会频繁上下动作。可以加入“滞后区间”逻辑。# 定义状态变量和滞后阈值 shades_up True LIGHT_THRESHOLD_HIGH 220 # 变亮阈值更高 LIGHT_THRESHOLD_LOW 180 # 变暗阈值更低 while True: light_level cpx.light # ... LED控制逻辑 ... # 伺服控制带滞后 if light_level LIGHT_THRESHOLD_HIGH and shades_up: my_servo.angle 0 shades_up False elif light_level LIGHT_THRESHOLD_LOW and not shades_up: my_servo.angle 90 shades_up True time.sleep(0.25)添加渐变效果可以让伺服缓慢移动而不是瞬间跳变更显平滑。# 在 servo 初始化后可以设置其 actuation_range 和 min_pulse/max_pulse 来精确校准 # 使用 for 循环实现角度渐变 if light_level 200: for angle in range(my_servo.angle, 0, -5): # 从当前角度逐步降到0度步长-5 my_servo.angle angle time.sleep(0.05)利用板载按钮切换模式例如按A键切换自动/手动模式。auto_mode True while True: if cpx.button_a: # 如果A键被按下 auto_mode not auto_mode # 切换模式 time.sleep(0.3) # 防抖延时 if auto_mode: # 原有的自动控制逻辑 else: # 手动控制逻辑例如用B键控制镜片 if cpx.button_b: my_servo.angle 0 else: my_servo.angle 90 time.sleep(0.1)7. 调试、问题排查与优化心得即使按照步骤操作也难免会遇到问题。下面是我在制作和调试过程中遇到的一些典型情况及解决方法。7.1 伺服电机不动作或抖动症状上传代码后伺服电机毫无反应或者发出“吱吱”声并轻微抖动但不转动。排查步骤检查电源这是最常见的问题。确保伺服的红线VCC和黑线GND直接连接到了电池的正负极而不是CPX的3.3V输出。用万用表测量伺服VCC和GND之间的电压在电池满电时应接近4.2V。如果电压低于4V可能电池电量不足或线缆接触不良。检查信号线确认信号线黄线/橙线牢固地连接在CPX的A1引脚。尝试换到另一个支持PWM的引脚如A2或A3并在代码中相应修改引脚号。检查代码频率在CircuitPython中pwmio.PWMOut的频率必须设置为50Hz标准伺服控制频率。MakeCode中由积木底层处理一般没问题。检查角度范围确保代码中设置的角度如0, 90在伺服的有效范围内通常是0-180。尝试设置为中间值90看是否有反应。单独测试伺服编写一个最简单的测试程序只让伺服在0和180度之间来回运动排除主程序逻辑干扰。7.2 光线传感器读数不准或反应迟钝症状LED该亮时不亮镜片该下时不下或者反应速度慢。排查与优化读取实时值在CircuitPython中使用Mu Editor的串行REPL或MakeCode的设备控制台打印出cpx.light或光线级别的实时数值。用手遮住和用灯照射观察数值变化范围。这有助于你重新校准阈值。我办公室的日常光线值大约在50-150之间阳光下会超过250完全遮住会低于5。传感器遮挡检查是否有东西如胶水、头发挡住了CPX正中央的光电晶体管一个黑色的小方块。主循环延迟time.sleep(0.25)或暂停(250ms)决定了检测频率。如果觉得反应慢可以减小这个值比如改为0.1100ms。但要注意过于频繁的检测和伺服动作会增加功耗。加入滤波算法光线可能瞬间波动如影子闪过。可以采样最近几次的读数取平均值使判断更稳定。# 简单的移动平均滤波 light_readings [] while True: light_readings.append(cpx.light) if len(light_readings) 5: # 保留最近5次读数 light_readings.pop(0) avg_light sum(light_readings) / len(light_readings) # 使用 avg_light 进行判断 time.sleep(0.1)7.3 机械结构问题症状镜片运动不顺畅、卡住或者伺服电机发热严重。解决方案减少阻力确保镜片或连接臂在运动路径上没有任何阻碍。所有转动关节要留有微小间隙避免摩擦。可以在转轴处涂抹一点点润滑油如硅脂。检查负载如果镜片太重或力臂太长可能会超过微型伺服的电机的扭矩。尝试减轻镜片重量如换用更薄的亚克力片或缩短力臂长度。避免堵转在代码中确保伺服不会试图转到超出其物理限制的角度如尝试转到-10度或190度。堵转会极大增加电流导致伺服发热甚至损坏。结构加固用热熔胶固定的地方如果经常受力可能会松动。可以在关键受力点用强力胶辅助加固或者改用螺丝、扎带等机械固定方式。7.4 功耗与续航优化问题电池消耗很快。优化策略降低检测频率在光线稳定的室内可以将检测间隔从250ms增加到1秒甚至5秒。关闭NeoPixel在不需要手电筒功能时确保cpx.pixels.fill((0,0,0))被执行。NeoPixel全亮时功耗不小。使用深度睡眠高级如果CPX支持可以在光线稳定时让主板进入深度睡眠模式定时唤醒检测这能大幅降低功耗。但这需要更复杂的编程和可能的外部中断触发。这个项目从构思到实现最耗时的部分往往是机械结构的调整和阈值的精细校准。电路和代码本身并不复杂但如何让一个电子原型可靠地、优雅地穿戴在身上需要不断的测试和迭代。我做的第一个版本伺服直接用胶粘在塑料框上结果因为力矩问题半天就脱落了。后来加了辅助支撑结构才解决。所以耐心和动手尝试是关键。最终当眼镜能随着你走进走出房间而自动升降镜片时那种成就感是非常直接的。它不仅仅是一个玩具更是你对传感器、控制器、执行器这个物联网核心闭环的一次亲手实践。
基于CircuitPython与伺服电机的自动调光眼镜制作指南
1. 项目概述与核心思路最近在整理工作室的零件盒翻出来一块Adafruit的Circuit Playground Express开发板和几个闲置的微伺服电机。看着窗外刺眼的阳光我忽然想到能不能用这些手头的“边角料”做个实用的小玩意儿于是就有了这个“自动调光眼镜”的原型。它的核心逻辑非常简单直接利用开发板上集成的光传感器实时监测环境亮度当光线过强时控制一个微伺服电机将墨镜片或者任何遮光片降下来当环境变暗时再将镜片升上去。这本质上是一个经典的“传感器-控制器-执行器”闭环控制系统在智能家居的自动窗帘、根据光线调节亮度的台灯等场景里都能看到它的影子。这个项目特别适合刚接触嵌入式开发和物联网的朋友上手。它没有复杂的电路不需要焊接当然你想焊也行核心硬件就是一块Circuit Playground Express和一个微伺服。代码部分我提供了图形化的MakeCode和文本式的CircuitPython两种实现无论你是喜欢拖拽积木的初学者还是想练习Python编程的爱好者都能找到适合自己的路径。最终成品虽然看起来有点“极客风”不那么时尚但制作过程能让你透彻理解数据采集、阈值判断和电机控制这几个嵌入式开发中最基础也最重要的环节。下面我就把从零件准备、结构搭建到代码调试的完整过程以及我踩过的几个坑详细拆解一遍。2. 硬件选型与物料清单解析2.1 核心控制器为什么是Circuit Playground Express选择Circuit Playground Express后面简称CPX作为大脑是让这个项目变得简单的关键。市面上开发板很多比如经典的Arduino Uno但对于这个可穿戴项目CPX有几点不可替代的优势高度集成开箱即用CPX板载了我们需要的光传感器光电晶体管、10个可编程RGB LEDNeoPixels、多个触摸感应引脚甚至还有运动传感器和温度传感器。这意味着我们不需要额外购买和连接光敏电阻模块省去了电路搭建和分压计算的麻烦极大降低了入门门槛。供电灵活它可以通过USB口供电也支持连接3.7V的锂电池。对于需要戴在头上的眼镜来说一块小巧的锂电池是必须的CPX板载的JST PH电池接口让连接变得非常方便。编程友好同时支持MakeCode基于Blocks的图形编程和CircuitPython基于Python 3对新手和有一定基础的开发者都非常友好。特别是其“U盘拖拽式”编程用于CircuitPython无需安装复杂的IDE体验流畅。注意市面上有“Circuit Playground Classic”和“Express”两个版本。务必选择“Express”版本因为只有它原生支持CircuitPython和更强大的MakeCode功能光传感器的API调用也更简单。2.2 执行机构微伺服电机的选择与考量执行机构负责将电信号转化为机械运动这里我们选择微伺服电机。为什么是伺服电机而不是步进电机或普通直流电机精准的角度控制伺服电机可以通过脉冲信号精确控制旋转角度通常是0-180度。我们只需要它停在“镜片升起”如90度和“镜片降下”如0度两个位置伺服是天然适合的。集成度高伺服内部包含了电机、减速齿轮组和控制电路我们只需要提供电源和一根控制信号线无需额外的电机驱动板如L298N。扭矩保持到达指定角度后伺服会尽力保持位置这对于托住镜片至关重要。微伺服型号选择推荐使用SG90或MG90S这类常见的9克微伺服。它们价格便宜扭矩通常1.2-1.8 kg/cm足够带动一个小型墨镜片。购买时注意接口通常是三根线的杜邦线棕色/黑色-地线GND红色-电源VCC橙色/黄色-信号线Signal。需要确认其工作电压。大多数微伺服标称电压在4.8V-6V但在5V下可以稳定工作。我们的CPX逻辑电平是3.3V但控制伺服信号是没问题的伺服电源则需要单独从电池取电后面接线会讲。2.3 供电方案锂电池的选型与安全可穿戴设备必须考虑移动供电。我们选用一块3.7V、500mAh的锂聚合物电池。容量计算CPX待机和工作电流不大微伺服在动作瞬间电流可能达到200-300mA。500mAh的电池假设平均工作电流100mA理论上可连续工作约5小时。对于原型演示和间歇性使用完全足够。电压匹配锂电池满电电压约4.2V标称电压3.7V放电截止电压约3.0V。CPX的电池输入端口有保护电路可以安全地接3.7V锂电池。关键点在于伺服电机的电源不能直接从CPX的3.3V输出取电因为电流不够会导致CPX重启或伺服无法工作。正确做法是电池同时给CPX和伺服供电但信号线由CPX控制。充电与保护务必使用专用的锂电池充电器如USB接口的LiPo充电器切勿过充过放。CPX板载的USB口可以充电但充电时最好断开伺服避免意外动作。2.4 其他材料与工具清单类别物品说明/替代方案主体结构旧眼镜/太阳镜框架一副建议用塑料或轻质金属框架的便宜太阳镜方便改造。需要能拆卸镜片或本身是“翻盖”式。遮光片原装墨镜片或深色亚克力片如果原镜片不可拆卸可以寻找大小相近的深色塑料片用胶水粘在伺服舵盘上。连接线鳄鱼夹转杜邦公头跳线若干强烈推荐初期使用。无需焊接可快速连接和修改电路。固定材料热熔胶枪及胶棒固定伺服和CPX到眼镜框的主要工具。快速、牢固且有一定弹性。双面泡沫胶/纳米胶用于粘贴电池或辅助固定比热熔胶更易拆卸。强力胶如401胶水用于粘合伺服舵盘等需要高强度、小面积粘接的部位。工具小螺丝刀套装可能需要拆卸眼镜螺丝。剪刀、尖嘴钳、美工刀用于修剪材料、剪断扎带等。可选电烙铁、焊锡、助焊剂如果你想做一个更整洁、永久的版本焊接是必要的。3. 机械结构设计与组装实战3.1 眼镜框的预处理与伺服安装规划首先你需要仔细观察你的眼镜框。我们的目标是将伺服电机固定在眼镜框的中央顶部鼻梁上方让它的旋转轴朝前这样舵盘连接臂的旋转就能带动镜片上下翻动。确定安装位将伺服电机临时放在眼镜框顶部目测其旋转轴心位置。确保舵盘在旋转到水平位置作为镜片的初始“升起”状态时不会碰到你的额头或眉毛。同时舵盘降到垂直位置“降下”状态时连接的镜片能恰好覆盖你的视线区域。处理镜片如果是翻盖太阳镜这是最理想的情况。通常可以拆下原装的翻盖组件将伺服舵盘直接粘在翻盖的转轴部位。如果是普通太阳镜你可能需要小心地取出镜片有些是卡扣式然后制作一个连接臂一端粘在镜片顶部另一端粘在伺服舵盘上。或者干脆用一块独立的深色亚克力板作为遮光片。延长舵臂标准伺服附带的塑料舵臂舵盘通常很短。为了有足够的力臂带动镜片并且让镜片在升起时能完全移出视线范围我们需要延长它。一个简单可靠的方法是用强力胶将两个舵臂首尾粘接在一起。粘接前用砂纸轻轻打磨粘接面增加接触面积和胶水附着力。等待胶水完全固化通常24小时达到最大强度。3.2 伺服电机的固定技巧伺服电机本身的固定是个挑战因为眼镜框形状不规则。这里提供几种思路方法一热熔胶直接固定最常用。在伺服电机底部和侧面大量涂抹热熔胶然后迅速按压到眼镜框顶部预定位置。热熔胶冷却快有调整余地。技巧先点少量胶初步定位确认位置无误后再大量堆胶加固。可以在伺服和眼镜框之间垫一小块硬纸板或塑料片增加粘接面积。方法二利用伺服安装耳。很多伺服电机两侧有小的安装耳带孔。你可以用细扎带穿过这些孔然后紧紧绑在眼镜框上。如果眼镜框是金属的且较细甚至可以尝试将框体直接卡进伺服外壳的固定槽里如果尺寸巧合的话。方法三3D打印定制支架。如果你有3D打印机可以设计一个“眼镜框转伺服底座”的支架这是最完美、最牢固的方案。实操心得在最终固定伺服前务必先临时接通电源和信号线用一段测试代码让伺服在0度和90度之间来回运动几次。观察其运动轨迹确保镜片连接件在旋转过程中不会刮擦眼镜框或打到你的脸。这是避免返工的关键一步。3.3 Circuit Playground Express与电池的安装CPX和电池需要安装在眼镜的“后脑勺”位置即伺服电机的后方以达到前后重量的基本平衡避免眼镜整体前倾。固定CPX同样使用热熔胶将CPX的背面粘在伺服电机的后壳上。注意避开伺服电机轴和CPX的复位按钮、电源开关等。确保CPX正面的光传感器没有被遮挡能正常感知前方环境光。固定电池将500mAh锂电池用双面泡沫胶贴在CPX的背面。双面胶的好处是便于日后更换电池。确保电池的JST插头能轻松连接到CPX的电池端口。理线与收纳用一小段扎带或电工胶布将连接伺服的三根线以及可能用到的其他飞线捆扎在一起沿着眼镜腿向后固定让整体看起来更整洁也防止线缆被意外拉扯。4. 电路连接详解与安全要点电路连接是本项目的“任督二脉”接错了轻则不工作重则烧毁元件。请对照下图和文字说明仔细操作。[逻辑连接示意图] 锂电池 () ---- CPX BAT端口 () 锂电池 (-) ---- CPX GND端口 (-) | |----- 伺服电机 VCC (红线) |----- 伺服电机 GND (棕线/黑线) CPX 3.3V/GPIO A1 ---- 伺服电机 Signal (橙线/黄线)具体接线步骤与安全警告断开所有电源确保电池未连接USB线未插入。连接电池到CPX将锂电池的JST插头插入CPX板上的“BAT”端口。注意正负极通常红线为正黑线为负JST插头有防呆设计一般不会插反。连接伺服电机电源这是最容易出错的地方。切勿将伺服的VCC红线接到CPX的3.3V或5V输出口CPX板载稳压器无法提供伺服动作时所需的大电流峰值可达500mA以上。正确做法是将伺服的红线VCC和棕线GND与锂电池的正负极并联。你可以使用面包板或分线板将电池正极引到面包板正极总线负极到负极总线。然后CPX的BAT和伺服VCC都接正极总线CPX的GND和伺服GND都接负极总线。焊接或使用鳄鱼夹可以将伺服的红线与电池正极线在插头后端拧在一起并用焊锡固定同样处理黑线。或者用鳄鱼夹同时夹住电池线和伺服线。连接伺服控制信号将伺服的信号线橙线/黄线连接到CPX的A1引脚。A1是CPX上支持PWM脉冲宽度调制输出的引脚之一这是控制伺服角度所必需的。使用杜邦线或鳄鱼夹连接即可。最终检查对照示意图再次确认电池同时给CPX和伺服供电。伺服信号线接到了CPX的A1。所有连接牢固无短路风险特别是正负极金属部分不能相碰。5. 代码实现MakeCode图形化编程对于完全没有编程经验的朋友微软的MakeCode for Adafruit是绝佳的起点。它通过拖拽彩色代码块的方式编程直观易懂。5.1 初始化设置与伺服校准访问 https://makecode.adafruit.com/ 新建一个项目。在代码块分类中找到“高级”点击以展开更多类别。我们需要添加伺服扩展。点击“扩展”在搜索框中输入“servo”然后添加“servo”扩展包。添加后左侧会出现新的“Servo”类别。开始编程从“输入”类别中拖出当开机时积木。从“灯光”类别中拖出更多-设置亮度为 0积木放入当开机时下面。这会将NeoPixel亮度设为0关闭避免开机时灯光刺眼。从“Servo”类别中拖出伺服 写入引脚 P0 到 90 °积木。将P0改为A1。这个积木的作用是让伺服电机在上电后立即转到90度的位置我们定义为“镜片升起”状态。将90度改为你实际测试后确定的“升起”角度。5.2 主循环逻辑与阈值调试核心逻辑在一个无限循环中读取光线值 - 判断 - 控制灯光和伺服。从“循环”类别中拖出无限循环积木。读取光线在“输入”类别中找到光线级别积木它模拟了一个从0-255的值0最暗255最亮。拖入循环内。条件判断与控制我们需要两个“如果...那么...”的判断。判断黑暗开LED从“逻辑”类别拖出如果 true 那么积木。将光线级别积木拖入true的位置点击下拉菜单选择并在后面输入一个值比如10。这个值就是“黑暗阈值”。在“那么”里面从“灯光”类别拖入设置所有像素颜色为 红 255 绿 255 蓝 255这将点亮所有NeoPixel作为“手电筒”功能。你可以调整RGB值如200,200,200来改变亮度和色温。否则关闭LED点击如果积木上的号添加否则部分。在里面放入设置所有像素颜色为 红 0 绿 0 蓝 0来关闭灯光。再判断明亮降下镜片在第一个如果积木下方再拖入一个如果 true 那么积木。条件设置为光线级别 200这是“明亮阈值”。在“那么”里面放入伺服 写入引脚 A1 到 0 °“镜片降下”位置。否则升起镜片同样添加否则里面放入伺服 写入引脚 A1 到 90 °。添加延迟在循环末尾从“循环”类别拖入暂停ms 100积木将100改为250。这表示每250毫秒0.25秒检查一次光线。延迟太短会频繁动作耗电且机械磨损快延迟太长则反应迟钝。250ms是一个不错的平衡点。5.3 完整MakeCode代码块参考与调试技巧你的完整代码块应该类似这样当开机时 设置亮度为 0 伺服 写入引脚 A1 到 90 ° 无限循环 如果 光线级别 10 那么 设置所有像素颜色为 红 200 绿 200 蓝 200 否则 设置所有像素颜色为 红 0 绿 0 蓝 0 如果 光线级别 200 那么 伺服 写入引脚 A1 到 0 ° 否则 伺服 写入引脚 A1 到 90 ° 暂停ms 250调试技巧阈值校准代码中的10和200是示例阈值。你需要根据实际环境测试。在MakeCode编辑器中点击左下角的“...”菜单选择“设备控制台”。将程序下载到CPX后控制台会实时显示光线级别的数值。用手电筒照和用手遮住传感器观察数值变化范围从而确定适合你环境的“黑暗”和“明亮”阈值。伺服角度校准代码中的0°和90°是理论值。实际中由于安装的机械偏差可能需要微调。例如你可能需要将“降下”改为5°“升起”改为85°才能让镜片到达理想位置。6. 代码实现CircuitPython文本编程对于希望更灵活控制、学习真正编程语言的开发者CircuitPython是更好的选择。它语法简洁接近标准Python。6.1 开发环境搭建与库安装刷入CircuitPython固件如果你的CPX还不是CircuitPython状态需要先刷机。访问 https://circuitpython.org/board/circuitplayground_express/ 下载最新的.uf2固件文件。按住CPX上的复位按钮然后用USB线连接电脑直到出现一个名为CPLAYBOOT的U盘。将下载的.uf2文件拖入该U盘它会自动刷机并重启之后会出现一个名为CIRCUITPY的U盘。安装必要的库CircuitPython的核心库已内置但控制伺服需要额外的库。访问 https://circuitpython.org/libraries 下载适用于你CircuitPython版本的“适配包”Bundle。解压后找到以下文件或文件夹复制到CIRCUITPYU盘的根目录下的lib文件夹里如果没有就新建一个adafruit_motor(文件夹)adafruit_circuitplayground(文件夹) - 通常已经在适配包里它包含了控制板载所有传感器的简便方法。6.2 代码逐行解析与编写在CIRCUITPYU盘根目录下用任何文本编辑器推荐Mu Editor或VS Code打开或新建一个名为code.py的文件。设备启动时会自动运行这个文件。# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries # SPDX-License-Identifier: MIT Circuit Playground Express 自动调光眼镜/手电筒 基于环境光线自动控制镜片升降和LED开关 import time # 导入时间模块用于延时 import board # 导入板级定义模块用于指定引脚 import pwmio # 导入PWM模块用于产生控制伺服的脉冲信号 from adafruit_circuitplayground.express import cpx # 导入CPX专用库简化操作 from adafruit_motor import servo # 导入伺服电机库 # 1. 初始化PWM输出用于控制伺服 # 在A1引脚上创建一个PWM对象频率设为50Hz标准伺服控制频率 pwm pwmio.PWMOut(board.A1, duty_cycle2**15, frequency50) # 2. 创建伺服对象关联到上面的PWM输出 my_servo servo.Servo(pwm) # 3. 初始化状态关闭所有NeoPixel LED cpx.pixels.fill((0, 0, 0)) # 4. 初始化伺服位置将镜片升起设为90度 my_servo.angle 90 # 主循环 while True: # 5. 读取当前环境光强度范围大致0-255但实际可能更高 light_level cpx.light # 6. 判断光线并控制LED手电筒功能 if light_level 10: # 如果非常暗 cpx.pixels.fill((200, 200, 200)) # 点亮所有LED为白色中等亮度 else: # 否则 cpx.pixels.fill((0, 0, 0)) # 关闭所有LED # 7. 判断光线并控制伺服调光镜片功能 if light_level 200: # 如果非常亮 my_servo.angle 0 # 降下镜片0度位置 else: # 否则包括中等亮度和黑暗情况 my_servo.angle 90 # 升起镜片90度位置 # 8. 等待0.25秒后再次循环避免过于频繁的检测和动作 time.sleep(0.25)6.3 代码优化与高级功能拓展上面的代码是基础版本。在实际使用中我们可以进行优化和扩展防止频繁动作滞后在明暗阈值附近如果光线稍有波动伺服会频繁上下动作。可以加入“滞后区间”逻辑。# 定义状态变量和滞后阈值 shades_up True LIGHT_THRESHOLD_HIGH 220 # 变亮阈值更高 LIGHT_THRESHOLD_LOW 180 # 变暗阈值更低 while True: light_level cpx.light # ... LED控制逻辑 ... # 伺服控制带滞后 if light_level LIGHT_THRESHOLD_HIGH and shades_up: my_servo.angle 0 shades_up False elif light_level LIGHT_THRESHOLD_LOW and not shades_up: my_servo.angle 90 shades_up True time.sleep(0.25)添加渐变效果可以让伺服缓慢移动而不是瞬间跳变更显平滑。# 在 servo 初始化后可以设置其 actuation_range 和 min_pulse/max_pulse 来精确校准 # 使用 for 循环实现角度渐变 if light_level 200: for angle in range(my_servo.angle, 0, -5): # 从当前角度逐步降到0度步长-5 my_servo.angle angle time.sleep(0.05)利用板载按钮切换模式例如按A键切换自动/手动模式。auto_mode True while True: if cpx.button_a: # 如果A键被按下 auto_mode not auto_mode # 切换模式 time.sleep(0.3) # 防抖延时 if auto_mode: # 原有的自动控制逻辑 else: # 手动控制逻辑例如用B键控制镜片 if cpx.button_b: my_servo.angle 0 else: my_servo.angle 90 time.sleep(0.1)7. 调试、问题排查与优化心得即使按照步骤操作也难免会遇到问题。下面是我在制作和调试过程中遇到的一些典型情况及解决方法。7.1 伺服电机不动作或抖动症状上传代码后伺服电机毫无反应或者发出“吱吱”声并轻微抖动但不转动。排查步骤检查电源这是最常见的问题。确保伺服的红线VCC和黑线GND直接连接到了电池的正负极而不是CPX的3.3V输出。用万用表测量伺服VCC和GND之间的电压在电池满电时应接近4.2V。如果电压低于4V可能电池电量不足或线缆接触不良。检查信号线确认信号线黄线/橙线牢固地连接在CPX的A1引脚。尝试换到另一个支持PWM的引脚如A2或A3并在代码中相应修改引脚号。检查代码频率在CircuitPython中pwmio.PWMOut的频率必须设置为50Hz标准伺服控制频率。MakeCode中由积木底层处理一般没问题。检查角度范围确保代码中设置的角度如0, 90在伺服的有效范围内通常是0-180。尝试设置为中间值90看是否有反应。单独测试伺服编写一个最简单的测试程序只让伺服在0和180度之间来回运动排除主程序逻辑干扰。7.2 光线传感器读数不准或反应迟钝症状LED该亮时不亮镜片该下时不下或者反应速度慢。排查与优化读取实时值在CircuitPython中使用Mu Editor的串行REPL或MakeCode的设备控制台打印出cpx.light或光线级别的实时数值。用手遮住和用灯照射观察数值变化范围。这有助于你重新校准阈值。我办公室的日常光线值大约在50-150之间阳光下会超过250完全遮住会低于5。传感器遮挡检查是否有东西如胶水、头发挡住了CPX正中央的光电晶体管一个黑色的小方块。主循环延迟time.sleep(0.25)或暂停(250ms)决定了检测频率。如果觉得反应慢可以减小这个值比如改为0.1100ms。但要注意过于频繁的检测和伺服动作会增加功耗。加入滤波算法光线可能瞬间波动如影子闪过。可以采样最近几次的读数取平均值使判断更稳定。# 简单的移动平均滤波 light_readings [] while True: light_readings.append(cpx.light) if len(light_readings) 5: # 保留最近5次读数 light_readings.pop(0) avg_light sum(light_readings) / len(light_readings) # 使用 avg_light 进行判断 time.sleep(0.1)7.3 机械结构问题症状镜片运动不顺畅、卡住或者伺服电机发热严重。解决方案减少阻力确保镜片或连接臂在运动路径上没有任何阻碍。所有转动关节要留有微小间隙避免摩擦。可以在转轴处涂抹一点点润滑油如硅脂。检查负载如果镜片太重或力臂太长可能会超过微型伺服的电机的扭矩。尝试减轻镜片重量如换用更薄的亚克力片或缩短力臂长度。避免堵转在代码中确保伺服不会试图转到超出其物理限制的角度如尝试转到-10度或190度。堵转会极大增加电流导致伺服发热甚至损坏。结构加固用热熔胶固定的地方如果经常受力可能会松动。可以在关键受力点用强力胶辅助加固或者改用螺丝、扎带等机械固定方式。7.4 功耗与续航优化问题电池消耗很快。优化策略降低检测频率在光线稳定的室内可以将检测间隔从250ms增加到1秒甚至5秒。关闭NeoPixel在不需要手电筒功能时确保cpx.pixels.fill((0,0,0))被执行。NeoPixel全亮时功耗不小。使用深度睡眠高级如果CPX支持可以在光线稳定时让主板进入深度睡眠模式定时唤醒检测这能大幅降低功耗。但这需要更复杂的编程和可能的外部中断触发。这个项目从构思到实现最耗时的部分往往是机械结构的调整和阈值的精细校准。电路和代码本身并不复杂但如何让一个电子原型可靠地、优雅地穿戴在身上需要不断的测试和迭代。我做的第一个版本伺服直接用胶粘在塑料框上结果因为力矩问题半天就脱落了。后来加了辅助支撑结构才解决。所以耐心和动手尝试是关键。最终当眼镜能随着你走进走出房间而自动升降镜片时那种成就感是非常直接的。它不仅仅是一个玩具更是你对传感器、控制器、执行器这个物联网核心闭环的一次亲手实践。