使用树莓派搭了一个私人FM电台,然后给它写了个Web控制台

一个业余无线电爱好者 & 树莓派折腾记录

起因:为什么要在2026年还在玩FM电台?

入坑业余无线电已经四年了。从最初的宝峰UV5R手台、北峰SC500UV,再到去年的泉盛UVK6、泉盛大金刚,这一路走来,最大的乐趣其实不是"通联到多远",而是自己动手做东西

5f29be410e1ad7a4e93d6d04c75c9e99.jpg

fe6b15d12429be310e8e5169b514d37d.jpg

下面是手搓的信号线

4cf3bce00056ece473363153f104ed15.jpg

前年的冬天,我在GitHub上刷到了 PiFmRds 这个项目——它能用树莓派的GPIO引脚直接发射FM信号,不需要任何额外的发射模块!

作为一个"树莓派吃灰爱好者"(谁家里没几块呢?),我立刻翻出了那块吃灰的Raspberry Pi 2,接上一根20厘米的杜邦线当天线,烧录系统,编译代码,然后——

我的收音机里传来了沙沙的背景噪音中夹杂的音频信号。

那种感觉,和在淘宝买个FM发射器完全不一样。这是你自己的电台,你自己的频率,你自己的信号。你完全掌控它。

但是问题也来了:PiFmRds 是个纯命令行工具。每次换歌要敲命令,调频率要停进程重启,想看看频谱?对不起,没有。我想要的是一边躺在沙发上,一边用手机浏览器切歌、调频、看频谱跳动——这才像个"电台台长"的样子。

于是,pi-fm-rds-go 诞生了。


这玩意儿能干嘛?

简单说:把你的树莓派变成一个可以通过网页控制的FM广播电台。

fa21f6964f02eaa2a97d2d55b5691cdb.jpg

具体来说:

  • FM频段全覆盖:87.5 MHz ~ 108.0 MHz,0.1 MHz步进,想用哪个频率用哪个
  • 网页远程控制:电脑、手机、平板,打开浏览器就能操作,不用SSH登录
  • 播放管理:上传音乐文件(MP3、FLAC、WAV通吃),建播放列表,拖拽排序
  • 实时频谱可视化:看着音乐在频谱上跳动,有一种"我在操控电波"的奇妙仪式感
  • 自动连播:当前曲目播完自动切下一首,不用手动操作
  • 自动转码:上传MP3/FLAC自动转成WAV,重复文件有缓存不浪费算力

一句话总结:这就是你的私人电台导播台。


硬件有多简单?

只需要:

  1. 一块树莓派(2/3/4/5都行,我用的2B)
  2. 一根杜邦线或者一段导线——插在GPIO 4(第7脚)上当天线
  3. 就是这些,没了。

不需要什么"FM发射模块"、"数模转换器"、"功放板"——PiFmRds直接利用了树莓派的时钟发生器(PCM时钟)来产生FM载波信号。这是纯软件实现的FM调制,信号从GPIO 4引脚直接输出。

当然,如果你想要更好的信号质量,可以:

  • 加个带通滤波器(减少谐波)
  • 接一根更专业的天线(比如1/4波长GP天线)
  • 加个小的RF功放(但注意法规限制!)

⚠️ 免责声明:请遵守当地无线电法规。在大多数国家/地区,未经许可的FM广播是受管制的。我通常只在室内用极低功率(不加功放,传播距离几十米)播放音乐,这属于合理使用的范畴。请务必了解并遵守你所在地区的相关法律。


软件长什么样?

我给它做了一个Web控制台,风格偏向复古电台导播台的感觉。来看看主要界面:

频率调谐区

中间一个大旋钮(用CSS画的),可以拖动调频,旁边也有滑块和数字输入框。频率范围87.5~108.0 MHz,精确到0.1 MHz。

频谱可视化

