1. 项目概述:当复古美学遇见现代物联网
我一直痴迷于老式电子产品那种独特的设计语言和机械质感,同时也享受着现代技术带来的便利与无限可能。我的乐趣,就是把这两者结合起来。最近在旧货市场的一次“淘宝”经历,让我邂逅了一台1970年代生产的“Flirt”晶体管收音机。它那亮橙色的外壳和简洁的拨盘,瞬间把我拉回了那个充满模拟信号的年代。但我不想仅仅把它当作一个静态的摆件,一个念头在我脑海中成型:何不保留它所有的经典外观和物理操控,但赋予它一颗能连接世界的心脏?于是,一个基于树莓派Zero W的互联网收音机改造项目就此诞生。
这个项目的核心目标非常明确:在不破坏原机任何外观和主要物理结构的前提下,将其内部完全现代化。最终,这台老收音机成功“复活”,通过Wi-Fi流畅播放我最爱的Soma FM电台,原始的电源开关、音量旋钮和调谐旋钮全部被重新利用,甚至电池仓门后隐藏的Micro USB充电口,都完美复刻了当年更换9V电池的体验。它现在安静地待在我的浴室里,每天早上用音乐唤醒我。整个改造从萌生想法到完工上架,只用了一周时间,算是我做过最快、也最满意的树莓派项目之一。如果你手头也有类似的老物件,或者对嵌入式硬件、物联网改造感兴趣,希望这篇详细的拆解与实现记录能给你带来启发。
2. 核心改造思路与硬件选型解析
2.1 设计哲学:形式追随功能,但体验至上
在动手之前,我花了大量时间思考“改造”的边界。是彻底颠覆,还是修旧如旧?我选择了后者。我认为,改造的最高境界是让用户察觉不到“改造”的痕迹,所有交互都符合直觉。对于这台Flirt收音机,这意味着:
- 外观零改动:外壳、旋钮、拨盘、电池盖全部保留,不能钻孔、不能切割面板(除了必要的内部固定点)。
- 操控全继承:电源开关必须能物理控制电路通断;两个大旋钮必须保留并赋予新的控制功能(如音量加减)。
- 体验现代化:核心功能从接收AM/FM广播变为播放高品质网络流媒体,并且要解决供电问题,摆脱电源线的束缚。
基于这三点,整个硬件架构就清晰了:我们需要一个足够小巧、低功耗、能运行Linux并连接Wi-Fi的核心板;一个能驱动扬声器、最好还能提供视觉反馈的音频模块;一套将原有机械控件转换为数字信号的方案;以及一个紧凑、安全的可充电供电系统。
2.2 硬件清单与选型理由
以下是本次改造用到的所有核心部件,每一件的选择都有其具体考量:
核心大脑:Raspberry Pi Zero W
- 理由:尺寸是决定性因素(65mm x 30mm),能轻松塞进大多数老式收音机紧凑的内部空间。其ARM处理器性能足以流畅解码MP3/AAC网络音频流。集成的Wi-Fi和蓝牙(本项目未使用蓝牙)是关键,免去了外接USB网卡的麻烦。功耗相对较低,适合电池供电场景。
音频与视觉核心:Pimoroni Speaker pHAT
- 理由:这是一个专为Pi Zero设计的“帽子”(HAT),解决了两个大问题。一是音频输出,它集成了一个MAX98357A I2S类D音频放大器,能直接驱动一个4-8Ω的扬声器,音质远优于Pi Zero自带的PWM模拟音频输出。二是视觉反馈,它板载了一个12段的LED VU表,可以随音乐节奏闪烁。我计划让这个VU表的光透过收音机半透明的调谐刻度盘,重现老式收音机指示灯的效果,这是点睛之笔。
供电系统:Adafruit Micro Lipo充电板 + Pimoroni Lipo Shim + 锂聚合物电池
- 理由:便携设备的灵魂在于供电。我选择了一套组合方案:
- Pimoroni Lipo Shim:这是一个超薄的扩展板,直接插在Pi Zero的GPIO引脚上。它负责两件事:一是将单节锂聚合物电池(3.7V)的电压升压至树莓派所需的5V;二是提供电池电量监控(通过I2C),虽然本项目代码未使用此功能,但为未来扩展留有余地。
- Adafruit Micro Lipo充电板:这是一个独立的充电模块,输入为5V Micro USB,输出连接电池。它的尺寸恰好能放入原收音机的电池仓。
- 联动设计:通过一个特殊的开关(下文详述),实现“关机即充电”的逻辑。当开关拨到“关”,电池与Pi断开,转而接入充电板,此时插入Micro USB线即可充电,无需拔插电池。
- 理由:便携设备的灵魂在于供电。我选择了一套组合方案:
控制转换:杠杆式微动开关 x 2 + 双刀双掷自锁开关 x 1
- 理由:这是实现“操控全继承”的关键。
- 杠杆微动开关:用于替换原来的音量/调谐旋钮。它的触发臂(杠杆)很长,可以用胶水与原旋钮的背面连接。当用户旋转旋钮时,实际上是在按压一个方向的杠杆,实现“点击”式的电子控制。我选择的是两侧均有杠杆的型号,这样每个旋钮可以控制两个方向(如音量加/减)。
- 双刀双掷(DPDT)自锁开关:用于替换原来的电源开关。自锁意味着拨动一次保持状态,符合电源开关的使用习惯。“双刀双掷”提供了两组独立的电路切换能力,这正是实现“关机充电”电路逻辑的基础。
- 理由:这是实现“操控全继承”的关键。
其他材料:跳线、小型扬声器(替换原装低质量喇叭)、Sugru(一种可塑型硅胶胶水)、热熔胶、焊锡等。
注意:开关选型陷阱。市面上开关种类繁多,务必确认参数。微动开关要注意触发力(手感)和引脚类型(直插/贴片)。DPDT开关要注意尺寸是否与原位匹配,以及引脚排列,最好在购买前用卡尺测量旧开关或安装孔位。
3. 硬件改造与集成实战
3.1 拆解与评估:了解你的“病人”
改造的第一步永远是小心翼翼的拆解。这台Flirt收音机结构出奇的简单,仅有一颗螺丝和几个塑料卡扣固定。打开后盖,内部的电路板、老式碳膜电位器、空气可变电容和磁棒天线一览无余。我拍照记录了所有原件的位置和连接方式后,便移除了所有旧电路和那个纸盆已经有些老化的扬声器。只保留了外壳、前面板、三个旋钮(连同背后的转轴)和电源开关的塑料按钮。
关键评估点:
- 内部空间:用游标卡尺精确测量长、宽、高,特别是主板(Pi Zero + pHAT)和电池的预计安装区域。
- 旋钮固定方式:原旋钮是套在金属转轴上的,我需要将转轴从内部的电位器上取下,并评估如何将微动开关固定在转轴或面板内侧。
- 面板透光性:将pHAT的LED VU表对准调谐刻度盘区域,在暗处测试,确认LED光能有效透出,营造氛围。
3.2 核心板“分体”焊接与引线
通常,Speaker pHAT是直接堆叠在Pi Zero上的。但为了将LED部分对准面板,同时方便连接外部的微动开关,我决定采用“分体式”连接。
- 研究引脚定义:打开 pinout.xyz 网站,查看Pi Zero和Speaker pHAT的GPIO引脚图。我需要确认:
- 哪些引脚是pHAT必须的(电源、I2S音频数据、I2C for LEDs)。
- 哪些GPIO引脚是空闲的,可用于连接微动开关。
- 焊接跳线:我剪断了若干根母对母杜邦线,将线的一端直接焊接到Speaker pHAT的对应引脚焊盘上。主要连接包括:5V、GND、I2S的BCLK、LRCLK、DIN,以及I2C的SDA、SCL。这是一个精细活,需要一把好的烙铁和助焊剂。
- 连接Pi Zero:将焊接好的跳线另一头,像插杜邦线一样,插到Pi Zero对应的GPIO引脚上。同时,将Pimoroni Lipo Shim插到Pi Zero的GPIO排母上。
- 焊接电池与充电板:将锂聚合物电池的插头连接到Lipo Shim的电池接口。将Adafruit Micro Lipo充电板的输出端(BAT+, BAT-)与电池的导线并联(注意正负极!),这意味着电池同时连接着Lipo Shim和充电板。充电板的输入端(5V, GND)则留待与DPDT开关连接。
实操心得:跳线质量至关重要。我最初为了省钱用了最便宜的跳线,其线芯极细且脆弱。在后续组装中,仅仅是在工作台上移动,就有好几根线在焊点处断裂,导致不得不返工。强烈建议使用线径较粗、硅胶外皮的高质量杜邦线,它们更柔韧,耐弯折。
3.3 经典控件的现代化改造
这是整个项目中最有趣也最考验手艺的部分。
旋钮改造(音量/调谐):
- 将原旋钮的金属转轴从旧电位器上取下。
- 取两个杠杆微动开关,用钳子或小锯子非常小心地将旋钮背面(通常是塑料)切割下一小块,其形状和大小要能与微动开关的杠杆臂用强力胶(如401胶水)牢固粘合。
- 粘合时务必确保旋钮在自然位置时,不压迫微动开关;当向一个方向旋转时,能稳定地压下对应的杠杆。需要反复测试手感。
- 将改造好的“旋钮-微动开关”组合体,用Sugru固定在收音机前面板的内侧,确保旋钮能从前方的原孔位伸出,且旋转顺滑。
电源开关改造(实现关机充电):
- 找到一款尺寸与原位匹配的DPDT自锁开关。
- 电路逻辑设计:这是本项目的电路设计精华。开关的两“刀”独立工作,每刀有三个触点:中间(COM)、向上(NO/NC)、向下(NC/NO)。
- 第一刀(控制主电源):COM端接Lipo Shim的5V输出(即给Pi供电的电压)。一端(如“开”位)接Pi Zero的5V引脚。另一端(“关”位)悬空。这样,开关拨到“开”,Pi得电;拨到“关”,Pi断电。
- 第二刀(控制充电回路):COM端接锂聚合物电池的正极(注意:这里是电池电压,约3.7-4.2V)。一端(“关”位)接Adafruit充电板的BAT+输入端。另一端(“开”位)悬空。这样,开关拨到“关”,电池接入充电板,此时插入Micro USB线即可充电;拨到“开”,充电回路断开,防止边充边放对电池造成损害。
- 将开关用Sugru牢固地固定在机壳内,确保其拨杆能与原电源按钮联动。
3.4 总装与布局:一场三维拼图游戏
将所有部件塞进那个狭小的空间,需要一些耐心和策略。
- 定位LED VU表:首先用热熔胶将Speaker pHAT(主要是LED部分)固定在机壳内壁,对准调谐刻度盘。热熔胶的好处是可逆,便于调整。
- 固定开关和旋钮组件:使用Sugru将三个微动开关和DPDT开关永久性固定。Sugru固化后像橡胶,能缓冲震动且非常牢固。
- 安装扬声器:我选择了一个比原装喇叭更厚但音质更好的小型扬声器。将其用热熔胶粘在原来喇叭的位置。将其导线焊接到Speaker pHAT的Speaker+和Speaker-焊盘上。注意正负极,接反了声音会变轻。
- 安置Pi Zero和电池:最后将Pi Zero用热熔胶粘在剩余空间。电池则使用一个带背胶的扎带座固定,方便未来更换。
- 理线与测试:仔细整理所有跳线,避免缠绕和挤压。在合盖前,连接电池,打开开关,测试系统能否启动,LED是否亮起,旋钮控制是否有效。
4. 软件配置与Python脚本解析
硬件是身体,软件是灵魂。这个项目的软件目标极其纯粹:上电自动播放指定网络电台,并通过两个物理按钮控制音量。
4.1 操作系统与基础环境
我选择了Raspbian Lite(无桌面环境)以最大化启动速度和节省存储空间。在另一台电脑上使用Raspberry Pi Imager工具将系统烧录至Micro SD卡,并在烧录前预先配置好Wi-Fi和国家设置。
- 系统烧录与启动:使用官方Imager,选择“Raspberry Pi OS (Legacy) Lite”,在设置中填入SSID、密码、地区。首次启动后通过SSH (
ssh pi@raspberrypi.local) 连接。 - 基础配置:更新系统 (
sudo apt update && sudo apt upgrade -y),设置时区,并启用I2S音频驱动,这是Speaker pHAT工作的关键。# 编辑系统配置 sudo raspi-config # 选择 `Interface Options` -> `I2S` -> `Yes` 启用I2S接口。 - 安装音频播放器与依赖:我们使用
vlc来播放网络流,因为它对流媒体支持好且易于用命令行控制。sudo apt install vlc python3-pip -y
4.2 Python控制脚本详解
核心脚本flirt.py的工作流程是:启动VLC播放流媒体 -> 进入循环监听GPIO按钮状态 -> 根据按钮按下调整音量。
#!/usr/bin/env python3 import vlc import RPi.GPIO as GPIO import time import subprocess import os # 设置GPIO模式为BCM编码 GPIO.setmode(GPIO.BCM) # 关闭GPIO警告 GPIO.setwarnings(False) # 定义音量加、减按钮连接的GPIO引脚(根据实际焊接调整) VOL_UP_PIN = 5 # GPIO5 VOL_DOWN_PIN = 7 # GPIO7 # 设置这两个引脚为输入模式,并启用内部上拉电阻(默认高电平,按下接地变低电平) GPIO.setup(VOL_UP_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(VOL_DOWN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) # 初始化VLC实例和播放器 instance = vlc.Instance('--aout=alsa') # 指定音频输出为ALSA,驱动I2S设备 player = instance.media_player_new() # 设置要播放的电台流媒体URL,这里以Soma FM的Secret Agent频道为例 radio_url = "http://ice1.somafm.com/secretagent-128-mp3" media = instance.media_new(radio_url) player.set_media(media) # 开始播放 player.play() # 等待播放器稳定启动 time.sleep(2) # 设置初始音量(0-100) current_volume = 70 player.audio_set_volume(current_volume) print("Internet Radio Started. Volume:", current_volume) def set_volume(level): """设置音量并确保在0-100范围内""" level = max(0, min(100, level)) player.audio_set_volume(level) return level try: # 主循环,持续检测按钮 while True: # 检测音量加按钮是否被按下(低电平触发) if GPIO.input(VOL_UP_PIN) == GPIO.LOW: current_volume = set_volume(current_volume + 5) print("Volume UP:", current_volume) time.sleep(0.3) # 简单防抖,防止一次按下多次触发 # 检测音量减按钮是否被按下 if GPIO.input(VOL_DOWN_PIN) == GPIO.LOW: current_volume = set_volume(current_volume - 5) print("Volume DOWN:", current_volume) time.sleep(0.3) # 短暂休眠,降低CPU占用 time.sleep(0.05) except KeyboardInterrupt: print("\nStopping radio...") player.stop() GPIO.cleanup()脚本关键点解析:
- GPIO防抖:机械开关在闭合/断开时会产生短暂的抖动信号,可能导致程序误判为多次按下。代码中通过
time.sleep(0.3)在检测到按下后暂停一小段时间,这是一个简单的软件防抖方法。对于要求更高的场景,可以结合硬件电容滤波或更复杂的状态机逻辑。 - VLC参数:
--aout=alsa强制VLC使用ALSA音频系统,这对于确保声音从正确的I2S设备(Speaker pHAT)输出至关重要。 - 音量控制:
player.audio_set_volume()控制的是VLC软件的音量,最终通过I2S传递给放大器。Speaker pHAT本身没有硬件音量旋钮,所以这是唯一的控制方式。
4.3 设置开机自启动
为了让收音机像家电一样即开即用,需要让脚本在树莓派启动时自动运行。
- 将脚本复制到合适位置,例如
/home/pi/flirt.py,并赋予执行权限:chmod +x /home/pi/flirt.py - 编辑自动启动文件。对于使用Lite版系统(无桌面)的情况,一个可靠的方法是使用
systemd服务。但为了简单,我们可以使用rc.local(在Raspbian旧版中)或用户级autostart(如果装了桌面)。由于我们用了Lite版,推荐使用systemd或crontab的@reboot。方法:使用Crontab
在文件末尾添加一行:crontab -e
保存退出。这样系统启动后就会自动运行脚本。@reboot /usr/bin/python3 /home/pi/flirt.py &
注意事项:音频设备权限。有时VLC或ALSA可能因为权限问题无法访问音频设备。如果开机后无声,可以尝试在脚本中或在命令行测试时以
sudo权限运行,但这并非最佳实践。更安全的方法是将用户pi加入audio组:sudo usermod -a -G audio pi,然后重启。
5. 调试、优化与常见问题排查
即使按照步骤操作,也可能会遇到各种问题。以下是我在项目中和后续测试中遇到的一些典型情况及解决方法。
5.1 硬件层面问题
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 系统完全无反应,LED不亮 | 1. 电池电量耗尽。 2. DPDT开关接线错误。 3. Lipo Shim未正确插入或损坏。 | 1. 用USB线直接连接充电板给电池充电一段时间。 2. 用万用表检查开关在不同档位下,Pi Zero的5V引脚与GND之间是否有5V电压。 3. 重新插拔Lipo Shim,检查其指示灯状态。 |
| 有系统启动声(如有)但播放无声 | 1. 扬声器接线错误或断开。 2. I2S未启用。 3. VLC音频输出设备设置错误。 4. Speaker pHAT损坏。 | 1. 检查扬声器焊点,用万用表通断档测试。 2. 运行 sudo raspi-config确认I2S已启用。3. 在SSH中运行 speaker-test -t sine -f 440测试ALSA能否通过I2S发声。如果无声,检查/boot/config.txt中dtoverlay设置。4. 尝试用耳机连接Pi Zero的模拟音频口(需在config.txt中切换),测试音频通路是否正常。 |
| 旋钮控制不灵敏或连击 | 1. 微动开关焊接不良或跳线断裂。 2. 软件防抖时间设置不当。 3. 旋钮与开关杠杆粘合不牢,触发位置不准。 | 1. 用万用表检查按钮按下/松开时,GPIO引脚对地电阻是否稳定变化。 2. 调整脚本中的 time.sleep(0.3)防抖延时,适当加长或缩短。3. 重新加固粘合点,确保旋钮旋转能干净利落地触发开关。 |
| LED VU表不闪烁 | 1. I2C未启用或地址冲突。 2. Speaker pHAT的I2C地址与系统不匹配。 | 1. 运行sudo raspi-config启用I2C。2. 安装Pimoroni官方库:`curl https://get.pimoroni.com/speakerphat |
| 电池续航远低于预期 | 1. 电池容量虚标或老化。 2. 系统负载高(如使用了桌面版系统)。 3. Wi-Fi信号弱,导致功耗增加。 | 1. 使用容量测试仪检查电池实际容量。 2. 使用Raspbian Lite系统,并禁用不需要的服务(如蓝牙、hdmi)。 3. 确保收音机放置在Wi-Fi信号良好的位置。 |
5.2 软件与系统层面问题
- 启动速度慢:这是使用完整版Raspbian(带桌面)的常见问题。强烈建议使用Raspbian Lite。此外,可以禁用不必要的服务:
sudo systemctl disable bluetooth hciuart。使用更快的Micro SD卡(Class 10/A1/A2)也有帮助。 - 播放卡顿或中断:通常是网络问题。确保树莓派Wi-Fi连接稳定。可以尝试在脚本中更换为更低码率的电台流(如64kbps),减轻网络和解码压力。使用
ping和speedtest-cli检查网络质量。 - 脚本开机不运行:首先检查crontab条目是否正确,注意使用绝对路径。其次,检查脚本是否有执行权限。最后,查看系统日志获取线索:
journalctl -u cron或查看cron的日志文件。 - 音量控制失效:检查GPIO引脚编号在脚本中和实际焊接是否一致。使用命令
gpio readall可以查看引脚状态。确保在脚本中正确设置了上拉电阻(GPIO.PUD_UP),并且按钮接线是按下接地(低电平触发)。
5.3 项目优化与扩展思路
这个基础版本已经很好用,但总有可以打磨和扩展的地方:
- 多电台支持:可以改造第三个旋钮(原调谐旋钮)作为“频道切换”按钮。在Python脚本中预定义一个电台URL列表,每按一下切换一个。甚至可以在外壳上贴个小标签,标明每个“档位”对应的电台。
- 添加状态指示灯:利用一个空闲的GPIO引脚连接一个LED,用不同的闪烁模式表示“启动中”、“连接中”、“播放中”、“错误”等状态。
- 网络配置简化:如果想把作品送给不熟悉技术的朋友,可以配置树莓派在无法连接预设Wi-Fi时,自动开启一个配置热点(AP模式),让用户用手机连接并配置网络。
- 使用更高效的播放器:对于纯音频流,
mpg123或omxplayer可能比VLC更轻量,启动更快。 - 外壳美化:对老旧的塑料外壳进行抛光、补漆,让外观焕然一新,同时保持复古韵味。
改造完成,合上后盖的那一刻,看着这个半个世纪前诞生的物件,因为一些现代的芯片和代码而重新焕发生机,播放着当下的音乐,这种跨越时间的对话感,正是此类项目最迷人的地方。它不再只是一个功能性的收音机,更是一个承载着技术演进和情感联结的物件。整个过程中,最深的体会是“规划优于蛮干”——在焊接第一根线之前,花时间在纸上画清电路逻辑、在三维空间想象部件布局,能节省大量后期的返工和调试时间。希望这个详细的记录,能帮你唤醒你家中某个尘封的“老伙计”。