ライザップミク
Raspberry Piで音声認識・音声合成する記事を以前書きました。
これにちょいとハードウェアとプログラムを付け加えてライザップするミクさんをつくってみました。
完成動画
動画は以下のような感じ。
ニコニコ動画で公開しているのは、ライザップの効果音に以下のニコニコ動画でしか使えない素材を使っているので仕方なくというところです。
必要なもの
購入品をまとめておきます。
[asin:B00T356SFO:detail]
Raspberry Pi 2
USBマイク
アクティブスピーカ
[asin:B00VUJ3GYM:detail]
激安サーボモータ(SG90)
ミクさんの人形は、北海道の新千歳空港の初音ミクタウンのガチャガチャでゲットしました。どうも限定みたいなので、気合のある人は買いに行ってください。サーボモータで動かせるくらいのものだったら何でもよいので適当に用意してモータの軸にくっつけて下さい。
何か紙にミクさんの絵を描いて貼り付けるだけでもよいと思います。
その他のSDカード、電源、ディスプレイケーブル等の必要品は、以下のセットアップの記事を参考に各自必要なものを買ってください。
ハードウェアセットアップ
以下のとおり接続します
- USBマイクをRaspberry PiのUSBポートに接続
- アクティブスピーカのオーディオコネクタをRaspberry Piのヘッドフォン端子に接続。電源はRaspberry PiのUSBポートからとりましょう
- 激安サーボモータをRaspberry PiのGPIOコネクタに接続。具体的には以下のような感じ
黒:GND(6pinとか)
赤:Vcc(2pinか4pin)
オレンジ:(12pin)
ソフトウェアセットアップ
以下ソフト関係のセットアップ。ここからはLinuxのコマンドやプログラム(宇宙語)が続くので興味ある方のみ続きをクリックください。
音声認識辞書作成
エディタで辞書ファイルを作成します。
$ vi recog.yomi
ファイルの中身は以下としてください。以下の例だと「みく」と認識すると「C1」というコマンドに対応。「こんにちは」と認識すると「C2」というコマンドに対応するようになります。
C1 みく C2 こんにちは
あとは、辞書を変換して移動
$ iconv -f utf8 -t eucjp recog.yomi | yomi2voca.pl > recog.dic $ mv recog.dic ./julius-kits/dictation-kit-v4.2.3
WiringPiセットアップ
音声に反応して、サーボモータを介してミクさんが動くようにします。サーボモータを動かすために、WiringPiを使ってRaspberry PiのGPIO端子を制御するので、WiringPiをセットアップします。
WiringPiのインストールのため以下コマンド実行
$ git clone git://git.drogon.net/wiringPi
$ cd WiringPi
$ ./build
次にpythonでWiringPiを使うため、以下コマンドでWiringPi2-Pythonのインストール
$ cd $ sudo apt-get update $ sudo apt-get install python-dev python-setuptools $ git clone https://github.com/Gadgetoid/WiringPi2-Python.git $ cd WiringPi2-Python $ sudo python setup.py install
WiringPiのピン配置は以下参照。プログラムでwiringPiSetup()という関数を使用して設定すると以下のピン配置になります。wiringPiSetupGpio()だといわゆる普通(?)のRaspberry Piのピン配置になるようです。
mikusan.py
メインプログラムとなるmikusan.pyというスクリプトを作成
$ vi mikusan.py
mikusan.pyの中身は以下ね
#!/usr/bin/env python # -*- coding: utf-8 -*- import socket #import serial import xml.etree.ElementTree as ET import subprocess import time import wiringpi2 as wiringpi host = 'localhost' port = 10500 # port setting SERVO = 4 wiringpi.wiringPiSetup() wiringpi.pinMode(SERVO,1) wiringpi.softPwmCreate(SERVO,0,100) # Setup PWM using Pin, Initial Value and Range parameters def miku(): # music cmd ="aplay -Dhw:1,0 /home/pi/rz.wav&" subprocess.call(cmd, shell=True) # action wiringpi.delay(500) for time in range(0,2): for brightness in range(0,100): # Going from 0 to 100 will give us full off to full on wiringpi.softPwmWrite(SERVO,brightness) # Change PWM duty cycle wiringpi.delay(10) # Delay for 0.2 seconds for brightness in reversed(range(0,100)): wiringpi.softPwmWrite(SERVO,brightness) wiringpi.delay(10) for time in range(0,3): for brightness in range(0,100): # Going from 0 to 100 will give us full off to full on wiringpi.softPwmWrite(SERVO,brightness) # Change PWM duty cycle wiringpi.delay(5) # Delay for 0.2 seconds for brightness in reversed(range(0,100)): wiringpi.softPwmWrite(SERVO,brightness) wiringpi.delay(5) wiringpi.delay(600) for time in range(0,2): for brightness in range(0,100): # Going from 0 to 100 will give us full off to full on wiringpi.softPwmWrite(SERVO,brightness) # Change PWM duty cycle wiringpi.delay(10) # Delay for 0.2 seconds for brightness in reversed(range(0,100)): wiringpi.softPwmWrite(SERVO,brightness) wiringpi.delay(10) for time in range(0,3): for brightness in range(0,100): # Going from 0 to 100 will give us full off to full on wiringpi.softPwmWrite(SERVO,brightness) # Change PWM duty cycle wiringpi.delay(5) # Delay for 0.2 seconds for brightness in reversed(range(0,100)): wiringpi.softPwmWrite(SERVO,brightness) wiringpi.delay(5) def hello(): # voice cmd ="/home/pi/soft/aquestalkpi/AquesTalkPi こんにちは: | aplay -Dhw:1,0&" subprocess.call(cmd, shell=True) # action for time in range(0,2): for brightness in range(0,80): # Going from 0 to 100 will give us full off to full on wiringpi.softPwmWrite(SERVO,brightness) # Change PWM duty cycle wiringpi.delay(2) # Delay for 0.2 seconds for brightness in reversed(range(0,80)): wiringpi.softPwmWrite(SERVO,brightness) wiringpi.delay(2) clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) clientsock.connect((host, port)) sf = clientsock.makefile('rb') while True: line = sf.readline().decode('utf-8') if line.find('WHYPO') != -1: print line if line.find(u'C1') != -1: print("miku") miku() elif line.find(u'C2') != -1: print("hello") hello()
スクリプトに実行権限与えて、/usr/local/bin/ 以下に移動
$ chmod 755 mikusan.py $ sudo cp mikusan.py /usr/local/bin/
mikusan.sh
次にmikusan.shというプログラムを作成。juliusを起動してから mikusan.pyを立ち上げるというだけのプログラム。
$ vi mikusan.sh
中身は以下ね。
#!/bin/sh julius -C /home/pi/julius-kits/dictation-kit-v4.2.3/recog.jconf & sleep 5 mikusan.py & exit 0
めっちゃ手抜きです…本当はjuliusの正常起動フラグをみてから次のプログラムを起動するべきとは思うのですが適当にスリープを入れて対処というダメダメプログラム。2行目のrecog.jconfのファイルの場所は自分の環境に合わせて適宜変更してあげてください。
実行権限与えて /usr/local/bin/ 以下に移動
$ chmod 755 mikusan.sh $ sudo cp mikusan.sh /usr/local/bin/
mikusan自動起動
最後に、自動起動させるためのプログラム。その名もmikusan を作成
$ vi mikusan
中身は以下
### BEGIN INIT INFO # Provides: mikusan # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start Mikusan at boot time # Description: Start Mikusan at boot time ### END INIT INFO #! /bin/sh # /etc/init.d/mikusan DAEMON=/usr/local/bin/mikusan.sh case "$1" in start) echo -n "Starting Mikusan" sudo $DAEMON ;; stop) echo -n "Stopping Mikusan" sudo killall julius sudo killall python ;; esac exit 0
実行権限与えて /etc/init.d/ 以下に移動
$ chmod 755 mikusan $ sudo cp mikusan /etc/init.d/
プログラムはこれでOK。
ソフト動作確認
続いて順に動作確認。まずは「mikusan.py」が正しく動くか。
$ julius -C
$ sudo mikusan.py
これで「ミク」とか話しかけてみましょう。動いたらもうできたも同然。うまく動かなかったら、残念でしたね。そういうこともあります。「mikusan.py」とかハードの接続チェックしてみましょう。それでもダメだったら私が何か誤記しているのかもしれないです。大変申し訳ないことです。
無事動いたの確認できたら一旦停止しましょう。
$ killall julius $ sudo killall python
次に「mikusan.sh」実行して一つのコマンドでjulius起動と「mikusan.py」起動して無事動くこと確認
$ sudo mikusan.sh
多分これは動くでしょ。ダメだったら再起動とかしてみるとひょっとしたらうまくいくかも。うまくいったら、また一旦停止
$ killall julius $ sudo killall python
サービス起動の確認。これで起動すればOK。
$ sudo /etc/init.d/mikusan start
stop(停止)は、実は手抜きスクリプトなのでできません…ごめんちゃい、誰か直して。
あとは、以下のコマンドを実行して自動起動の設定をします。
$ sudo update-rc.d mikusan defaults
この後、再起動すると、プログラムが自動で起動してミクさんが声に反応してくれるようになります。これで完了です。お疲れ様でした。自動起動を止めたくなったら以下コマンドを実行してください。
$ sudo update-rc.d mikusan remove
まとめ
音声認識、最初に参考にしたサイトのプログラムがうまく動かなかったりして意外に難しかったです。正直もうちょっとスマートなプログラムにしたい気もしますが、今回は諦めました。誰かもっと良い例教えてくれると嬉しいです。
試した感じは、結構正しく認識するなという印象ですが、ざわざわしているところだとどうなるかは不明です。家とかなら普通に使えそうな印象を持ちました。フリーでこれだけできちゃうのは凄いですね。リモコン制御とかやったら便利そうな気もするけど、おおよそ結果が見えているのとそれだけのためにRaspberry Piの電源入れっぱなしはちょっとイマイチな気もするのでちょっと迷い中です。なんかもっと役に立たない電波なことをしたいなという気がします。
関連記事
参考リンク
参考にしたサイトや、似たようなことをしているサイト。どうも私の説明が怪しいなと感じたら、以下のサイトを信じてみるのも一つの作戦です。
工作と小物のがらくた部屋: Raspduino (Raspberry Pi 用GPIOアダプタ) 動作確認1
Devel/電子工作/irMagician/赤外線学習リモコンR2-D2 - cubic9.com