Электронный компонент:Набор компонентов Grove Speech Recognizer для распознавания речи

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Набор компонентов Grove Speech Recognizer для распознавания речи[1]

Этот набор предназначен для конструирования Arduino-проектов в области умного дома. Он состоит из базовых устройств для домашней автоматизации вроде распознавателя речи, ИК-передатчика и т.д. Также в комплекте есть руководство с инструкциями по сборке нескольких демо-проектов – например, для проигрывания музыки после голосовой команды «Включить музыку» или включения освещения после голосовой команды «Включить свет».

Купить набор Grove Speech Recognizer можно по этой ссылке.

Список компонентов

Пример использования: Включение телевизора

Иногда некоторыми системами хочется управлять не с помощью пультов, а голосовыми командами. В пультах используется, как правило, управление при помощи ИК-излучения, поэтому сначала нам нужно узнать, какой код запускается при нажатии на каждую кнопку пульта, а затем поместить этот код в нашу программу. В результате голос будет активировать код кнопок, благодаря чему системами можно будет управлять аналогично тому, как это происходит при помощи пульта дистанционного управления.

Для проекта понадобятся следующие компоненты:

Извлечение кода кнопок при помощи Grove-модуля с ИК-приемником

Сначала загрузите библиотеку «IRSendRev». Для этого кликните в IDE Arduino на Скетч > Подключить библиотеку... > Добавить .ZIP библиотеку (Sketch > Include Library > Add .ZIP Library...), а затем в открывшемся меню выберите скачанный ZIP-архив с библиотекой и нажмите на кнопку «Open». Далее выполните следующие действия:

  • Откройте скетч-пример «recv». Для этого кликните в IDE Arduino на Файл > Примеры > IRSendRev > recv (File > Examples > IRSendRev > recv)
  • Загрузите скетч в Arduino Uno
  • Подключите базовый Grove-шилд к Arduino Uno. Затем подключите Grove-модуль с ИК-приемником к порту D2 на шилде. Вы можете подключить его к другому порту, но тогда нужно будет поменять в коде номер контакта:
const int pinRecv = 2;

Теперь нажмите на пульте какую-нибудь кнопку. В результате монитор порта должен показать подробную информацию о коде кнопки, которая была нажата. Это выглядит примерно так:

Скопируйте куда-нибудь информацию о коде кнопки. Если конкретнее, нам понадобятся следующие данные:

+------------------------------------------------------+
LEN = 9
START_H: 179    START_L: 88
DATA_H: 11    DATA_L: 33

DATA_LEN = 4
DATA: 0x80    0x7E    0x10    0xEF
DATA: 128    126    16    239
+------------------------------------------------------+

Редактирование скетча-примера

Теперь давайте воспользуемся добытой информацией о коде кнопки:

Во-первых, отредактируйте данные о кнопке:

unsigned char dtaSend[20];

void dtaInit()
{
  ............
}

Во-вторых, отредактируйте эту информацию согласно данным, извлеченным благодаря ИК-приемнику:

unsigned char dtaSend[20];

void dtaInit()
{
    dtaSend[BIT_LEN]        = 9;    // размер буфера (не считая
                                    // самих данных о размере буфера)
    dtaSend[BIT_START_H]    = 179;  // время стартового сигнала HIGH
    dtaSend[BIT_START_L]    = 88;   // время стартового сигнала LOW
    dtaSend[BIT_DATA_H]     = 11;   // время «длинного» сигнала
    dtaSend[BIT_DATA_L]     = 33;   // время «короткого» сигнала

    dtaSend[BIT_DATA_LEN]   = 4;    // количество отправляемых данных; 
                                    // если оно другое, вам нужно 
                                    // уменьшить или увеличить
                                    // количество dtaSend[BIT_DATA+x]

    dtaSend[BIT_DATA+0]     = 128;  // отправляемые данные
    dtaSend[BIT_DATA+1]     = 126;
    dtaSend[BIT_DATA+2]     = 16;
    dtaSend[BIT_DATA+3]     = 239;
    //dtaSend[BIT_DATA+4]     = 192;
    //dtaSend[BIT_DATA+5]     = 63;
}

Количество отправляемых данных равно «4»:

DATA_LEN = 4

Поэтому две последние строчки можно удалить:

    //dtaSend[BIT_DATA+4]     = 192;
    //dtaSend[BIT_DATA+5]     = 63;

Разумеется, можно задать и другие кнопки:

#include <IRSendRev.h>

#define BIT_LEN         0
#define BIT_START_H     1
#define BIT_START_L     2
#define BIT_DATA_H      3
#define BIT_DATA_L      4
#define BIT_DATA_LEN    5
#define BIT_DATA        6

const int ir_freq = 38;

unsigned char OpenTV[20];
unsigned char CloseTV[20];
unsigned char IncreaseTemp[20];
unsigned char DecreaseTemp[20];

void OpenTVInit()
{
    OpenTV[BIT_LEN]        = 11;
    OpenTV[BIT_START_H]    = 179;
    /*............ пропуск ............*/
}

void CloseTVInit()
{
    CloseTV[BIT_LEN]        = 11;
    CloseTV[BIT_START_H]    = 179;
    /*............ пропуск ............*/
}

void IncreaseTempInit()
{
    IncreaseTemp[BIT_LEN]        = 11;
    IncreaseTemp[BIT_START_H]    = 179;
    /*............ пропуск ............*/
}

void DecreaseTempInit()
{
    DecreaseTemp[BIT_LEN]        = 11;
    DecreaseTemp[BIT_START_H]    = 179;
   /*............ пропуск ............*/
}

void setup()
{
    OpenTVInit();
    CloseTVInit();
    IncreaseTempInit();
    DecreaseTempInit();
}

void loop()
{
    IR.Send(OpenTV, 38);
    delay(200);
    IR.Send(CloseTV, 38);
    delay(200);
    IR.Send(IncreaseTemp, 38);
    delay(200);
    IR.Send(DecreaseTemp, 38);

    delay(2000);
}

Добавление в скетч-пример распознавателя речи

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

Команда Возвращаемое значение
Turn on the light (Включить свет) 1
Turn off the light (Выключить свет) 2
Play music (Проиграть музыку) 3
Pause (Пауза) 4
Next (Следующий) 5
Previous (Предыдущий) 6
Up (Вверх) 7
Down (Вниз) 8
Turn on the TV (Включить телевизор) 9
Turn off the TV (Выключить телевизор) 10
Increase temperature (Увеличить температуру) 11
Decrease temperature (Уменьшить температуру) 12
What’s time (Сколько время) 13
Open the door (Открыть дверь) 14
Close the door (Закрыть дверь) 15
Left (Влево) 16
Right (Вправо) 17
Stop (Стоп) 18
Start (Старт) 19
Mode one (Режим номер один) 20
Mode two (Режим номер два) 21
Go (Вперед) 22

Скетч-пример ниже использует команды «Turn on the TV» (т.е. «Включить телевизор») и «Turn off the TV» (т.е. «Выключить телевизор»).

Сначала определяем код кнопок для включения/выключения телевизора, а затем добавляем соответствующий код в скетч-пример «send». В итоге скетч-пример должен выглядеть следующим образом:

#include <IRSendRev.h>
#include <SoftwareSerial.h>

/*======== Исходные данные для пульта ========*/

#define BIT_LEN         0
#define BIT_START_H     1
#define BIT_START_L     2
#define BIT_DATA_H      3
#define BIT_DATA_L      4
#define BIT_DATA_LEN    5
#define BIT_DATA        6
const int ir_freq = 38;                 //  38 кГц

/* ========  Используемые кнопки  ========*/

unsigned char OpenTV[20];
unsigned char CloseTV[20];


/*=========  Контакты для распознавателя речи  ==========*/

#define SOFTSERIAL_RX_PIN  5
#define SOFTSERIAL_TX_PIN  6

SoftwareSerial speech(SOFTSERIAL_RX_PIN,SOFTSERIAL_TX_PIN);


/* =======  Запись ИК-данных  ========*/
/* ====  Получить их можно с помощью ИК-ресивера  ==== */

void OpenTVInit()
{
    OpenTV[BIT_LEN]        = 9;    // размер буфера (не считая
                                   // самих данных о размере буфера)
    OpenTV[BIT_START_H]    = 180;  // время стартового сигнала HIGH
                                   // для «Включить телевизор»  
    OpenTV[BIT_START_L]    = 88;   // время стартового сигнала LOW
                                   // для «Включить телевизор»  
    OpenTV[BIT_DATA_H]     = 11;   // время «длинного» сигнала
    OpenTV[BIT_DATA_L]     = 33;   // время «короткого» сигнала

    OpenTV[BIT_DATA_LEN]   = 4;    // количество отправляемых данных; 
                                   // если оно другое, вам нужно 
                                   // уменьшить или увеличить
                                   // количество OpenTV[BIT_DATA+x]

    OpenTV[BIT_DATA+0]     = 50;   // отправляемые данные
    OpenTV[BIT_DATA+1]     = 166;
    OpenTV[BIT_DATA+2]     = 80;
    OpenTV[BIT_DATA+3]     = 175;
}

void CloseTVInit()
{
    CloseTV[BIT_LEN]        = 9;    // размер буфера (не считая
                                    // самих данных о размере буфера)
    CloseTV[BIT_START_H]    = 178;  // время стартового сигнала HIGH
                                    // для «Выключить телевизор»  
    CloseTV[BIT_START_L]    = 89;   // время стартового сигнала LOW
                                    // для «Выключить телевизор»  
    CloseTV[BIT_DATA_H]     = 10;   // время «длинного» сигнала
    CloseTV[BIT_DATA_L]     = 33;   // время «короткого» сигнала

    CloseTV[BIT_DATA_LEN]   = 4;    // количество отправляемых данных; 
                                    // если оно другое, вам нужно 
                                    // уменьшить или увеличить
                                    // количество CloseVT[BIT_DATA+x].

    CloseTV[BIT_DATA+0]     = 50;   // отправляемые данные
    CloseTV[BIT_DATA+1]     = 166;
    CloseTV[BIT_DATA+2]     = 168;
    CloseTV[BIT_DATA+3]     = 87;
}


void setup()
{
    OpenTVInit()
    CloseTVInit()
    Serial.begin(9600);
    speech.begin(9600);
    speech.listen();
}

void loop()
{
    int a=0;

    if(speech.available())
    {
        a = speech.read();  // считываем значение, которое вернул
                            // распознаватель речи
        switch (a)
        {
            case 9:         //  если (возвращаемое значение),
                            //  то отправляем ИК-данные
            IR.Send(OpenTV, 38);
            delay(1000);
            break;
            case 10:
            IR.Send(CloseTV, 38);
            delay(1000);
            break;
            default:
            break;
        }
    }
}

Пример использования: Управление музыкой

Как видите, в таблице возвращаемых значений (см. выше) много команд, связанных с музыкой – вроде «Play music», «Pause», «Stop», «Previous», «Next». Давайте попробуем сделать проект, демонстрирующий использование этих команд.

Во-первых, загрузите и установите библиотеку «Grove_Serial_MP3_Player_V2.0». Сделайте это, кликнув в IDE Arduino на Скетч > Подключить библиотеку... > Добавить .ZIP библиотеку (Sketch > Include Library > Add .ZIP Library...), а затем в открывшемся меню выбрав скачанный ZIP-архив с библиотекой и нажав на кнопку «Open».

Полезные функции для использования Grove-модуля MP3 V2

Библиотека «Grove_Serial_MP3_Player_V2.0» имеет несколько удобных функций для управления Grove-модулем MP3 V2.0. Самые основные перечислены ниже:

  • Функция PlayPause()
    • Проигрывание музыки.
  • Функция PlayResume()
    • Возобновление проигрывания музыки.
  • Функция PlayNext()
    • Переход к следующей песне.
  • Функция PlayPrevious()
    • Переход к предыдущей песне.
  • Функция PlayLoop()
    • Проигрывание всех песен по кругу.
  • Функция SetVolume(uint8_t volume)
    • Задает громкость. Значение по умолчанию – «0x0E», диапазон допустимых значений – от «0x00» до «0x1E».
  • Функция IncreaseVolume()
    • Увеличивает громкость.
  • Функция DecreaseVolume()
    • Уменьшает громкость.

Кроме того, в библиотеке есть и более специализированные функции, на которые тоже стоит обратить внимание:

  • Функция SelectPlayerDevice(uint8_t device)
    • Выбирает SD-карту, с которой будет проигрываться музыка. Значение по умолчанию – «0x02».
  • Функция SpecifyMusicPlay(uint16_t index)
    • Выбирает трек, который нужно включить, по названию файла. Названия треков должны быть заданы определенным образом (см. картинку ниже). Таким образом, в аргументе можно указать, например, значение «005».
  • Функция SpecifyfolderPlay(uint8_t folder, uint8_t index)
    • Выбирает трек, который нужно включить, по названиям папки и файла.

Примечание: Диапазон значений для папок варьируется между «01» и «99». Следовательно, названия папок, используемые этой библиотекой, могут быть только в диапазоне между «01» и «99». Обратите внимание, что у первых десяти значений первой цифрой должен быть «0», т.е. они должны выглядеть как «01», «02», «03» и т.д.

Таким образом, чтобы проиграть трек «005» в папке «01», в скетч нужно вписать такую функцию:

SpecifyfolderPlay(1,5);

Кроме того, каждая песня длится определенное время, поэтому если вы хотите, чтобы несколько песен проигрывалось друг за другом, можно воспользоваться двумя способами:

  1. delay(время) – задает задержку, пока трек не закончится
  2. while(QueryPlayStatus() != 0) – если функция QueryPlayStatus() возвращает «0», то трек закончился, а если «1», то еще не закончился

Как правило, легче использовать второй способ:

SpecifyMusicPlay(1);
while(QueryPlayStatus() != 0);
SpecifyMusicPlay(2);
while(QueryPlayStatus() != 0);
SpecifyMusicPlay(3);
while(QueryPlayStatus() != 0);

Скетч

Окей, а теперь давайте объединим MP3-плеер с распознавателем речи. Скетч ниже позволяет управлять некоторыми функциями MP3-плеера: проигрыванием музыки, паузой, возобновлением, переключением на следующую песню и переключением на предыдущую песню.

#include <SoftwareSerial.h>
#include <MP3Player_KT403A.h>

/****** Контакты для MP3-плеера ******/
SoftwareSerial mp3(2, 3);

/****** Контакты для распознавателя речи ******/
#define SOFTSERIAL_RX_PIN  5
#define SOFTSERIAL_TX_PIN  6

SoftwareSerial speech(SOFTSERIAL_RX_PIN,SOFTSERIAL_TX_PIN);


void setup()
{
    mp3.begin(9600);
    speech.begin(9600);
    Serial.begin(9600);
    delay(100);

    SelectPlayerDevice(0x02);  //  выбираем SD-карту 
                               //  как устройство, с которого 
                               //  будет проигрываться музыка
    SetVolume(0x15);           //  задаем громкость; 
                               //  диапазон: 0x00-0x1E
}

void loop()
{
    int a=0;
    if(speech.available())
    {
        a = speech.read();  //  считываем значение, 
                            //  возвращаемое распознавателем речи
        switch (a)
        {
            case 3:               //  голосовая команда: «Play music»
            SpecifyMusicPlay(1);  //  MP3: включить трек «001»
            break;
            case 4:               //  голосовая команда: «Pause»
            PlayPause();          //  MP3: остановить музыку
            break;
            case 19:              //  голосовая команда: «Start»
            PlayResume();         //  MP3: возобновить проигрывание
            break;
            case 5:               //  голосовая команда: «Next»
            PlayNext();           //  MP3: включить следующий трек
            break;
            case 6:               //  голосовая команда: «Previous»
            PlayPrevious();       //  MP3: включить предыдущий трек
            break;
            default:
            break;
        }

        delay(1000);
    }
}

Вещание текущего времени

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

Настройка времени

Сначала загружаем и устанавливаем библиотеку «RTC_DS1307», необходимую для использования Grove-модуля для часов реального времени. Сделайте это, кликнув в IDE Arduino на Скетч > Подключить библиотеку... > Добавить .ZIP библиотеку (Sketch > Include Library > Add .ZIP Library...), а затем в открывшемся меню выбрав скачанный ZIP-архив с библиотекой и нажав на кнопку «Open».

  • Откройте скетч-пример «SetTimeAndDisplay», кликнув в IDE Arduino на Файл > Примеры > RTC_DS1307 > SetTimeAndDisplay (File > Examples > RTC_DS1307 > SetTimeAndDisplay)
  • Подключите базовый Grove-шилд к Arduino Uno, а затем подключите Grove-модуль с часами реального времени к I2C-интерфейсу на базовом Grove-шилде
  • Задайте текущее время:
clock.fillByYMD(2016,1,19);  //  23 мая 2016 года
clock.fillByHMS(15,28,30);   //  15:28:30
clock.fillDayOfWeek(Mon);    //  Среда
  • Загрузите модифицированную программу на Arduino Uno.

Вещаемый текст

Как известно, для вещания времени достаточно 69 цифр (от «0» до «59»). Кроме того, перед вещанием самого времени можно добавить какой-нибудь текст. Например, «It’s», что можно перевести как «сейчас». Таким образом, в целом на SD-карту нужно загрузить 61 звуковой файл.

Но при использовании SD-карты нужно соблюдать определенные правила:

  • SD-карта должна быть типа FAT32
  • Перед добавлением треков SD-карту нужно отформатировать. Во время записи треков не должно совершаться никаких других действий
  • Порядок проигрывания треков зависит от порядка их записи. То есть, если мы хотим проигрывать треки по порядку, то эти треки на SD-карту тоже нужно записывать по порядку

К слову, разработчики пронумеровали все звуковые файлы (всего их 61) в папке, поэтому их можно просто загрузить, а потом записать на SD-карту. Разумеется, перед этим карту нужно отформатировать.

Название звукового файла Номер файла на SD-карте Проговариваемый текст
000 Первый 0
001 Второй 1
... ... ...
059 Шестидесятый 59
060 Шестьдесят первый «It’s»

Сборка системы

  • Подключите базовый Grove-шилд к Arduino Uno, затем подключите Grove-модуль с MP3-плеером к порту D2 на базовом Grove-шилде, затем подключите Grove-модуль с распознавателем речи к порту D5 на базовом Grove-шилде и, наконец, подключите Grove-модуль с часами реального времени к порту I2C на базовом Grove-шилде
  • Скопируйте код ниже в новый скетч IDE Arduino, а затем загрузите программу на Arduino Uno
  • Скажите «Hi Cell, what’s the time?», и система должна проговорить текущее время
#include <Wire.h>
#include "DS1307.h"
#include <SoftwareSerial.h>
#include <MP3Player_KT403A.h>

/******* Контакты для MP3-плеера ******/
SoftwareSerial mp3(2, 3);

/******* Контакты для распознавателя речи ******/
#define SOFTSERIAL_RX_PIN  5
#define SOFTSERIAL_TX_PIN  6

SoftwareSerial speech(SOFTSERIAL_RX_PIN,SOFTSERIAL_TX_PIN);

/******* Задаем объект для класса DS1307 ******/
DS1307 clock;

void setup ()
{
  mp3.begin(9600);
  speech.begin(9600);
  clock.begin();
  Serial.begin(9600);
  delay(100);

  SelectPlayerDevice(0x02);  //  выбираем SD-карту, с которой будут 
                             //  проигрываться звуковые файлы
  SetVolume(0x15);           //  задаем громкость: диапазон: 0x00-0x1E
}

void loop ()
{
  int a=0;
  speech.listen();  //  начинаем получать данные от программного порта 
                    //  распознавателя речи
  if(speech.available())
  {
    a = speech.read();  //  считываем значение, возвращаемое
                        //  распознавателем речи
    if(a==13)
    {
      clock.getTime();        //  считываем время 
                              //  от часов реального времени
      int b=1+clock.hour;     //  считываем часы; поскольку 
                              //  первый трек – это «0»,
                              //  то для трека со словами «It’s», 
                              //  который находится в самом конце, 
                              //  к «60» нужно добавить «1»
       int c=1+clock.minute;  //  считываем минуты; поскольку 
                              //  первый трек – это «0»,
                              //  то для трека со словами «It’s», 
                              //  который находится в самом конце, 
                              //  к «60» нужно добавить «1»

      mp3.listen();           //  начинаем получение данных 
                              //  от программного порта MP3-плеера
      SpecifyMusicPlay(61);   //  номер «It’s» на SD-карте – это «61»
      while(QueryPlayStatus() != 0);  //  когда закончится
                                      //  предыдущий трек,
                                      //  начинаем проигрывать
                                      //  следующую трек
      SpecifyMusicPlay(b);  //  проигрываем трек, сохраненный 
                            //  на SD-карте под названием «b»
      while(QueryPlayStatus() != 0);
      SpecifyMusicPlay(c);  //  проигрываем трек, сохраненный 
                            //  на SD-карте под названием «c»

      while(QueryPlayStatus() != 0);
    }
  }
    delay(1000);
}

Полезные ссылки

См.также

Внешние ссылки