基于树莓派与Google AIY的交互式故事机:硬件改造与语音AI集成实践

发布时间:2026/6/5 18:33:13

基于树莓派与Google AIY的交互式故事机:硬件改造与语音AI集成实践 1. 项目概述当复古收音机遇见AI语音几年前我在一个旧货市场淘到了一台产自上世纪60年代的Telefunken收音机。它有着漂亮的木质外壳和充满机械美感的旋钮但内部的电子管和电路早已老化无法再发出声音。作为一个硬件爱好者我总想着让它“复活”但又不希望只是简单地替换成现代蓝牙模块。我希望它能以一种符合这个时代、同时又保留其物理交互魅力的方式重生。于是一个想法诞生了把它改造成一台能听懂人话、并能根据你的选择讲述不同故事的“交互式故事机”。这个项目的核心是利用Raspberry Pi树莓派单板计算机和Google AIY Voice Kit语音套件为这台老收音机注入“灵魂”。AIY Voice Kit提供了离线的关键词唤醒和基础的语音识别能力而更复杂的对话理解和故事逻辑则交给了云端的Google Dialogflow自然语言处理平台。最终当你打开收音机的开关对着它说“开始讲故事”它便会带你进入一个冷战背景的间谍世界而故事的走向完全由你的语音指令来决定。这不仅仅是一个怀旧改造更是一次完整的语音交互应用实践。它涵盖了从硬件拆解、集成、到本地语音处理、云端意图识别、再到本地语音合成的完整链路。无论你是对智能硬件感兴趣的创客还是想了解如何将NLP自然语言处理技术落地到具体产品中的开发者这个项目都能提供一个非常直观的、端到端的参考案例。接下来我将详细拆解整个改造过程包括硬件选型的考量、软件集成的坑点以及如何设计一个有趣的交互式故事逻辑。2. 硬件选型与核心组件解析2.1 为什么是Raspberry Pi 3B与Google AIY Voice Kit v1在项目启动时我手头有Raspberry Pi 4和3B两种选择。最终选择了3B主要基于几点考量。首先功耗与散热。对于需要长期通电、并集成在密闭木质外壳中的设备3B的功耗和发热量相对更低稳定性更有保障。其次性能足够。这个项目的计算负载主要分为两部分本地运行AIY Voice Kit的驱动和语音活动检测这部分负载较轻另一部分是网络请求即将音频流或文本发送到云端并接收返回结果。3B的CPU和网络性能完全能够胜任无需4代的过剩性能。最后是兼容性。Google AIY Voice Kit v1在设计时主要针对3B/3B进行了优化其排针接口和电源设计与之匹配度更高省去了额外的转接或供电调整的麻烦。Google AIY Voice Kit v1是这个项目的“感官”核心。它本质上是一个围绕Voice HATHardware Attached on Top扩展板构建的套件。这块扩展板集成了关键组件一个专为树莓派优化的音频编解码芯片提供高质量的音频输入麦克风和输出扬声器接口一个用于连接双麦克风阵列的接口这是实现远场语音拾取和一定程度降噪的基础以及一个简单的按钮和LED指示灯接口。选择它的原因很明确它极大地简化了语音交互硬件原型的搭建。你不用自己去挑选麦克风阵列、研究如何与树莓派的I2S音频接口连接、处理模拟音频信号的放大和降噪电路。AIY Voice Kit把这些都做好了并提供了完善的软件驱动和示例让你可以快速验证“唤醒词检测-录音-播放”这个核心流程。注意Google AIY Voice Kit v2版本已经发布其设计更紧凑并使用了USB麦克风阵列。但v1版的Voice HAT扩展板与树莓派GPIO直接连接的方式在集成度和信号质量上仍有其优势尤其适合我们这种需要利用原有设备内部空间和扬声器的改造项目。2.2 旧收音机部件的筛选与利旧改造的精髓在于“新旧融合”。盲目清空所有旧部件是浪费全盘保留又无法实现新功能。我的筛选原则是保留具有物理交互价值和声学价值的部件。扬声器这是首要保留的部件。老收音机的扬声器通常纸盆较大音色温暖带有独特的“复古味”。用万用表测量其阻抗通常是8Ω或4Ω确认线圈没有断路。AIY Voice Kit的Voice HAT板可以直接驱动4-8Ω的扬声器功率也足够在室内清晰播放。保留原装扬声器故事的声音就从这台收音机历史的“喉咙”里发出体验感完全不同。电源/开关旋钮这是交互的灵魂。原机的旋钮开关通常控制着电源和音量我们将其改造为纯粹的电源开关。拆下后用万用表测量其在“开”和“关”状态下的通断情况。我们需要利用这个物理通断信号来控制树莓派的供电或启动/休眠这是实现“物理按钮激活语音交互”的关键一步比在机器上额外粘一个按钮要优雅得多。调谐旋钮与刻度盘这些是纯粹的装饰品但至关重要。它们定义了设备的“复古”外观。我小心地将它们从内部机构上分离只保留外部旋钮和玻璃/塑料刻度盘。后期我们可以将其背后粘上固定柱让其仍然可以“空转”保持操作手感但不产生电信号。木质外壳与内部支撑结构外壳是项目的“脸面”必须完好保留并精心打磨上蜡。内部的金属或塑料支撑框架是安装新主板、固定扬声器的绝佳基础可以省去我们重新设计安装结构的麻烦。通过这样的筛选我们既得到了实现新功能的核心硬件树莓派AIY Kit又最大程度保留了旧设备的物理形态和交互质感实现了真正的“改造”而非“替换”。3. 硬件集成与内部结构改造3.1 安全拆解与空间规划拆解老旧电子设备尤其是这种带有真空电子管和大型电容的老收音机安全是第一位的。即使它已经几十年不通电某些电容也可能残留电荷。我的第一步是戴上绝缘手套使用一把带有绝缘柄的螺丝刀将所有可见的螺丝拧下。对于无法直接取下的部件绝不使用蛮力而是仔细观察是否有隐藏的卡扣或固定销。拆开后的内部通常比想象中空旷因为老式元件体积大但数量少。这为我们提供了宝贵的安装空间。我用卷尺精确测量了内部空间的长度、宽度和高度特别是主板安装区域的净空。然后我用硬纸板制作了一个树莓派和Voice HAT扩展板的1:1模型在机箱内进行“预安装”模拟。这里的关键是规划散热风道和避免信号干扰。树莓派的CPU和电源芯片是主要热源我计划将其安装在靠近机箱背板通常有散热孔的位置并确保其与木质外壳之间有至少5mm的空隙。Voice HAT的音频部分要尽量远离树莓派的高频数字电路和开关电源以减少底噪。3.2 主板安装与旧部件接口适配空间规划好后开始实际安装。我使用铜柱和尼龙螺丝将树莓派固定在原机内部的一个金属横梁上这样既牢固又绝缘。Voice HAT则通过排针直接插在树莓派的GPIO引脚上这是最可靠的连接方式。接下来是旧部件与新主板的连接这是最体现动手能力的部分原装扬声器连接原扬声器通常通过两根导线焊接到旧功放板上。我将这两根线小心地焊接下来并延长。Voice HAT的扬声器输出接口是弹簧夹式端子。我将延长后的扬声器线头剥开拧紧后直接插入端子夹紧。务必注意正负极虽然接反了也能响但会影响音质和相位。通常原焊点上会有标记或者红线为正极。原电源开关改造这是实现“物理灵魂”的关键。原开关是双刀双掷的结构复杂。我们不需要其切换功能只需要一个简单的通断。我用万用表找出开关在“开”位置时导通的那一对触点。然后我断开树莓派5V电源输入线来自外置USB电源适配器的正极5V线将开关串联进去。这样只有当用户旋转收音机旋钮到“开”的位置树莓派才会获得供电启动。这是一种最彻底、最可靠的“关机”方式完全断电零待机功耗。指示灯复用原收音机的调谐指示灯通常是一个小灯泡或氖管位置很好。我移除了旧灯泡在原位置安装了一个3mm的LED颜色自选我用了暖白色。将这个LED通过一个220Ω的限流电阻连接到Voice HAT上预留的LED输出引脚。这样我就可以通过程序控制这个LED例如在监听唤醒词时让它缓慢呼吸在播放故事时让它闪烁赋予其新的状态指示功能。实操心得在焊接和接线时使用热缩管是必须的。每一个焊接点都用合适尺寸的热缩管包裹用热风枪或打火机小心加热收缩。这不仅能防止短路还能让内部走线非常整洁专业。另外所有线缆都用扎带或线卡固定在机箱内部避免其在运输或移动中松脱碰到风扇或尖锐部件。4. 软件环境搭建与AIY套件配置4.1 系统烧录与基础配置硬件组装完毕后接下来是赋予它“智慧”。我选择Raspberry Pi OS Lite无桌面环境作为操作系统因为它更轻量启动更快且完全通过命令行和远程SSH管理更适合作为嵌入式设备运行。烧录系统使用Raspberry Pi Imager工具选择Raspberry Pi OS Lite64位插入MicroSD卡进行烧录。烧录完成后不要急于弹出在电脑上打开SD卡的boot分区创建一个名为ssh的空文件无后缀以启用SSH服务再创建一个名为wpa_supplicant.conf的文件在其中写入你的Wi-Fi配置这样树莓派首次启动就能自动联网。首次启动与更新将SD卡插入树莓派上电启动。通过路由器管理界面或使用arp -a命令查找树莓派的IP地址然后用SSH客户端如PuTTY连接。默认用户名是pi密码是raspberry。登录后第一件事就是更新系统sudo apt update sudo apt upgrade -y。安装AIY Voice Kit驱动这是最关键的一步。Google提供了官方的安装脚本。运行以下命令echo deb https://packages.cloud.google.com/apt aiyprojects-stable main | sudo tee /etc/apt/sources.list.d/aiyprojects.list curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - sudo apt update sudo apt install aiy-voicebonnet-soundcard-dkms sudo apt install aiy-voicebonnet-soundcard-dkms安装过程中会提示配置声音驱动选择VoiceBonnet即可。安装完成后必须重启。4.2 音频系统配置与测试重启后需要确认音频系统已正确切换到Voice HAT。运行aplay -l和arecord -l查看播放和录音设备列表你应该能看到名为VoiceBonnet或aiy-voicebonnet的声卡。接下来进行关键测试播放测试speaker-test -t wav -c 2。你应该能从收音机的原装扬声器中听到“front left, front right”的测试音。如果没有声音检查alsamixer确保VoiceBonnet声卡被选中且所有通道未被静音MM显示为00。录音测试arecord -d 5 -f cd -t wav test.wav录制5秒然后用aplay test.wav播放。确保能清晰录下自己的声音且播放无异常噪音。运行AIY示例AIY套件自带丰富的Python示例。克隆代码库并运行一个简单的语音识别democd ~ git clone https://github.com/google/aiyprojects-raspbian.git cd aiyprojects-raspbian/src python3 checkpoints.py这个脚本会检查所有硬件按钮、LED、麦克风、扬声器是否工作正常。按照提示操作确保每一项都通过。常见问题排查问题运行示例时提示“无法导入aiy模块”。解决AIY的Python库可能需要手动链接或安装。尝试运行cd ~/aiyprojects-raspbian scripts/install-drivers.sh并确保使用python3命令。问题录音有巨大电流声或啸叫。解决首先检查接地。确保树莓派电源是良好的5V/2.5A适配器且Voice HAT安装稳固排针接触良好。其次在alsamixer中适当调低麦克风增益Capture。最后检查扬声器线是否远离电源线和树莓派主板。5. 云端大脑Dialogflow聊天机器人构建5.1 Dialogflow核心概念与项目创建硬件能听会说之后我们需要一个“大脑”来理解话语并决定如何回应。我选择Google Dialogflow ES免费版因为它与Google Cloud服务集成好免费额度对于个人项目完全够用且可视化界面非常友好。在Dialogflow中需要理解几个核心概念代理Agent你的整个聊天机器人应用这里就是我们的“故事讲述者”。意图Intent用户说话的目的。例如“开始故事”、“选择左边的门”、“攻击守卫”都是不同的意图。训练短语Training Phrases用来训练Dialogflow识别某个意图的例子。比如对于“开始故事”意图可以添加“我们开始吧”、“讲故事”、“嘿收音机醒醒”等短语。响应Responses当识别到某个意图后机器人应该回复的文本。在我们的故事里这就是讲述的下一段情节。上下文Contexts用于管理对话的流程。比如在“你面前有两扇门”这个情节下用户说“左边”这个“左边”只有在特定的上下文即选择门的场景中才有效。创建代理后我首先设置了欢迎意图和回退意图。欢迎意图用于用户首次打招呼回退意图则用于处理所有无法理解的语句可以设置为一个友好的提示如“我没听清你能再说一遍吗”。5.2 设计交互式故事决策树我们的故事是一个冷战间谍题材的“选择你自己的冒险”游戏。设计的关键在于将故事线转化为Dialogflow的意图网络。我首先用纸笔画出了整个故事的地图开始 - 你是一名间谍潜入基地。任务获取机密文件。意图start_story你来到一个岔路口左走去通风管道右走去主走廊。意图present_choice_1如果用户说“左边” - 进入通风管道但被卡住需要丢弃装备或原路返回。意图choice_left_1如果用户说“右边” - 遇到守卫可选择贿赂或潜入。意图choice_right_1…后续分支继续展开在Dialogflow中我为每一个故事节点包括分支点和结局都创建一个独立的意图。例如present_choice_1意图的响应是讲述岔路口的情景并同时设置一个输出上下文比如awaiting_door_choice。这个上下文就像一个标签标志着对话进入了“等待选择门”的状态。然后我创建choice_left_1和choice_right_1两个意图。在它们的训练短语中分别添加“左边”、“左转”、“选左边”和“右边”、“右转”、“选右边”。最关键的一步在这两个意图的上下文设置中添加awaiting_door_choice作为输入上下文。这意味着只有当系统处于awaiting_door_choice这个上下文中时用户说“左边”才会触发choice_left_1意图否则可能会被误认为是其他无关的“左边”。choice_left_1意图被触发后其响应是讲述进入通风管道后的情节并可以设置新的上下文如stuck_in_vent从而引出下一个选择。通过这种方式所有意图通过上下文串联起来形成了一个可导航的对话流完美对应了故事的决策树。实操心得在编写训练短语时要尽可能多样化。不要只写“是”、“不是”可以加上“好的我选是”、“那就这样吧”、“我同意”、“否定”。Dialogflow的机器学习模型需要足够的样本来理解同义词和不同表达方式。同时合理使用**实体Entities**可以简化设计。例如可以创建一个direction实体包含“左、右、前、后”等值然后在训练短语中用direction来标注这样所有方向词都能被统一识别和处理。6. 本地与云端的桥梁Python核心逻辑实现6.1 语音识别与合成流程编排现在硬件就绪云端大脑也构建好了我们需要一个运行在树莓派上的“指挥官”程序来协调整个流程。这个程序的核心逻辑是一个无限循环其步骤如下等待唤醒程序启动后首先初始化AIY的语音识别器并设置一个本地唤醒词例如“Hey Storyteller”。程序持续监听麦克风只有检测到唤醒词后才进入下一步。这可以避免误触发并节省电力。提示与录音被唤醒后通过扬声器播放一个简短的提示音如“叮”的一声同时点亮LED表示“我在听”。然后开始录制用户的语音指令直到检测到一段静音表示用户说完了。语音转文本将录制好的音频数据通过Google Cloud Speech-to-Text API转换为文字。这里需要在Google Cloud Platform上启用该API并创建一个服务账户密钥文件JSON格式将其保存在树莓派上。程序代码中会加载这个密钥文件进行身份验证。文本送交Dialogflow将识别出的文本通过Dialogflow的API使用dialogflowPython SDK发送到我们之前创建的代理。SDK会处理认证并将请求发送到正确的意图检测端点。处理响应Dialogflow会返回一个结构化的响应对象。其中最重要的字段是query_result.fulfillment_text这就是我们的故事机应该“说”出来的下一段文本。此外响应里还可能包含自定义的数据字段如故事分支的ID我们可以用来在本地控制一些特效比如让LED闪烁特定颜色。文本转语音将fulfillment_text中的文本通过Google Cloud Text-to-Speech API转换为自然、流畅的语音音频。我们可以选择不同的声音如男声、女声、不同语言甚至调整语速和音调让讲述更有感情。生成的音频文件是MP3格式。播放与循环使用树莓派上的音频播放库如pydub结合ffplay或aplay将MP3文件通过Voice HAT播放出来。播放完毕后程序根据当前对话状态决定下一步如果是故事中的一个选择节点就回到步骤2继续监听如果是故事结局则播放结束语并回到步骤1等待下一次唤醒。6.2 核心代码结构与关键API调用以下是主程序循环的简化代码框架展示了关键步骤import aiy.voicehat from google.cloud import speech, texttospeech, dialogflow import pyaudio import wave import os # 1. 初始化 led aiy.voicehat.get_led() button aiy.voicehat.get_button() # 初始化Google Cloud客户端需提前设置环境变量GOOGLE_APPLICATION_CREDENTIALS speech_client speech.SpeechClient() tts_client texttospeech.TextToSpeechClient() dialogflow_client dialogflow.SessionsClient() def wait_for_wakeword(): # 使用AIY本地检测或Porcupine等库检测“Hey Storyteller” pass def record_audio(): # 配置录音参数开始录音检测静音后停止 pass def stt_process(audio_data): # 调用Speech-to-Text API audio speech.RecognitionAudio(contentaudio_data) config speech.RecognitionConfig( encodingspeech.RecognitionConfig.AudioEncoding.LINEAR16, sample_rate_hertz16000, language_codezh-CN, # 或 en-US ) response speech_client.recognize(configconfig, audioaudio) return response.results[0].alternatives[0].transcript def dialogflow_detect_intent(text, session_id): # 调用Dialogflow API session_path dialogflow_client.session_path(PROJECT_ID, session_id) text_input dialogflow.TextInput(texttext, language_codezh-CN) query_input dialogflow.QueryInput(texttext_input) response dialogflow_client.detect_intent( request{session: session_path, query_input: query_input} ) return response.query_result.fulfillment_text def tts_generate_and_play(text): # 调用Text-to-Speech API synthesis_input texttospeech.SynthesisInput(texttext) voice texttospeech.VoiceSelectionParams( language_codezh-CN, namezh-CN-Standard-A # 选择声音 ) audio_config texttospeech.AudioConfig( audio_encodingtexttospeech.AudioEncoding.MP3 ) response tts_client.synthesize_speech( inputsynthesis_input, voicevoice, audio_configaudio_config ) # 将二进制音频数据写入文件 with open(output.mp3, wb) as out: out.write(response.audio_content) # 使用系统命令播放MP3文件 os.system(ffplay -nodisp -autoexit output.mp3) def main(): while True: wait_for_wakeword() led.set_state(aiy.voicehat.LED.ON) print(Listening...) audio_data record_audio() user_text stt_process(audio_data) print(fYou said: {user_text}) story_response dialogflow_detect_intent(user_text, unique_session_id) print(fStory: {story_response}) tts_generate_and_play(story_response) led.set_state(aiy.voicehat.LED.OFF) if __name__ __main__: main()注意事项Google Cloud API的调用是收费的但有充足的免费额度。Speech-to-Text和Text-to-Speech每月都有一定时长的免费处理量Dialogflow的请求次数免费额度也很高对于个人项目和小规模使用完全足够。务必在Google Cloud Console中监控你的API使用情况并设置预算提醒避免意外产生费用。7. 系统集成、调试与优化心得7.1 联调测试与问题定位当硬件、云端、本地代码都准备好后真正的挑战才开始把它们无缝地整合在一起工作。我的调试是分阶段进行的单元测试首先确保每个模块独立工作。用Python脚本单独测试录音和播放功能是否清晰用curl命令模拟向Dialogflow发送文本看是否能返回正确的响应用一段固定文本测试TTS合成和播放是否流畅。端到端静默测试在代码中先将语音识别STT部分注释掉直接模拟一个固定的用户输入文本如“开始故事”然后运行整个流程看是否能正确调用Dialogflow并播放出第一段故事。这可以排除掉语音识别环节的干扰先验证云端和本地播放的链路。加入语音识别打开STT在安静的环境下进行测试。这里最容易出现的问题是识别错误。比如你说“左边”可能被识别成“右边”。这需要优化录音质量调整麦克风增益并在Dialogflow中增加更多同义训练短语来提高容错。同时观察网络延迟从说完话到听到回应如果超过3秒体验就会变差。上下文与状态管理测试这是交互式故事的核心。需要完整地走一遍故事的所有分支确保在每个选择点Dialogflow的上下文都正确设置和清除。常见bug是上下文残留导致在故事后期说“左边”却触发了前期的意图。这需要仔细检查每个意图的输入和输出上下文设置。7.2 性能优化与体验打磨一个原型能跑起来和一个好用的产品之间隔着许多优化细节降低延迟预加载在程序启动时就初始化好所有Google Cloud API客户端而不是每次调用时再创建这能节省几百毫秒。音频格式优化Speech-to-Text API对音频格式有要求。使用单声道、16kHz采样率的LINEAR16WAV格式既能保证识别率文件又小上传速度快。避免使用高保真、立体声的录音。边录边传对于较长的语音可以考虑使用流式识别Streaming Recognize用户一边说音频就一边上传和处理说完几乎立刻就能得到文本结果。提升鲁棒性网络异常处理必须用try...except包裹所有网络请求STT, Dialogflow, TTS并设计重试逻辑和友好的离线提示如“网络好像有点问题请稍后再试”。音频播放兼容性树莓派上播放MP3可能需要额外的解码库。我最终使用了pydub库它依赖于ffmpeg。确保ffmpeg已安装并且pydub的播放后端设置正确例如使用ffplay。电源管理由于我们使用了物理开关彻底断电不存在待机问题。但可以在软件中监听GPIO按钮如果接了的话实现长按休眠等功能。增强用户体验视觉反馈除了原收音机的指示灯LED我还在Voice HAT自带的RGB LED上做了文章。监听状态时显示蓝色呼吸灯录音时显示红色思考/网络请求时显示黄色旋转播放时显示绿色。多感官反馈让交互更直观。个性化语音在Google TTS API中可以尝试不同的声音WaveNet声音质量更高和调整语速、音高为你的故事讲述者找到一个最合适的“声线”。本地缓存对于固定的、常用的响应如欢迎语、错误提示可以将其TTS音频文件预先合成好并存储在树莓派本地需要时直接播放实现零延迟。完成所有这些步骤后这台诞生于60年代的Telefunken收音机便成功转型为一台承载着AI灵魂的交互式故事讲述者。每一次旋转其厚重的开关唤醒它的不再是电波而是一段由你参与创造的冒险。这个项目从想法到实现贯穿了硬件改造、嵌入式开发、云计算和自然语言处理多个领域是一次极其充实的学习和创造之旅。它证明了即使是最老旧的物件在当代技术的赋能下也能焕发出全新的、充满想象力的生命力。

相关新闻