手把手教你做一个天猫精灵(二)

上一章讲到如何使用fubuki-iot制作一个简单的电脑版的天猫精灵,这次需要把它运行在硬件上。考虑到硬件环境比较复杂,我最终选择了相对简单的树莓派(Ubuntu 22.04 LTS 64bit)。同时,配合麦克风、扬声器等元件可以满足基本的语音输入和输出功能。

硬件准备

  • 树莓派(Raspberry Pi 3/4/zero w均可,但是要能联网)
  • 扬声器、麦克风(最好是免驱动的)
  • 开关、面包板、杜邦线、充电线等

硬件环境搭建

树莓派

我用的是Raspberry Pi Zero 2w,但是发现USB接口不够又添加了扩展版。如图所示:

树莓派

提醒:如果第一次使用需要刷系统。最新的刷系统方式是通过 Raspberry Pi Imager 刷的,可以在官网下载这个软件,然后选择对应的Linux系统,并配置账户、WIFI等信息,最后写到SD卡中。然后将SD卡插入树莓派,连上电源就可以运行了。

启动树莓派后先通过SSH登陆树莓派,然后下载 fubuki-iot包和RPI.GPIO包。如果没有pip需要先安装对应版本的pip。

fubuki-iot安装

fubuki-iot这个包是默认包含pyaudio包的,而pyaudio是需要C++扩展包安装的,所以要安装对应的api:

sudo apt-get update
sudo apt-get install build-essential
复制代码

这个软件包括arm-linux-gnueabihf-gcc这个C++编译器,在Linux环境下开发经常要用到。此外,我们还要下载对应的Python接口和Audio接口以供C++调用:

sudo apt-get install python3-dev
sudo apt install portaudio19-dev python3-pyaudio
复制代码

最后安装fubuki-iot应该可以能正常安装了:

pip install fubuki-iot
复制代码

RPI.GPIO安装

这个包也需要底层依赖的支持,只需要安装Linux的GPIO支持即可:

sudo apt-get install rpi.gpio
pip install RPI.GPIO
复制代码

其实,树莓派的GPIO还支持I2C和SPI协议,它们可以通过极少的引脚数完成元件设备之间的通信。此外,树莓派也支持UART串口通信,这大大加速了元件之间的交流速率。但是这些内容我们目前还接触不到,只需要最原始的GPIO对引脚操作即可。

树莓派引脚图

按钮

在上一章中,我们通过键盘唤醒智能终端的,在树莓派中,我们可以结合其GPIO能力,通过按钮唤醒它。根据上图,我们选择一个GPIO引脚作为输入,如果为高电平则表示唤醒,可以如图所示接入:

接入

接入-事务

通过开关直接和电源和GPIO4相连,这样当开关闭合的时候就可以给树莓派一个高电平触发唤醒功能了。但是这样接会导致开关断开的时候引脚是高阻态,因此最好是按照下面方法接入:

接入2

这样,闭合开关后相当于把电阻短路了,这样是高电平。而断开状态引脚则直接和GND相连,所以是低电平。

提醒:在数字信号领域中有“上拉电阻”和“下拉电阻”的概念,具体可以查找相关资料。

麦克风、扬声器和电源

由于使用的是免驱动的麦克风和扬声器,所以直接通过USB接口和扬声器接口接到树莓派上即可。但是仍有可能遇到依赖缺失的问题,比如ALSA报错,这时候需要安装alsa-utils,具体可点击这里

树莓派的供电是为人诟病的地方,其所有版本的电压不能超过 5V ,而电流则是在条件允许的情况下越大越好。我采用的是原配的充电器,即5V-2000mA。刚开始会有点供电不足的情况但后来有点缓解,而使用移动电源(3.6V-10000mA)则有明显的异味。同时,用原配电源也不宜太长。

连接图

程序开发

上一章我们用fubuki-iot创建了一个语义模型,并实现了提醒事项的功能,这次我们要创建一个录音设备,从而实现通过GPIO唤醒终端。

首先,我们在原有的mods目录下创建一个文件,命名为gpio.py,并在入口文件app.py中加入一行引入这个文件:

from iot import Terminal
Terminal.load_models('mods.timer')
Terminal.load_models('mods.gpio')

if __name__ == '__main__':
    Terminal.run()
复制代码

然后,在gpio.py中创建一个类,让它继承Recorder代表录音机,并实现两个方法。其中awake方法调用GPIO轮询检查GPIO4的电平状态,如果是高电平则返回True代表唤醒。而record函数则仍然使用内置的AudioClient,具体如下调用:

import RPi.GPIO as GPIO
import time as tm

from iot import Recorder, RecorderFactory
from iot.integration.audio import AudioClient
from iot.utils import get_slash
from iot.context import Context


@RecorderFactory.set
class RaspberryRecorder(Recorder):

    def awake(self) -> bool:
        print("按下按钮唤醒终端")
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(7, GPIO.IN)
        while True:
            if GPIO.input(7):
                GPIO.cleanup()
                return True

    def record(self, time: int) -> str:
        data = AudioClient.record(time=time)
        local_time = tm.strftime('%Y-%m-%d_%H-%M-%S', tm.localtime())
        path = f'{Context.config["RESOURCE_PATH"]}{get_slash()}wav{get_slash()}{local_time}.wav'
        AudioClient.save(data=data, path=path)
        return path
复制代码

最后,我们再修改一下配置文件,添加一行如下:

DEVICE_REC=RaspberryRecorder
复制代码

注意:dotenv包在我的Linux环境下有点问题,有时找不到.env文件,但是把它移到项目根目录的外层。即/home/pi/目录下就可以找到了。

最后,我们运行程序。就可以通过按钮实现对终端的唤醒,并使用提醒事项的功能。

同样,树莓派的环境下仍可以使用PocketSphinx的语音唤醒功能,也需要下载相关的依赖,具体点击这里

在这一章中,我们把项目移植到了树莓派中,但是受硬件限制所以需要安装很多依赖,可能每个人遇到的问题都不一样。下一章我们要实现智能终端操作硬件的功能。

猜你喜欢

转载自juejin.im/post/7149693804181159944