Юбилейный, сотый, проект от "Карандаша и Самоделкина" просто обязан быть чем-то особенным! В прошлых сериях мы успели поработать в области машинного зрения, и наш робот на базе LEGO Mindstorms EV3 смог различать простейшие образы и даже сыграть с нами в "Камень, ножницы, бумага". На этот раз мы решили освоить работу со звуком и решить одну из задач, связанных с "машинным слухом".
Сделать робота, управляемого голосом, не так уж и сложно - достаточно воспользоваться готовым API от того же Google. В этом случае распознаваемый фрагмент отсылается онлайн-сервису, который в ответ сообщает распознанную текстовую строку. Если роботу нужна подобная автономная функциональность, существуют и готовые оффлайновые решения, вроде PocketSphinx, правда работают они в условиях ограниченных ресурсов на роботе крайне задумчиво. Главной же фишкой нашего проекта станет то, что мы не будем использовать никакие вспомогательные инструменты для распознавания речи, а напишем свой собственный "движок" для голосового управления, пусть и простенький.
Перво-наперво нам понадобится устройство, способное дать возможность роботу физически ощущать звуковую волну для возможности преобразования ее в цифровую форму. В комплекте с наборами LEGO NXT первой версии поставлялся датчик звука (NXT Sound Sensor). C его помощью можно измерять звуковое давление в условных единицах. Такого датчика у нас нет, поэтому мы решили использовать USB-микрофон, подключенный в соответствующий порт блока EV3. Что касается датчика звука NXT, то по информации от его владельцев, скорость опроса этого датчика невелика, поэтому на него рассчитывать все равно не стоит.
В качестве USB-микрофона может выступать почти любая USB-звуковая плата, с подключенным к ней аналоговым микрофоном или USB-веб-камера, как правило имеющая встроенный микрофон. EV3-блок тоже имеет в своем составе звуковую плату, к выходу которой подключен встроенный динамик, а вот встроенного микрофона, увы, нет..Максимальная частота дискретизации этого устройства - 22кГц, поэтому качественно воспроизводить звук EV3-блок не может физически.
При подключении дополнительного USB звукового устройства появляется возможность работать с ними одновременно, например получая данные с микрофона внешней звуковой платы и воспроизводя звук по прежнему встроенным динамиком. Возможна и конфигурация, при которой звук будет воспроизводиться внешней USB звуковой платой, при этом появляется возможность подключить к роботу качественную или "громкую" акустику.
В проекте мы снова используем операционную систему ev3dev и будем программировать робота на языке Python. Для работы с звуковыми устройствами существует целый ряд python-модулей, мы остановили свой выбор на pyalsaaudio, обладающим высоким быстродействием в условиях ограниченных ресурсов. Для ускорения обработки данных и воспользуемся модулем NumPy. Хотя можно хранить данные и в традиционных для Python структурах, вроде списков, однако работа с звуковыми потоками, имеющими зачастую немалый объем, при таком подходе происходит крайне неторопливо.
Общий алгоритм работы нашего робота таков:
1) Стартуем процесс записи и анализируем приходящие со звуковой платы данные небольшими порциями, оценивая громкость. Как только она превысит заданный порог - начинаем запись заданной (избыточной для фразы) длительности, например 2 секунлы
2) Анализируем полученный звуковой отрезок (сэмпл) на предмет выделения на нем слова (фразы).
Так как мы начинали запись активацией по пороговому значению, слово всегда будет в начале сэмпла, а вот конец нужно обрезать:
3) Воспроизводим сэмпл для мониторинга корректности его записи и выделения слова.
4) Разбиваем звуковой фрагмент на небольшие интервалы, длительностью около 20 мс. Лучший результат получается если разбивать на интервалы, перекрывающиеся н 50%, в этом случае скорость произношения фразы не будет заметно влиять на результат распознавания.
5) Анализируем каждый отрезок, выделяя в нем частоты с максимальной "громкостью". Частотный анализ фрагмента можно выполнить используя встроенную в NumPy функция быстрого преобразования Фурье.
На рисунке выделено 8 таких частот.
6) Получаем двумерную матрицу, содержащую несколько наиболее выраженным частот в каждом отрезке:
Сделать робота, управляемого голосом, не так уж и сложно - достаточно воспользоваться готовым API от того же Google. В этом случае распознаваемый фрагмент отсылается онлайн-сервису, который в ответ сообщает распознанную текстовую строку. Если роботу нужна подобная автономная функциональность, существуют и готовые оффлайновые решения, вроде PocketSphinx, правда работают они в условиях ограниченных ресурсов на роботе крайне задумчиво. Главной же фишкой нашего проекта станет то, что мы не будем использовать никакие вспомогательные инструменты для распознавания речи, а напишем свой собственный "движок" для голосового управления, пусть и простенький.
В качестве USB-микрофона может выступать почти любая USB-звуковая плата, с подключенным к ней аналоговым микрофоном или USB-веб-камера, как правило имеющая встроенный микрофон. EV3-блок тоже имеет в своем составе звуковую плату, к выходу которой подключен встроенный динамик, а вот встроенного микрофона, увы, нет..Максимальная частота дискретизации этого устройства - 22кГц, поэтому качественно воспроизводить звук EV3-блок не может физически.
При подключении дополнительного USB звукового устройства появляется возможность работать с ними одновременно, например получая данные с микрофона внешней звуковой платы и воспроизводя звук по прежнему встроенным динамиком. Возможна и конфигурация, при которой звук будет воспроизводиться внешней USB звуковой платой, при этом появляется возможность подключить к роботу качественную или "громкую" акустику.
В проекте мы снова используем операционную систему ev3dev и будем программировать робота на языке Python. Для работы с звуковыми устройствами существует целый ряд python-модулей, мы остановили свой выбор на pyalsaaudio, обладающим высоким быстродействием в условиях ограниченных ресурсов. Для ускорения обработки данных и воспользуемся модулем NumPy. Хотя можно хранить данные и в традиционных для Python структурах, вроде списков, однако работа с звуковыми потоками, имеющими зачастую немалый объем, при таком подходе происходит крайне неторопливо.
Общий алгоритм работы нашего робота таков:
1) Стартуем процесс записи и анализируем приходящие со звуковой платы данные небольшими порциями, оценивая громкость. Как только она превысит заданный порог - начинаем запись заданной (избыточной для фразы) длительности, например 2 секунлы
2) Анализируем полученный звуковой отрезок (сэмпл) на предмет выделения на нем слова (фразы).
Так как мы начинали запись активацией по пороговому значению, слово всегда будет в начале сэмпла, а вот конец нужно обрезать:
3) Воспроизводим сэмпл для мониторинга корректности его записи и выделения слова.
4) Разбиваем звуковой фрагмент на небольшие интервалы, длительностью около 20 мс. Лучший результат получается если разбивать на интервалы, перекрывающиеся н 50%, в этом случае скорость произношения фразы не будет заметно влиять на результат распознавания.
На рисунке выделено 8 таких частот.
6) Получаем двумерную матрицу, содержащую несколько наиболее выраженным частот в каждом отрезке:
7) Сохраняем матрицу в виде именованного образца. Для каждого слова (голосовой команды) нужно записать несколько таких образков, с разной интонацией, можно разными голосами, если это необходимо.
8) Чтобы распознать слово-команду необходимо выполнить наги 1-5 и сравнить полученную матрицу с сохраненными образцами. Здесь есть несколько вариантов:
- Найти самый похожий образец
- Найти группу образцов, к которой анализируемый ближе всего
- Скомбинировать поиск по близости к образцу и по близости к группе образцов. Если, например, анализируемый образец ближе всего к группе с образцами "Влево" и, одновременно, ближе в образцу "Вправо", у робота появляется возможность ответить "Не понял команды, повторите!".
- Использовать нейронную сеть, обученную на записанных образцах.