記事一覧

hal コマンドの解説

公開日時:2016/12/15 21:08

自動インストールスクリプトで HAL をインストールすると、ソケットサーバー「HAL」の起動を簡単にする hal コマンドが作成されます。

この hal コマンドでは、HAL、Julius、voice_client を同時に起動、停止します。HAL を単体で利用する(Julius による音声認識を利用しない)場合は、

sudo php -q /var/www/HAL/system/hal.php

のようにして、hal.php のみを起動して下さい。

起動
sudo hal start
停止
sudo hal stop
再起動
sudo hal restart
sudo hal reboot
HAL の自動起動設定
sudo hal auto
sudo hal enable
HAL の自動起動解除
sudo hal disable

サンプル・アクションを使ってみよう

公開日時:2016/12/15 21:07

ソケットサーバー「HAL」の version 2.0 では、アクションが機能単位に分割され、使いたいアクションのみを選んでインストールしたり、アンインストールしたり出来るようになっています。

ユーザーは自由なアクションを定義して HAL に追加できますが、どのようにアクションを記述したら良いのか分かるよう、サンプルのアクションを用意しています。

以下のサンプルアクションは自由に改変していただいて構いません。お好きなアクションをインストールしていただき、アクション記述の参考にして頂ければ幸いです。

サンプルアクションのインストールとアンインストール

サンプルアクションをインストールするには、

sudo bakepi -g [string アクションタイプ] [string アクション名] [string チェクサム]

のように bakepi コマンドを -g オプションで実行し、HAL を再起動します。例えば voice の chat アクションは

sudo bakepi -g voice chat 19dfd9d6b9a651d39656e9f37554a386b4a24018

のようにした後、

sudo hal restart

とします。

また、アクションをアンインストールするには bakepi コマンドを -r オプションで実行します。

sudo bakepi -r [string アクションタイプ] [string アクション名]

その後、

sudo hal restart

で HAL を再起動して下さい。

サンプルアクション一覧

タイプ アクション名 チェックサム 概要
net brightness 84a1bcdcd109a74fde988448fd7488b00ab75af5 WEBアプリケーションから Raspberry Pi に接続した明るさセンサーにアクセスして値を取得します。
net light 60bf71d127661a285b3c3fd91146f2ed45e61c29 WEBアプリケーションから Raspberry Pi に接続した赤外線 LED を操作し、赤外線リモコン信号を送信します。
sensor volume f74339443f33e7e6cf3484d5eb420e7c25a6da57 Raspberry Pi に接続した半固定抵抗の値を読み取り、Raspberry Pi のボリュームに適用します。
voice chat 19dfd9d6b9a651d39656e9f37554a386b4a24018 雑談を行います。
voice common b5b1255f819abaaa1ce4075b2255aabd097275d6 同意・キャンセルといった、システム共通の対話用アクションです。
voice dummy ea50bc29ba370dcf77b9907494e9e311fbe91f59 Juliusを起動するための初期認識文法を含んだアクションです。
voice joke 1705f52bc78578a0784724065853f4245072c628 冗談を言います。
voice language ad7862413199b69d7596e90aec92ffb405cfdadc 言語切り替え用アクションです。
voice light 6b8feac1257b918df5d524c894ec2dac3d0e51c0 Raspberry Pi に接続した赤外線 LED を操作し、赤外線リモコン信号のスキャンや送信を行います。
voice music edd32f62252783f30d6e7ee587c1dc4f04854d08 プレイリストの再生を行うための認識文法を含んだアクションです。
voice musicPlay 8d654a2d25f22d63f4936acbe257377a8823fe04 音楽リストの取り込みと再生を行います。
voice news 1466136f68de39ef2633bb805c2474fbd9cc9c9a NHK ニュース RSS を取得し、読上げを行います。
voice noodle 89d83b01d034c860ff5aab145c835f8eb3929066 カップラーメンタイマーです。
voice speachEngine bb096dd37e9317c6c6f54c115fae0f98169047fd スピーチエンジンの切り替え用アクションです。
voice system 05b703b91ffd6e68f406c8c9802c3aa4f50dbed4 HAL と Raspberry Pi を操作するシステム用アクションです。
voice temperature 30c49cc0c2765389b7ae54fc79b544faf2a7a536 Raspberry Pi に接続した温度計で、現在の温度を取得します。
voice time c95422de6c9452e9557a0817cb83d73e35d2be5c 現在の時刻を取得します。
voice volume 6de05d8e186af199303926e974b794c9374566f8 Raspberry Pi の音量を操作します。
voice weather 0c8552dfa803b8fe9cb48b744ab30a615912149b livedoor「Weather Hack」から RSS を取得し、読上げを行います。
voice welcomeBack 0eb6b9e187db4ddd28353cdc17a29d36dc90300a Raspberry Pi に接続した人感センサーを使って、あなたの帰宅を迎えてくれます。

サンプルアクション「Voice_Chat」の説明

公開日時:2016/12/14 21:15

サンプルアクション「Voice_Chat」は、簡単な雑談をするサンプルアクションです。

特に難しいことはしていません。音声入力に対して、乱数または時間で、応答メッセージにバリエーションを持たせています。

ソースコード

Chat.yml
## Chat YAML.
---
-
    type:   "ありがとう?"
    do:     "chat_thanx"
-
    type:   "(今日)?は?疲れた(よ|ね)?"
    do:     "chat_tired"
-
    type:   "おはよう?"
    do:     "chat_good_morning"
-
    type:   "おやすみ?"
    do:     "chat_good_night"
-
    type:   "\\A(あなた|お前|君)は?誰\\z"
    do:     "who_are_you"
Chat.php
<?php
/* *
 * 
 * socket server HAL v2.0
 * 
 * (c) 2016 Katsuhiko Miki
 * 
 * */
namespace Feijoa\HAL\Action\Voice;
use Feijoa\HAL as HALSYS;

class Chat extends HALSYS\Action\BaseAction
{

     /**
     * 呼び出し元クラス名を返すImplementsメソッド
     * 
     * @return string       // クラス名
     */
    public static function getClass(){ return __CLASS__; }

    /**
     * インターバル毎のイベント
     * 
     * @param \Feijoa\HAL\HALDto $dto
     */
    public static function sensor(HALSYS\HALDto $dto)
    {
    }

     /**
     * ありがとう
     * 
     * @param \Feijoa\HAL\HALDto $dto
     */
    public static function chat_thanx(HALSYS\HALDto $dto, $read_sock)
    {
        $rand = mt_rand(1, 3);
        switch(true){
             case $rand === 1:
                self::say($dto, "thanx1", "あなたのパートナーとして、当たり前のことです");
                break;
             case $rand === 2:
                self::say($dto, "thanx2", "そう言っていただけるとうれしいです");
                break;
            default:
                self::say($dto, "thanx3", "どういたしまして");
                break;
        }
    }

    /**
     * 疲れた
     * 
     * @param \Feijoa\HAL\HALDto $dto
     */
    public static function chat_tired(HALSYS\HALDto $dto, $read_sock)
    {
        $rand = mt_rand(1, 2);
        switch(true){
            case $rand === 1:
                self::say($dto, "i_am_tired_1", "大丈夫ですか?ゆっくり休んでください");
                break;
            default:
                self::say($dto, "i_am_tired_2", "お疲れ様でした。ビールでも飲んでゆっくりしましょう");
                break;
        }
    }

    public static function chat_good_morning(HALSYS\HALDto $dto, $read_sock)
    {
        $time = (int)date("Hi");
        if($time < 400){
            self::say($dto, "morning_0", "まだ深夜のようですが、よく眠れませんでしたか?");
        } else if($time < 600){
            self::say($dto, "morning_1", "おはようございます。随分お早いですね");
        } else if($time < 900){
            self::say($dto, "morning_2", "おはようございます。");
        } else if($time < 1000){
            self::say($dto, "morning_3", "おはようございます。今日はゆっくりですね");
        } else if($time < 1200){
            self::say($dto, "morning_4", "おはようというには遅すぎるきがします");
        } else if($time < 2359){
            self::say($dto, "morning_5", "どうお返事したら良いのか迷います");
        }
    }

    public static function chat_good_night(HALSYS\HALDto $dto, $read_sock)
    {
        $time = (int)date("Hi");
        if($time < 400){
            self::say($dto, "good_night_0", "遅くまでお疲れ様でした。ゆっくりお休みください");
        } else if($time < 1900){
            self::say($dto, "good_night_1", "変わった時間におやすみになるのですね");
        } else if($time < 2100){
            self::say($dto, "good_night_2", "お早いおやすみですね。ゆっくりお休みください");
        } else {
            self::say($dto, "good_night_3", "おやすみなさい");
        }
    }

    public static function who_are_you(HALSYS\HALDto $dto, $read_sock, $args)
    {
        self::say($dto, "who_are_you", "わたしは:@NAMEです");
    }
}
Chat.julius.yml
## Chat Julius YAML.
---
rules:
    - "SINGLE"
    - "ZATSUDAN_"
    - "WHAT_ ZATSUDAN_"
    - "YOU_ WHO"
alias:
    ZATSUDAN_:
        - "ZATSUDAN"
        - "ZATSUDAN NE"
        - "ZATSUDAN YO"
    WHAT_:
        - "WHAT"
        - "WHAT HA"
        - "WHAT MO"
    YOU_:
        - "YOU"
        - "YOU HA"
words:
    SINGLE:
        -
            word:   "ありがとう"
            kana:   "アリガトウ"
        -
            word:   "おはよう"
            kana:   "オハヨウ"
        -
            word:   "おやすみ"
            kana:   "オヤスミ"
    WHAT:
        -
            word:   "今日"
            kana:   "キョウ"
    ZATSUDAN:
        -
            word:   "疲れた"
            kana:   "ツカレタ"
    YOU:
        -
            word:   "あなた"
            kana:   "アナタ"
        -
            word:   "お前"
            kana:   "オマエ"
        -
            word:   "君"
            kana:   "キミ"
    WHO:
        -
            word:   "誰"
            kana:   "ダレ"
    HA:
        -
            word:   "は"
            kana:   "ワ"
    MO:
        -
            word:   "も"
            kana:   "モ"
    NE:
        -
            word:   "ね"
            kana:   "ネ"
    YO:
        -
            word:   "よ"
            kana:   "ヨ"

ラズパイの最低限セキュリティ・セッティング

公開日時:2016/12/14 21:12

Raspberry Pi を初めて起動したら、最低限しておきたいことを纏めました。付帯情報も書いたので少し長めに見えますが、すること自体はほんの僅かなので 10 分もあれば終わるでしょう。

root パスワードの設定

Linux では、root ユーザーは全ての操作ができる最高権限のユーザーです。このユーザーでログインされるとそのラズパイでできることは全てできてしまうので、そういうことがないように、まず強固なパスワードを設定してしまいましょう。

sudo passwd root

パスワードが 2 回聞かれます。パスワードが一致すれば変更完了です。入力したパスワードは忘れないようにしましょう。

pi ユーザーでログインした後、一時的に root ユーザーに切り替えるには

su -

として、パスワードを入力します。この場合、ホームディレクトリが /root になることを留意して下さい。ホームディレクトリや設定を pi ユーザーのもののままにしたい場合は単に su で切り替えます。

pi ユーザーに戻る場合は

exit

です。

Raspberry Pi のアップデート

sudo apt-get update

apt は Debian 用に開発されたパッケージ管理システムで、アプリケーションの管理を行ってくれます。

apt-get update を行うと、リポジトリ(ソースコード等の情報が保管されているデータベース)からパッケージインデックスファイルを取得し、お使いの OS と再同期します。apt-get update の後で apt-get install を行うと、最適なパッケージが取得できるようになります。

なお、apt-get upgrade というコマンドを実行すると、先程取得したインデックスに従ってお使いのラズパイにインストールされている全てのパッケージを最新版にアップグレードします。これはかなりの時間がかかります。必要な場合のみ行って下さい。

