如何自制1个超迷你的语音助手?
此篇文章约5000字,看完需10分钟。干货满满,加油读完
先来直接看视频↓
为什么叫Pico呢
Pico是一个数量级单位,也即10^-12(中文叫做皮)。大家都知道我对小巧精致的东西有着执着的追求😉以往的作品中mini、nano之类字眼的已经都使用过了,所以这次找到了Pico来作为名称。
可真是聪明啊!
按照这个(并不)巧妙的命名套路,相信大家已经可以预见我未来作品中的词汇量了😃。其实还有一个更合理的原因,p-i-c-o的发音清脆,音节突出,语音唤醒的成功率会更高,所以拿来做唤醒词实在是坠吼的啦。
“你好,Pico!”
功能设计篇
首先我们得搞清楚一件事情,我到底要做一个什么样的语音助手,实现那些功能呢?
等等不对😂我为什么要做个语音助手啊,市面上不是已经有海量各种智能音箱了嘛?何必重复造轮子呢?
事情是这样的,由于我毫无理由地相信物联网和人工智能结合是未来智能家居的方向,而以目前的状况来看智能音箱很可能成为其中一个重要的入口。被亚马逊Echo带的头,各大厂商纷纷跟进推出了自己的音箱产品:外有GoogleHome 、苹果HomePod,内有天猫精灵、小爱同学…
实际上这些音箱的功能上都大同小异,无非是整合别人或自家生态链产品,作为一个智能设备控制中心,这很好,然后再外带一些娱乐功能。
但是说实话本人并不看好现阶段AI音箱的各种对话功能,聊天?你又不是不知道Siri有多蠢所有的产品都有工具属性,在工具属性之上才能延展出来娱乐属性。而由于目前市场上大多数智能音箱背后的AI程度都还不足以让它们真正地实现“合理对话”,因此个人认为,现阶段能做好一个“工具”,就是我对一个智能音箱该有功能的全部期待了。
关于这一点,个人试用过以上几乎所有音箱,在功能性上做的最好的我认为是依托米家生态链的小爱同学。
那就买买买,小爱同学入手!
但随后残酷的现实给了我狠狠的一jio。原本我已听信发布会宣传准备注册好小米IoT平台开发者账号,想展现真正的技术把小爱同学改造成对我言听计从的私人助理了(当然是指接入我自己的硬件)
结果:
好吧,看来只面向企业的,不过这也可以理解,毕竟米家走的精品路线,个人开发者水平参差不齐不利于品牌维护。造轮子去😤
实际上对于接入自定义硬件,也就是说系统开放性这一项上面,Echo相对来说是做的比较好的,Github上也有很多教你如何接入Alexa平台的教程和开源项目。但是呢,由于某些不可抗力的网络原因,Alexa在国内的使用并不是很顺利。
以上种种原因,加上个人好奇心驱使,便有了这次制造Pico的企划。废话不多说,下面直接贴一张功能设计和拟用技术路线的思维导图(点击图片可放大)↓
以上功能的重心是实现语音的TTS和ASR功能,并且通过识别结果回调接口配合Mqtt协议来接入并控制各种自定义的硬件。其余功能属于锦上添花,会在日后有空的时候慢慢完善。
概括一下,Pico主要有以下特点:
自主设计的电路硬件,可以方便地增减需要的硬件模块,比如添加多麦模块、手势识别模块,删去不必要的蓝牙音箱功能等等
从最底层实现语音功能,所有代码都可以开放成SDK
使用最常用的Mqtt协议实现自定义硬件接入,将语音识别结果用来控制任何东西(后期加入语义理解的话效果更佳)
带一个OLED显示屏
极致小巧,仅仅比口香糖大一点
结构设计篇
Pico的结构设计草图↑
对于Pico的ID设计之前想过好几种方案:
使用铝合金CNC加工,做成类似魔方的正方体外壳样式
使用DLP树脂3D打印,设计成类似天猫精灵的迷你版圆柱体外壳,以光固化打印的精度也能达到不错的质感
使用透明亚克力切割成形,设计为三明治夹层式的堆叠设计,这也是我最终采用的方案
最终选择亚克力作为外壳结构有几个原因:
其一是该方案的“视觉极客感”最强,由于直接使用透明盖板将PCB电路展现出来,个人觉得颜值方面化繁为简,符合个人审美哲学
其次是对于CNC加工和3D打印在之前的作品中都已经有所使用,而亚克力设计方式还是第一次接触,尝试未知技术是很重要的一个考量因素
其三是由于整体体积非常紧凑小巧,因而如果使用封闭式设计的话散热就变成需要考量的因素了,而夹层式的开放设计则在这方面完全无需担心
最后一个原因是,亚克力便宜
如上面草图所示,结构主要为三层:亚克力前盖、PCB电路板、亚克力后盖,使用M2的滚花轴铜柱进行组合连接,其中前板采用热弯折的方式弯折10度左右形成底座,后方走USB线。
机械结构的设计使用Rhinoceros完成,该软件个人使用了3年多的时间,觉得还是非常顺手的。
当初并没有选用公认更专业和更常用的Solidworks和ProE等三维设计软件来学习,纯粹是因为当时用的超极本性能太渣带不动,而看重了Rhino只有几百兆的安装包而已😂。但是毕竟本人也非机械专业,对于EDA工具来说只要能帮助我实现我的想法就满足了,更何况工具只是工具,更重要的是创意和设计思想,而这些是只有多开脑洞多做项目才能有所精进的。
亚克力厚度使用的2mm, 找了个小伙伴操作机床雕刻成型, 然后用电烙铁加热弯折。值得注意的是亚克力的熔点是300度左右,但100度左右的时候就会变软了,因此这里将烙铁温度设定为100度,不带调温功能的烙铁是不能直接拿来操作的。
使用机床雕刻的亚克力外壳
使用电烙铁进行热弯
电路设计篇
硬件电路方面,有之前MiniPi的完整项目在前,这里当然就直接利用起来啦。(下图为MiniPi渲染图,喜欢的可以拿去做壁纸😉 )
MiniPi作为核心板,运行Linux系统,mini-PCIE的金手指封装引出了需要的IO。
这里Pico主要使用到两个USB接口(一个接USB声卡,一个接无线网卡),串口(用于调试和控制台输出),几个GPIO(用于驱动按键和LED),I2C接口(保留,后期可能会用于和板载的Arduino通信,Arduino用于驱动一些外围交互模块如红外感应、手势识别等),此外OLED也是使用I2C接口驱动的。
由于底板的功能比较简单,主要就是作接口扩展,因此底板的PCB采用2层Layout。板载的IC主要有:
OLED12864,驱动IC为SSD1306,这个应该属于很常用了
PCM2912A,TI出的USB接口声卡(很贵,30多一片,价格快赶上用的CPU了),音质还是不错的
CP2102,USB转串口芯片,也很常用,通过USB线把Pico连接电脑之后,就可以直接用串口控制台使用Linux了
LM4871,功放IC,用于音频放大然后扬声器输出
USB-Type C母座,USB接口当然是使用我最爱的Type C啦,话说我把身边的电子产品能再改造的都改成Type C接口了,舒服了😆
PCB的设计当然还是使用Altium Designer,AD忠实粉,软件最近升级了18以后UI炫酷程度爆表,感受一下↓
Altium Designer 18软件设计
底板的设计没有太多可讲的,两层板走线很随意,也没有高速器件,USB那边做好差分走线就行,最好再加上ESD(本版属于功能验证性质就没加了)。声卡方面经过试验耦合电容的选择对声音效果还是有一些影响的,但是音质方面属于玄学,个人就不深究了~
核心板的介绍在我之前文章里有讲解,感兴趣的可以看这篇(如何自制一块“树莓派”--DIY ARM-Linux卡片电脑)
这次的Pico上用的MiniPi核心板做了微调,之前一共做过两版:第一版由于是初次设计高速多层板,虽然功能没问题,但是有不少小缺陷,比如电源电路BUG、没有加板载的关机按键、音频电路没有做数字地和模拟地的隔离等等;第二版则是做了一些IO调整;第三版是比较稳定了,但是考虑到把SD卡设计在核心板上可能会在一些项目中不太方便更换(被夹在核心板和地板中间了),因而在金手指上添加了外置SD卡的接口。
话说我后来才知道原来Altium也是自带VCS(版本控制系统)的,类似于写软件的时候用的Git,Altium也可以很方便地控制每个文件的版本–提交更新、恢复版本、切换分支…这么好的特性看来后面要好好利用上了,这之前我都还在傻夫夫地用着压缩包备份大法。
MiniPi的CPU和DDR部分的电路如下,滤波电容非常多,CPU这样极高频率的器件对电源的纯净度要求很高,要尽量保证每个电源脚都有一个滤波电容↓
CPU部分外围电路
PCB投板回来之后就是蓝翔技能施展阶段了,主要用到的工具有:热风枪、烙铁、镊子、锡浆、吸锡带、助焊剂等。这里科普一下贴片元件的焊接方法:与直插元件不同,贴片的器件由于焊盘太小(我用的0402阻容),器件分布太密集,是基本不可能用烙铁一个一个去焊接的,手工焊接采用的方法主要是回流焊。
所谓回流焊,其实就是利用液体的张力,让融化之后的液态锡把器件拉到焊盘中央完成焊接,不太理解的可以百度搜索一下“回流焊”。进行回流焊的第一步是制作钢网,也就是器件焊盘的掩模,这个在设计好PCB之后把相关的加工文件发给厂家就可以进行激光切割制作了,价格也不贵一般50左右。
PCB钢网掩膜
把空PCB对准钢网掩模之后就可以刮上锡浆了,这样就完成了一次性对所有的焊盘上锡。然后把元件都按设计摆放上到PCB上,这一步不需要讲位置摆的非常准确因为再下一步回流的时候器件会由于液态锡的张力自动归位的。
上好锡膏的PCB板子
上一步贴片完成之后就需要用风枪进行吹焊回流了,相对于一般的器件来说BGA的吹焊难度要大很多因而将其放在最后焊接。吹焊温度大概控制在250-300度,风枪的吹嘴去掉以增大风口便于均匀加热,这一步对焊接经验要求较高,只能多练习尝试掌握技巧了。
风枪吹焊
底板的焊接相对简单,就不多罗嗦了,焊接完毕之后首先用万用表测电源是否短路,没问题的话上电检测电压,没有BUG的话就可以进行功能测试了。
焊接成品
软件实现篇
硬件搞定之后就开始移植软件啦,MiniPi核心板运行的是Debian系的Ubuntu系统,完全兼容树莓派的各种软件,所以可以利用上很多优秀的开源资源。软件的实现上也参考了另外一个基于树莓派的智能音箱项目叫做叮当,主页在这里(叮当dingdang.hahack.com)
整个软件框架借鉴了Jasper项目。
软件主要分为以下几个模块:
ASR模块(AutomaticSpeech Recognition,语音识别),用于获取用户的指令,其中包括语音唤醒功能
TTS模块(Text-To-Speech,语音合成),用于给出语音应答
NLP模块(NaturalLanguage Processing,自然语言处理),用于理解指令的语义,以便采取相应的动作,包括对话功能
MQTT模块,用于实现智能家居联网控制功能
智能音箱正常工作要解决的第一个问题就是如何接收指令,这里主要涉及两个问题:
1. 被动唤醒(Passive Listening),即“什么时候开始听”。这个阶段只监听唤醒词,当听到唤醒词时,进入主动聆听。
2. 主动聆听(Active Listening),即“什么时候结束听”。这个阶段主动聆听用户的任何语音指令,然后对听到的内容进行分析处理。
被动唤醒阶段的基本策略是:以1s的时间窗口通过麦克风进行滑窗采集语音,计算每一帧的波形强度,超过设定的阈值的话就把语音送到ASR模型中判断是否是唤醒词(“你好Pico”),判断为真的话,进入下一个阶段进行主动聆听。
主动聆听的策略与被动唤醒基本相似,以1s的时间窗口通过麦克风进行滑窗采集语音,计算每一帧的波形强度,超过设定的阈值的话,就认为用户已说完了指令。
唤醒关键词的识别使用的是一个开源引擎叫snowboy(另外还有一个库叫PocketSphinx也很好用), 这两个引擎都是离线工作的,不需要连接云端,识别率经测试还是比较高的,当然实际效果跟关键词的选取有关。
snowboy个人使用是免费的
前端的唤醒和指令获取工作完成之后,剩下的功能都由讯飞SDK实现,具体的API介绍和使用说明可以参考官方的Reference文档:(在线语音合成Linux SDK 文档www.xfyun.cn)
当然讯飞作为中文语音技术的扛把子,SDK开放的功能是非常丰富的,只要不是商业使用,很多功能基本也是免费的:
对于智能家居的控制功能,这个就很有意思了,因为我之前用Android平台做过一个机器人项目,也实现了几乎一样的需求,所以智能家居控制的大部分的功能可以直接移植过来使用,包括自制的物联网网关硬件。但是跟上面那个娱乐向的手机器人不一样的是,这次要做的是一个正儿八经的语音助手设备,如果最后只能控制几个LED的话显然无法满足我的无理要求。
所以我做出了一个大胆的决定,让Pico向【小爱同学】伸出魔爪。
家里正好安装了米家全家桶,相比于自己把所有电器改造一遍,显然这样的骚操作更有助于增进家里两个语音助手直接的感情。
所以便有了视频里面开电视那一段的名场景。
结束语
Pico是我去年毕业之前的几个月做的一个小玩意,算是我的个人毕业作品吧,虽然跟我的毕业论文研究方向(一点都)不相关😂。我的毕业论文是研究通信算法的。
不过俗话说得好,买卖不成仁义在 ,科研归科研,毕业不瞎搞快乐哪里找?
当时学生生涯迎来尾声,我feel like急需一个炫酷的作品来安置我积压许久无处安放的创造力😂所以这个作品,就是我品察生活、大开脑洞、倾力实践之后,耗时5个月时间完成的一个解决个人使用智能音箱痛点的语音助手小机器人。可能还不算完美,但是有什么关系呢,这不就又为我下次制造更成熟的项目提供了完美的借口吗?
整篇介绍文章从去年七月开始就拖更至今将近一年,这次终于一鼓作气把材料都整理好了,但愿大家从我的项目经历中总结出了自己学习的方向。
达尔闻入驻分享者 稚晖系列——我是稚晖,常驻“达尔闻说”,不定期为大家分享人工智能前沿知识。
稚晖的往期回顾: