一个业余无线电爱好者 & 树莓派折腾记录
起因:为什么要在2026年还在玩FM电台?
入坑业余无线电已经四年了。从最初的宝峰UV5R手台、北峰SC500UV,再到去年的泉盛UVK6、泉盛大金刚,这一路走来,最大的乐趣其实不是"通联到多远",而是自己动手做东西。


下面是手搓的信号线

前年的冬天,我在GitHub上刷到了 PiFmRds 这个项目——它能用树莓派的GPIO引脚直接发射FM信号,不需要任何额外的发射模块!
作为一个"树莓派吃灰爱好者"(谁家里没几块呢?),我立刻翻出了那块吃灰的Raspberry Pi 2,接上一根20厘米的杜邦线当天线,烧录系统,编译代码,然后——
我的收音机里传来了沙沙的背景噪音中夹杂的音频信号。
那种感觉,和在淘宝买个FM发射器完全不一样。这是你自己的电台,你自己的频率,你自己的信号。你完全掌控它。
但是问题也来了:PiFmRds 是个纯命令行工具。每次换歌要敲命令,调频率要停进程重启,想看看频谱?对不起,没有。我想要的是一边躺在沙发上,一边用手机浏览器切歌、调频、看频谱跳动——这才像个"电台台长"的样子。
于是,pi-fm-rds-go 诞生了。
这玩意儿能干嘛?
简单说:把你的树莓派变成一个可以通过网页控制的FM广播电台。

具体来说:
- FM频段全覆盖:87.5 MHz ~ 108.0 MHz,0.1 MHz步进,想用哪个频率用哪个
- 网页远程控制:电脑、手机、平板,打开浏览器就能操作,不用SSH登录
- 播放管理:上传音乐文件(MP3、FLAC、WAV通吃),建播放列表,拖拽排序
- 实时频谱可视化:看着音乐在频谱上跳动,有一种"我在操控电波"的奇妙仪式感
- 自动连播:当前曲目播完自动切下一首,不用手动操作
- 自动转码:上传MP3/FLAC自动转成WAV,重复文件有缓存不浪费算力
一句话总结:这就是你的私人电台导播台。
硬件有多简单?
只需要:
- 一块树莓派(2/3/4/5都行,我用的2B)
- 一根杜邦线或者一段导线——插在GPIO 4(第7脚)上当天线
- 就是这些,没了。
不需要什么"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 | 标准库够用,不引入框架依赖 |
| WebSocket | gorilla/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
相关链接
- 项目地址:github.com/liigoo/pi-fm-rds-web
- 底层FM引擎:PiFmRds
暂无评论