あとは、Raspberry Pi のファームウェアの更新です。ファームウェアを更新したら 再起動 が必要です。

sudo rpi-update

Vim のインストール

Raspberry Pi ではテキストファイルを編集することが頻繁にありますので、テキストエディタを入れておきます。標準でも入って入るのですが、vim-tiny という最小構成のエディタなので、かなり使いづらいと感じるでしょう。

sudo apt-get -y install vim

これで、正規版の Vim が入ります。これ以降の設定では多少のファイルの編集が必要になりますので、Vim の簡単な使い方として 設定ファイルの編集方法を適宜参照して下さい。

※なお、Emacs 派の方は勿論、Emacs をお使い下さい。

SSH と IP アドレスの固定について

最新の Raspbian(RASPBIAN JESSIE WITH PIXEL Version:November 2016 Release date:2016-11-25)では、デフォルトで SSH が無効になりました。

これまでの Raspbian では初回起動直後から SSH が有効であり、デフォルトユーザー pi、デフォルトパスワード raspberry で固定であったためセキュリティ的には穴だらけで、コンピュータに詳しくない人はそのまま運用するなど、かなり危険な状態でした。

今回の Raspbian の仕様変更はそうした背景を考慮しての苦渋の決断だったと聞いています。

さて、前置きが長くなりましたが、だからといって SSH 自体はとても便利な機能であり、使わない手はありません。特に Raspberry Pi は超小型、省電力でサーバーとしても利用できるため、場所をとらず、本棚の隅でひっそりと常時可動させるなどの用途に特に向いています。実際、普通のサーバー用途の場合、常時可動でも月の電気代は50円程度です。

こうした場合、ちょっと設定をいじるためにモニタやキーボードを接続するのは無駄なので、ネットワーク経由で他のパソコンから操作出来たほうが断然便利ですから、やはり、SSH は利用したいでしょう。

SSH で接続できるようにするには、まず、DHCP サーバーが勝手に IP アドレスを変えてしまわないように Raspberry Pi の IP アドレスを固定します。

IP アドレスの固定

sudo vi /etc/dhcpcd.conf

で設定ファイルを開き、

有線 LAN 接続の場合
interface eth0
static ip_address=192.168.**.**/32
static routers=192.168.**.1
static domain_name_servers=192.168.**.1
無線 LAN 接続の場合
interface wlan0
static ip_address=192.168.**.**/32
static routers=192.168.**.1
static domain_name_servers=192.168.**.1

を、/etc/dhcpcd.conf の末尾に追加します。** のあたりはお使いの環境に合わせて下さい。

「static ip_address=192.168.**.**/32」が、固定する IP アドレス、「static routers=192.168.**.**」「static domain_name_servers=192.168.**.**」が、ルーターと DNS サーバーの IP アドレスです。

これに加え、無線 LAN を利用する場合は

sudo sh -c 'wpa_passphrase SSID パスフレーズ >> /etc/wpa_supplicant/wpa_supplicant.conf'

を実行して下さい。SSID とパスフレーズは通常、お使いの無線 LAN 親機の本体に記載されているはずです。上記を実行した後、

sudo cat /etc/wpa_supplicant/wpa_supplicant.conf

で、無線 LAN 接続設定ファイルを開き、

#psk="*************"

の行を削除して下さい。

この行は先程入力したパスフレーズの平文ですので、セキュリティホールになります。# はコメントとなっているため、この行自体をまるごと削除しても何も問題ありません。実際に利用されるパスフレーズは、その下の psk= の行です。

設定が終わったら再起動して下さい。IP アドレスが固定されます。

sudo reboot

SSH 接続用の鍵ファイル作成

ここでは、SSH を安全に利用するための方法を記します。

まず、SSH 接続で使う鍵ファイルを作成します。

cd ~

で、ユーザーのホームディレクトリに移動した後、

ssh-keygen -t rsa

を実行して下さい。以下のようなメッセージが表示されます。鍵ファイルを作成する場所を聞かれているだけなので、特に問題がなければエンターを押すだけで構いません。

Generating public/private rsa key pair.
Enter file in which to save the key (/home/pi/.ssh/id_rsa):

この後、2回パスフレーズの入力が求められるので適当なパスフレーズを入力して下さい。このフレーズ自体はそれほど強固でなくても構いません。(このフレーズは忘れないでください)。

これで、/home/pi/.ssh/ ディレクトリに id_rsa(秘密鍵) と、 id_rsa.pub(公開鍵)が作成されます。

次は、作成された公開鍵を pi ユーザーの公開鍵として登録します。

cat .ssh/id_rsa.pub >> .ssh/authorized_keys

一方、秘密鍵(/home/pi/.ssh/id_rsa)の方は外部から Raspberry Pi にアクセスする際に利用するので、他のパソコンや USB メモリ等にコピーして下さい。この鍵はとても大切なので、絶対に第三者に漏れる事がないようにしてください。

あとは、念のため今までのファイルのアクセス権を pi ユーザーのみ読み書き出来るようにしておきます。

chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa.pub

sshd の設定

鍵ファイルが作成できたら、あとは SSH サーバーの設定の変更です。

sudo vi /etc/ssh/sshd_config

で、設定ファイルを開いて 4 箇所書き換えます。なお、Vim では / をタイプしてから検索したい文字列を入力してエンターを押すことで、任意の文字検索が出来ますので利用して下さい。

ポート番号の変更

通常、不正アクセスを試そうとする人は SSH が動作しているか確認するため、デフォルトポートである 22 番をスキャンします。ここが開いていない場合、殆どの人は諦めて次のサーバーを探します。ですから、SSH で使うポート番号を変えてしまうのが最も手っ取り早いセキュリティ対策です。49152~65535 あたりで好きなポート番号を選んで設定して下さい。(ここで記したので、51327以外が良いでしょう)

# What ports, IPs and protocols we listen for
#Port 22   ← #でコメントアウト
Port 51327
管理者権限での SSH ログインの禁止。必要であれば pi ユーザーでログインしてから管理者権限になります
#PermitRootLogin without-password ← #でコメントアウト
PermitRootLogin no
平文パスワードでのログイン禁止。必ず秘密鍵が必要です。
#PasswordAuthentication yes ← #でコメントアウト
PasswordAuthentication no
空のパスワードでのログイン禁止。上記で秘密鍵が必ず必要になっていますが、一応、空パスワードでのログインも明示的に禁止します
PermitEmptyPasswords no

上記設定が終わったら設定内容を Systemd に反映します。

sudo systemctl daemon-reload

次のコマンドを実行すると、SSH サーバーの自動起動が設定され、Raspberry Pi が起動すると自動で SSH が起動します。

sudo systemctl enable ssh

次のコマンドでSSH サーバーを再起動します。SSH サーバーの停止は stop、再起動は restart に読み替えて下さい。

sudo systemctl start ssh

これで再起動したら、外部のパソコンから、ID とパスワードのみではログインできないこと、id_rsa 秘密鍵のみで SSH 接続出来ること等を確認して下さい。

補足

以前の Raspbian では sudo service sshd restart で sshd を再起動できましたが、2016-11-25-raspbian-jessie からは systemctl コマンド必須に切り替わりました。これは、Debian Jessie からシステム管理が Systemd に変更されたためです。

これまでは暫定的にそれ以前のコマンドもサポートされていましたが、順次、Systemd の作法に則った操作方法に切り替わっているようです。

init.d なども、将来的には廃止されるでしょう。

Juliusの使い方(version 4.4.2 対応版)

公開日時:2016/12/14 21:12

イントロダクション

※Julius 4.3.1 までの記事は Juliusによる音声認識~国産オープンソースライブラリの活用 ラズベリーパイ研究室にあります。

Julius」は、日本の大学やIPAによって開発されているオープンソースの音声認識システムです。Raspberry Pi での音声認識の記事というと、大抵はこのJuliusを利用したもののようです。Google音声認識を利用した例もありますが、ライセンス的にかなり濃いグレーになりますので、ここではJuliusを使った音声認識を取り上げてみたいと思います。

バージョンについて

Juliusの最新バージョンは 4.4.2 となっています。(2016/9/12リリース)

Julius 4.3系からの大きな変更点はあまり無いようで、地道な機能追加とバグフィックスが行われているようです。体感的には、4.3系よりも音声認識が敏感になっているようで、小さな音でも拾ってくれるようになった感じがありますが、拾いすぎて認識文法を使った用途でゃ誤認識が多くなったように感じます。この辺はトレードオフですね。

なお、Julius のソースコードは時代の流れに即して GitHub で公開されるようになりましたので、git clone コマンドで入手できるようになりました。

ダウンロード

Julius 本体をダウンロードするには、まず、git をインストールします。

git --version

で、git version 2.1.4 といった情報が表示されない場合は未インストールですので、

sudo apt-get install libi2c-dev
sudo apt-get install git-core

で、git をインストールしてください。

合わせて、ビルドしたソフトウェアの管理アプリケーション paco をインストールします。

sudo apt-get install paco

※paco は 2014 年でメンテナンスが終了しており、現在は次期プロダクトの porg に移行しているようです。paco で管理していたデータを porg に移行するのも簡単なようなので、状況次第で、当サイトも porg に切り替えていきます。

git と paco の準備が整ったら、Julius のソースコードを GitHub から入手します。

cd ~

git clone https://github.com/julius-speech/julius.git

これで Julius のソースコードが入右手できたので、以下のコマンドを順次実行してインストールします。

cd julius
./configure --enable-words-int
make
sudo paco -lD "make install"

これで、Julius のコンパイルとインストールは完了です。

julius -version

で、正しくインストールされているか確認してください。また、以下のコマンドで paco で管理できていることを確認できます。

paco -a

Julius をアンインストールする場合は、

sudo paco -r パッケージ名(この場合はjulius)

とするだです。簡単ですね。

加えて、Julius の実行時に必要なカーネルモジュールを有効化します。

sudo modprobe snd-pcm-oss
sudo sh -c "echo snd-pcm-oss >> /etc/modules"

追加モジュール

併せて、ディクテーションキットと文法認識キットをダウンロードします。ディクテーションキットはディクテーション(自動口述筆記)に必要な最小限モデルが含まれたキット、文法認識キットは実用的な音声認識を行うために定型の文法を用いるためのキットです。

Julius のディレクトリから抜けて、2つのキットをwgetします。こちらはコンパイルする必要はありません。解凍して julius-kits ディレクトリに纏めておきます。

cd ../
wget -O dictation-kit-v4.4.zip "https://osdn.net/frs/redir.php?m=jaist&f=%2Fjulius%2F66544%2Fdictation-kit-v4.4.zip"

wget -O grammar-kit-4.3.1.zip "https://github.com/julius-speech/grammar-kit/archive/v4.3.1.zip"
unzip dictation-kit-v4.4.zip
unzip grammar-kit-4.3.1.zip

mkdir julius-kits

mv dictation-kit-v4.4 julius-kits/
mv grammar-kit-4.3.1 julius-kits/

マイクのテスト

音声認識をさせるためにはマイクが必要です。Raspberry Pi にはアナログマイク端子が無いのでUSBマイクを利用するのが一番効率が良いかと思います。

弊社でテストしたマイクはこちらです。

MM-MCUSB16 の方はシンプルなマイクで単一指向性ですが、MM-MCUB22 の方は全指向性でミュートボタンもついています。

特に MM-MCUB22 の方はかなり感度がよく良く音を拾いますが、物を置いた時の雑音など小さな音も拾うので、記述文法を使った限定的な音声認識では逆に誤認識が多くなるケースもあります。この場合はミュートボタンを使って適切に切り替えを行う事で対処して下さい。

なお、アナログマイクを利用されたい場合はUSB変換アダプターを利用する方法もあります。変換アダプターはノイズが多い物がありますので、弊社がテストした中ではこちらがお勧めです。

PlugableR USB オーディオ変換アダプタ 3.5mm ヘッドホン・マイク端子付(黒アルミニウム仕上げ、C-Media社CM108 チップ採用、Windows、Mac、 Linux 対応)

