ラズパイを音声でシャットダウン
車にラズパイを持ち込んで使いたいけど
シャットダウンするときに困りそうなので
音声でシャットダウンできるようにする
bluetooth ボタンも考えたけど
ハズレをひくと買い直しになるし紛失を考えると
音声でシャットダウンし
シガーソケットから給電すればエンジンをかければ電源がはいる
音声認識エンジンJulius をまずはいれる
Raspberry Pi×JuliusとPythonでスマートスピーカー風にカメラを操作
Raspberry PiとJuliusで特定の単語を認識させる
を参考に
mkdir julius cd julius/ wget https://github.com/julius-speech/julius/archive/v4.4.2.1.tar.gz tar xvzf v4.4.2.1.tar.gz cd julius-4.4.2.1/
でGit で取得し展開したファイルに移動
sudo apt-get install libasound2-dev libesd0-dev libsndfile1-dev
で必要なライブラリのインストール
Raspberry pi3B+でjuliusを動かせるようになるまでの覚書き(2019.3.10現在)
にあるように
RaspberryPi3b+の最新カーネルでは
snd-pcm-ossモジュールが含まれていないので
sudo apt-get install osspd-alsa sudo apt-get install libasound2-dev
でサウンドドライバをインストール
./configure --with-mictype=alsa make sudo make install
でコンパイルしてインストール
次に音声認識パッケージの
ディクテーションキットの取得
cd ../ mkdir julius-kit cd julius-kit/ wget https://osdn.net/dl/julius/dictation-kit-v4.4.zip unzip dictation-kit-v4.4.zip
で取得
さらに必要なライブラリのインストール
sudo apt-get install alsa-utils sox libsox-fmt-all
次にマイクの設定
arecord -l
の結果が
**** ハードウェアデバイス CAPTURE のリスト **** カード 2: Device [USB PnP Sound Device], デバイス 0: USB Audio [USB Audio] サブデバイス: 1/1 サブデバイス #0: subdevice #0
これを元に
ALSADEV設定で使用デバイスを指定
vim ~/.profile
で設定ファイルを開き
export ALSADEV=hw:2
を最終行へ追記
hw;にはカード番号を記述
source ~/.profile
で設定反映
あとは起動して実験
cd ~/julius/julius-kit/dictation-kit-v4.4 julius -C main.jconf -C am-gmm.jconf -demo
起動はするけど精度が低すぎて使い物にならない
このため辞書ファイルを作成する
日本語入力ができるように mozc をインストール
sudo apt-get install fcitx-mozc
次に辞書ファイルの作成
cd ~/julius/ mkdir dict cd dict/
sudo vim hello.yomi
でファイルを作成
おはよう おはよう こんにちわ こんにちわ
として保存
左に認識させる言葉
右にはよみかたをひらがなで記述して
.yomi という拡張子で保存
区切りのスペースを半角にしないとバグるので注意
これを元に音素ファイルを作成する
このときに文字コードをUTF8 から EUC-JP に変換するので
iconv -f utf8 -t eucjp hello.yomi | ../julius-4.4.2.1/gramtools/yomi2voca/yomi2voca.pl | iconv -f eucjp -t utf8 > hello.phone
これでファイルが作成される
拡張子は
.phone となる
内容は
おはよう o h a y o u こんにちわ k o N n i ch i w a
となる
次に構文ファイルの作成
これで
認識する文章の構成を定義している
sudo vim hello.grammar
でファイルを作成
S : NS_B HELLO NS_E HELLO OHAYOU HELLO KONNICHIWA
として保存
S : NS_B HELLO NS_E
で
NS_Bが文章の開始
NS_Eが文章の終了
という意味
HELLO OHAYOU
HELLO KONNICHIWA
の部分は
.phone ファイルの読みを大文字にしたもの
あとは語彙ファイルの作成
これはJulius に認識させたい言葉を定義するもので
拡張子は
.voca になる
sudo cp hello.phone hello.voca
でファイルをコピーし編集
% OHAYOU おはよう o h a y o u % KONNICHIWA こんにちは k o N n i ch i w a % NS_B [s] silB % NS_E [/s] silE
というようにする
次に辞書ファイルへ変換
cd ~/julius/julius-4.4.2.1/gramtools/mkdfa/ mkdfa.pl ~/julius/dict/hello
を実行したがエラー
/home/pi/julius/dict/hello.grammar has 3 rules /home/pi/julius/dict/hello.voca has 4 categories and 4 words --- Now parsing grammar file Error: parse error Error: cannot open "/home/pi/julius/dict/hello.dfa.tmp" --- no .dfa or .dict file generated
となる
このため
julius 辞書 自作
で検索
をみたところ
grammar ファイルの区切りで
:
で区切っていないので修正
cd julius/dict/ sudo vim hello.grammar
でファイル編集
S : NS_B HELLO NS_E HELLO : OHAYOU HELLO : KONNICHIWA
として保存
mkdfa.pl ~/julius/dict/hello
を実行すると
.dfa
.term
.dict
ファイルが生成される
これで独自辞書ができたので
音声認識をするため
julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/julius/dict/hello -input mic
を実行
これで辞書ファイルへ登録した
おはよう
こんにちわ
だけは認識するようになるが
それ以外は表示されない
次に辞書の追加
Raspberry Pi×JuliusとPythonでスマートスピーカー風にカメラを操作
を参考に
.yomi ファイルを編集
おはよう おはよう こんにちわ こんにちわ 電源オフ でんげんおふ
として保存
iconv -f utf8 -t eucjp hello.yomi | ../julius-4.4.2.1/gramtools/yomi2voca/yomi2voca.pl | iconv -f eucjp -t utf8 > hello.phone
を実行
sudo vim hello.grammar
でファイルを編集
S : NS_B HELLO NS_E HELLO : OHAYOU HELLO : KONNICHIWA HELLO : DENGENNOHU
として保存
sudo vim hello.voca
でファイルを編集
% OHAYOU おはよう o h a y o u % KONNICHIWA こんにちは k o N n i ch i w a % DENGENNOHU 電源オフ d e N g e N o f u % NS_B [s] silB % NS_E [/s] silE
として保存
mkdfa.pl ~/julius/dict/hello
で辞書ファイル作成
julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/julius/dict/hello -input mic
で
電源オフ
と認識されるのがわかる
次にモジュールモードでJulius の起動
julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/julius/dict/hello -input mic -module
これで Julius がサーバとなり
python プログラムとの通信待ちになる
次に
sudo vim speech.py
でファイルを区制
も参考に
いくつかコードも調べてみた
# -*- coding: utf-8 -*-
はpython3 なら記載不要
なおインストールしたままの状態だと
python --version
で調べると
Python 2.7.16
Python で文頭に記載する文字コードの「アレ」の名称(なんちゃら UTF-8 みたいなやつ)
を参考に
ファイルの内容は
# -*- coding: utf-8 -*- import socket host = 'localhost' # Raspberry PiのIPアドレス port = 10500 # juliusの待ち受けポート # パソコンからTCP/IPで、自分PCのjuliusサーバに接続 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) res = '' while True: # 音声認識の区切りである「改行+.」がくるまで待つ while (res.find('\n.') == -1): # Juliusから取得した値を格納していく res += sock.recv(1024) # 音声XMLデータから、<WORD>を抽出して音声テキスト文に連結する word ='' for line in res.split('\n'): # Juliusから取得した値から認識文字列の行を探す index = line.find('WORD=') # 認識文字列があったら... if index != -1: # 認識文字列部分だけを抜き取る line = line[index + 6 : line.find('"', index + 6)] # 文字列の開始記号以外を格納していく if line != '[s]': word = word + line # 「電源オフ」という文字列を認識したら... if word == '電源オフ': print("電源オフ") res =''
この後に
sudo python speech.py
とすると
マイクで
電源オフ
と話しかけると
電源オフ
と表示される
これで音声の認識はできたので
次に
python で linux コマンドの実行
これは subprocess モジュールを使うことでできる
Python: subprocessでOSコマンドを実行する
Pythonからシェルコマンドを実行!subprocessでサブプロセスを実行する方法まとめ
を参考に
使い方は
subprocess.run([“実行したいコマンド”,”オプションなど”,…])
でOK
今回はshutdown コマンドを使うので
を参考に
# -*- coding: utf-8 -*- import socket import subprocess cmd = "sudo shutdown -h now" host = 'localhost' # Raspberry PiのIPアドレス port = 10500 # juliusの待ち受けポート # パソコンからTCP/IPで、自分PCのjuliusサーバに接続 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) res = '' while True: # 音声認識の区切りである「改行+.」がくるまで待つ while (res.find('\n.') == -1): # Juliusから取得した値を格納していく res += sock.recv(1024) # 音声XMLデータから、<WORD>を抽出して音声テキスト文に連結する word ='' for line in res.split('\n'): # Juliusから取得した値から認識文字列の行を探す index = line.find('WORD=') # 認識文字列があったら... if index != -1: # 認識文字列部分だけを抜き取る line = line[index + 6 : line.find('"', index + 6)] # 文字列の開始記号以外を格納していく if line != '[s]': word = word + line # 「電源オフ」という文字列を認識したら... if word == '電源オフ': print("電源オフ") subprocess.call(cmd, shell=True) res ='' として保存 再度 sudo python speech.py
を実行し
マイクに電源オフと話すと
電源オフと表示された後にラズパイの電源が落ちる