Посты

Распознавание речи на RPI2 с помощью Google Speech API

1. Introduction

Не так давно мне пришла идея сделать некоторое приспособление, способное управляться голосовыми командами и выполнять определенные действия. Для реализации этой затеи я приобрел микрокомпьютер Raspberry PI 2 и внешнюю аудиокарту, а также использовал микрофон от наушников.

2. Сет-ап или сколько я мучился с дровами

После некоторых неудачных попыток реализовать распознавалку на C#, языком программирования был выбран Python, т. к. с ним довольно удобно работать на RPI, а также на нем уже были примеры готовых библиотек для распознавания голоса, что позволило посмотреть алгоритмы различных авторов и оптимизировать систему.

С приобретением всех необходимых компонентов я ринулся писать код, но столкнулся с множеством проблем, большинство из них было связано с доступом к микрофону, а также библиотекой для python pyAudio.

Я считаю, что решение возникающих проблем может быть отдельной статьей. В конечном счете я пришел к использовании библиотеки system совместно с утилитой ALSA (arecord, aplay).

3. Конвертация идеи в код.

Подключение всех необходимых библиотек

# -*- coding: utf-8 -*-
from urllib2 import Request, urlopen
from os import system
import json
import uuid
#import pyaudio
import wave
import xml.etree.ElementTree as etree
import RPi.GPIO as gpio

Сразу хочу добавить, что в речь в данной статье не идет об потоковом распозновании.

Необходимые функции для записи и конвертации записанного файла в различные форматы:

def convert_to_flac():
print("Converting...")
system("flac -w -f output.wav output.flac")
def convert_to_speex():
print("Converting to speex")
system("speexenc -w output.wav output")
def convert_to_raw():
print("Converting to raw")
system("sox output.wav output.raw")
def arecord():
print("Recording...")
system("arecord -r16000 -d3 output.wav")

А вот и сам запрос на сервера Google.

def speech_to_text_google():
key = "” #Ключ для API.
url = "http://www.google.com/speech-api/v2/recognize?output=json&lang=ru-ru&key="+key
file_upload = "output.flac"
audio = open(file_upload, "rb").read()
header = {"Content-Type": "audio/x-flac; rate=16000"}
data = Request(url, audio, header)
post = urlopen(data)
response = post.read()
print(response)
js = json.loads(response[13:])
slovo = js["result"][0]["alternative"][0]["transcript"]
global result
result = slovo

Ключ для api необходимо получить тут (ключ для сервера), и подключить в кабинете speech api тут

Затем структура кода

arecord()
convert_to_flac()
speech_to_text_google()
print(result)
gpio.setmode(gpio.BCM)
gpio.setup(17,gpio.OUT)
gpio.setup(22,gpio.OUT)
gpio.setup(27,gpio.OUT)
if(result == u"Включи красный"):
gpio.output(17,True)
if(result == u"Включи желтый"):
gpio.output(22,True)
if(result == u"Включи синий"):
gpio.output(27,True)
if(result == u"Выключи желтый"):
gpio.output(22,False)
if(result == u"Выключи красный"):
gpio.output(17,False)
if(result == u"Выключи синий"):
gpio.output(27,False)
system("rm output.flac output.wav");

Светодиоды подключены следующим образом:

Внимание! Для корректного сравнений результата распознавания со строкой, содержащей unicode, необходимо поставить таг „u“.

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

P.S. для удобства настройки микрофона я пользовался библиотекой alsamixer.

Вот, что получилось:

Шина I2C и применение её в МК STM32

Шина I2C существует уже достаточно давно: ее в 1980х создала компания Philips для низкоскоростных устройств. В настоящий момент она достаточно широко применяется, и, скорей всего, дома у вас есть хоть одно устройство с данной шиной. Название шины расшифровывается как Inter-Integrated Circuit. Хардварным модулем I2C в настоящее время обладает большинство микроконтроллеров, в некоторых их и вовсе несколько, как у тех же STM32 (в серии F4 есть целых три модуля I2C).

I2C_bus

Шина представляет собой 2 линии, одна из которых данные (SDA), другая — синхросигнал (SCL), обе линии изначально притянуты к питанию. Следует отметить, что четкого указания какое именно должно быть напряжение нет, но чаще всего используется +5В и +3.3В. Устройства в линии не одноранговые, как в CAN, поэтому всегда должно быть Master-устройство. Допускается наличие нескольких Master-устройств, но это все же гораздо реже, чем один Master и ворох Slave устройств.

Передача данных инициируется мастером, который отправляет в шину адрес необходимого устройства, тактирование осуществляется так же мастером. Но, при этом, Slave-устройство имеет возможность «придержать» линию тактирования, как бы сообщая Master-устройству, что не успевает принять или отправить данные, что порой бывает очень полезно. Наибольшее распространение получили в текущий вариант реализации I2C с частотой шины 100 kHz (Standard mode) и 400 kHz (Fast mode).

Существует реализация I2C версии 2.0, которая позволяет достичь гораздо больших скоростей, в 2-3 Мбит/с, но они пока что весьма редкие. Так же у линии есть ограничение по емкости в 400 пФ. Обычно в даташитах для датчиков и прочих I2C устройств указывается их емкость, так что приблизительно можно вычислить «влезет» ли еще один датчик или нет.

Большая встреча сайта Catethysis.ru

Уже сегодня мы проводим большую встречу с лекциями и демонстрациями, она пройдёт в отличном зале недалеко от метро «Парк культуры». Это будет четвёртая по счёту встреча, но теперь наш уровень заметно возрос :)

Приглашаю всех принять участие!

В программе:

  1. Вводный курс в ПЛИС (Григорий Кузьмин)
  2. Динамическая трансляция (Михаил Чуриков)
  3. USB HID со стороны девайса и ПК, интеграция его в Qt (Тимур Хасаншин)

Добавляйтесь в группу мероприятия!

Итак, 16 января (сегодня), 17:00, зал недалеко от Парка культуры. Собираемся в 16:40 возле метро и стартуем в сторону зала.

Телефон организатора: +7(903)14-14-501, по всем вопросам звоните, я постоянно на связи.

Вставка файлов в прошивку — 2 часть

Я уже писал о методе добавления внешних файлов в прошивку микроконтроллера, даже написал для этой цели онлайн-конвертер бинарного файла в c-хедер. Однако есть более простой и удобный способ, который предоставляет IAR, да и строго говоря, любой линкер обязан уметь так делать.

Конечно, вы уже поняли — мы полезем в параметры линкера.

Одна из самых частых моих задач за последнее время — это сборка прошивки основного девайса, в которую вкомпилена прошивка дочерней платы. Основной девайс при запуске проверяет версию прошивки дополнительной платы, и если она младше — обновляет её до свежей. Поэтому я должен включить в основную прошивку бинарный файл с дочерней прошивкой.

Открываем окно Options -> Linker -> Input:

Снимок экрана 2016-01-09 в 13.02.24

Внизу видим опции «Raw binary image». Это именно то, что нам нужно, указываем файл.

Поиск ошибки, портящей память, в C коде для STM32

Прямо сейчас я нахожусь в командировке в Беларуси, и поймал странное поведение программы, проявляющееся после 20-30 секунд работы девайса на STM32.

У меня в программе есть энумератор, который может принимать только три значения, от 0 до 2:

Снимок экрана 2015-12-21 в 14.45.13

Однако, при отладке оказалось что в этой переменная лежит 0x72, вот скриншот окна Watch:

Снимок экрана 2015-12-21 в 14.46.14

Как так? Ещё и на осциллографе какая-то фигня вместо нормальных посылок на UART, который обрабатывается вообще в другом месте кода.