Голосовое управление микроконтроллером

В поисках экономичного способа общения с микроконтроллером некоторое время назад я пришел к варианту голосового управления со смартфона. Для начала опытов с голосовым управлением потребовалось совсем немного ресурсов: смартфон, Ардуинка и Bluetooth-модуль. Все остальное (за исключением скетча на Ардуинка) предоставил Андроид: система распознавания речи встроена в стандартную клавиатуру (не запускает клик по иконке микрофона в верхней части клавиатуры), а связь с микроконтроллером может обеспечить любое приложение с функцией Bluetooth-терминала. За пару часов был написан скетч, имитирующий управление тележкой с помощью набора команд (“налево”, “направо”, “быстрее”, “медленнее”, …).

В итоге получился вот такой скетч:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(7, 6); // RX, TX
int Azimuth,  // направление движения и
    Velocity; // скорость тележки
String  cmdBufferS,
        cmdBufferH,
        sResponse;
bool  bDebug;
long  mSec;
double curX, curY, curA;
void setup() {
  Azimuth = 0;
  Velocity = 0;
  curX  = 0;
  curY  = 0;
  curA  = 0;
  mSec = millis();
  bDebug = false;
  cmdBufferS = "";
  cmdBufferH = "";
    mySerial.begin(9600); // инициализация и настройка скорости программного последовательного порта
  Serial.begin(9600);
  Serial.println(F("----------------------------------------------------------"));
  Serial.println(F("-------------------- Sketch avr_Voice --------------------"));
  Serial.println(F("----------------------------------------------------------"));
}

void loop() {
  readSerialData();
  if(millis()-mSec>=999) {
    mSec = millis();
    updateCrds();
  }
}

void changeVelocity(int8_t r,String cmd) {
  byte p;
  int v;
  String sv;
    if(p = cmd.indexOf(' ')) {
    cmd.remove(0,p+1);
    v = cmd.toInt();
    if(r<0) {
      Serial.print("V-, ");
      Velocity = Velocity-v;
      if(Velocity<0) Velocity = 0;
    }
    else {
      Serial.print("V+, ");
      Velocity = Velocity+v;
    }
    Serial.print("Parameter: ");
    Serial.print(cmd);
    Serial.print(" -> ");
    Serial.println(Velocity);
  }
} // of changeVelocity

void changeAzimuth(int8_t r,String cmd) {
  byte p;
  int v;
  if(p = cmd.indexOf(' ')) {
    cmd.remove(0,p+1);
    v = cmd.toInt();
    if(r<0) {
      Serial.print("toleft, ");
      Azimuth = Azimuth-v;
      if(Azimuth<0) Azimuth = Azimuth + 360;
    }
    else {
      Serial.print("toright, ");
      Azimuth = Azimuth+v;
      if(Azimuth>360) Azimuth = Azimuth - 360;
    }
    Serial.print("Parameter: ");
    Serial.print(cmd);
    Serial.print(" -> ");
    Serial.println(Azimuth);
  }
}

void updateCrds() {
  double R,A;
  // направление движения (угол в градусах) переводим в радианы
  A = Azimuth*3.1415926/180;
  curX = curX + Velocity*sin(A);
  curY = curY + Velocity*cos(A);
  R = sqrt(curX*curX+curY*curY);
 
  //curA = asin(curX/R);
  // получим угол в радианах
  if(curY==0) {
    if(curX>=0) curA = 0; else curA = 2*3.1415926;
  } else curA = atan(curX/curY);
  // и переведем его в градусы
  curA = curA/3.1416*180;
  if(curX<0) curA = 270 - curA;
}
void SendState() {
  mySerial.print("A=");   mySerial.print(Azimuth);
  mySerial.print(", V="); mySerial.print(Velocity);
  if(bDebug) {
    mySerial.print(" (X=");   mySerial.print(curX);
    mySerial.print(" / Y=");   mySerial.print(curY);
    mySerial.print(" / A=");   mySerial.print(curA);
    mySerial.print(")");
  }
  mySerial.println("");
}

void interpreteCommand(String &cmdBuffer) {
  if(cmdBuffer.length()==0) return;
  Serial.print("Command: ");
  Serial.println(cmdBuffer);
  if(cmdBuffer.startsWith("налево")) changeAzimuth(-1,cmdBuffer);
  else if(cmdBuffer.startsWith("направо")) changeAzimuth(+1,cmdBuffer);
  else if(cmdBuffer.startsWith("быстрее")) changeVelocity(+1,cmdBuffer);
  else if(cmdBuffer.startsWith("медленнее")) changeVelocity(-1,cmdBuffer);
  else if(cmdBuffer.startsWith("отладка")) bDebug = true;
  SendState();
  cmdBuffer = "";
}
void readSerialData() {
  char c;
  if (mySerial.available()) {
    c = (char)mySerial.read();
    //if(c<' ') {Serial.print("<"); Serial.print(byte(c)); Serial.print(">");}
    //else Serial.print(c);
    if (c==0x0A || c==0x0D) interpreteCommand(cmdBufferS);
    else cmdBufferS=cmdBufferS+c;
  }
  if (Serial.available()) {
    c = (char)Serial.read();
    if(c<' ') {Serial.print("<"); Serial.print(byte(c)); Serial.print(">");}
    else Serial.print(c);
    if (c==0x0A || c==0x0D) interpreteCommand(cmdBufferH);
    else cmdBufferH=cmdBufferH+c;
  }
} // of readSerialData

После первых опытов пришло понимание, что такой вариант не слишком комфортен - необходимо постоянно включать-выключать клавиатуру а в ней дополнительно клацать по значку микрофона, чтобы получить возможность с помощью Google-сервиса распознать сказанную фразу, а затем отправить полученный текст на Ардуину.

Было принято решение создать небольшое приложение, которое взяло бы на себя все лишние телодвижения и позволило сконцентрироваться на процессе подачи команд голосом. Через некоторое время приложение-демонстратор появилось и было опубликовано в Google Play под именем Ard Control.

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

Без схемы подключения и общей схемы взаимодействия устройств эта тема не дотягивает до раздела «Проекты»,

2 лайка

Что-то не то нажал - в качестве ответа выскочило мое первое сообщение. Попробую исправиться.

Схемы подключения в этом проекте, собственно, и нет. Разве что подключение модуля Bluetooth к Ардуине.

А общая схема взаимодействия такова:

  1. Подготовка: Устанавливаем на смартфоне приложение Ard Control из магазина приложений Google Play, подключаем к Ардуине Bluetooth-модуль (RX к пину 7, TX к пину 6). Закачиваем приведенный в сообщении скетч. Запускаем его…
  2. Открыв Ard Control, и нажав на кнопку “BT Device”, производим выбор сопряженного устройства, соответствующего тому Bluetooth-модулю, который подключен к Ардуине
  3. После успешного соединения с выбранным устройством на главном экране появится сообщение “Канал связи готов, соединение выполнено“
  4. Теперь можно нажимать желтую кнопку внизу с изображенным на ней микрофоном и произносить разные магические фразы, например, “быстрее десять“ или “направо двадцать“. Google-сервис распознает их и отправит на Ардуину текстовые сообщения (“быстрее 10“ или “направо 20“). В скетче полученные текстовые сообщения пройдут простенький разбор и микроконтроллер заставит нашу виртуальную тележку двигаться быстрее на 10 единиц и повернуть вправо на 20 градусов.
  5. Ну и т. д. в цикле, пока не надоест.

К какой ардуине и какой модуль?

1 лайк

step962 а для esp32 нет версии ? что бы она парсила распознователь текста гогле, превращала в строку, + парсер, который при нахождении определенных слов, будет выполнять такое то действие…. а то у меня андройда нет, как и гогле плей…

Я подключил к Нано, HC-05

В приведенном скетча использован программный сериал, поскольку аппаратный.зарезервирован под вывод отладочной информации.

Приложение проверено на Андроидах 5, 10 и 14 (других под рукой не нашлось)

Не, без Андроид-смартфона не получится - за распознавание речи отвечает соответствующий сервис Google…

Да интересная игрушка, делал, там приложение несколько строк пазлов.

Кстати без интернета работает. Но кнопку блямку оставил, хотя мне пазл дарили и без неё :slight_smile:

А если в 43 строке результат будет равен нулю?

Питание 3.3В. Соответственно понадобится преобразователь уровня. Соответственно нужна схема подключения.
Вы ни прямого текста, ни намёков не понимаете?

1 лайк

Да в есп32 всё есть, сразу в плату текст идёт :slight_smile: Я ёлку-моргалку делал с вариантом голосового - : Автомат нет, эффект десять, яркость четыре, пауза сто, цвет пять…так и работала.

Что-то не получается вставить изображение… попробую словами.

На моем модуле написано:

JY-MCU / Power 3.6-5v / 3.3V LEVEL / BT_BOARD V1.60

Берет с Наны питание 5 Вольт и работает, подключенный к ней четырьмя проволочками.


Такой?

Не совсем - кнопки точно нет.

А где про выставку изображений можно почитать? Все кнопки в окне редактора перепробовал - не получается…

На изобоажении - “копироаать”, в окне ввода вставить/ctr-v

Ну так у Вас на Rx с Tx ардуины 5 Вольт шарашит.

Для эксперементов, терпимо, для проекта нет.

2 лайка

Как бы ещё на планшете кнопку Ctrl найти….

Причем который год - ни дна ему, ни покрышки.