新しいものづくりがわかるメディア

RSS


それ、ラズパイでつくれるよ

それ、ラズパイでつくれるよ——日本語音声認識もできるよ!

「Raspberry Pi」の活用例を紹介する連載企画「それ、ラズパイでつくれるよ」。第6回は、日本語音声認識システム「Julius」を使ってラズパイに人間が話した内容を理解してもらう。

二度手間をなんとかしたい!

最近のマンションのセキュリティは非常に堅く作られている。私がこの頃出入りしているマンションでは、エントランスに入る時とエレベーターに乗る時にそれぞれ部屋番号を端末で入力しないと扉が開かない。来訪者がエントランスからエレベーターまで移動している間、住人がモニターの前で待っている姿はすごく滑稽だ。そこで、2回目くらいはボタンを押して認証するのではなく「開けて!」と叫ぶだけでラズパイが解錠できるようにしてみよう。せっかくのセキュリティをガバガバにしてしまう恐れはあるがやってみよう!

音声認識を用いて「開けて!」を検出し、解錠ボタンをモーター制御で押してもらう。

用意するもの

  • USBマイク(今回使用したものはサンワサプライ製)
  • サーボモーター
USBマイク USBマイク
サーボモーター サーボモーター

音声認識システム「Julius」のインストール

Juliusは音声認識を行うオープンソースのソフトウェア。モジュールモードというモードを用いると、リアルタイムに話した内容を認識できる優れものだ。なのだが、私の環境ではインストールからちゃんと動かすまでが非常に難しかった。今回のコピペに重みを感じてしまうのはそのせいだ。

まずはアップデート。

$ sudo apt-get update
$ sudo apt-get upgrade

USBマイクをラズパイのUSBポートに挿入し、認識されていることを確認。

$ lsusb

画像のようにC-Mediaと書かれているものが出て入ればOK(この製品の場合)。次に音声入力デバイスの設定を行うために、割り振られているカード番号やデバイス番号と呼ばれている数字を確認する。

$ arecord -l

この数字は環境によって変わる可能性があるのでよく確認する。私の環境ではカード1のデバイス0だった。この数字を使って音声入力デバイスの設定を行う。

$ export ALSADEV="plughw:1,0"

「plughw:」の後の数字は、「カード番号,デバイス番号」とする。このまま何もしないと再起動時に何度も実行しなければならないので、

$ sudo nano /etc/profile

などで、/etc/profileにexport ALSADEV=“1:0”を追記。

これでデバイスの準備はOK。Juliusのインストールを始めよう。まずは必要なライブラリをインストール。

$ sudo aptitude install libasound2-dev

次にJulius本体をダウンロード、インストールする。

$ cd
$ sudo wget -O julius-4.4.2.tar.gz https://github.com/julius-speech/julius/archive/v4.4.2.tar.gz
$ tar zxvf julius-4.4.2.tar.gz
$ cd Julius-4.4.2/
$ ./configure --with-mictype=alsa
$ make
$ sudo make install

./configureの後についている「--with-mictype=alsa」がキモで、これを付けないと無情なエラーと対面することとなる。続いて認識率を上げたり自分用の辞書を作ったりするために、ディクテーションキットと文法認識キットをダウンロードする。データサイズが大きめなので少し時間がかかる。容量不足にも注意しよう。

~/Julius-4.4.2/のディレクトリで

$ mkdir julius-kit
$ cd julius-kit
$ sudo wget https://osdn.net/dl/julius/dictation-kit-v4.4.zip
$ sudo wget -O grammar-kit-v4.3.1.zip https://github.com/julius-speech/grammar-kit/archive/v4.3.1.zip
$ unzip dictation-kit-v4.4.zip
$ unzip grammar-kit-v4.3.1.zip

Juliusのテストをやってみよう。

$ julius -C ~/Julius-4.4.2/Julius-kit/grammar-kit-4.3.1/testmic.jconf -charconv SJIS UTF-8

画像のようにplease speakと出ればOK。「リンゴ」「ミカン」「ブドウ」を認識できるサンプルなので、「ブドウ3個ください」と話しかけてみよう。

