Raspberry Pi, Python и распознавание голоса

Raspberry Pi распознавание голоса

Распространённая бытовая проблема — мы забываем, что именно купили из еды и когда она испортится. С помощью Raspberry Pi, Python и распознавания голоса можно собрать систему, которая позволяет добавлять и убирать продукты из списка того, что хранится в холодильнике.

Что нам пригодится

Аппаратные средства:

1 - Raspberry Pi модель B (с Wi-Fi)

1 - USB аудиокарта

1 - Микрофон

Программное обеспечение:

1 - Python 3

1 - Библиотека распознавания речи Python

1 - Библиотека PyAudio Python

Установка библиотек Python и настройка аудио

Перед запуском нашей Python-программы необходимо установить две библиотеки — SpeechRecognition и PyAudio. Для их установки выполните в терминале следующие команды:

$ sudo pip install SpeechRecognition
$ sudo pip install PyAudio

Если при установке PyAudio возникнут проблемы, попробуйте установить библиотеку вручную с помощью такой последовательности команд:

$ sudo apt-get install git
$ sudo git clone http://people.csail.mit.edu/hubert/git/pyaudio.git
$ sudo apt-get install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev
$ sudo apt-get install python-dev
$ cd pyaudio
$ sudo python setup.py install

Когда обе библиотеки установлены, необходимо деактивировать встроенный аудиодрайвер Raspberry Pi, поскольку он может мешать корректной работе PyAudio. Для этого откройте новое окно терминала и выполните следующие команды:

$ cd /etc/modprobe.d
$ sudo nano alsa-blacklist.conf

Nano — это простой текстовый редактор для командной строки. После его запуска введите единственную строку:

blacklist snd_bcm2835

Для выхода из nano и сохранения файла нажмите Ctrl + X. Присвойте файлу имя alsa-blacklist.conf. Этот файл блокирует аудиосистему Broadcom на Raspberry Pi, благодаря чему единственным доступным звуковым устройством останется USB-аудиокарта.

Как работает голосовой контроль списка холодильника

Python-скрипт начинается с импорта модуля распознавания речи, отвечающего за преобразование произнесённых слов в текстовую строку. После импорта модуля создаётся объект «r» — экземпляр распознавателя речи, который записывает звук с микрофона и отправляет его на обработку. Помимо объекта распознавания определяются переменные: список элементов, команда, текущий элемент и массив для хранения разобранных команд.

import speech_recognition as sr

r = sr.Recognizer()
items = dict()
command = ""
item = ""

После начальной настройки запускается основной цикл. Первым делом в цикле программа выводит пользователю приглашение «Speak», а затем формирует аудиообъект «audio», содержащий звуковой поток с микрофона.

while(1):
    with sr.Microphone() as source:
        print("Speak:")
        audio = r.listen(source)

Когда микрофон зафиксировал звук и завершил запись (запись останавливается при падении уровня звука ниже порога), записанный аудиофрагмент передаётся объекту распознавателя. Объект r обращается к сервисам Google для преобразования звука в текст, результат которого сохраняется в переменной speechString. Этот код обёрнут в блок try/except на случай, если аудио не удалось распознать или сервис недоступен. Полученная строка также разбивается на parsedCommands с пробелом в качестве разделителя. Например, при произнесении слов «добавить бекон» результатом будет parsedCommands[0] = «добавить» и parsedCommands[1] = «бекон».

try:
        speechString =r.recognize_google(audio)
        parsedCommands = speechString.split(" ")
    except sr.UnknownValueError:
        print("Could not understand audio")
    except sr.RequestError as e:
        print("Could not request results; {0}".format(e))

if(len(parsedCommands) > 0):
        command = parsedCommands[0]

    if(len(parsedCommands) > 1):
        item = parsedCommands[1]

Получив разобранные команды и элементы, можно добавить их в список товаров. Для обеспечения корректной работы выполняется ряд проверок со следующей логикой:

  • Если элемент уже присутствует в списке и поступает команда добавления — его количество увеличивается

  • Если элемент отсутствует и поступает команда добавления — элемент вносится в список

  • Если элемент присутствует, поступает команда удаления, а его количество больше одного — значение уменьшается на 1

  • Если элемент присутствует, поступает команда удаления, и остался лишь один экземпляр — элемент полностью удаляется из списка

  • Если элемента нет в списке — команда игнорируется

if(command == "add"):
        if item in items:
            items[item] = str(int(items[item]) + 1)
        else:
            items[item] = str(1)

        print(item + " added")

    if(command == "remove"):
        if item in items:
            if(int(items[item]) > 1):
                items[item] = str(int(items[item]) - 1)
            else:
                try:
                    items.pop(item, None)
                except:
                    pass
        print(item + " removed")

Последняя команда в этом простом скрипте — «display», которая выводит содержимое переменной items на экран.

if(command == "display"):
        print(items)

Полный код

import speech_recognition as sr

r = sr.Recognizer()
items = dict()
command = ""
item = ""

while(1):
    with sr.Microphone() as source:
        print("Speak:")
        audio = r.listen(source)
    try:
        speechString =r.recognize_google(audio)
        parsedCommands = speechString.split(" ")
    except sr.UnknownValueError:
        print("Could not understand audio")
    except sr.RequestError as e:
        print("Could not request results; {0}".format(e))

    if(len(parsedCommands) > 0):
        command = parsedCommands[0]

    if(len(parsedCommands) > 1):
        item = parsedCommands[1]

    if(command == "add"):
        if item in items:
            items[item] = str(int(items[item]) + 1)
        else:
            items[item] = str(1)

        print(item + " added")

    if(command == "remove"):
        if item in items:
            if(int(items[item]) > 1):
                items[item] = str(int(items[item]) - 1)
            else:
                try:
                    items.pop(item, None)
                except:
                    pass
        print(item + " removed")

    if(command == "display"):
        print(items)

    command = ""
    item = ""
    days = ""
    parsedCommands.clear()

Само устройство

Данный проект построен на базе Raspberry Pi и не требует дополнительных схем или компонентов, помимо микрофона и дисплея.

В качестве экрана можно использовать обычный монитор или телевизор, однако это не слишком удобно для настенного монтажа. Поэтому в проекте применяется компактный 3,5-дюймовый дисплей для Raspberry Pi с разрешением 480x320. Для обычной работы он маловат, но для командной строки подходит идеально. А если «малина» настроена для удалённого доступа по SSH, запустить Python-программу можно с любого компьютера, имеющего подключение к Интернету.