音声認識設定

マイクをRaspberry Pi に刺し、オーディオカードの優先順位を確認します。Julius では、マイクのサウンドカードが 0 番に設定されていないとエラーが出るようですので、マイクを優先させます。(Julius の設定で変更できるかどうかは不明です)

sudo cat /proc/asound/modules
 0 snd_usb_audio
 1 snd_bcm2835

上記の様に snd_usb_audio が上にあればUSBデバイスがオンボードのサウンドカードよりも優先されています。下にあった場合はUSBデバイスの優先度を上げるため、以下のように設定ファイルを作成します。

sudo vi /etc/modprobe.d/alsa-base.conf

で開いた設定ファイルを新規作成します。

options snd slots=snd_usb_audio,snd_bcm2835
options snd_usb_audio index=0
options snd_bcm2835 index=1

設定ファイルを保存して Raspberry Pi を再起動すると、USBオーディカードが優先されているはずです。再び sudo cat /proc/asound/modules で優先順位を確認してください。

いよいよ録音テストです。まずマイクのカード設定を確認します。

arecord -l

以下のような表示が出れば、マイクは認識されています。この場合、カード 0、デバイス 0 です。

i@raspberrypi:~ $ arecord -l
**** ハードウェアデバイス CAPTURE のリスト ****
カード 0: Device [USB Audio Device], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 0/1
  サブデバイス #0: subdevice #0

次はマイクの音量を調節します。 -c オプションでカード番号を指定し、sset コンテンツ名 設定値 の順で値を設定します。

sudo amixer -c 0 sset 'Mic' 90%

マイクの調整が終わったら、次はスピーカーです。

aplay -l

次のようなリストが返るかと思います。この場合、カード 1、デバイス 0 がアナログスピーカー、カード 1、デバイス 1 が HDMI 出力です。

**** ハードウェアデバイス PLAYBACK のリスト ****
カード 1: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
  サブデバイス: 8/8
  サブデバイス #0: subdevice #0
  サブデバイス #1: subdevice #1
  サブデバイス #2: subdevice #2
  サブデバイス #3: subdevice #3
  サブデバイス #4: subdevice #4
  サブデバイス #5: subdevice #5
  サブデバイス #6: subdevice #6
  サブデバイス #7: subdevice #7
カード 1: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0

以下で、音声のコントロールセッティングが確認できます。

amixer controls

次のようなリストが確認できます。

pi@raspberrypi:~ $ amixer controls
numid=2,iface=MIXER,name='Mic Capture Switch'
numid=3,iface=MIXER,name='Mic Capture Volume'
numid=1,iface=PCM,name='Capture Channel Map'

参考)Sound configuration on Raspberry Pi with ALSA

この numid を使って、優先するカードを設定します。1 がアナログ出力、2 が HDMI、0 が自動認識です。

amixer -c 1 cset numid=3 1

HDMI端子は音の立ち上がりが遅いため、再生の最初が途切れてしまいます。このため、今回はアナログ端子でテストを行います。サンプルファイルを再生してみましょう。

スピーカーの音量を設定します。 -c と sset の意味は、マイクの時と同じです。

sudo amixer -c 1 sset 'PCM' 95%

では、サンプル音源を再生してみましょう。

aplay -D plughw:1,0 /usr/share/sounds/alsa/Front_Center.wav

無事、音声が再生されたでしょうか?

あとは録音・再生テストです。以下で、録音データが test.wav というファイルで書き出されます。録音を中止するにはCtrl + C を押してください。

arecord -D plughw:0,0 -f cd test.wav

-f cd というのは、16 bit little endian, 44100Hz, stereo のフォーマットで録音する事のようです。

参考)arecord(1) - Linux man page

再生してみましょう。

aplay -D plughw:1,0 test.wav

音声が再生されれば音声認識の準備は完了です。

Juliusでの音声認識

さて、では実際に Julius で音声認識です。最初はディクテーションキットを使って音声認識してみましょう。

cd julius-kits/dictation-kit-v4.3.1-linux
julius -C main.jconf -C am-gmm.jconf -demo