自分用の辞書を作る

Juliusでは自分用辞書を作ることで必要のない言葉の検索をやめさせ、自分の用途に合わせて音声の認識率を上げることができる。今回は「開けて!」などだけ認識できればいいので「コマネチ!」のような言葉は認識しなくてよいということだ。辞書をJuliusに読み込ませるためには、音素データと文法データを作成、処理し、設定ファイルを作らなくてはならない。Juliusのテストで読み込んでいたstmic.jconfも設定ファイルのひとつだ。

まず音素データを作る。拡張子は.voca。エンコードはEUC-JPとした。

$ cd ~/Julius-4.4.2/gramtools/mkdfa
$ vim akete.voca

% AKETE
開けて a k e t e
聞いて k i i t e
どうぞ d o u z o
コマネチ k o m a n e ch i
% PLEASE
ください k u d a s a i
% NS_B
[s] silB
% NS_E
[s] silE

音素データはローマ字で記述し、スペースで区切る。%から始まる行はカテゴリと呼ばれ、文法ファイルを作るときに使う。NS_BとNS_Eは文頭および文末に必ず必要となる要素なので書いておこう。続いて文法データ。拡張子は.grammarだ。

$ vim akete.grammar

S : NS_B AKETE PLEASE NS_E

音素データと文法データは対になるものなので同じ名前にしておく。これに謎の処理を行う。

$ sudo cp -b ~/Julius-4.4.2/gramtools/mkdfa/mkfa-1.44-flex/mkfa ~/Julius-4.4.2/gramtools/mkdfa/mkfa
$ sudo cp -b ./Julius-4.4.2/gramtools/dfa_minimize/dfa_minimize ~/julius-4.4.2/gramtools/mkdfa/dfa_minimize
$ sudo ~/Julius-4.4.2/gramtools/mkdfa/mkdfa.pl akete

とすると、akete.dfa,akete.term,akete.dictの3つのファイルが作成される。

$ cp akete.dfa akete.term akete.dict ~/Julius-4.4.2/Julius-kit/grammar-kit-4.3.1

設定ファイルを作るのは少し大変なので、テスト用の設定ファイルを改変する。

$ ~/Julius-4.4.2/Julius-kit/grammar-kit-4.3.1
$ vim testmic.jconf

-gram akete
-C hmm_ptm.jcomf
-input mic –demo

と書き換えて、実行してみる。先ほどとエンコードの部分が違うので注意。

$ julius -C testmic.jconf -charconv EUC-JP UTF-8

これで音声認識の準備はOK。

サーボモーターを動かそう

サーボモーターはロボットアームなどにも用いられるモーターで、アームの位置(角度)や回転する速度を制御できる。今回用いるサーボモーターでは、PWM(Pulse Width Modulation)と呼ばれる電圧パルスの幅による制御を、GPIOを使って行う。

まずは接続。図のようにつなぐ。

サーボモーターの接続方法 サーボモーターの接続方法

次にサーボの制御に必要なライブラリをインストール。

$ cd
$ sudo apt-get install libi2c-dev
$ git clone git://git.drogon.net/wiringPi
$ cd wiringPi
$ ./build

Pythonスクリプトでサーボを動かしてみよう。

import wiringpi
import time
import sys

servo_pin  =  18
param = sys.argv
set_degree = int(param[1])
print(set_degree)

wiringpi.wiringPiSetupGpio()
wiringpi.pinMode( servo_pin, 2 )
wiringpi.pwmSetMode(0)
wiringpi.pwmSetRange(1024)
wiringpi.pwmSetClock(375)

if ( set_degree <= 90 and set_degree >= -90 ):
	move_deg = int( 81 + 41 / 90 * set_degree )
	wiringpi.pwmWrite( servo_pin, move_deg )

をservo_test.pyなどとして保存。

$ sudo python3 servo_test XX

XXは-90から90の数字を入力。サーボモーターは動いただろうか? サーボモーターの準備は以上。

開けゴマ