一个Canvas绘制的实时频谱图,64个频段,15帧每秒通过WebSocket推送到浏览器。你会发现不同风格的音乐,频谱形态完全不同——电子乐的低频段是整块跳动的,古典乐则能看到丰富的泛音结构。

文件库 & 播放列表

左侧是文件管理区,可以上传、预览、删除音频文件。右侧是播放列表,支持拖拽排序(用原生Drag & Drop API实现的,没有引入任何第三方JS库)。当前播放的曲目会高亮显示。

播放控制

播放/暂停/停止/上一首/下一首,该有的都有。还有一个自动连播的开关。


技术栈:Go + 原生前端

作为一个"后端程序员"(主业写Go),技术栈选得很克制:

技术选择为什么
后端Go 1.23+, net/http标准库够用,不引入框架依赖
WebSocketgorilla/websocket社区首选,稳定可靠
配置YAML + 环境变量12-Factor App 惯例
前端原生HTML/CSS/JS零依赖,零构建工具,零npm
FM引擎PiFmRds (C)底层调频发射
音频处理ALSA + ffmpeg树莓派标配

前端完全是原生写的——没有React,没有Vue,没有任何构建工具。直接打开HTML文件就能看到完整界面。这是我故意的——对于这种嵌入式场景的工具,引入一整套前端工具链太重了。

Go后端编译出来就是一个静态链接的二进制文件,丢到树莓派上直接跑,内存占用不到30MB。配合systemd服务单元,开机自启、异常重启全搞定。


踩过的坑

坑1:GPIO权限

PiFmRds需要直接操作GPIO硬件寄存器,所以必须root权限运行。但我的Go服务又不想用root跑。最终方案是:通过sudoers配置,允许pi用户免密码执行pi_fm_rds这一个命令,Go服务用sudo pi_fm_rds的方式启动子进程。

坑2:进程管理

pi_fm_rds是个C程序,从stdin读取PCM音频数据。一旦stdin关闭或者进程异常退出,需要自动重启。我写了一个进程管理器,监听进程状态,崩溃后指数退避重试,服务关闭时优雅SIGTERM(超时后SIGKILL)。

坑3:音频格式

PiFmRds只接受WAV格式的PCM数据。用户上传的MP3、FLAC需要先转码。我引入ffmpeg做转码,并对转码结果做MD5缓存——同一首歌第二次播放时直接用缓存,不用重新转码。

坑4:自动连播的时机

怎么知道一首歌播完了?pi_fm_rds的stdin读完会自然退出。我在Go侧轮询进程状态,一旦检测到进程退出且播放列表还有下一首,就自动启动播放下一首。


快速上手

如果你想自己搭一个,大概需要这些步骤:

# 1. 在树莓派上安装依赖
sudo apt install ffmpeg

# 2. 编译 pi_fm_rds(C程序)
git clone https://github.com/ChristopheJacquet/PiFmRds.git
cd PiFmRds/src && make

# 3. 配置sudo免密
echo "pi ALL=(ALL) NOPASSWD: /path/to/pi_fm_rds" | sudo tee /etc/sudoers.d/pi-fm-rds

# 4. 编译Go服务
git clone https://github.com/liigoo/pi-fm-rds-web.git
cd pi-fm-rds-go
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o pi-fm-rds-server ./cmd/server/

# 5. 启动!
./pi-fm-rds-server
# 打开浏览器访问 http://树莓派IP:8080

详细的部署文档和systemd配置在项目的README里,这里就不展开了。


写在最后

这个项目断断续续写了几天,从最开始的"能跑就行"到后来逐渐完善成现在的样子——加了频谱可视化、加了WebSocket实时推送、加了文件管理、加了播放列表、加了自动连播、加了systemd部署配置……

回过头看,这大概就是业余无线电和开源软件最好的结合方式:你不需要是射频专家,不需要昂贵的设备,一块300块的树莓派,加上开源的代码,就能拥有完全属于自己的FM电台。

73! BG6HUD


相关链接


暂无评论