このキットは特定の文法や単語の定義セットを用いずに音声を認識するのでかなり時間がかかります。

まず、Raspberry Pi 3 の Julius 4.4 で認識を行ってみます。

補足ですが、Raspberry Pi 2 の Julius 4.3.1 の時の認識。処理速度は上がっていますが、認識精度は落ちているような…

このように自由文章ではかなり時間がかかるため、あらかじめ予想される文法を登録する「記述文法」を使って認識速度を向上させます。

このように自由文章ではかなり時間がかかるため、あらかじめ予想される文法を登録する「記述文法」を使って認識速度を向上させます。

文法ファイル作成

まず、voca ファイルに発音音素列を記述します。記述はローマ字(ヘボン式のようです)で行います。区切り文字は半角スペースです。

%で始まる行は、カテゴリ登録です。この後、構文制約ファイルを作成するときに使います。

"NS_B" と "NS_E" はそれぞれ文頭および文末の「無音区間」に対応する単語カテゴリで、文の最初と最後に必ず挿入する必要があります。

vi kaden.voca
% KADEN
テレビ   t e r e b i
電気    d e n k i
% WO        
を      w o 
% PLEASE    
つけて   t u k e t e
消して   k e sh i t e
% NS_B
[s]     silB
% NS_E
[s]     silE

次に、 構文制約を行うための grammar ファイルを作成します。

vi kaden.grammar
S      : NS_B KADEN_ PLEASE NS_E
KADEN_ : KADEN
KADEN_ : KADEN WO

KADEN と KADEN WO の両方のエイリアスとして KADEN_ を定義しています。これにより「電気つけて」と「電気をつけて」の両方の音声に対し、1つの構文制約で対応できます。

voca ファイルと grammar ファイルは基本的には一対になります。ですので同じ名前にしてください。

両ファイルを作成したらコンパイルを行って .dfa ファイル、.term ファイル、 .dict ファイルを生成するのですが、コンパイルに用いるプログラム mkdfa.pl について、少し注意が必要です。grammar-kit-v4.1 及び julius-4.3.1/gramtools/mkdfa/ に付属している mkdfa.pl(から参照されるmkfa) は正常に動作しないので、julius ディレクトリ内にある対応版の mkfa を利用する必要があります。

このため、以下のコマンドで mkfa と dfa_minimize を julius-4.3.1/gramtools/mkdfa/ 内のファイルと差し替えます。(コピー時に -b オプションを付けているので、旧ファイルは末尾に \~ 付きでバックアップされます)

sudo cp -b ./julius/gramtools/mkdfa/mkfa-1.44-flex/mkfa ./julius/gramtools/mkdfa/mkfa

sudo cp -b ./julius/gramtools/dfa_minimize/dfa_minimize ./julius/gramtools/mkdfa/dfa_minimize

ではコンパイルしてみましょう。

sudo ./julius/gramtools/mkdfa/mkdfa.pl kaden

上手く変換が出来た場合は kaden.dfa kaden.term kaden.dict の3ファイルが作成されます。kaden.dfa ファイルは「有限状態オートマトンに変換したもの」だそうで、構文制約によって定義される発音音素の遷移パターンのようです。kaden.term と kaden.dict の数値がこれに対応するようですが、詳しい仕様はThe Juliusbookを参照してください。

では、作成した .dfa ファイルを用いて音声認識を行ってみます。Julius では、マイクの入力がないと大量の Warning を出力しますが、-nostrip オプションをつけるとこれを抑制できます。

sudo julius -C /home/pi/julius-kits/grammar-kit-4.3.1/hmm_mono.jconf -input mic -gram kaden -nostrip

ディクテーションキットをそのまま使う場合と比べてほぼ実用的な速度になっていると思います。なお、音声認識に用いる文法ファイルですが、以下の様にカンマ区切りで複数列挙すれば同時に利用することも可能です。

julius -C /home/pi/julius-kits/grammar-kit-4.3.1/hmm_mono.jconf -input mic -gram kaden,fruit -nostrip

記事リンク