1. 项目概述打造一个完全离线的树莓派语音天气站在智能家居、信息提示或者一些需要语音交互的嵌入式项目中让设备“开口说话”一直是个挺酷的功能。过去我们往往需要依赖云端API比如Google Cloud TTS或者Amazon Polly这意味着你的项目必须时刻在线还得处理网络延迟、API密钥和潜在的隐私问题。对于想放在地下室的车库门状态播报器或者一个完全离线的户外气象站来说这显然不是最优解。最近一个名为KittenTTS的轻量级文本转语音模型进入了我的视野。它的最大特点就是“小而美”能够在没有GPU的普通CPU上比如树莓派4或5上合成出相当不错的英语语音。这正好解决了嵌入式场景下离线、低功耗语音合成的痛点。于是我决定动手结合手头的Adafruit Voice Bonnet音频扩展板打造一个完全离线的、一键播报天气和时间的桌面小装置。这个项目的核心流程很清晰树莓派运行一个Python脚本定时从美国国家气象局NWS的开放API抓取本地的天气预报数据然后利用KittenTTS将文本格式的天气信息转换成WAV音频文件最后通过Voice Bonnet上的按钮触发将这些音频文件按顺序播放出来。整个过程完全在本地完成无需任何网络连接除了定时获取天气数据时响应迅速且没有额外的服务费用。2. 硬件选型与核心组件解析2.1 计算核心为什么选择树莓派4/5这个项目的计算负载主要集中在语音合成阶段。KittenTTS虽然轻量但依然需要进行神经网络推理。树莓派4和5的ARM Cortex-A72/A76 CPU架构提供了足够的通用计算能力来处理这个任务。树莓派5 (8GB RAM)这是目前性能最强的选择。在我的实测中生成一段10秒的语音树莓派5仅需约2-3秒几乎是“实时”的体验。其更强的CPU和内存带宽使得多任务运行如后台运行其他服务更加从容。如果你追求最快的合成速度和最流畅的整体体验树莓派5是首选。树莓派4 (8GB RAM)完全够用且性价比更高。生成同样一段语音可能需要5-8秒。对于天气播报这种非实时交互的应用几秒钟的等待完全可以接受。树莓派4拥有庞大的用户基础和成熟的生态是稳妥且经济的选择。注意不建议使用树莓派3或更早的型号。虽然KittenTTS可能能运行但合成时间会过长可能超过15秒严重影响用户体验。内存建议4GB起步8GB为佳以确保系统运行流畅并为Python环境、模型缓存留出足够空间。2.2 音频输出Adafruit Voice Bonnet的优势你可能会问树莓派本身有3.5mm音频接口为什么还需要额外的Voice Bonnet这里有几个关键考量音频质量与驱动简化树莓派自带的音频输出模拟容易受到板载电路噪声的干扰音质通常较差。Voice Bonnet集成了专用的音频编解码器芯片提供了更干净、更高质量的音频信号路径。即插即用的输入/输出这块扩展板不仅提供了3.5mm耳机孔和JST接口的扬声器输出还集成了两个麦克风。这意味着未来如果你想扩展项目增加语音唤醒或指令识别功能硬件基础已经具备。硬件按钮与LED板上自带了一个可编程按钮和几个LED。在这个项目中我们正是利用这个按钮来触发播报无需外接任何电路极大简化了物理交互的设计。统一的软件栈Adafruit为其硬件提供了完善的软件驱动seeed-voicecard和Python库支持Blinka在树莓派OS上配置起来相对标准化避免了手动配置ALSA高级Linux声音架构的繁琐过程。扬声器选择3.5mm有源音箱最简单即插即用音量和音质通常较好。适合桌面固定使用。JST接口的无源喇叭如Adafruit的3W喇叭。需要Voice Bonnet直接驱动适合集成到自制外壳的项目中更紧凑。注意要匹配阻抗通常是4Ω或8Ω。2.3 其他必要配件电源务必使用官方或质量可靠的5V/3A树莓派4或5V/5A树莓派5USB-C电源。语音合成是CPU密集型任务瞬时功耗较高劣质电源可能导致树莓派重启或运行不稳定。存储卡建议使用Class 10或以上、容量至少16GB的MicroSD卡。首次运行KittenTTS需要下载约300MB的模型文件足够的空间和读写速度是必要的。外壳与散热树莓派5运行时发热量较大强烈建议配备散热片或小型风扇。一个合适的外壳不仅能保护主板也能让整个项目看起来更完整。3. 系统环境搭建与驱动配置3.1 操作系统准备与基础更新首先你需要一个干净的起点。前往树莓派官网下载最新的Raspberry Pi OS (64-bit) with desktop镜像。使用Raspberry Pi Imager工具刷写到SD卡中。在Imager工具里我强烈建议在刷写前就进行高级设置按CtrlShiftX设置主机名、用户名和密码。配置Wi-Fi和国家代码这样开机就能联网。启用SSH服务方便后续无头无显示器操作。设置区域和时区。系统首次启动并完成基础设置后第一件事就是打开终端更新系统软件包sudo apt update sudo apt full-upgrade -y sudo reboot这个操作会更新所有软件包并安装最新的内核确保硬件兼容性达到最佳状态。3.2 Voice Bonnet驱动安装与音频测试这是确保硬件正常工作的关键一步。步骤虽多但按顺序操作成功率很高。启用I2C接口Voice Bonnet通过I2C总线与树莓派通信。在终端输入sudo raspi-config选择Interface Options-I2C-Yes启用它。完成后退出并重启。安装BlinkaBlinka是Adafruit为了让CircuitPython库能在像树莓派这样的Linux单板计算机上运行而开发的层。安装它非常简单cd ~ sudo pip3 install --upgrade adafruit-python-shell wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py sudo python3 raspi-blinka.py脚本运行后会询问是否重启选择是。安装声卡驱动重启后首先验证系统是否识别到了Voice Bonnet的硬件地址。sudo i2cdetect -y 1你应该能在输出表格中看到地址1a显示为1A或UU。如果看不到请检查Voice Bonnet是否插紧或者返回raspi-config确认I2C已启用。确认硬件被识别后安装专用驱动git clone https://github.com/HinTak/seeed-voicecard cd seeed-voicecard git checkout v6.12 # 使用与指南兼容的稳定版本 sudo ./install.sh sudo rebootinstall.sh脚本会编译并加载内核模块并配置系统音频设置。验证与配置音频输出再次重启后运行aplay -l列出所有音频设备。你应该能看到一个名为seeed-voicecard的声卡记下它的卡号例如card 3。现在进行音频测试。请务必先将Voice Bonnet板上的音频开关拨到“ON”位置并接好扬声器或耳机。# 如果声音没有自动从Voice Bonnet输出需要指定设备 # 假设你的声卡号是3 speaker-test -c2 -D plughw:3,0你应该能听到两个声道交替的“滋滋”白噪声。如果成功恭喜你音频硬件通道已经打通。你可以运行alsamixer来调整音量。按F6键选择seeed-voicecard设备。用方向键调整“Headphone”3.5mm口或“Speaker”JST口的音量建议先调到60-70%以免初始音量过大。3.3 创建Python虚拟环境为了避免Python包之间的版本冲突为这个项目创建一个独立的虚拟环境是很好的实践。cd ~ python3 -m venv kittentts_env source kittentts_env/bin/activate激活后你的命令行提示符前会出现(kittentts_env)字样。后续所有Python包的安装都需要在虚拟环境激活的状态下进行。4. KittenTTS的部署与初步测试4.1 安装KittenTTS模型在激活的虚拟环境中直接使用pip安装KittenTTS的预编译包pip install https://github.com/KittenML/KittenTTS/releases/download/0.1/kittentts-0.1.0-py3-none-any.whl安装过程会下载必要的依赖如numpy,soundfile,torch等。在树莓派4上这可能需要5-10分钟在树莓派5上会快一些。安装torchPyTorch时可能会耗时较长这是正常的因为它需要为ARM架构编译部分组件。4.2 编写你的第一个合成脚本创建一个名为test_tts.py的文件内容如下from kittentts import KittenTTS import soundfile as sf # 初始化模型指定模型版本。nano-0.2是更推荐的新版本。 model KittenTTS(KittenML/kitten-tts-nano-0.2) # 可用的声音列表共8种2种风格(expr-voice-2, expr-voice-3等)每种风格分男(m)女(f) available_voices [ expr-voice-2-m, expr-voice-2-f, expr-voice-3-m, expr-voice-3-f, expr-voice-4-m, expr-voice-4-f, expr-voice-5-m, expr-voice-5-f ] # 生成语音音频数据 text_to_speak Hello from Raspberry Pi. This is an offline text to speech test. # 这里选择第二个女性声音 audio_data model.generate(text_to_speak, voiceexpr-voice-2-f) # 保存为WAV文件。采样率必须是24000这是模型固定的输出格式。 sf.write(hello_pi.wav, audio_data, 24000) print(Audio file hello_pi.wav has been generated.)保存并运行python test_tts.py首次运行会下载KittenTTS模型文件约300MB这需要一些时间。下载完成后它会生成hello_pi.wav文件。4.3 播放与调试使用aplay播放生成的音频。同样如果声音没有从Voice Bonnet输出需要指定设备# 假设声卡号为3 aplay -D plughw:3,0 hello_pi.wav如果一切顺利你将通过扬声器听到清晰、自然的合成语音。你可以尝试修改脚本中的text_to_speak和voice参数感受不同声音的风格差异。实操心得expr-voice-2和expr-voice-3系列听起来更自然一些expr-voice-4和expr-voice-5语速和语调略有不同有点像不同的“播音员”。可以根据你播报内容的风格如严肃的天气播报 vs. 活泼的提醒来选择。5. 构建离线天气播报系统5.1 项目文件结构与配置从Adafruit的指南页面下载项目包Project Bundle。解压后我们主要需要三个文件weather_narrator.toml配置文件。generate_forecast.py获取天气并生成语音文件的脚本。code.py主程序监听按钮并播放音频。首先我们来配置weather_narrator.tomlvoice expr-voice-2-f location_points 39.7456,-97.0892 forecast_length 2 sound_device plughw:3,0voice: 选择你喜欢的声音。location_points: 这是项目的关键。你需要找到你所在地的NWS网格点坐标。访问weather.gov搜索你的城市在预报页面URL中通常能找到类似gridX100gridY80的参数。这里的location_points格式是“纬度,经度”但NWS使用的是网格点。更简单的方法是使用其API端点https://api.weather.gov/points/{纬度},{经度}。它会返回一个JSON其中包含gridId,gridX,gridY。location_points应填写为“{gridX},{gridY}”。例如对于某个位置可能是“100,80”。forecast_length: 决定播报未来几个时段的天气。2通常意味着今天白天和今晚。sound_device: 如果之前测试时需要指定plughw:3,0才能出声这里就填上。如果默认就能从Voice Bonnet出声可以留空或注释掉。5.2 天气数据获取脚本剖析generate_forecast.py脚本做了以下几件事读取配置加载上面的TOML文件。请求天气API向NWS的API发送HTTP请求获取指定网格点的详细预报数据。NWS API是免费且无需密钥的但需要注意用户代理User-Agent标识脚本中通常会设置一个。解析与文本格式化从返回的JSON中提取温度、风速、天气状况如“Mostly Sunny”、详细描述等字段并将其拼接成一段通顺的英文句子。例如“Today, the weather will be mostly sunny, with a high near 72 degrees. Tonight, partly cloudy, with a low around 55.”调用KittenTTS合成语音将格式化好的文本分段根据forecast_length传递给KittenTTS模型生成对应的WAV文件并保存在sound_files/目录下文件名通常包含时间戳。注意事项NWS API的返回格式可能变化且其预报文本有时包含缩写或特殊符号。脚本中的文本格式化逻辑可能需要根据实际情况微调以确保合成出的语音流畅自然。例如将“mph”明确写成“miles per hour”将“Chance of showers”处理得更口语化。5.3 主控程序与硬件交互逻辑code.py是系统的“大脑”它负责初始化加载配置、初始化KittenTTS模型、初始化Voice Bonnet上的按钮GPIO 17上拉输入。按钮监听使用adafruit_debouncer库对按钮信号进行消抖处理避免因机械抖动导致误触发。日期时间合成当按钮被按下时首先获取当前时间并格式化成“October 29th, 2023. The time is: two thirty PM.”这样的句子然后调用KittenTTS生成date.wav文件。这里脚本巧妙地将“02”替换为“oh two”使时间读法更符合习惯。音频播放队列将刚生成的date.wav和sound_files/目录下所有之前生成的天气语音文件按照文件修改时间排序组成一个播放列表。顺序播放使用os.system调用aplay命令依次播放列表中的每一个WAV文件。如果配置了sound_device则会通过-D参数指定到Voice Bonnet输出。部署与运行将三个项目文件放在树莓派家目录下的一个文件夹内例如~/weather_station。确保虚拟环境已激活并安装额外依赖pip install adafruit-circuitpython-debouncer tomllib如果使用Python 3.11以上版本tomllib是内置的。首次运行前先执行一次数据获取python generate_forecast.py。检查sound_files/目录下是否生成了WAV文件。运行主程序python code.py。终端会显示“Press button to hear time and weather...”。按下Voice Bonnet上的按钮等待几秒钟生成日期时间音频随后就会依次播报当前时间、今天的天气和今晚的天气。6. 系统优化与进阶玩法6.1 性能调优与稳定性提升使用systemd服务自启动为了让项目在树莓派开机后自动运行可以创建一个systemd服务。创建文件/etc/systemd/system/weather-narrator.service[Unit] DescriptionWeather Narrator Service Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Userpi WorkingDirectory/home/pi/weather_station EnvironmentPATH/home/pi/kittentts_env/bin ExecStart/home/pi/kittentts_env/bin/python /home/pi/weather_station/code.py Restarton-failure RestartSec10 [Install] WantedBymulti-user.target然后启用并启动它sudo systemctl enable --now weather-narrator.service。这样设备上电后就会自动进入待命状态。定时更新天气通过cron定时任务可以定期如每3小时更新天气语音文件保证信息的时效性。编辑crontabcrontab -e添加一行0 */3 * * * cd /home/pi/weather_station /home/pi/kittentts_env/bin/python /home/pi/weather_station/generate_forecast.py /dev/null 21模型加载优化KittenTTS模型加载需要一定时间。主程序code.py在启动时加载一次模型是合理的。避免在每次按钮按下时都重新加载模型。6.2 功能扩展思路多语言与自定义语音目前KittenTTS仅支持英语。如果你需要其他语言可以探索其他离线TTS方案如Coqui TTS支持多语言但模型更大或者使用Piper另一个高效的离线TTS。对于中文可以研究基于VITS等架构的轻量化中文TTS模型并在树莓派上尝试部署。播报更多信息修改generate_forecast.py不仅可以播报温度和概况还可以加入湿度、降水概率、日出日落时间、空气质量指数需要其他API等。触发方式多样化除了按钮还可以通过红外遥控使用红外接收传感器用电视遥控器来控制播报。语音唤醒利用Voice Bonnet的麦克风集成一个轻量级的唤醒词引擎如Porcupine实现“Hey Pi, whats the weather?”的语音交互。定时自动播报结合cron和code.py的修改在每天早上8点自动播报当日天气。状态反馈利用Voice Bonnet上的LED在合成语音时让LED闪烁播放时常亮给予用户明确的视觉反馈。网络电台播报将生成的音频流通过Icecast等服务器推送变成一个微型网络电台用手机或电脑随时收听。6.3 常见问题排查实录问题运行python generate_forecast.py时报错无法获取天气。排查首先检查网络连接ping api.weather.gov。然后检查location_points格式是否正确。使用浏览器或curl直接访问https://api.weather.gov/points/39.7456,-97.0892替换为你的坐标看是否能返回合法的JSON。NWS API要求设置合理的User-Agent检查脚本中是否有类似{User-Agent: my-weather-app/1.0}的请求头。问题按下按钮没反应程序也没输出错误。排查首先检查code.py是否在运行ps aux | grep code.py。检查Voice Bonnet的按钮是否连接到GPIO 17物理引脚11。可以运行一个简单的GPIO测试脚本确认按钮按下时电平变化正常。检查adafruit_debouncer库是否已正确安装在当前虚拟环境中。问题有声音但音量极小或杂音很大。排查运行alsamixer确保选中了seeed-voicecard设备并且“Headphone”或“Speaker”音量未静音按‘M’键切换且音量滑块已调高。检查扬声器连接是否牢固以及扬声器本身是否需要外部供电有源音箱需插电。问题语音合成速度非常慢树莓派4上超过20秒。排查检查CPU温度是否过高导致降频vcgencmd measure_temp。确保电源供电充足。可以尝试在generate_forecast.py中减少单次合成的文本长度。确认没有其他重型进程在后台运行。问题播放音频时aplay报错“Device or resource busy”。排查这意味着音频设备被另一个进程占用。可能是你开了多个code.py实例或者有其他程序如桌面环境的音频服务在占用声卡。尝试停止其他可能使用音频的程序或重启树莓派。在code.py的播放命令中可以加入2/dev/null来忽略这类次要错误但最好根治占用问题。这个项目从硬件组装、驱动配置、软件部署到功能集成完整地走通了一个嵌入式离线语音应用的全流程。它不仅仅是一个天气播报器更是一个可复用的“离线TTS”模板。你可以轻松地将核心的KittenTTS调用部分剥离出来应用到任何需要语音提示的树莓派项目中无论是智能家居的状态播报、实验室设备的语音告警还是自制玩具的交互声音都能游刃有余。
树莓派离线语音天气站:基于KittenTTS与Adafruit Voice Bonnet的嵌入式实践
发布时间:2026/5/18 17:58:55
1. 项目概述打造一个完全离线的树莓派语音天气站在智能家居、信息提示或者一些需要语音交互的嵌入式项目中让设备“开口说话”一直是个挺酷的功能。过去我们往往需要依赖云端API比如Google Cloud TTS或者Amazon Polly这意味着你的项目必须时刻在线还得处理网络延迟、API密钥和潜在的隐私问题。对于想放在地下室的车库门状态播报器或者一个完全离线的户外气象站来说这显然不是最优解。最近一个名为KittenTTS的轻量级文本转语音模型进入了我的视野。它的最大特点就是“小而美”能够在没有GPU的普通CPU上比如树莓派4或5上合成出相当不错的英语语音。这正好解决了嵌入式场景下离线、低功耗语音合成的痛点。于是我决定动手结合手头的Adafruit Voice Bonnet音频扩展板打造一个完全离线的、一键播报天气和时间的桌面小装置。这个项目的核心流程很清晰树莓派运行一个Python脚本定时从美国国家气象局NWS的开放API抓取本地的天气预报数据然后利用KittenTTS将文本格式的天气信息转换成WAV音频文件最后通过Voice Bonnet上的按钮触发将这些音频文件按顺序播放出来。整个过程完全在本地完成无需任何网络连接除了定时获取天气数据时响应迅速且没有额外的服务费用。2. 硬件选型与核心组件解析2.1 计算核心为什么选择树莓派4/5这个项目的计算负载主要集中在语音合成阶段。KittenTTS虽然轻量但依然需要进行神经网络推理。树莓派4和5的ARM Cortex-A72/A76 CPU架构提供了足够的通用计算能力来处理这个任务。树莓派5 (8GB RAM)这是目前性能最强的选择。在我的实测中生成一段10秒的语音树莓派5仅需约2-3秒几乎是“实时”的体验。其更强的CPU和内存带宽使得多任务运行如后台运行其他服务更加从容。如果你追求最快的合成速度和最流畅的整体体验树莓派5是首选。树莓派4 (8GB RAM)完全够用且性价比更高。生成同样一段语音可能需要5-8秒。对于天气播报这种非实时交互的应用几秒钟的等待完全可以接受。树莓派4拥有庞大的用户基础和成熟的生态是稳妥且经济的选择。注意不建议使用树莓派3或更早的型号。虽然KittenTTS可能能运行但合成时间会过长可能超过15秒严重影响用户体验。内存建议4GB起步8GB为佳以确保系统运行流畅并为Python环境、模型缓存留出足够空间。2.2 音频输出Adafruit Voice Bonnet的优势你可能会问树莓派本身有3.5mm音频接口为什么还需要额外的Voice Bonnet这里有几个关键考量音频质量与驱动简化树莓派自带的音频输出模拟容易受到板载电路噪声的干扰音质通常较差。Voice Bonnet集成了专用的音频编解码器芯片提供了更干净、更高质量的音频信号路径。即插即用的输入/输出这块扩展板不仅提供了3.5mm耳机孔和JST接口的扬声器输出还集成了两个麦克风。这意味着未来如果你想扩展项目增加语音唤醒或指令识别功能硬件基础已经具备。硬件按钮与LED板上自带了一个可编程按钮和几个LED。在这个项目中我们正是利用这个按钮来触发播报无需外接任何电路极大简化了物理交互的设计。统一的软件栈Adafruit为其硬件提供了完善的软件驱动seeed-voicecard和Python库支持Blinka在树莓派OS上配置起来相对标准化避免了手动配置ALSA高级Linux声音架构的繁琐过程。扬声器选择3.5mm有源音箱最简单即插即用音量和音质通常较好。适合桌面固定使用。JST接口的无源喇叭如Adafruit的3W喇叭。需要Voice Bonnet直接驱动适合集成到自制外壳的项目中更紧凑。注意要匹配阻抗通常是4Ω或8Ω。2.3 其他必要配件电源务必使用官方或质量可靠的5V/3A树莓派4或5V/5A树莓派5USB-C电源。语音合成是CPU密集型任务瞬时功耗较高劣质电源可能导致树莓派重启或运行不稳定。存储卡建议使用Class 10或以上、容量至少16GB的MicroSD卡。首次运行KittenTTS需要下载约300MB的模型文件足够的空间和读写速度是必要的。外壳与散热树莓派5运行时发热量较大强烈建议配备散热片或小型风扇。一个合适的外壳不仅能保护主板也能让整个项目看起来更完整。3. 系统环境搭建与驱动配置3.1 操作系统准备与基础更新首先你需要一个干净的起点。前往树莓派官网下载最新的Raspberry Pi OS (64-bit) with desktop镜像。使用Raspberry Pi Imager工具刷写到SD卡中。在Imager工具里我强烈建议在刷写前就进行高级设置按CtrlShiftX设置主机名、用户名和密码。配置Wi-Fi和国家代码这样开机就能联网。启用SSH服务方便后续无头无显示器操作。设置区域和时区。系统首次启动并完成基础设置后第一件事就是打开终端更新系统软件包sudo apt update sudo apt full-upgrade -y sudo reboot这个操作会更新所有软件包并安装最新的内核确保硬件兼容性达到最佳状态。3.2 Voice Bonnet驱动安装与音频测试这是确保硬件正常工作的关键一步。步骤虽多但按顺序操作成功率很高。启用I2C接口Voice Bonnet通过I2C总线与树莓派通信。在终端输入sudo raspi-config选择Interface Options-I2C-Yes启用它。完成后退出并重启。安装BlinkaBlinka是Adafruit为了让CircuitPython库能在像树莓派这样的Linux单板计算机上运行而开发的层。安装它非常简单cd ~ sudo pip3 install --upgrade adafruit-python-shell wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/raspi-blinka.py sudo python3 raspi-blinka.py脚本运行后会询问是否重启选择是。安装声卡驱动重启后首先验证系统是否识别到了Voice Bonnet的硬件地址。sudo i2cdetect -y 1你应该能在输出表格中看到地址1a显示为1A或UU。如果看不到请检查Voice Bonnet是否插紧或者返回raspi-config确认I2C已启用。确认硬件被识别后安装专用驱动git clone https://github.com/HinTak/seeed-voicecard cd seeed-voicecard git checkout v6.12 # 使用与指南兼容的稳定版本 sudo ./install.sh sudo rebootinstall.sh脚本会编译并加载内核模块并配置系统音频设置。验证与配置音频输出再次重启后运行aplay -l列出所有音频设备。你应该能看到一个名为seeed-voicecard的声卡记下它的卡号例如card 3。现在进行音频测试。请务必先将Voice Bonnet板上的音频开关拨到“ON”位置并接好扬声器或耳机。# 如果声音没有自动从Voice Bonnet输出需要指定设备 # 假设你的声卡号是3 speaker-test -c2 -D plughw:3,0你应该能听到两个声道交替的“滋滋”白噪声。如果成功恭喜你音频硬件通道已经打通。你可以运行alsamixer来调整音量。按F6键选择seeed-voicecard设备。用方向键调整“Headphone”3.5mm口或“Speaker”JST口的音量建议先调到60-70%以免初始音量过大。3.3 创建Python虚拟环境为了避免Python包之间的版本冲突为这个项目创建一个独立的虚拟环境是很好的实践。cd ~ python3 -m venv kittentts_env source kittentts_env/bin/activate激活后你的命令行提示符前会出现(kittentts_env)字样。后续所有Python包的安装都需要在虚拟环境激活的状态下进行。4. KittenTTS的部署与初步测试4.1 安装KittenTTS模型在激活的虚拟环境中直接使用pip安装KittenTTS的预编译包pip install https://github.com/KittenML/KittenTTS/releases/download/0.1/kittentts-0.1.0-py3-none-any.whl安装过程会下载必要的依赖如numpy,soundfile,torch等。在树莓派4上这可能需要5-10分钟在树莓派5上会快一些。安装torchPyTorch时可能会耗时较长这是正常的因为它需要为ARM架构编译部分组件。4.2 编写你的第一个合成脚本创建一个名为test_tts.py的文件内容如下from kittentts import KittenTTS import soundfile as sf # 初始化模型指定模型版本。nano-0.2是更推荐的新版本。 model KittenTTS(KittenML/kitten-tts-nano-0.2) # 可用的声音列表共8种2种风格(expr-voice-2, expr-voice-3等)每种风格分男(m)女(f) available_voices [ expr-voice-2-m, expr-voice-2-f, expr-voice-3-m, expr-voice-3-f, expr-voice-4-m, expr-voice-4-f, expr-voice-5-m, expr-voice-5-f ] # 生成语音音频数据 text_to_speak Hello from Raspberry Pi. This is an offline text to speech test. # 这里选择第二个女性声音 audio_data model.generate(text_to_speak, voiceexpr-voice-2-f) # 保存为WAV文件。采样率必须是24000这是模型固定的输出格式。 sf.write(hello_pi.wav, audio_data, 24000) print(Audio file hello_pi.wav has been generated.)保存并运行python test_tts.py首次运行会下载KittenTTS模型文件约300MB这需要一些时间。下载完成后它会生成hello_pi.wav文件。4.3 播放与调试使用aplay播放生成的音频。同样如果声音没有从Voice Bonnet输出需要指定设备# 假设声卡号为3 aplay -D plughw:3,0 hello_pi.wav如果一切顺利你将通过扬声器听到清晰、自然的合成语音。你可以尝试修改脚本中的text_to_speak和voice参数感受不同声音的风格差异。实操心得expr-voice-2和expr-voice-3系列听起来更自然一些expr-voice-4和expr-voice-5语速和语调略有不同有点像不同的“播音员”。可以根据你播报内容的风格如严肃的天气播报 vs. 活泼的提醒来选择。5. 构建离线天气播报系统5.1 项目文件结构与配置从Adafruit的指南页面下载项目包Project Bundle。解压后我们主要需要三个文件weather_narrator.toml配置文件。generate_forecast.py获取天气并生成语音文件的脚本。code.py主程序监听按钮并播放音频。首先我们来配置weather_narrator.tomlvoice expr-voice-2-f location_points 39.7456,-97.0892 forecast_length 2 sound_device plughw:3,0voice: 选择你喜欢的声音。location_points: 这是项目的关键。你需要找到你所在地的NWS网格点坐标。访问weather.gov搜索你的城市在预报页面URL中通常能找到类似gridX100gridY80的参数。这里的location_points格式是“纬度,经度”但NWS使用的是网格点。更简单的方法是使用其API端点https://api.weather.gov/points/{纬度},{经度}。它会返回一个JSON其中包含gridId,gridX,gridY。location_points应填写为“{gridX},{gridY}”。例如对于某个位置可能是“100,80”。forecast_length: 决定播报未来几个时段的天气。2通常意味着今天白天和今晚。sound_device: 如果之前测试时需要指定plughw:3,0才能出声这里就填上。如果默认就能从Voice Bonnet出声可以留空或注释掉。5.2 天气数据获取脚本剖析generate_forecast.py脚本做了以下几件事读取配置加载上面的TOML文件。请求天气API向NWS的API发送HTTP请求获取指定网格点的详细预报数据。NWS API是免费且无需密钥的但需要注意用户代理User-Agent标识脚本中通常会设置一个。解析与文本格式化从返回的JSON中提取温度、风速、天气状况如“Mostly Sunny”、详细描述等字段并将其拼接成一段通顺的英文句子。例如“Today, the weather will be mostly sunny, with a high near 72 degrees. Tonight, partly cloudy, with a low around 55.”调用KittenTTS合成语音将格式化好的文本分段根据forecast_length传递给KittenTTS模型生成对应的WAV文件并保存在sound_files/目录下文件名通常包含时间戳。注意事项NWS API的返回格式可能变化且其预报文本有时包含缩写或特殊符号。脚本中的文本格式化逻辑可能需要根据实际情况微调以确保合成出的语音流畅自然。例如将“mph”明确写成“miles per hour”将“Chance of showers”处理得更口语化。5.3 主控程序与硬件交互逻辑code.py是系统的“大脑”它负责初始化加载配置、初始化KittenTTS模型、初始化Voice Bonnet上的按钮GPIO 17上拉输入。按钮监听使用adafruit_debouncer库对按钮信号进行消抖处理避免因机械抖动导致误触发。日期时间合成当按钮被按下时首先获取当前时间并格式化成“October 29th, 2023. The time is: two thirty PM.”这样的句子然后调用KittenTTS生成date.wav文件。这里脚本巧妙地将“02”替换为“oh two”使时间读法更符合习惯。音频播放队列将刚生成的date.wav和sound_files/目录下所有之前生成的天气语音文件按照文件修改时间排序组成一个播放列表。顺序播放使用os.system调用aplay命令依次播放列表中的每一个WAV文件。如果配置了sound_device则会通过-D参数指定到Voice Bonnet输出。部署与运行将三个项目文件放在树莓派家目录下的一个文件夹内例如~/weather_station。确保虚拟环境已激活并安装额外依赖pip install adafruit-circuitpython-debouncer tomllib如果使用Python 3.11以上版本tomllib是内置的。首次运行前先执行一次数据获取python generate_forecast.py。检查sound_files/目录下是否生成了WAV文件。运行主程序python code.py。终端会显示“Press button to hear time and weather...”。按下Voice Bonnet上的按钮等待几秒钟生成日期时间音频随后就会依次播报当前时间、今天的天气和今晚的天气。6. 系统优化与进阶玩法6.1 性能调优与稳定性提升使用systemd服务自启动为了让项目在树莓派开机后自动运行可以创建一个systemd服务。创建文件/etc/systemd/system/weather-narrator.service[Unit] DescriptionWeather Narrator Service Afternetwork-online.target Wantsnetwork-online.target [Service] Typesimple Userpi WorkingDirectory/home/pi/weather_station EnvironmentPATH/home/pi/kittentts_env/bin ExecStart/home/pi/kittentts_env/bin/python /home/pi/weather_station/code.py Restarton-failure RestartSec10 [Install] WantedBymulti-user.target然后启用并启动它sudo systemctl enable --now weather-narrator.service。这样设备上电后就会自动进入待命状态。定时更新天气通过cron定时任务可以定期如每3小时更新天气语音文件保证信息的时效性。编辑crontabcrontab -e添加一行0 */3 * * * cd /home/pi/weather_station /home/pi/kittentts_env/bin/python /home/pi/weather_station/generate_forecast.py /dev/null 21模型加载优化KittenTTS模型加载需要一定时间。主程序code.py在启动时加载一次模型是合理的。避免在每次按钮按下时都重新加载模型。6.2 功能扩展思路多语言与自定义语音目前KittenTTS仅支持英语。如果你需要其他语言可以探索其他离线TTS方案如Coqui TTS支持多语言但模型更大或者使用Piper另一个高效的离线TTS。对于中文可以研究基于VITS等架构的轻量化中文TTS模型并在树莓派上尝试部署。播报更多信息修改generate_forecast.py不仅可以播报温度和概况还可以加入湿度、降水概率、日出日落时间、空气质量指数需要其他API等。触发方式多样化除了按钮还可以通过红外遥控使用红外接收传感器用电视遥控器来控制播报。语音唤醒利用Voice Bonnet的麦克风集成一个轻量级的唤醒词引擎如Porcupine实现“Hey Pi, whats the weather?”的语音交互。定时自动播报结合cron和code.py的修改在每天早上8点自动播报当日天气。状态反馈利用Voice Bonnet上的LED在合成语音时让LED闪烁播放时常亮给予用户明确的视觉反馈。网络电台播报将生成的音频流通过Icecast等服务器推送变成一个微型网络电台用手机或电脑随时收听。6.3 常见问题排查实录问题运行python generate_forecast.py时报错无法获取天气。排查首先检查网络连接ping api.weather.gov。然后检查location_points格式是否正确。使用浏览器或curl直接访问https://api.weather.gov/points/39.7456,-97.0892替换为你的坐标看是否能返回合法的JSON。NWS API要求设置合理的User-Agent检查脚本中是否有类似{User-Agent: my-weather-app/1.0}的请求头。问题按下按钮没反应程序也没输出错误。排查首先检查code.py是否在运行ps aux | grep code.py。检查Voice Bonnet的按钮是否连接到GPIO 17物理引脚11。可以运行一个简单的GPIO测试脚本确认按钮按下时电平变化正常。检查adafruit_debouncer库是否已正确安装在当前虚拟环境中。问题有声音但音量极小或杂音很大。排查运行alsamixer确保选中了seeed-voicecard设备并且“Headphone”或“Speaker”音量未静音按‘M’键切换且音量滑块已调高。检查扬声器连接是否牢固以及扬声器本身是否需要外部供电有源音箱需插电。问题语音合成速度非常慢树莓派4上超过20秒。排查检查CPU温度是否过高导致降频vcgencmd measure_temp。确保电源供电充足。可以尝试在generate_forecast.py中减少单次合成的文本长度。确认没有其他重型进程在后台运行。问题播放音频时aplay报错“Device or resource busy”。排查这意味着音频设备被另一个进程占用。可能是你开了多个code.py实例或者有其他程序如桌面环境的音频服务在占用声卡。尝试停止其他可能使用音频的程序或重启树莓派。在code.py的播放命令中可以加入2/dev/null来忽略这类次要错误但最好根治占用问题。这个项目从硬件组装、驱动配置、软件部署到功能集成完整地走通了一个嵌入式离线语音应用的全流程。它不仅仅是一个天气播报器更是一个可复用的“离线TTS”模板。你可以轻松地将核心的KittenTTS调用部分剥离出来应用到任何需要语音提示的树莓派项目中无论是智能家居的状态播报、实验室设备的语音告警还是自制玩具的交互声音都能游刃有余。