» » » «Умный» удлинитель с голосовым управлением для гирлянд (esp8266+stm32)

 

«Умный» удлинитель с голосовым управлением для гирлянд (esp8266+stm32)

Автор: admin от 4-01-2018, 19:55, посмотрело: 39

Привет, Хабр. В прошлом году сделал "умный" удлинитель для управления гирляндами на елочке. Но тогда руки так и не дошли написать об этом статью. Исправляюсь.


Сама елочка


«Умный» удлинитель с голосовым управлением для гирлянд (esp8266+stm32)


На елочке 3 гирлянды, а под ней выводок светящихся белых мишек. Когда гирлянд много, встает вопрос — как ими управлять? Каждый раз залезать под елочку и включать/выключать из розетки нужные гирлянды — сомнительное удовольствие.


Конечно, продается большое количество "умных розеток" — но с голосовым управлением, и так что бы 4 розетки сразу в одном устройстве, без лишних проводов и блоков питания — таких не встречал.

Исходники скетча


Инициализация и запуск распознавания


// Подключаем библиотеку аудиозаписи
#include <WiievaRecorder.h>
WiievaRecorder recorder (2000*5);

// Переменные для распознавалки
unsigned long timeRecorderStart = 0,timeRecorderEnd=0;
bool wasVAD = false;

void startRecognize () {
    // Запуск рекордера
    recorder.start (AIO_AUDIO_IN_SPEEX);
    Serial.printf ("Start recordingn");

    timeRecorderStart = millis();
    timeRecorderEnd=0;
    wasVAD = false;
}

Само распознавание и выполнение команд


void processRecognize () {
    if (!timeRecorderStart) {
        return;
    }

    // Проверка состояния Voice Activity
    bool res = recorder.run ();
    bool vad = recorder.checkVad();

    if (vad && !wasVAD) {
        Serial.printf("VAD: speech startedn");
    }

    wasVAD = wasVAD || vad;

    if (millis () - timeRecorderStart < 3000 || vad)
        timeRecorderEnd = millis ();

    if (res && (!timeRecorderEnd || millis () - timeRecorderEnd < 500))
        // VAD еще не сработал - записываем дальше
        return;

    recorder.stop();
    timeRecorderStart = 0;
    if (!wasVAD) {
        // Не было голосовой активности - выходим
        return;
    }

    // Создаем http клиент и далеам POST в google speech recognition
    HTTPClient http;
    http.begin(url);
    http.addHeader ("Content-Type","audio/x-speex-with-header-byte; rate=8000");
    int httpCode = http.sendRequest ("POST",&recorder,recorder.recordedSize());

    if(httpCode > 0) {
        Serial.printf("[HTTP] POST... code: %dn", httpCode);
        String payload = http.getString();
        Serial.println(payload);

        String cmd = "toggle";
        // Грепаем по ответу из гугла команду
        // Ответ приходит в JSON, но для простоты мы просто ищем вхождение подстроки с командой
        if (payload.indexOf ("выклю")>=0 || payload.indexOf ("погас")>=0)
            cmd = "off";
        else if (payload.indexOf ("вклю")>=0 || payload.indexOf ("зажг")>=0)
            cmd = "on";

        if (payload.indexOf ("музык")>=0) startPlay();
        else if (payload.indexOf ("все")>=0) controlAllRelay (cmd); else {
            // Ищем имя гирлнянды
            if (payload.indexOf ("шарики")>=0) controlRelay (0,cmd);
            if (payload.indexOf ("свечки")>=0) controlRelay (1,cmd);
            if (payload.indexOf ("мишки")>=0|| payload.indexOf ("виски")>=0) controlRelay (2,cmd);
            if (payload.indexOf ("огоньки")>=0) controlRelay (3,cmd);
        }
    }
    http.end();
}

Под капотом


Оцифровка звука


PDM Микрофон подключен к SPI/I2S2 процессора stm32. В качестве референса использовал этот Application Note от ST


Для того, что бы не загружать процессор данные из I2S получаются с использованием DMA в кольцевой ping-pong буфер.
PDM. Обработка полученных PDM данных происходит по прерываниям от DMA. Работа с прерываниями DMA достаточно стандартная для stm32:
Есть два признака прерывания по заполнению верхний/нижней половин буфера. В обработчике прерывания выбирается половинка буфера, с уже готовыми данными


Затем происходит преобразование буфера из формата PDM в обычный PCM: набор сэмплов (значений уровня сигнала) с требуемой частотой дискретизации.


После преобразования и ресемплинга данные в формате PCM складываются в кольцевой буфер pdm_samples_buf.


Кодирование в speex


Следующий этап конвейера — упаковка звука кодеком SPEEX. Обработка звука кодеком весьма ресурсоемкий процесс, кушающий много процессорного времени и вызывать его в обработчике прерывания не очень хорошо.


Поэтому упаковка происходит асинхронно, в основном цикле программы — код код часть вторая


Заодно с кодированием в SPEEX анализируется наличие голосовой активности алгоритмом VAD.
А закодированная кодеком speex речь складывается в еще один кольцевой буфер speex_buf, из которого они уже и передаются в esp9266


Передача закодированного буфера из stm32 в esp8266


Интерфейс между esp8266 и stm32 построен по принципу команда ответ. esp8266 отправляет команду, stm32 отрабатывает команду и возвращает ответ. У части команд вместе с телом команды/или телом ответа передается буфер данных.


Со стороны esp8266 алгоритм работы получился очень простой:
Отправить команду чтения буфера данных и считать данные:


Так выглядит код со стороны esp8266:
код рекордера
код работы с SPI


Со стороны stm32 задача выглядит сложнее:
По прерываниям от SPI парсится код команды, и в зависимости от кода команды выполняются требуемые действия. В нашем случае — пересылка данных из кольцевого буфера SPEEX кодека в SPI


Вместо заключения


Многие интересные моменты, например, такие как проигрывание mp3, подключение графической библиотеки, реализацию драйверов экрана и тач панели, интеграцию с умным домом и многое-многое другое пришлось оставить за скобками этой статьи — получилось бы слишком много текста.


В планах еще допилить активацию распознавания речи по hot-word, например "елочка". Для этого планирую затащить небольшой кусочек pocketsphinx на борт и делать на борту что то типа MFCC+DTW...


несколько полезных ссылок


Исходники скетча


Схемотехника платы


Программа для stm32


Форк Arduino среды для платы Wiieva



Источник: Хабрахабр

Категория: Компании » Facebook

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *