Реклама ⓘ
Главная » Автоматика в быту
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

Голосовое управление освещением X10. Часть 2

Продолжение. Начало - Часть1

Преобразование голоса в текст

Для преобразования голоса в текст будем использовать сервис Google Speech, который предоставляет API, позволяющее использовать сервис в своих приложениях. Технология следующая (подробно см. http://ab-log.ru/smart-house/speech/speech-recognition):

В Linux необходимо установить пакеты sox и flac.

apt-get install sox
apt-get install flac

Далее пишем bash-скрипт.

#!/bin/bash
while [ true ]; do
     rec -q -c 1 -r 16000 current.wav silence 1 0.2 3% 1 0.2 3%
     flac -f -s current.wav -o current.flac
     php textfromgoogle.php
done

Программа sox слушает микрофон и когда обнаруживает наличие звука, записывает фрагмент в wav файл. Записывать звук нужно с частотой 16КГц. Далее этот wav файл конвертируется в формат FLAC. После этого запускается PHP-скрипт, в котором реализовано обращение к Google Speech API .

Вот сам скрипт textfromgoogle.php

// Используем cURL для формирования HTTP POST-запроса к Google API

// Пакет php5-curl
$file_to_upload = array('myfile'=>'@current.flac');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=ru-RU");
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: audio/x-flac; rate=16000"));
curl_setopt($ch, CURLOPT_POSTFIELDS, $file_to_upload);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result=curl_exec ($ch);
curl_close ($ch);

// Google возвращает JSON, поэтому парсим стандартной функцией. Доступна в PHP 5.2
$json_array = json_decode($result, true);
$voice_cmd = $json_array["hypotheses"][0]["utterance"];

// Вывод на экран
if(isset($json_array["hypotheses"][0]))
 echo $voice_cmd;

Запускаем bash-скрипт и проверяем. Задержка выдачи результата несколько секунд, результат распознования не очень хороший, гораздо хуже Google search для планшета HTC. Но при правильном выборе слов (видимо звонкие слова) , четком произношении можно получить достаточно приемлемый результат. Ниже немного изменим скрипт, чтобы отклонения результата от Google Speech API направить к нужной фразе. Использовались встроенный микрофон и еще следующий беспроводной микрофон, который и будет использоваться в рабочем варианте.

x10-9.jpg

Создание пакета для ROS

На нетбуке запущена ROS (операционная система для роботов). ROS - это фреймворк для программирования роботов, предоставляющий функционал для распределённой работы. Сайт проекта - http://www.ros.org .Достаточно хороший русскоязычный туториал здесь. Использование ROS необязательно, достаточно написать скрипт на python для преобразования голоса в текст и отправки результата в Arduino. Но в дальнейшем предполагается управлять приборами X10 с передвигающегося робота, поэтому использую ROS.

Создаем новый проект в ROS (сразу указываем зависимости пакета )

cd ~/ros_pkgs
roscreate-pkg  vp_x10_voice std_msgs rospy

Далее устанавливаем систему зависимостей командой rosdep

rosdep install vp_x10_voice

Теперь можно построить наш пакет

rosmake vp_x10_voice

Пакет построен

Теперь создадим узел node_x10_voicetotext, который осуществляет операции преобразования голоса в текст с помощью Google Search API, затем немного "причесывает" ответ и публикующий результат как сообщения в тему x10_voicetotext. Узел - это термин для обозначения исполняемого файла, который подключен к сети ROS. Узел создадим в директории nodes.

roscd vp_x10_voice
mkdir nodes
cd nodes
touch node_x10_voicetotext.py

Вот содержимое файла node_x10_voicetotext.py

#!/usr/bin/env python
#-*-coding:utf-8 -*-
import roslib; roslib.load_manifest('vp_x10_voice')
import rospy
import subprocess
import shlex

from std_msgs.msg import String
from std_msgs.msg import Int16

fraza=["люстра","лента","лампа","ночник","елка",
   "люстра включить","лента гори","лампа включить","ночник включить","елка гори",
   "отбой",
   "программа 1","программа 2","программа 3","программа 4","программа 5"]

matrix = [["люстра","быстро"],
   ["лента"],
   ["лампа","лапа"],
   ["ночник","начни"],
   ["елка","елочка"],
   ["люстра включить","люстра ключи","быстро включить"],
   ["лента гори","mp3"],
   ["лампа включить","лампа включи","лампа ключи"],
   ["ночник ключи","ночник включить","ночник включи","ночник горит","ночник гори"],
   ["елка гори","елочка гори","елка горит"],
   ["отбой","всем спать","я спать"],
   ["программа 1","драма 1"],
   ["программа 2","драма 2"],
   ["программа 3","драма 3","программа тв"],
   ["программа 4","драма 4"],
   ["программа 5","драма 5"]]


def talker():
    pub = rospy.Publisher('x10_voicetotext', Int16)
    rospy.init_node('node_x10_voicetotext')

    while not rospy.is_shutdown():
      rospy.loginfo("ожидание записи с микрофона")
      subprocess.Popen('rec -q -c 1 -r 16000 current.wav silence 1 0.2 3% 1 0.2 3%',shell=True,cwd = '/home/petin/ros_pkgs/vp_x10_voice/nodes/').communicate()      
      rospy.loginfo("wav - ok") 
      subprocess.Popen('flac -f -s current.wav -o current.flac',shell=True,cwd = '/home/petin/ros_pkgs/vp_x10_voice/nodes/').communicate()
      rospy.loginfo("flac - ok") 
      proc3=subprocess.Popen('php textfromgoogle.php',shell=True, stdout =   subprocess.PIPE,cwd = '/home/petin/ros_pkgs/vp_x10_voice/nodes/') 
      result=proc3.communicate()[0]
      str1 = "result api google = %s"%result
      rospy.loginfo(str1)
      str2=""
      index=0
      for ind,elements in enumerate(matrix):
        for element in elements:
          if result.count(element)>0:
            str2=fraza[ind]
            index=ind+1
      if(index>0):      
        pub.publish(index+1)
        rospy.loginfo(str2)
      
if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException: pass

Список фраз (команд) моей комнаты (4 позиции, включающиеся приборами x10). фразы подбирались для слов лучшего распознавания

  • "люстра" - отключить верхний свет
  • "лента" - отключить светодиодную ленту верхнего света
  • "лампа" - отключить светильник на рабочем столе
  • "ночник" - отключить светильник возле дивана
  • "елка" - отключитьгирлянда на елке (зарезервировано для Нового года)
  • "люстра включить" - включить верхний свет
  • "лента гори" - включить светодиодную ленту верхнего света
  • "лампа включить" - включить светильник на рабочем столе
  • "ночник включить" - отключить светильник возле дивана
  • "елка гори" - включить гирлянда на елке
  • "отбой" - выключить все
  • "программа 1",
  • "программа 2",
  • "программа 3",
  • "программа 4",
  • "программа 5"

Команды "программа 1", "программа 2", "программа 3", "программа 4", "программа 5" -серии команд для одновременного действия с приборами по одной команде - например включить верхний свет, ночник, елку

(определим позже)

Файл node_x10_voicetotext.py делаем исполняемым. Запускаем.

Первый терминал 

roscore

Второй терминал 

rosrun vp_x10_voice node_x10_voicetotext.py

Проверяем, что в списке узлов появился узел

rosnode list

Ответ

/node_x10_voicetotext
/rosout

В списке тем - тема

rostopic list

Ответ

/rosout
/rosout_agg
/x10_voicetotext

 

Видео результата работы скрипта преобразования голоса в текст и публикация в тему ROS

Узел node_x10_voicetotext публикует номер выбранной программы (сообщения типа Int16) в тему. Создадим файл node_x10_texttocommand.py, который создаст узел node_x10_texttocommand, который будет получать сообщения из темы x10_voicetotext и отправлять последовательность команд в тему data_to_x10. Последовательность команд будем отправлять как сообщения типа X10. Создадим файл, описывающий тип сообщений X10. Создадим в директории проекта vp_x10_voice папку msg, а в ней файл X10.msg следующего содержания

int16 command1
int16 command2
int16 repeatTime

Заново пересобираем проект

roscd vp_x10_voice

rosdep install vp_x10_voice std_msgs rospy

rosmake vp_x10_voice

И содержимое файла node_x10_texttocommand.py (с программами пока не определился, поэтому каждая программа просто выключает весь свет)

#!/usr/bin/env python
#-*-coding:utf-8 -*-
 
#  Слушатель x10_voicetotext
#  
#  и отправка команд и установка параметров
#  для управления ardrone 2.0
#

import roslib; roslib.load_manifest('vp_x10_voice')
import rospy
import subprocess
import shlex

from vp_x10_voice.msg import X10
from std_msgs.msg import String
from std_msgs.msg import Int16
from std_msgs.msg import Empty


HOUSE_A=6       #B00110

UNIT_1=12	#B01100
UNIT_2=28	#B11100
UNIT_3=4	#B00100
UNIT_4=20	#B10100
UNIT_5=2	#B00010
UNIT_6=18	#B10010
UNIT_7=10	#B01010
UNIT_8=26	#B11010
UNIT_9=14	#B01110
UNIT_10=30	#B11110
UNIT_11=6	#B00110
UNIT_12=22	#B10110
UNIT_13=0	#B00000
UNIT_14=16	#B10000
UNIT_15=8	#B01000
UNIT_16=24	#B11000

ALL_UNITS_OFF=1	#B00001
ALL_LIGHTS_ON=3	#B00011
ON=5			#B00101
OFF=7			#B00111
DIM=9			#B01001
BRIGHT=11		#B01011
ALL_LIGHTS_OFF=13	#B01101

arr_commands=[[[HOUSE_A,UNIT_2,1],[HOUSE_A,OFF,1]],        # люстра выключить
              [[HOUSE_A,UNIT_3,1],[HOUSE_A,OFF,1]],        # лента RGB выключить
              [[HOUSE_A,UNIT_4,1],[HOUSE_A,OFF,1]],        # лампа выключить
              [[HOUSE_A,UNIT_5,1],[HOUSE_A,OFF,1]],        # ночник выключить
              [[HOUSE_A,UNIT_6,1],[HOUSE_A,OFF,1]],        # гирлянда елочная выключить
              [[HOUSE_A,UNIT_2,1],[HOUSE_A,ON,1]],        # люстра включить
              [[HOUSE_A,UNIT_3,1],[HOUSE_A,ON,1]],        # лента RGB включить
              [[HOUSE_A,UNIT_4,1],[HOUSE_A,ON,1]],        # лампа включить
              [[HOUSE_A,UNIT_5,1],[HOUSE_A,ON,1]],        # ночник включить 
              [[HOUSE_A,UNIT_6,1],[HOUSE_A,ON,1]],        # гирлянда елочная включить
   [[HOUSE_A,UNIT_5,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,ON,1],[HOUSE_A,UNIT_4,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_2,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,OFF,1]],   #отбой
   [[HOUSE_A,UNIT_5,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,ON,1],[HOUSE_A,UNIT_4,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_2,1],[HOUSE_A,ON,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,OFF,1]],   #программа 1
   [[HOUSE_A,UNIT_5,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_4,1],[HOUSE_A,ON,1],[HOUSE_A,UNIT_2,1],[HOUSE_A,OFF,1],[HOUSE_A,UNIT_6,1],[HOUSE_A,OFF,1]],   #программа 2



              [[HOUSE_A,ALL_LIGHTS_OFF,1]],        # программа 3
              [[HOUSE_A,ALL_LIGHTS_OFF,1]],        # программа 4
              [[HOUSE_A,ALL_LIGHTS_OFF,1]]         # программа 5
              ]

def controller(data):

    index = data.data
    data1=X10()
    for ind,elements in enumerate(arr_commands[index-1]):
          data1.command1=elements[0]
          data1.command2=elements[1]
          data1.repeatTime=elements[2]
          pub1 = rospy.Publisher('data_to_x10', X10)
          pub1.publish(data1)
          rospy.loginfo(data1)

      
def listener():
   rospy.init_node('node_x10_texttocommand')
   sub = rospy.Subscriber("x10_voicetotext",Int16,controller)
   rospy.spin()
 
if __name__ == '__main__':
   listener()

Смотрим сообщения, выдаваемые в тему data_to_x10

rostopic echo data_to_x10

x10-11.png

В 3-ей части мы рассмотрим отправку сообщений в Arduino из ROS

Теги:

Опубликована: 20.02.2013 Изменена: 22.02.2013 0 0
Я собрал 0 Участие в конкурсе 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (7) | Я собрал (0) | Подписаться

0
talibanich #
Каков объем сетевого трафика между Google Speech API и компьютером при распознавании?
Какие требования к интернет-каналу при задействовании сервиса Google Speech API для устройств домашней автоматизации? Я так понимаю на распознавание необходимо какое-то время.
Ответить
0

[Автор]
victoruni #
У меня ответ от сервера Google идет примерно 1-2 сек (ADSL до 6 мБит/сек (по факту ниже)), хотя редко бывают и задержки и до 3-4 сек, но это действительно редко.
Чуствительность микрофона выставлена так, что команды необходимо произносить достаточно громко, чтобы фоновый звук от телевизора не вызывал постоянных обращений к серверу Google, поэтому обращения к серверу минимальны.
Главное добиться, чтобы формировался небольшой файл current.wav, т.е. после произнесения фразы sox сразу определял "тишину",

rec -q -c 1 -r 16000 current.wav silence 1 0.2 3% 1 0.2 3%

В ближайшем будущем думаю поменять распознавание Google Speech (кстати, на смартфонах Google Speech выдает гораздо лучшее распознование, возможно там есть предварительная обработка голоса перед отправкой запрос на сервер) на распознование голоса с помощью движка julius. На английском языке при создании своего словаря результат очень хороший (надеюсь скоро закончю и опубликую проект управления квадрокоптера голосом с помощью движка julius). Но с русским языком там пока проблеммно.
Ответить
0

[Автор]
victoruni #
Уточняю , все-таки не 1-2, а 2-4 сек - обычное время ответа от сервера Google Search
Ответить
0
Oleg #
Возможно скорость отклика будет выше, если прописать DNS 8.8.8.8 от Google!
Ответить
0

[Автор]
victoruni #
Спасибо, обязательно попробую
Ответить
0
Александр #
Есть что-то подобное под Windows?
Ответить
0

[Автор]
victoruni #
Не знаю, наверняка что-то есть. На Linux это бесплатно, на Windows - нет.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется сила тока?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Радиореле 220В
Радиореле 220В
Конструктор: DDS генератор сигналов 200 Вт усилитель класса D на IRS2092
вверх