概要

 Raspberry PiにつないだフルカラーLEDをjuliusでの認識結果に応じて操作させることにチャレンジし、無事操作させることができた。


背景と目的

 前回、認識させたい言葉を自分で定義し、それが認識されることが確認できた。そこで、今回はその仕組みを利用し、Raspberry PiにつないだフルカラーLEDを操作できるようにPythonスクリプトを作成し、動作を確認する。


詳細

1.Pythonスクリプトで、juliusをモジュールモードで起動、終了させる

 他のプログラムでjuliusとやりとりするには、こちらによればjuliusをモジュールモードと呼ばれる音声認識サーバとして動かせばよさそう。なので、まず以下のシェルスクリプト(start_julius.sh)を作成。Juliusサーバをバックグラウンドプロセスにし、標準出力にプロセスIDを出力させる。また、起動直後サーバ接続するとエラーになるので時間稼ぎのsleep。

julius -C ../julius-kits/dictation-kit-v4.3.1-linux/word.jconf -module > /dev/null &
echo $!
sleep 3

 次に、Pythonスクリプトでは、subprocessモジュールを使って上記シェルスクリプトを実行させる。最後に、killを実行してjuliusのプロセスを殺す。

import subprocess

# julius起動スクリプトを実行
p = subprocess.Popen(["bash start_julius.sh"], stdout=subprocess.PIPE, shell=True)
pid = p.stdout.read() # juliusのプロセスIDを取得
:
:
p.kill() # 起動スクリプトのプロセスを終了
subprocess.call(["kill " + pid], shell=True) # juliusのプロセスを終了
2.Pythonでjuliusの出力をもらう

 juliusの出力をPythonでもらうには、Pythonのsocketモジュールを使えばよいらしいので、こちらを参考に以下のようなコードを書く。Dataという変数に、参考1にあるようなXML形式の文字列が入ってくるので、それをPython側で適当に処理すれば認識結果が取得できるだろう。

import socket

HOST = "192.168.11.7" # アドレス
PORT = 10500 # ポート

# TCPクライアントを作成し接続
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))

# サーバの応答を受信
data = client.recv(1024)
3.フルカラーLEDを音声で操作してみる

 最後に、ラズベリーパイにつないだフルカラーLEDを操作。LEDは、図3.1のようなもので、GPIO17,27,22をHIGHにすればRGBそれぞれが点灯できるようにしてある。

IMG_2793
図3.1 ラズパイにつないだフルカラーLED

 1,2の要素を組み合わせて作成したPythonスクリプトは以下。Dataという変数に入ってきたデータのうち、RECOGOUTという要素をXMLとしてパースし認識されたワードを取り出している。赤、青、緑、白、消灯の5種類に反応できる。

# coding:utf-8
import socket
import subprocess
import xml.etree.ElementTree as ET
import RPi.GPIO as GPIO

HOST = "192.168.11.7"
PORT = 10500

PORT_RED = 17
PORT_GREEN = 27
PORT_BLUE = 22
colors = {
  u"赤" : [True, False, False], \
  u"緑" : [False, True, False], \
  u"青" : [False, False, True], \
  u"白" : [True, True, True], \
  u"消灯" : [False, False, False]
}

GPIO.setmode(GPIO.BCM)
GPIO.setup(PORT_RED, GPIO.OUT)
GPIO.setup(PORT_GREEN, GPIO.OUT)
GPIO.setup(PORT_BLUE, GPIO.OUT)
  
def changeColor(colorName):
  GPIO.output(PORT_RED, colors[colorName][0])
  GPIO.output(PORT_GREEN, colors[colorName][1])
  GPIO.output(PORT_BLUE, colors[colorName][2])
  print colorName

def main():

  # julius起動スクリプトを実行
  p = subprocess.Popen(["bash start_julius.sh"], stdout=subprocess.PIPE, shell=True)
  pid = p.stdout.read() # juliusのプロセスIDを取得
  
  # TCPクライアントを作成し接続
  client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  client.connect((HOST, PORT))

  # サーバからのデータ受信と
  try:
    data = ""
    while 1:
      if "</RECOGOUT>\n." in data:
        # RECOGOUT要素以下をXMLとしてパース
        root = ET.fromstring('<?xml version="1.0"?>\n' + data[data.find("<RECOGOUT>"):].replace("\n.", ""))
        # 言葉を判別
        for whypo in root.findall("./SHYPO/WHYPO"):
          if whypo.get("WORD") in colors.keys():
            # 判別した言葉に応じて色を変える
            changeColor(whypo.get("WORD"))
          else:
            print "Unknown"
        data = ""
      else:
        data = data + client.recv(1024)
  
  except KeyboardInterrupt:
    # CTRL+Cで終了
    print "KeyboardInterrupt occured."
    p.kill() # 
    subprocess.call(["kill " + pid], shell=True) # juliusのプロセスを終了
    client.close()
    GPIO.cleanup()
  
if __name__ == "__main__":
  main()
4.動作確認

 プログラムを実行し、声を発すると、無事5種類の言葉を正しく認識しLEDの色が変わった。非常に簡単なものだが、音声で操作できる装置が作れた!


まとめと今後の課題

 今回のjuliusのお試しを通じて、Raspberry Piを使った音声操作できる装置を作れる可能性が広がった。これを使えばなかなか面白い装置が作れそう。今後も、いろいろなアイディアを試してみたい。