
如果你见过中风出院后的患者就会明白“有口难言”这四个字有多重。我最近做完的一个小项目就是用Raspberry Pi PicoRP2040微控制器、一块0.96寸OLED屏和几个大尺寸按键做了一台巴掌大的辅助沟通设备。患者不必逐字打字只要按下一个键设备就会替他说出“我想喝水”“我疼”“谢谢”这类高频短句同时OLED会把对应的文字大字号显示出来让照护者快速确认。项目面向的是失语/构音障碍的康复期患者也适合家属、治疗师和想用嵌入式硬件做点实在事的开发者参考。先说明它是一台低成本DIY康复辅助工具不是医疗设备更不是医院里的计算机辅助言语评估系统但正因为简单它才能真正放到床头。1. 项目思路与方案选型1.1 先搞明白失语患者真正需要什么中风后的沟通障碍往往不是单一类型。有的患者是完全运动性失语听得懂但说不出有的是构音障碍喉咙、舌头肌肉控制不住说话含糊不清还有一部分患者存在认知层面的理解困难需要更大字号、缓慢重复的交互。如果只把着眼点放在“用树莓派播放语音”上那就做偏了。核心不是技术而是患者在“生理急切需求”和“社交表达需求”之间的快速切换。我最初以为要做成带语音识别、能自动生成句子的高级设备后来跟一个康复治疗师聊了一次才发现患者最迫切需要的只有那么几句话喝水、上厕所、疼痛、想翻身、叫人、谢谢。列一个清单找最常用的十个就足够了。为什么因为中风患者体力有限每一次重复表达都是消耗。如果按一个键要等屏幕菜单翻页或者要找半天某个词他宁可憋着。所以整个设备的交互模型应该是一眼看到、一按就播、失手了能重来零学习成本。另外还要考虑肢体活动能力。很多中风患者只有一只手比较灵活甚至只是一根手指。按键必须大间距要宽按击不需要精确瞄准。这直接决定了硬件形态不能用普通键盘的小按键而是用直径在20mm以上的带触觉反馈的圆形大按钮或者用薄膜型按键阵列。1.2 主控选择RP2040而不是完整树莓派这个项目标题里写着“A Raspberry Pi Voice”听起来好像一定得用一台运行Linux的树莓派单板机。但真正选型时我对比了三种方案最后选了基于RP2040的Raspberry Pi Pico。方案启动时间功耗播放音频方式开发难度适合场景Raspberry Pi Zero 2 W十几秒到几十秒开机后经常到几百mAPythonPyGame或aplay很方便低Linux环境熟悉需要语音识别、网络、复杂界面Arduino Uno/Nano毫秒级很低PWM播放WAV内存小扩展烦中音质和处理效率受限极简按键播放器Raspberry Pi PicoRP2040毫秒级低可做到几十mAMicroPython/C SDKPWM或I2S中灵活性高小型交互播报设备我选择Pico的关键理由是“开机快”。一个沟通辅助设备是随时待命的患者半夜想喝水如果设备要等开机那就失去意义。Pico上电到扫描按键只需要几百毫秒这在体验上是质的差别。再加上热词里提到的“raspberry pi 2040 oled 0.96”正好就是这个组合RP2040作为主控0.96寸OLED作为显示反馈完全能承接这个项目。当然如果你后续想做“眼动输入”或“语义预测”这类需要跑模型的扩展还是得换成树莓派Zero 2 W或Pi 4Pico跑不了复杂算法。这也是为什么我在下文会单独讲扩展方向而不是把Pico神话。1.3 系统组成与信息流设计整台设备的架构非常简单是一条单向信息流患者按下某个物理按键RP2040读取GPIO电平Pico确认键值后从存储介质中找到对应的音频文件索引播放语音通过功放和喇叭输出同时把这句话的文字内容显示在OLED 0.96寸屏幕上播放结束后屏幕保持显示这句话若干秒方便照护者确认。整个交互中不需要患者打字不需要菜单跳转。我用的是“一按键对应一句话”的固定映射方式而不是鼠标式光标选择。固定映射的好处在于肌肉记忆患者一旦习惯哪个位置键是“喝水”就算半睡半醒也不会按错。存储方面如果只是十个短句Pico板载的2MB Flash足够放若干段8kHz采样率的低码率WAV。但实际使用中患者可能有方言可能想要多语言或者家属会经常修改语句。所以我在外壳里留了一个TF卡模块的位置把音频文件放在TF卡上这样不烧固件只换文件就能更新。不过为了保持Pico快速启动TF卡读取只发生在开机初始化阶段之后所有索引都存在内存里。2. 硬件搭建与电路接线实操2.1 元件清单与采购避坑实际项目中我用到的核心件如下Raspberry Pi PicoRP2040带排针0.96寸OLEDSSD1306驱动I2C接口128x64分辨率MAX98357A I2S功放模块3W输出3W、4欧或8欧的小喇叭直径尽量小于5cm10个6x6mm轻触开关加20mm大按键帽或者直接买类似“大圆点按钮”的成品面板TP4056锂电池充电模块带保护一节3.7V 1200mAh聚合物锂电TF卡读写模块SPI接口Pico用它读音频索引滑动电源开关、音量电位器、防反接二极管采购时最容易踩的坑有两个。第一OLED模块的I2C地址。市面上的SSD1306绝大多数是0x3C但偶尔有0x3D的。买回来先别焊直接用杜邦线接Pico用I2C扫描程序确认地址否则代码写得再好也白搭。第二MAX98357A模块的增益引脚。很多模块上有一个GAIN引脚悬空时是9dB接高电平时是12dB接地时是15dB。我们这设备距离患者近喇叭不需要特别响悬空或接高电平就行。如果买的模块没有明确标注增益看下PCB背面丝印别一上来就接到最大增益容易破音。喇叭和功放的搭配也要注意MAX98357A是D类功放输出为BTL模式喇叭的L、L-两条线直接接模块的OUT和OUT-千万不能把其中一根接到地线上否则会少一半功率甚至烧芯片。这个接线细节看起来简单却是新手最容易踩的坑。2.2 OLED 0.96寸屏连接与初始化细节OLED选择I2C而不是SPI主要是为了省引脚。SPI屏帧率更高但显示内容只是文字和简单图标I2C足够而且I2C接线只需要SDA、SCL两根信号线后期布线更清爽。接线参考Pico引脚OLED/功放/其他3V3(OUT)OLED VCC、MAX98357A VINGND所有模块GND共地GPIO4OLED SDAGPIO5OLED SCLGPIO0MAX98357A BCLKGPIO1MAX98357A LRCGPIO2MAX98357A DINGPIO6-1510个按键输入内部上拉GPIO16TF卡模块CSGPIO17TF卡模块MOSIGPIO18TF卡模块MISOGPIO19TF卡模块SCKADC0(GPIO26)电池电压采样通过两个10k电阻分压这里建议所有模块共用一个3V3电源轨而不是分别给模块接5V。MAX98357A虽然是功放但它可以在2.7V-5.5V下工作而且它的VIN会用作内部数字音频参考直接从Pico的3V3取电可以减少共地噪声。如果音量上不去不一定是供电问题往往是喇叭阻抗和功放输出不匹配换一个高灵敏度喇叭比升压更有效。软件上SSD1306的初始化可以用现成的MicroPython库。但要注意设置I2C频率400kHz通常没问题但Pico的I2C0 I2C频率如果设到1MHz某些OLED屏的排线较长时会出现花屏。我最后用的是100kHz显示刷新对静态文字完全够。2.3 音频输出方案从PWM到I2S的取舍RP2040本身没有DAC要发声有几条路用PWM模拟输出、用外部DAC芯片、用I2S数字接口连接音频DAC功放模块。我试过PWM直推音频质量一般带点“嗡嗡”底噪如果患者对声音不是很敏感倒也能用但如果是有一点听力的老人长时间听会累。最终我还是用了MAX98357A的I2S方案因为RP2040的PIO可以实现I2S时序Micropython/C SDK都有相关驱动音质明显干净而且芯片内部已经把DAC、功放、滤波全做了外围电路最简单。播放WAV时建议把音频转成8kHz采样率、16位、单声道。语音信号本身频率集中在300Hz-3.4kHz8kHz采样率足够。每分钟语音对应的WAV大小约为16kBytes一个3秒的短语也就48KB十个短句不到500KB放在Pico的Flash里都行。如果你要保持CD音质44.1kHz单声道16bit的话每秒音频要88.2KB对嵌入式存储压力大完全没有必要。在代码层面如果用MicroPython可以这样初始化I2Sfrom machine import Pin, I2S import ustruct audio_out I2S( 0, sckPin(0), wsPin(1), sdPin(2), modeI2S.TX, bits16, formatI2S.MONO, rate8000, ibuf20000, )IRQ接口读取WAV块然后循环写入audio_out。需要注意I2S写操作是阻塞式的播放过程中不能同时执行其他耗时操作否则OLED刷新会卡顿。我在主循环里是先把整句WAV数据读入内存缓存比如限制每句不超过150KB播放期间只处理一个极小的高频任务OLED更新放在播放结束后。这样虽然牺牲了一点实时性但逻辑简单可靠。2.4 按键面板与交互体验设计按键布局决定了这台设备能被谁顺利使用。我第一版用了十个普通轻触开关间距15mm患者手指稍有不稳就会碰到旁边的键。后来改成两列五排每列按键间距增大到30mm键帽直径提到20mm以上再把每个键用热熔胶固定在亚克力面板上。这样手指可以顺着面板滑动按错概率降低很多。为了让照护者也方便我在每个键旁边贴了可更换的滴胶标签上面是文字加简单图标比如水滴代表“喝水”马桶图形代表“上厕所”。患者如果认知能力尚可直接看图标就能判断如果认知受限照护者可以指着图标引导他按键并发声。常用语排序也有讲究。最靠右手大拇指位置的是“喝水”和“疼痛”这两个需求最紧急也最高频。“帮我叫医生”放在第二列顶部键帽涂成红色是应急键。播放时不仅要出声音OLED还要把对应文本顶格放大显示在屏幕中间字号至少要在16px以上不然照护者要凑近屏幕看。3. 软件实现从录音到播报的完整流程3.1 语音素材准备让每一句话都听清语音素材是整个项目体验的关键大多数人一开始把精力全放在代码上结果录出来的声音闷、快、含糊老人听不清。我的做法是分三步第一步用手机录音机或Audacity录制原始语音录音环境保持安静离麦克风15cm左右语速放慢每句话之间停顿两秒。普通话版本的文本校准好了之后再让一个声音清晰的人读一遍。如果可以最好用患者自己的声音录常用短句这是有情感含义的。患者听到自己的声音说出来会比陌生人的录音更有自主感和回应感。当然如果患者发音能力已经受损也可以让家属录音。第二步用Audacity对音频做处理。按到达电平0.8左右结尾静音截到300ms内避免播放时“啪”的一声爆音。转换参数设为8000Hz、16bit、单声道输出为WAV/PCM。第三步文件名统一编号比如001_water.wav对应按键1。TF卡根目录下放一个map.json或map.txt记录按键序号、文件名、显示文本。Pico启动时读这个文件建立索引以后家人只要改文件名字和文本不需要重新烧固件。3.2 MicroPython按键扫描与播放控制的骨架程序用MicroPython实现。核心逻辑不复杂关键是处理好“抖动”和“重复触发”。所有按键按下后我统一做30ms延时去抖然后检查是否有其他键同时按下。如果检测到多个键同时按下优先执行红色应急键对应的句子。下面是一个简化的主循环骨架from machine import Pin, I2C import time import uos import utime from ssd1306 import SSD1306_I2C import audio_player # 自己封装I2S播放模块 KEY_PINS [6, 7, 8, 9, 10, 11, 12, 13, 14, 15] keys [Pin(p, Pin.IN, Pin.PULL_UP) for p in KEY_PINS] # 建立按键序号-文本文件名映射 phrases { 0: (我要喝水, 001.wav), 1: (我有点疼, 002.wav), 2: (帮我翻一下身, 003.wav), # ... } oled SSD1306_I2C(128, 64, I2C(0, sclPin(5), sdaPin(4), freq100_000)) def show_text(text): oled.fill(0) oled.text(text, 0, 4) oled.show() def play_file(index): fname phrases[index][1] audio_player.play(sd/ fname) last_key -1 last_time 0 while True: now utime.ticks_ms() for i, pin in enumerate(keys): if pin.value() 0: if now - last_time 300: break last_time now text, _ phrases[i] show_text(text.encode(utf8)) play_file(i) time.sleep(0.05) while any(pin.value() 0 for pin in keys): utime.sleep_ms(50) break注意MicroPython的SSD1306库中oled.text()默认使用ASCII 8x8字库不能直接显示中文这里只是一个示意。实际项目我给OLED做了中文字库支持把需要用到的中文短语烧成16x16点阵字模存放在单独的font.py里调用时按字模数组绘制。如果你不想折腾字库也可以直接显示拼音或者显示图标式的简单位图。如果你一定要显示中文可以这样把需要显示的短语预渲染成位图比如每个短语对应一个64x48的图片字节数组按键时直接往OLED缓冲区copy。这样效果更可控也省去中文字库的回流烦恼。3.3 OLED界面大字体与状态反馈OLED在白天调背光到中等夜晚自动降低。这里不是装摄像头测环境光而是根据时间判断如果当前PC时钟在21点到6点之间背光亮度设为低档。低亮度显示内容叠加大按键后夜晚不会刺眼。屏幕默认状态可以显示两行内容第一行是上次播报的语句第二行是提示“按任意键开始”。播放时屏幕顶部显示一个很小的喇叭图标用两行像素拼的中间是当前句子的大号文字。这个设计对听者尤其重要房间里有电视声音或者患者说话音量小旁边的人光靠听可能反应不过来屏幕上出现字就能同时多渠道确认。如果长时间无操作比如超过120秒系统自动进入“暗屏待机”OLED清屏Pico进入lightsleep并配置一个定时唤醒或按键唤醒。功耗可以降到1-2mA级别1200mAh电池一周一充没问题。我实测正常模式平均30mA、待机模式2mA一天播报三十次、看屏幕四十次的情况下六天半才充一次电。3.4 电源管理电池电量检测与充电安全音量放大和喇叭是耗电主力待机时功放模块如果不关静态电流也有几mA。我给MAX98357A的VIN串了一个PMOS作为软件开关播放时才打开功放播完立即关闭。这个开关用GPIO3控制同时也在紧急应急时保证安静环境比如患者按了紧急键但照护者在睡觉不会突然爆音响半天而是先亮屏再播放一次。电池电压采样使用了两个10k电阻分压把3.7V锂电池电压分到ADC0可测范围内并用machine.ADC循环读取十六次取平均。充电用TP4056模块充电电流设到500mAPico的3V3轨不直接接电池高位而是通过电源管理小板稳压成3.3V。注意Pico的3V3输出能力有限所以OLED和功放都不挂在Pico的3V3引脚上而是共用模块级稳压后的3V3轨否则总电流超过60mA时Pico内部LDO可能会发热明显。如果电池电压低于3.55VOLED显示充电提示并阻止播放只保留按键唤醒显示。这个逻辑看起来简单但防止了患者用到关机突然失去沟通能力的情况。4. 实际使用中的问题与调试心得4.1 常见问题速查表现象可能原因排查顺序OLED白屏或花屏I2C地址不对、SDA/SCL接反、供电不足、复位时序差先测3V3电压再用扫描代码读I2C地址播放时喇叭有尖锐杂音电源纹波大、I2S数据线与电源线靠太近、WAV文件本身采样率不对降低I2S速率检查电源滤波电容重转音频按键按了没反应GPIO内部上拉未启用、按键引脚与GND短路、40ms去抖不够代码检查Pin.PULL_UP硬件用万用表二极管档测通断只能播放第一个短语TF卡初始化失败、文件名大小写不匹配、文件系统缺失串口打印索引单独写一个TF卡读取测试脚本播放中OLED闪烁主循环被高频中断占用、I2S缓冲区太小、电源瞬时跌落增大I2S缓冲、播放期间OLED刷新放到播放结束后电池使用时间明显短功放未关、OLED一直亮、按键背光控制不合理测量满电放电曲线逐个去掉模块看电流其中“播放中OLED闪烁”是最容易迷惑我的现象。后来发现不是I2S中断抢了OLED的I2C总线而是电源瞬间跌落导致OLED内部电压泵工作不稳定。解决办法是给OLED的VCC和GND之间再加一个100uF钽电容同时把功放供电走独立一小段电源线。4.2 患者测试反馈与细节优化我让一位因脑梗导致运动性失语的七十多岁老人试用了两周三轮迭代里改了不少细节。第一轮的问题完全在于“按键太小”。旧面板是标准轻触开关加键帽间距只有20mm老人食指有轻微震颤经常同时按下两个键。后来我定制了直径25mm的大圆钮间距加到35mm误触率立刻下降了一大截。对于手部控制能力有限的患者键帽表面还需要有一点轻微的磨砂纹避免手指打滑但纹路不能太深否则指甲会卡住。第二轮的问题是“短句不够短”。最开始我放了十几条“请问能不能帮我倒杯水”“我想去卫生间”这类完整句子。听起来礼貌但老人用下来觉得太啰嗦。而且播放时长过长照护者听一半就能猜到剩下全是等待。最后保留的短句都压到四个字以内“要喝水”“疼”“去厕所”“找医生”“谢谢”。如果表达明确两个字反而最好记。第三轮是屏幕反馈的位置问题。刚开始屏幕显示“正在播放”没有显示语句内容结果老人按了“疼”之后旁边的护工没听到就错过了。后来把“当前语句的文字”作为播放期间的核心显示字号用最大号对比度调成白底黑字还是黑底白字也要试。白底黑字在白天更醒目但夜间低亮度时刺眼我最后做成黑白反色模式晚上自动切换成黑底白字。4.3 安全与合规辅助工具不能越界我必须反复强调一件事这个项目是康复辅助沟通工具不是医疗设备。它不能用来检测病情、不能替代医生评估、更不能在中风急性期或气道、吞咽高风险场景下当成应急呼叫设备。做这种项目任何一个“可以”“有可能”的表述都容易误导家属。所以我对外壳标签上明确写“仅用于日常沟通辅助紧急情况请拨打急救电话”。电气方面设备使用锂电池必须加保护板和防反接。充电时最好由家属操作不要让患者独自接充电器。所有按键裸露部分如果直接接触人体电压是3.3V安全低压不会有触电风险但还是要例行清洁。OLED表面和按键面板用75%医用酒精擦拭没有问题但不要让液体进入功放排孔。实际使用中患者可能流涎或误洒水所以我在面板和PCB之间加了一层透明硅胶按键垫既防水又增大按击阻尼。最后整个项目源码和字模生成工具要在社区里放出来这样才能让更多照护者不用从零造轮子。一个辅助设备的尊严恰恰来自它的开源和可复制性。5. 扩展方向从“按一下播一句”到更聪明的陪伴5.1 换成Raspberry Pi Pico W后播报记录可以推送如果想让家人远程了解患者的状态可以把主控换成Raspberry Pi Pico W。Pico W在RP2040基础上增加了Wi-Fi功能几乎不变。核心代码只需要多写一个MQTT客户端每次播放短句后把按键索引、时间戳、当前电池电量发布到本地MQTT broker手机装一个轻量MQTT订阅应用收到消息后通知家里孩子的手机如果连续8小时没有播放记录系统自动发一条“今日活动较少”的提醒但不代表具体状态更不能用于异常报警。这个扩展的意义在于减少照护者的心理负担。白天上班的家人不用反复打电话问“今天怎么样”而是通过非常低频的事件知道“他用过几次设备”。我知道这听起来像一个很冷漠的技术方案但对长期照护来说这已经能提供不少安心了。5.2 为更严重的肢体障碍扩展输入方式有些患者连一个手指都动不了按键方案完全不适用。RP2040本身算力有限但可以外接一个简单的压杆传感器或电容触摸条。在头部或者脚趾能小范围活动的情况下用两个开关做“扫描选择”屏幕上每1.5秒自动高亮一个短语患者用右肩轻抬触发“确认”左肩轻抬触发“切下一行”。这个扫描交互不需要精确操作只需要患者能完成“会在某个瞬间主动发力”即可。如果患者连这个都做不到那就只能上眼动摄像头方案了这会用到树莓派Zero 2 W加摄像头跑一个开源视线估计算法成本会上到千元。但从项目结构上Pico这一层可以保留作为最终播放终端主机和它之间通过串口或者简单TCP协议通信这样眼动检测失败的时候基础按键板还能独立工作。5.3 素材自定义与多语言支持中老年患者普遍对普通话普通话并不都顺耳方言素材需求很高。TF卡方案最大的好处就是更新素材不需要懂技术。只要将WAV文件按编号放进去再编辑一个简单的map.txt屏幕上显示的文字也可以换成方言注音或表情符号。我实际还做了一个小功能同一句话可以有两个变体比如“喝水”第一次按播放“我想喝水”紧接着再按同一键播放“水有点烫帮我晾一下”。这不只是简单的重复播放而是根据“上一次播放时间间隔”决定下一句内容。这个逻辑在代码里只多几行但实际效果是设备显得更像一个“会接话”的伙伴而不是只会复读的机器。语音可以换成病人自己生病前的声音吗如果可以那一定是全家最珍贵的录音。我在素材制作手册里专门加了一条请家属尽量找患者未生病时留下的清晰语音片段或者用之前录制的语音做线性预测编码合成。虽然合成的语气不可能完全自然但能听到自己的声音心理抚慰作用非常明显。写在最后做这种项目最深的体会是硬件本身并不值钱值钱的是“每一次按键背后的信任”。一台树莓派Pico加上OLED屏和功放材料成本不到一百块钱但它能让一个被困在沉默里的人在口渴时不必等到护工巡视才被发现。这比做任何参数跑分都踏实。如果你也想复刻这个设备建议先做一台“六个按键六个短语”的最小版本持续用一周。你会很快发现患者真正频繁使用的其实比你想的还要少而少而精的按键布局才是这个设备能留在床头的关键。我再留一个小经验给所有按键贴标签时不要只写字要在按键边缘贴一条很小的夜光贴纸。半夜不开灯时患者能看到按键位置比OLED屏幕亮起来更直观。关怀往往藏在这些不起眼的细节里而不是藏在复杂的代码里。