公司动态

基于树莓派Pico的自动洗碗精分配器:从传感器到电机驱动的嵌入式实践

📅 2026/8/19 2:22:14
基于树莓派Pico的自动洗碗精分配器:从传感器到电机驱动的嵌入式实践
1. 项目概述从洗碗精瓶子到智能“管家”每次洗碗你都得跟那个滑溜溜、黏糊糊的洗碗精瓶子搏斗一番。要么是按不动要么是按一下喷得到处都是用量全凭手感浪费不说还弄得水槽边一片狼藉。这个场景相信每个下过厨房的人都深有体会。作为一个喜欢折腾硬件的开发者我一直在想能不能用手里那些常见的电子模块给这个日常痛点来个“降维打击”于是就有了这个基于树莓派 Pico 的自动洗碗精分配器项目。这个项目的核心目标很简单实现非接触、定量、自动化的液体分配。你不再需要用手去按压瓶子只需将手或容器伸到感应区域机器就会自动、精准地为你挤出预设好量的洗碗精。它听起来像个小玩具但背后串联起了嵌入式开发中几个非常经典且实用的技术点微控制器编程、传感器数据采集、电机驱动控制以及简单的系统逻辑设计。无论你是刚接触树莓派 Pico 和 MicroPython 的新手想找一个有趣又实用的练手项目还是有一定经验的开发者希望深入理解传感器与执行器如何协同工作这个项目都能提供一条清晰的学习路径。我选择了树莓派 Pico 作为主控因为它性价比极高GPIO 丰富对 MicroPython 的支持也非常友好能让开发者快速上手。超声波传感器 HC-SR04 负责非接触式距离检测充当我们的“眼睛”。而将瓶内的液体推挤出来的任务则交给了由微型直流电机驱动的丝杆滑块机构并通过 TB6612 这类电机驱动模块进行精确的 PWM 调速控制。整个系统的逻辑用 Python 编写清晰易懂。接下来我将从设计思路、硬件选型、代码实现到调试心得完整地拆解这个项目让你不仅能复现更能理解每一个环节背后的“为什么”。2. 核心硬件选型与电路设计思路做一个项目硬件是骨架。选对部件设计好电路项目就成功了一半。这里的选择都是基于成本、易用性、可靠性和项目需求这四点做的权衡。2.1 主控芯片为什么是树莓派 Pico在众多微控制器中我选择了树莓派 Pico而不是更常见的 Arduino 或 STM32主要基于以下几点考量极致的性价比与开放性Pico 的核心是一颗 RP2040 双核 ARM Cortex-M0 芯片主频 133MHz性能对于本项目绰绰有余。其最大的亮点是价格低廉但提供了 26 个多功能 GPIO 引脚、2 个 SPI、2 个 I2C、2 个 UART 以及 16 个 PWM 通道资源非常丰富。官方提供的详尽 Datasheet 和 SDK使得底层开发也很透明。对 MicroPython 的“一等公民”支持本项目逻辑不复杂但对开发效率有要求。MicroPython 作为 Python 的精简子集语法简单交互性强非常适合快速原型开发。树莓派基金会为 Pico 提供了高度优化的 MicroPython 固件开箱即用省去了复杂的工具链配置过程。对于新手来说几行代码就能让 LED 闪烁这种即时反馈的成就感是巨大的动力。丰富的社区资源与扩展性Pico 的生态非常活跃任何你遇到的问题几乎都能在社区找到讨论或解决方案。这降低了学习和调试的门槛。此外Pico 的引脚排列规范便于在面包板或洞洞板上搭建电路也为未来可能的扩展比如增加显示屏显示用量留足了空间。注意Pico 的工作电压是 3.3V这意味着它的 GPIO 高电平是 3.3V。在连接其他 5V 器件如某些型号的超声波传感器、电机驱动模块时务必注意电平兼容性问题防止损坏芯片。2.2 感知之手HC-SR04 超声波测距模块详解要实现“伸手即来”我们需要一个能检测是否有物体靠近的传感器。红外、电容触摸和超声波是常见选择。我选择 HC-SR04原因如下原理简单可靠它通过发射一束 40kHz 的超声波并接收遇到物体反射回来的回波通过计算声波飞行时间来计算距离。其探测角度适中不易受日常光线影响比红外传感器更稳定。接口简单仅需一个 GPIO 触发Trig发射一个 GPIO 接收回波Echo。Echo 脚会输出一个高电平脉冲其宽度与距离成正比。 *.成本低廉且普及这是最经典的超声波模块之一几块钱就能买到资料遍地都是。工作原理与电路连接 HC-SR04 有四个引脚VCC5V、Trig触发、Echo回波、GND。这里有一个关键点Echo 脚输出的是 5V 电平的信号而 Pico 的 GPIO 只能耐受 3.3V。直接连接会损坏 Pico因此必须进行电平转换。一个简单可靠的方案是使用电阻分压电路。将 Echo 脚通过一个 1kΩ 电阻连接到 Pico 的 GPIO同时在该 GPIO 与 GND 之间连接一个 2kΩ 电阻。这样5V 信号经过分压后输入到 Pico 的电压约为 5V * (2k / (1k2k)) ≈ 3.33V处于安全范围内。Trig 脚由 Pico 的 GPIO 直接控制输出 3.3V 高电平HC-SR04 通常能识别为高电平可以正常工作。2.3 执行之臂电机、驱动与机械结构这是项目的动力核心也是最需要精心设计的部分。电机的选择我们需要一个能将旋转运动转化为直线推力的机构。普通的小型直流减速电机带齿轮箱是理想选择它扭矩大、转速适中、价格便宜。我选用的是工作电压 5-12V带有减速箱的 N20 微型直流电机。它的轴可以方便地连接各种联轴器。驱动模块的抉择TB6612 vs. L298NL298N老牌双 H 桥驱动芯片驱动能力强但发热量大效率相对较低需要外接散热片。TB6612新一代双 H 桥驱动芯片效率高、发热小、外围电路简单并且支持待机模式以省电。对于本项目驱动一个小型直流电机TB6612 的性能和体积优势更明显。TB6612 连接要点VM接电机电源如 7.4V 锂电池或 9V 电源适配器。VCC接逻辑电源与 Pico 共 3.3V 或 5V。GND共地。AIN1/AIN2接 Pico 的两个 GPIO控制电机转向正转/反转/刹车。PWMA接 Pico 的一个 PWM 引脚通过调节占空比来控制电机速度。STBY接高电平如 VCC使能驱动。机械结构设计这是将电机旋转转化为直线推挤的关键。我设计了一个简单的“丝杆滑块”机构丝杆一根普通的 M4 或 M5 螺杆。螺母滑块一个与丝杆配套的螺母通过热熔胶或螺丝固定在一块亚克力或 3D 打印的滑块上。联轴器连接电机轴和丝杆。可以使用现成的弹性联轴器也可以自制如用一小段硅胶管。推板固定在滑块前端用于直接推挤洗碗精瓶的按压头。导轨两根光滑的金属杆或圆杆作为滑块的导向确保推板直线运动不卡涩。当电机正转时带动丝杆旋转螺母滑块沿丝杆向前向瓶口直线运动推动推板挤压瓶嘴挤出液体。电机反转时滑块退回等待下一次触发。2.4 电源系统设计系统涉及多个电压等级树莓派 Pico通过 USB 或 VSYS 引脚供电电压范围 1.8-5.5V通常我们提供 5V。TB6612 逻辑部分VCC需要 3.3V 或 5V与 Pico 共电即可。TB6612 电机部分VM根据电机额定电压选择如 7.4V 或 9V。HC-SR04需要 5V。方案一推荐用于原型使用两个电源。一个 5V/2A 的 USB 充电器或电源模块同时给 Pico 和 HC-SR04 供电注意 HC-SR04 的 VCC 接 5V。另一个电源如 2S 锂电池或 9V 适配器单独给 TB6612 的 VM 供电。两个电源的 GND 必须连接在一起共地。方案二集成化如果想用一个电源可以选择一个 12V 电源适配器。然后通过一个 DC-DC 降压模块如 LM2596降压到 5V给 Pico 和 HC-SR04 供电。12V 直接供给 TB6612 的 VM需确保电机支持 12V。这种方案更简洁但需要注意降压模块的电流输出能力要足够。3. 软件逻辑与 MicroPython 代码实现硬件搭好了接下来就是赋予它灵魂的软件部分。我们将使用 MicroPython 在树莓派 Pico 上编写控制程序。3.1 开发环境搭建固件烧录首先访问树莓派基金会官网下载最新的 Pico MicroPython 固件.uf2文件。按住 Pico 上的BOOTSEL按钮同时通过 USB 连接到电脑然后松开按钮。电脑上会出现一个名为RPI-RP2的可移动磁盘将下载的.uf2文件拖入其中。Pico 会自动重启进入 MicroPython 模式。选择代码编辑器你可以使用任何文本编辑器但推荐使用 Thonny对新手极其友好自带 MicroPython 支持或 VS Code 配合 Pico-W-Go 等插件。它们支持直接连接 Pico上传/下载文件并在 REPL 交互式环境中调试代码。3.2 核心代码模块拆解我们将代码按功能模块化便于理解和维护。1. 超声波测距模块 (hcsr04.py)import machine import utime class HCSR04: def __init__(self, trigger_pin, echo_pin): self.trigger machine.Pin(trigger_pin, machine.Pin.OUT) self.echo machine.Pin(echo_pin, machine.Pin.IN) self.trigger.value(0) utime.sleep_us(2) def distance_cm(self): # 发送10us的高电平脉冲触发测距 self.trigger.value(1) utime.sleep_us(10) self.trigger.value(0) # 等待回波引脚变高并记录开始时间 while self.echo.value() 0: signaloff utime.ticks_us() # 等待回波引脚变低并记录结束时间 while self.echo.value() 1: signalon utime.ticks_us() # 计算时间差微秒 timepassed signalon - signaloff # 声音在空气中速度约343m/s (29.1us/cm)计算距离 (cm) # 除以2是因为声音走了来回两倍路程 distance (timepassed * 0.0343) / 2 return distance关键点这里使用了utime.ticks_us()来获取高精度时间戳。计算距离时声速取 343m/s对应 29.1 微秒每厘米。循环等待 Echo 引脚变化时最好增加超时判断防止因物体太远或无回波导致程序死锁。2. 电机驱动模块 (motor.py)from machine import Pin, PWM class DCMotor: def __init__(self, in1_pin, in2_pin, pwm_pin, stby_pinNone): self.in1 Pin(in1_pin, Pin.OUT) self.in2 Pin(in2_pin, Pin.OUT) self.pwm PWM(Pin(pwm_pin)) self.pwm.freq(1000) # 设置PWM频率为1kHz if stby_pin: self.stby Pin(stby_pin, Pin.OUT) self.stby.value(1) # 使能驱动 else: self.stby None def forward(self, speed50000): 正转speed为PWM占空比 (0-65535) self.in1.value(1) self.in2.value(0) self.pwm.duty_u16(speed) def backward(self, speed50000): 反转 self.in1.value(0) self.in2.value(1) self.pwm.duty_u16(speed) def stop(self): 刹车停止 self.in1.value(1) self.in2.value(1) self.pwm.duty_u16(0) # 或者 self.in1.value(0); self.in2.value(0); # 惯性停止 def brake(self): 快速刹车 self.in1.value(1) self.in2.value(1) self.pwm.duty_u16(65535) # 短接电机两端 utime.sleep_ms(50) # 刹车保持一小段时间 self.pwm.duty_u16(0)关键点PWM.duty_u16()的参数范围是 0-65535对应 0%-100% 占空比。forward和backward中的speed参数可以让你精细控制挤出速度。stop()和brake()的区别在于前者是让电机惯性停止后者是主动短路电机线圈产生制动力停止更快对于需要精确停止位置的场合如定量挤出更有用。3. 主控制逻辑 (main.py)这是整个系统的大脑负责协调传感器和电机。import utime from hcsr04 import HCSR04 from motor import DCMotor # 引脚定义 (根据你的实际接线修改) TRIG_PIN 2 ECHO_PIN 3 MOTOR_IN1 6 MOTOR_IN2 7 MOTOR_PWM 8 STBY_PIN 9 # 如果TB6612的STBY接高电平了这里可以设为None # 系统参数 DETECTION_DISTANCE_CM 15 # 感应距离小于此距离触发 DISPENSE_DURATION_MS 800 # 电机正转时间挤出 RETRACT_DURATION_MS 1000 # 电机反转时间退回 MOTOR_SPEED 40000 # 电机运行速度 (PWM占空比) COOLDOWN_TIME_MS 3000 # 两次触发之间的冷却时间防止连续误触发 # 初始化 sensor HCSR04(TRIG_PIN, ECHO_PIN) motor DCMotor(MOTOR_IN1, MOTOR_IN2, MOTOR_PWM, STBY_PIN) # 状态变量 last_trigger_time utime.ticks_ms() - COOLDOWN_TIME_MS # 确保初始可触发 def dispense_cycle(): 执行一次完整的分配循环 print(Dispensing...) motor.forward(MOTOR_SPEED) utime.sleep_ms(DISPENSE_DURATION_MS) motor.stop() utime.sleep_ms(200) # 停顿一下让液体流下 print(Retracting...) motor.backward(MOTOR_SPEED) utime.sleep_ms(RETRACT_DURATION_MS) motor.stop() print(Cycle complete.) def main(): global last_trigger_time print(Automatic Dish Soap Dispenser Started.) print(fDetection Range: {DETECTION_DISTANCE_CM}cm) while True: try: dist sensor.distance_cm() # print(fDistance: {dist:.1f} cm) # 调试时可打开 current_time utime.ticks_ms() # 判断逻辑有物体靠近且距离上次触发已过冷却时间 if dist DETECTION_DISTANCE_CM and \ utime.ticks_diff(current_time, last_trigger_time) COOLDOWN_TIME_MS: print(fObject detected at {dist:.1f}cm. Triggering.) last_trigger_time current_time dispense_cycle() except Exception as e: # 捕获测距可能的超时等错误 print(fSensor error: {e}) motor.stop() # 出错时确保电机停止 utime.sleep_ms(100) # 主循环延迟降低CPU占用 if __name__ __main__: main()逻辑解析初始化创建传感器和电机对象。主循环持续测量距离。触发条件当测量距离小于预设的DETECTION_DISTANCE_CM例如 15cm并且距离上一次触发的时间超过了COOLDOWN_TIME_MS例如 3秒则判定为一次有效的“伸手”动作。执行分配调用dispense_cycle()函数控制电机正转挤出→ 短暂停止 → 反转退回。冷却时间这是防止误触发的关键。如果没有冷却时间手放在感应区会导致电机连续动作。冷却时间确保了单次触发后系统会“无视”一段时间内的持续信号。异常处理用try-except包裹测距代码防止因传感器异常导致整个程序崩溃。4. 机械组装、校准与系统调试代码写好了硬件也齐了接下来就是把它们组合成一个可靠产品的过程。这一步充满了细节和“坑”。4.1 机械结构搭建与固定框架制作使用亚克力板、木板或 3D 打印一个坚固的框架。框架需要容纳以下部分电机固定座必须牢固防止电机运行时晃动。丝杆支撑座在丝杆远离电机的一端需要一个轴承或简单的穿孔支撑确保丝杆同心旋转不弯曲。导轨固定座两根导轨必须平行且与丝杆平行这是滑块顺畅运动的关键。传感器支架将 HC-SR04 固定在正对感应区域的位置通常朝下或略微倾斜。瓶子固定夹设计一个能稳定卡住洗碗精瓶身的机构确保瓶嘴对准推板中心。对齐是关键电机轴、联轴器、丝杆三者必须在同一直线上。轻微的偏差会导致巨大的阻力、噪音和磨损。安装时可以用手转动电机感受滑块运动是否顺滑有无卡顿。推板设计推板前端最好粘贴一块软硅胶或海绵以适配不同形状的瓶嘴并增加摩擦力确保能有效下压。4.2 系统参数校准这是让机器从“能动”到“好用”的关键步骤。你需要反复测试调整以下几个核心参数在main.py中感应距离 (DETECTION_DISTANCE_CM)将手或杯子放在你希望触发的位置用打印语句输出实时距离确定一个合适的值如 10-20cm。太近容易误触发比如路过太远则需要刻意伸手。挤出时间 (DISPENSE_DURATION_MS)这直接决定了挤出量。准备一个量杯或勺子。进行一次触发收集挤出的液体测量其体积如 5ml。根据公式调整时间目标时间 (目标体积 / 当前测试体积) * 当前测试时间。注意电机速度、丝杆螺距、瓶子内液体粘度和剩余量都会影响流速所以最好在瓶子半满状态下校准并留一点余量。退回时间 (RETRACT_DURATION_MS)确保滑块能完全退回到起始位置为下一次挤出做好准备。通常比挤出时间稍长一点。电机速度 (MOTOR_SPEED)速度太快可能导致液体喷射或机械冲击太慢则挤出过程拖沓。建议从中间值如 30000开始测试找到一个兼顾效率和稳定性的值。冷却时间 (COOLDOWN_TIME_MS)根据使用习惯设置。如果希望一次伸手只挤一次即使手没拿开可以设为 3-5 秒。如果想实现手持续放着就连续慢速挤出类似感应水龙头则需要更复杂的逻辑比如检测到手移除后再重置冷却。4.3 电路连接检查与上电测试在接通主电源前务必进行以下检查万用表通断测试检查所有电源线5V VM对地GND是否短路。电平确认确保 HC-SR04 的 Echo 脚到 Pico GPIO 之间有分压电路。电机线序确认 TB6612 的 AOUT1/AOUT2 连接电机正负极正确。如果方向反了交换这两根线即可不要交换电源以免损坏驱动芯片。分步上电先只连接 Pico 的 USB5V逻辑电通过 REPL 查看程序是否运行传感器数据是否正常。然后再连接电机动力电源VM。5. 常见问题排查与优化进阶在实际制作中你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的排查清单和优化建议。5.1 问题排查速查表现象可能原因排查步骤上电无反应1. 电源未接通或电压不对。2. Pico 固件丢失或损坏。3. 电源线/地线虚焊或断开。1. 用万用表测量 Pico 的 VSYS 或 3V3 引脚对地电压。2. 重新烧录 MicroPython 固件。3. 仔细检查所有电源和地线连接。超声波传感器读数恒为0或极大值1. 接线错误特别是 Trig 和 Echo 接反。2. Echo 脚 5V 电平损坏了 Pico GPIO未分压。3. 传感器模块本身故障。4. 测量物体超出范围或表面不反射声波。1. 核对引脚定义。2. 检查分压电路测量 Echo 到 Pico GPIO 的电压是否≤3.3V。3. 更换一个传感器测试。4. 测试时用手或硬纸板在近距离10cm尝试。电机不转1. 电机电源VM未接或电压不足。2. STBY 引脚未接高电平。3. TB6612 的输入控制逻辑错误。4. 电机堵转或负载过大。1. 测量 VM 引脚电压。2. 确保 STBY 接高电平或代码中已置高。3. 用代码单独测试电机motor.forward(30000)。4. 断开电机与机械结构的连接空载测试。电机只震动不转或单向转1. PWM 频率不合适建议 1k-10kHz。2. 电机某一相线接触不良。3. 驱动芯片某一路损坏。1. 检查代码中pwm.freq()设置。2. 重新焊接电机线。3. 交换 AIN1/AIN2 看故障是否跟随或更换驱动模块。挤出量不稳定1. 瓶子内液体量变化导致压力不同。2. 丝杆/导轨有阻力运动不顺畅。3. 电源电压波动导致电机速度变化。1. 这是物理限制可尝试在瓶盖上开个小气孔平衡气压。2. 润滑丝杆和导轨确保装配平行。3. 使用稳压电源或电池供电。程序运行一段时间后死机1. 电源功率不足带载后电压跌落。2. 电机启停电流冲击导致 Pico 复位。3. 代码中有内存泄漏或未处理的异常。1. 升级电源适配器如 5V/3A VM 用 2A以上。2. 在 Pico 的电源输入端并联一个大电容如 1000uF缓冲。3. 检查while循环是否有退出条件增强异常捕获。5.2 性能优化与功能扩展基础功能实现后你可以考虑以下优化让项目更上一层楼定量精度提升闭环控制在滑块上安装一个简单的限位开关微动开关作为“归零”传感器。每次循环开始时让电机反转直到触发限位开关这样每次的起始位置绝对一致挤出量只由正转时间控制精度大幅提高。编码器反馈使用带编码器的电机通过计算编码器脉冲数来精确控制滑块行程从而实现真正的高精度定量不受电压、负载变化影响。用户体验优化状态指示增加一个 RGB LED 或 NeoPixel 灯带。例如待机时呼吸灯效检测到物体时亮起挤出时流水灯效故障时红灯闪烁。人机交互增加一个旋转编码器或按键用于实时调整挤出量对应DISPENSE_DURATION_MS参数并将设定值保存到 Pico 的 Flash 中。低功耗设计如果使用电池供电可以让 Pico 在大部分时间进入深度睡眠模式仅由超声波传感器或其外部中断唤醒极大延长续航。智能化与联网使用 Pico W将主控换成带有 Wi-Fi 功能的树莓派 Pico W。你可以通过网页服务器配置参数甚至记录每天的洗碗次数和估算洗碗精余量并在快用完时发送提醒到手机。多档位分配通过多个按键或触摸传感器实现“少量洗水果”、“标准洗碗”、“大量洗锅”多档位分配。这个项目从构思到实现最深的体会是嵌入式开发是软件和硬件的紧密舞蹈。任何一个环节的疏漏——一个没焊好的焊点、一个没对齐的丝杆、一个没考虑到的电平问题——都会让整个系统失灵。调试的过程就是不断在“软件逻辑”和“物理现实”之间寻找平衡点的过程。当你看到机器终于能稳定、准确地响应你的手势挤出那一汪洗碗精时那种解决实际问题的满足感是单纯写代码无法比拟的。它不再是一个开发板而是一个你亲手创造的、有实用价值的智能小工具。