あとはJuliusで認識した後、サーボモーターで解錠ボタンを押してあげれば良い。USBマイクとサーボモーターを接続したラズパイを、

こう!

ラズパイのGUI画面を使っている方はターミナルを二つ立ち上げ、一方では、

$ julius -C ~/Julius-4.4.2/Julius-kit/grammar-kit-4.3.1 -charconv EUC-JP UTF-8 –module

もう一方では、

import socket
import wiringpi
import time
import sys

servo1_pin  =  12

wiringpi.wiringPiSetupGpio()
wiringpi.pinMode( servo1_pin, 2 )
wiringpi.pwmSetMode(0)
wiringpi.pwmSetRange(1024)
wiringpi.pwmSetClock(375)

def ServoMyServo(set_degree, word):
    if word == 'ringo':
        if ( set_degree <= 90 and set_degree >= -90 ):
        	move_deg = int( 81 + 41 / 90 * set_degree )
        	wiringpi.pwmWrite( servo1_pin, move_deg )
    elif word == 'mikan':
        if ( set_degree <= 90 and set_degree >= -90 ):
        	move_deg = int( 81 + 41 / 90 * set_degree )
        	wiringpi.pwmWrite( servo2_pin, move_deg )

def word(recv_data):
    for line in recv_data.split('\n'):
        index1 = line.find('WORD="')
        index2 = line.find('CM="')
        if index1!=-1:
            WORD = line[index1+6:line.find('"',index1+6)]
            if index2!=-1:
                CM = float(line[index2+4:line.find('"',index2+4)])
                if(WORD!='[s]' and WORD!='[/s]'):
                    if WORD == '開けて' and CM >= 0.97:
                        print(WORD)
                        print(CM)
                        ServoMyServo(30, 'ringo')
                        time.sleep(1)
                        ServoMyServo(0, 'ringo')
                    elif WORD == 'どうぞ' and CM >= 0.97:
                        print(WORD)
                        print(CM)
                        ServoMyServo(30, 'ringo')
                        time.sleep(1)
                        ServoMyServo(0, 'ringo')
                    elif WORD == 'コマネチ' and CM >= 0.97:
                        print(WORD)
                        print(CM)
                        ServoMyServo(30, 'ringo')
                        time.sleep(1)
                        ServoMyServo(0, 'ringo')
                    yield WORD

def main():
    host = 'localhost'
    port = 10500

    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((host, port))

    try:
        data = ''
        while 1:
            if '\n.' in data:
                data = data[data.find(''):].replace('\n.', '')
                print(''.join(word(data)))
                data = ''
            else:
                data = data + client.recv(1024).decode('utf-8')
    except KeyboardInterrupt:
        client.close()

if __name__ == "__main__":
    main()

を、odemukae.pyとして保存して、

$ sudo python3 odemukae.py

として起動すれば開けゴマだ。ピンポンが鳴っても遠くから「コマネチ!」と叫ぶだけで解錠できるようになった。

Juliusは-moduleをつけて起動することでモジュールモードとなり、認識結果をXML形式で受け渡してくれるようになる。odemukae.pyではそれを受け取り、「開けて」「どうぞ」「コマネチ」が認識された時にサーボを動かしている。

今回は、ラズパイを使って音声認識を行なった。辞書の作り方によって自由な内容を判別できるので、ぜひ遊んでみてほしい。

※このコーナーでは、みなさんの「それ、ラズパイでつくれるよ」をお待ちしています。問い合わせフォームからドシドシご応募ください。

参考リンク:
Juliusの使い方(version 4.4.2 対応版): http://www.feijoa.jp/laboratory/raspberrypi/julius442/
Raspberry Pi 3に USB Micを接続して日本語の音声認識をする方法(Julius編): 
http://www.neko.ne.jp/~freewing/raspberry_pi/raspberry_pi_3_julius/
Raspberry Pi 3でpythonを使いサーボモータを動かす: 
https://qiita.com/RyosukeKamei/items/9b15007bf1b77d33764f

ニュース

編集部のおすすめ

連載・シリーズ

注目のキーワード

もっと見る