2017年12月31日日曜日

「実例で学ぶRaspberry Pi電子工作」補足情報トップ

はじめに

本ページは、金丸隆志著「実例で学ぶRaspberry Pi電子工作」(講談社ブルーバックス)の補足情報をまとめるためのページです。

まず、書籍のサンプルファイル、回路配線図(PDF)、応用演習(PDF)が必要な方は、下記の公式サポートページからダウンロードしてください。

以下では、Raspberry PiのOSの更新に伴う内容の変更や、正誤情報などを記していきます。

補足情報一覧


前著の記事へのリンク

入門編である前著「Raspberry Piで学ぶ電子工作」のサポートページ中で、本書の読者の方にも役立ちそうな記事へのリンクを貼ります。

感想など




2017年12月30日土曜日

本書発売後の追加情報

はじめに

カラー版回路配線図について

前著の改訂版「カラー図解 最新 Raspberry Piで学ぶ電子工作」の発売に合わせ、本書「実例で学ぶRaspberry Pi電子工作」でも、カラー版の回路配線図をダウンロードできるようにしました。

本書公式サポートページからダウンロードできます。これまで通り、モノクロ版もダウンロードできますので、お好みの方を用いてください。


回路配線図について

サポートサイトでダウンロードできる回路配線図をWindowsやOS X上のAdobe Readerで閲覧する際、「編集」→「環境設定」を選択し、下図のように「細い線を拡張」のチェックを外すと、より綺麗な配線図を見ることができます。


チェックを外す前後の配線図の状態を示したのが下図です。「細い線を拡張」のチェックを外した方が図がきれいに表示されているのがわかるでしょう。

なお、この設定はPDFを印刷する際には影響しないはずです。

第1章

p.15:Raspberry Pi 3について

2016年2月29日、Raspberry Pi 3 Model Bが発表され、大きな話題となりました。目立つ変更点としては
  • プロセッサの性能向上(900MHz 32-bit4コアから1.2GHz 64-bit4コアへ)
  • Wifi / Bluetooth4.1 の標準サポート
が挙げられます。Wifi / Bluetooth4.1 用の無線チップが搭載されており、デフォルトで無線接続ができるのが特長です。

Raspberry Pi 3にて本書の内容の動作確認が取れましたので、Raspberry Pi 3も動作対象機種に含めます。

p.21:NOOBSのバージョンについて

書籍販売より、以下のようにNOOBSの更新が行われています。

日付バージョンカーネルバージョン
2016/2/3NOOBS 1.6.04.1.17 / 4.1.17-v7+
2016/2/9NOOBS 1.7.04.1.17 / 4.1.17-v7+
2016/2/26NOOBS 1.8.04.1.18 / 4.1.18-v7+
2016/3/18NOOBS 1.9.04.1.19 / 4.1.19-v7+
2016/5/10NOOBS 1.9.14.4.9 / 4.4.9-v7+
2016/5/27NOOBS 1.9.24.4.11 / 4.4.11-v7+
2016/9/23NOOBS 1.9.34.4.21 / 4.4.21-v7+
2016/10/5NOOBS 2.0.04.4.21 / 4.4.21-v7+
2016/11/29NOOBS 2.1.04.4.34 / 4.4.34-v7+
2017/2/27NOOBS 2.2.04.4.48 / 4.4.48-v7+
2017/3/3NOOBS 2.3.04.4.50 / 4.4.50-v7+
2017/4/10NOOBS 2.4.04.4.50 / 4.4.50-v7+
2017/6/23NOOBS 2.4.14.9.28 / 4.9.28-v7+
2017/7/5NOOBS 2.4.24.9.35 / 4.9.35-v7+

いずれもOSのベースのバージョンはJessieです。Raspberry Pi用のJessieはまだリリースされてから日が浅く、バグなどが新しいバージョンで修正されていることが多いため、インストールの際は最新バージョンをインストールしましょう。

本書に関連する内容では、NOOBS 1.6.0以降を用いることで以下のメリットがあります。
  • GUIによる新しい設定アプリケーションの項目が、日本語で表記されるようになった
  • タクトスイッチを用いるプログラムで、管理者権限が不要になった
  • OpenCVを用いるプログラムで、代替プログラムを用いる必要がなくなった。

なお、「sudo apt-get upgrade」により全パッケージを更新したり、「sudo rpi-update」によりfirmwareを更新したRaspbianはサポートの対象外とします。その理由は下記の通りですのでご了承ください。
  • パッケージやfirmwareは日々変化しており、タイミングによってはバグを含んだパッケージがインストールされることもあること(実際、その問題によりトラブルの原因発見に時間がかかったことがあります)
  • 同じ理由で、読者の方の環境と筆者の環境を一致させることが難しいこと

p.21:kernel 4.9について

2017年6月23日リリースされたNOOBS 2.4.1以降では、kernelのバージョンが4.4系列から4.9系列に更新されているため、これまでと異なるインストール法によるインストールが必要なソフトウェアが出てきました。 具体的には
  • 6~8章でサーボモーター制御用に用いたWiringPi2-Python
  • 5章、6章、8章でブラウザによる回路操作を実現するために用いたWebIOPi
です。「p.193:WiringPi2-Pythonのインストールコマンド」と「p.329:WebIOPiのインストールについて」には最新の環境でも動作するインストール法が記載されていますので、そちらを参照してください。

p.26:NOOBS でのOSの選択について

2017年4月にリリースられたNOOBS 2.4.0以降では、インストール時のOSの選択肢として下図のように「LibreELEC_RPi2」と「Raspbian with PIXEL」の2種類が現れるようになりました。下図のように「Raspbian with PIXEL」にチェックを入れて作業を進めてください。なお、RaspbianとLibreELECの表示の順番はNOOBSのバージョンにより異なることがありますのでご注意ください。



p.27:NOOBS 1.9.3以降のデスクトップについて

NOOBS 1.9.3以降に含まれるRaspbianでは、下記のように、デスクトップやアイコンのデザインが一新されました。また、ブラウザがGoogle ChromeのベースとなったChromiumブラウザに変更されています。しかし、デザイン以外の変更はあまり大きくありませんので、書籍の指示のまま変更の必要がない部分がほとんどです。

もし最新のNOOBSを用いて違和感を感じる部分があったら、下記に補足や注意点がないか、チェックしてみてください。


p.31:NOOBS 1.5.0以降におけるキーボードの設定について

NOOBS 1.4.2およびNOOBS 1.5.0に含まれるRaspbianでは、新設定アプリケーションのバグがあるため、書籍では「設定ファイル/etc/default/keyboardの編集」により日本語キーボードの設定を行いました。さらに、NOOBS 1.5.0ではその方法では設定が反映されない「相性の悪いキーボード」が存在しました。

この問題に対する対処法が分かりましたのでここで記します。GUIによる新設定アプリケーションを用いるのですが、NOOBS 1.4.2では新設定アプリケーションでキーボードの設定を行えませんので、それより新しいNOOBSを用いましょう。

書籍p.30のキーボードレイアウトの設定を、新設定アプリケーションにより、下記の手順で行います。
  • 「Menu」→「Preferences(設定)」→「Raspberry Pi Configuration(Raspberry Piの設定)」から設定アプリケーションを起動する
  • キーボードの設定を「Localisation(ローカライゼーション)タブ」→「Set Keyboard(キーボードの設定)ボタン」→「Country:Japan」→「Variant:Japanese(OADG 109A)」とセットする(NOOBS 1.5.0~1.9.0(Jessie)では一度セットすると、二度目はセットできなくなりますが、この問題への対応法は次の項目で述べます)
  • 「OK」を押し、新設定アプリケーションを終了する
この設定は即座に反映されますので、そのまま1.5.6のネットワークの接続に進みましょう。

なお、以前この項目で、英語キーボードと認識される場合の対処療法として下記の2命令を /etc/rc.local に記述する、という方法を記していましたが、新設定アプリケーションを用いる限り、この2命令は不要になりますので、削除をお願いします。「sudo leafpad /etc/rc.local」コマンドで編集するのでした。
# 以前、/etc/rc.localに下記の2命令を記述した方はこの2命令の削除をお願いします
sleep 10
udevadm trigger --subsystem-match=input --action=change

p.31:NOOBS 1.5.0~1.9.0(Jessie)のRaspbianでキーボードの設定が一度しか行えない問題

新しい設定アプリケーションを行うと、キーボードの設定を行うと、NOOBS 1.5.0~1.9.0(Jessie)のRaspbianでは二度目のキーボードの設定が行えなくなります。もう一度キーボードの設定を行いたい場合の対応方法を記します。

原因は、設定アプリケーションが内部で呼び出すPythonプログラム lxkeymap のバグです。以下のように修正しましょう。 まず、LXTerminalを起動し、下記のコマンドを実行します。ファイル /usr/bin/lxkeymap を管理者権限のテキストエディタで開いています。
sudo leafpad /usr/bin/lxkeymap
ファイルを壊してしまわないよう、慎重に操作しましょう。ファイル内を「match」という語で検索すると、下記の部分が見つかります。
    def return_path(self,model,path,iter,matched_text):
        if model.get_value(iter, 1).lower() == matched_text:
これを下記のように編集して保存し、leafpadを閉じましょう。if文の行に含まれるmatched_textのみに「.lower()」を付加しています。
    def return_path(self,model,path,iter,matched_text):
        if model.get_value(iter, 1).lower() == matched_text.lower():
以上で、二度目のキーボードの設定が行えないバグは修正されましたので試してみてください。なお、このバグはNOOBS 1.9.1以降のRaspbianでは修正されています。

なお、補足ですがこれまでのRaspbian (Wheezy)では、キーボードの設定ファイルは/etc/default/keyboardだったのですが、Jessieでは /home/pi/.config/lxkeymap.cfg を用いる方針のようです。細かく言えば、Raspberry Pi起動時は /home/pi/.config/lxkeymap.cfg が参照されるのに対し、起動後にキーボードを抜き差しすると /etc/default/keyboard が参照されます。

p.32:日本語フォントのインストールについて

NOOBS 1.4.2~NOOBS 1.9.2では、書籍に記したように日本語フォントを自分でインストールする必要がありました。NOOBS 1.9.3以降では、デフォルトで日本語フォントが含まれていますので「1.5.7 日本語フォントのインストール」の節を飛ばして1.5.8に進んで構いません。もちろん、書籍の通り日本語フォントをインストールしても問題ありません。

2章

p.53:NOOBS 1.9.3におけるIDLEのデフォルトフォントについて

NOOBS 1.9.3に含まれるRaspbianでIDLEを起動し、プログラムを記述すると下図(左)のようになります。

このバージョンでは、デフォルトのフォントとしてプロポーショナルフォント(文字により太さが異なるフォント)が用いられてしまっています。そのため、下図(左)中の注釈に示したように、本来4個または8個ある空白文字(スペース)の個数が非常に少なく見えてしまっています(本書p.53の図2-11(B)と比べてください)。

Pythonでは空白文字の個数による字下げの区別は重要ですので、空白文字の個数が一目でわかるフォントを用いるべきです。

そのために、IDLEのメニューにある「Options」→「Configure IDLE」を選択し、「DejaVu Sans Mono」や「Droid Sans Mono」のように、名前に「Mono」が含まれるフォントを選んでください。下図(右)のように等幅フォントが選択され、空白の個数がよくわかるようになります。


第3章

p.81およびp.85:タクトスイッチを用いるプログラムの管理者権限について

タクトスイッチを用いる bb2-03-03-dice-switch.py および bb2-03-04-dice-switch-delay.py はどのバージョンのNOOBSでも管理者権限が必要と述べましたが、 本書発売後にリリースされたNOOBS 1.6.0以降では、これらのプログラムでも管理者権限が不要になりました。興味のある方は試してみてください。

第4章

4章全般:音声合成機能の追加について

4章で作成した「天気予報機能付き温度計」に、音声合成機能を追加するための解説を下記に記しました。ご活用ください。

p.108:I2Cデバイスの認識について

ここで用いる温度センサとLCDの組み合わせは前著でも用いたのですが、LCDを用いたプログラムの動作に失敗するという方が多いようです。LCDを用いたプログラムを実行するためには、Raspberry PiからLCDが認識されていることが必要です。LCDが認識されているかどうかのチェック方法は、書籍に記さなかったのですが、ここで紹介します。

まず、温度センサとLCDを接続した回路(p.108の図4-9)を作成した状態でLXTerminalを起動し、下記のコマンドを実行しましょう。
sudo i2cdetect -y 1
このコマンドは、Raspberry Piに接続されたI2Cデバイスのアドレスを出力するものです。NOOBS 1.4.2以降(Jessie)のRaspbianでは管理者権限を表す「sudo」は不要ですが、上記のようにsudoをつけても問題なく動作します。

正常な出力結果は下図のようになります。48が温度センサのアドレス0x48を表し、3eがLCDのアドレス0x3eを表します。48が表示されなければ温度センサを用いるプログラムは正常動作しませんし、3eが表示されなければLCDを用いるプログラムは動作しませんので、まずは下図の出力が得られることを目指しましょう。

そのためには、温度センサ、LCDの製作過程や回路などを見直すのが基本的な方針ですが、次項で述べたように、「新しいロットのLCDはRaspberry Piから認識されない」という問題に該当しているかもしれません。そのため、次項も引き続きお読みください。


p.108:完成品のLCDを購入しても認識されない場合の暫定的な対処法

<LCD対処法:予備知識>

読者の方により、2015年12月頃以降に完成品のLCD(AQM0802)を購入した場合、Raspberry Piから認識されない(上記のi2cdetectコマンドを実行しても3eが表示されない)ことがあることを教えて頂きました。

私も新たに完成品のLCD(AQM0802)を購入してみましたが、確かに同じ状況になりました。販売店に問い合わせたところ、「LCDの新しいロットでは電流の引き込み能力が低くRaspberry Piで動作(認識)しない」との回答でした。

このままでは4章の演習を実行できなくなってしまいます。そこで、そのように問題のあるLCDを動作させる方法をここで紹介します。まず、対処法を理解するための予備知識から解説します。

LCDモジュールの基板の裏には、下図(A)または(B)のように、PUと書かれた部分にジャンパとよばれる電極が2セットあります。LCDモジュールを自分ではんだづけした方は下図(A)の状態、完成品を購入した方は下図(B)の状態の方が多いでしょう。下図(A)の状態では、一つの正方形内の凹凸状の電極は絶縁されています。ここにはんだを盛り下図(B)のようにすると電極が接続され、LCDモジュールの基板上のプルアップ抵抗が有効になります。そのため、これらの状態をそれぞれ
「PUなし」、「PUあり」と呼ぶことにします(PUはpull-upの略です)。


一般に、プルアップ抵抗はI2C接続時に必要になるものですが、Raspberry Pi内部に既にこのプルアップ抵抗が存在するので、LCDモジュールの基板上では必ずしもこのプルアップ抵抗の有効化は必要ありませんでした。そのため、4章において正常動作するLCDでは「PUなし」、「PUあり」のどちらでもLCDは動作しました(ただし、8章ではサーボドライバ上のプルアップ抵抗の影響で、LCDでは「PUなし」としなければ動作しないことがあります)。

既に述べたように、「PUなし」から「PUあり」の状態にするには、凸と凹の電極にまたがるようにはんだを盛ります。逆に、「PUあり」から「PUなし」の状態に戻すには、上図(C)のように、はんだ吸い取り線(例えばこちら)を用いてPU部からはんだを除去するのが簡単です。

以上の予備知識のもと、どなたにでも容易に実現可能な暫定的対処法と、上級者向けの正式な対処法との2つを紹介します。

<LCD対処法:暫定版>

まずは、どなたにでも容易に実現可能な暫定的対処法を紹介しましょう。

Raspberry Piから認識されない完成品LCD(AQM0802)に対して、回路に下図のようにSDA部からGNDの間に抵抗を追加すると、動作を確認することができました。


抵抗の大きさRとしては、下記の範囲のものが有効でした。
  • PUありの場合のR:2kΩ
  • PUなしの場合のR:2kΩ~4.7kΩ程度
  • ただし、8章でサーボドライバとともに用いる場合「PUなし、R=2kΩ」のみ。サーボドライバにプルアップ抵抗が含まれており、実質「PUあり」と同じ状態になるためです。
後に述べるように、私はPUなし(PU部のはんだをはんだ吸い取り線で除去した状態)で4.7kΩの抵抗を用いることを推奨します。4.7kΩでI2C通信のエラーの頻度が高い場合は3.9kΩが良いかもしれません。抵抗は例えば、2kΩ3.9kΩ4.7kΩなどが購入できます。

なお、この方法を用いると、3.3VピンからGNDまで1.8kΩ+RkΩの抵抗で接続されることになるので、約0.5mAから1.0mA程度の電流が流れ続けます(1.8kΩの抵抗は、Raspberry Pi本体内部にあるI2C用のプルアップ抵抗です)。この程度の大きさの電流がRaspberry Piに問題を起こすことはないと思われますが、本来不要な電流が流れる手法であることは注意しておいてください。なお、比較のために記すと、2章でLEDを点灯したときに流れる電流は約5mAです。

以上で、暫定的対処法の解説は終わりますが、以下、動作しない完成品LCDで何が起こっているか、そしてこの方法により何が起こるのかを簡単に記しておきます。

まず、「動作しない完成品LCD」の何が問題かを記したのが下図です。I2C通信時にLCDから
Raspberry Piに対してACK信号と呼ばれるLOW信号を出力する場面があります。正常動作するLCDでは、このACK信号は約0.8Vとなっています。これはこのLCDの仕様の範囲内の動作です。しかし、「動作しない完成品LCD」ではこれが約1.2Vとなってしまっています。これをRaspberry PiがLOWと認識できないため、処理がそこで止まっているようです。


これに対し、暫定的な対応法ではこのACK信号を下図のように約1.0Vまで引き下げています。ただし、下図に示されている通り、3.3VであるべきHIGH信号まで下げてしまいますので、下げすぎると、Rapberry PiからHIGH信号も認識できなくなってしまいます。図を見るとわかる通り、「PUあり、R=2kΩ」ではHIGHが2Vまで下がっており、HIGHと認識されなくなる直前だろうと思います。これが「PUなし、R=4.7kΩ」を推奨する理由です。


ただし、いずれにせよこれはあくまで暫定的な対処法です。正常なI2C通信では必要のない対処法ですのでご注意ください。

<LCD対処法:正式版(ただし上級者向け)>

最後に、LCD(AQM0802)を用いるための正式な方法を紹介します。ただし、これは「表面実装用」と呼ばれるタイプのチップをはんだづけする必要があり、かなりの上級者向けとなりますので、自信のある方のみお試しください。

この方法には、I2CバスリピーターPCA9515ADと呼ばれるチップが必要となります。これをブレッドボードで用いるためには、下記の3点が必要となり、下図のようにはんだづけする必要があります。

なお、上図の「EN」はENABLEの略で、利用時はHIGH(3.3V)に接続します。

PCA9515ADはリンク先の写真で分かる通り、表面実装用と呼ばれるタイプの部品であり、これを基板上にはんだづけするには、やや高度な技術が必要です。そのため、この方法は上級者向けと言えるでしょう。

表面実装用の部品のはんだづけする方法は、例えば下記のYouTube動画が参考になるでしょう。
さらに、この動画にあるように、ピンセットやフラックスもあると良いでしょう。例えば下記のようなものです。
このPCA9515を利用するための概念図が下図です。


この小型液晶AQM0802の新しいロットを使う上で問題になるのが、Raspberry Pi上にあるプルアップ抵抗1.8kΩが小さすぎることです。新しいロットのAQM0802を使う上では10kΩが推奨されています。しかし、Raspberry Piのプルアップ抵抗は基板上に固定されており、そのため、プルアップ抵抗を小さくすることは容易なものの(接続するプルアップ抵抗の数を増やせばよい)、大きくすることは簡単ではありません。

そこで、上図のようにPCA9515を用いてRaspberry Piおよび温度センサ側と小型液晶側を切り離し、左側をプルアップ抵抗1.8kΩで、右側をプルアップ抵抗10kΩで利用できるようにするというわけです。

そのためには、ブレッドボード上で下図のような回路を組みます。図を簡単にするために、小型液晶側のプルアップ抵抗は、小型液晶モジュールのプルアップ抵抗PUを用いることにしました。上の解説「<LCD対処法:予備知識>」を参考に、2箇所のPUに半田を盛り、基板上のプルアップ抵抗を有効にしてください。


4章全般:利用できるLCDについて1~秋月電子編

本書で紹介したLCDの新しいロットでは、上で記したように何らかの対処をしないとRaspberry Piでは利用できなくなってしまいました。抵抗1本の追加で暫定的に利用可能になるのは不幸中の幸いではありました。

2017年4月に、秋月電子通商さんより上記のLCDを正式にRaspberry Piで利用可能にしたモジュールキットが販売開始され、さらに2017年6月にはその完成版が販売開始されましたのでここで紹介します。なお、組み立てキットの方は狭いピッチ(ピン間隔)の半田付けが必要になりますので、半田付けにある程度慣れている方向けとなります。商品へのリンクは下記になります。
組み立てキットに含まれるパーツを図示したのが下図(左)となっています。ピンソケットが2種含まれていますので、お好みの方を半田付けします。 完成品にはLCDを立てて使うためのピンソケットがあらかじめ取り付けられているようです。

なお、本書のようにブレッドボードで利用するためには、組み立てキットに下図(中)のようにピンヘッダを別途購入して半田付けすることをお勧めします。ピンヘッダとは、例えば下記のようなものです。丁度のサイズのものを購入するよりは、長いものを購入してニッパでカットするのが一般的です。

ピン配置は本書のものとは異なり、上図(右)のようになっています。

利用例は下図のようになっています。下図(左)がピンソケットを用いた場合で、Raspberry PiのGPIO(3.3V/SDA/SCL/GPIO4/GNDと続くピン)に直接させるようになっています。完成品ではLCDを立てて使うようなピンソケットとなっています。ただし、これではGPIOのピンの一部が利用できなくなってしまいますので、「オス-メス ジャンパワイヤ」を介してGPIOに接続するのがお勧めです。

ピンヘッダを用いて作成したLCDならば本書のようにブレッドボートで利用可能です。その様子を示したのが下図(右)です。なお、基板の「LED」ピンを3.3Vに接続すると、図のようにLCDのバックライトが点灯した状態になります。お好みで利用してください。ピンソケットでGPIOに直接差したLCDならば、GPIO 4をHIGHにすることでバックライトが点灯します。なお、バックライトを利用するには、LCDを基板に半田付けする際に2か所の四角いピンも半田付けする必要がありますのでご注意ください。


4章全般:利用できるLCDについて2~ストロベリーリナックス編

本書では秋月電子通商で入手可能な8文字x2行のLCDを用いました。

他に用いることのできるLCDとしては、例えばストロベリーリナックスで取り扱われている以下のものがあります。どちらも16文字x2行ですので、本書で取り扱ったものの倍の文字数を表示できます。
下図は、
  • sudo python bb2-04-03-lcd-practice.py 'Hello, Raspberry Pi!'
を実行した様子です。NOOBS 1.4.2以降(Jessie)のRaspbianでは管理者権限を表す「sudo」は不要ですが、上のようにsudoをつけても問題なく動作します。

ただし、この2つのLCDでは、本書p.115図4-11の文字コード表の一番左の列(0x06~0x0f)の文字は表示されないようです。ご了承ください。

これらのLCDが本書のLCDと共通でのプログラムで利用可能な理由は、コントローラーICとしてST7032iと呼ばれるものが共通で用いられているためです。そのため、書籍で紹介したLCDにあったロットによる問題が将来起こらないとは限りません。その場合はやはり上記の暫定的対処法を試すことになるでしょう。


なお、回路の接続は本書のものとは少し異なります。上図のどちらの液晶を用いる場合も下図を参考にしてください。


プログラムは、一行だけ変更が必要です。LCDを用いるプログラムには下記のようにLCDの文字数を設定している行があります。これらは8x2の液晶であることを示しています。
chars_per_line = 8
display_lines = 2
これを下記のように変更して保存すれば完了です。
chars_per_line = 16
display_lines = 2
この変更をしなければ、単に8x2の液晶として動作します。

また、「I2C低電圧キャラクタ液晶モジュール(16x2行)」(小さいほう)を用いるとデフォルトでは文字がやや薄くなります。文字の濃さを調整できるようにしたプログラムは下記になりますので、必要に応じてダウンロードして利用してください。
また、これらのプログラムをターミナルでダウンロードしたい場合は下記の3つのコマンドを順に実行してください。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/bb2-04-03-lcd-practice-mod.py
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/bb2-04-04-lcd-4modes-mod.py
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/bb2-04-05-lcd-3modes-mod.py
ダウンロード後、それぞれのファイルで下記の行を見つけ、contrastの値を40に変更し保存してください。必要に応じて、上で記した「chars_per_line」を16にする変更も行なってください。
contrast = 32 # 0から63のコントラスト。通常は32、文字が薄いときは40を推奨

p.119:タクトスイッチを用いるプログラムの管理者権限について

タクトスイッチを用いる bb2-04-04-lcd-4modes.py および bb2-04-05-lcd-3modes.py はどのバージョンのNOOBSでも管理者権限が必要と述べましたが、 本書発売後にリリースされたNOOBS 1.6.0以降では、これらのプログラムでも管理者権限が不要になりました。興味のある方は試してみてください。

第5章

5章全般:音声認識によるリモコン操作

本章では、リモコン操作を行う方法として、「irsendコマンド」、「タクトスイッチ」、「ブラウザ」の3種類を用いました。さらに、「音声認識」によりリモコン操作を行う方法を応用演習として追加しましたのでご活用ください。

p.134:エアコンのリモコンの利用について

本書ではエアコンのリモコンからの信号をRaspberry Piで利用する方法については解説しませんでした。しかし、その方法はありますので、下記のページに解説を追加しました。
本書でテレビのリモコンからの信号を利用できるようになった後、興味のある方は取り組んでみてください。

p.165:タクトスイッチを用いるプログラムの管理者権限について

タクトスイッチを用いる bb2-05-01-TV.py はどのバージョンのNOOBSでも管理者権限が必要と述べましたが、 本書発売後にリリースされたNOOBS 1.6.0以降では、このプログラムでも管理者権限が不要になりました。興味のある方は試してみてください。

第6章

p.184:12ビットADコンバータMCP3208

6章ではADコンバータとして秋月電子通商で取り扱われている
を用いますが、この在庫が切れている場合、下記のMCP3204を用いても構いません
ただし、MCP3204はMCP3208に比べて2ピン少ないので、少しだけ回路の読み替えが必要です。図6-14、図6-15を例に、変更箇所を赤で示しますので参考にして下さい。
MCP3204を用いる場合の図6-14の変更点

MCP3204を用いる場合の図6-15の変更点

p.184:カメラモジュールv2について

2016年4月、Raspberry Piのカメラモジュールのバージョン2が発売になりました。こちらでも6章のプログラムは動作するのですが、NOOBS1.9.0までのRaspbianでは映像の向きが上下逆転してしまいますのでご注意ください。NOOBS 1.9.1に含まれるRaspbianでは正常動作します。

p.193:WiringPi2-Pythonのインストールコマンド

2017年6月23日リリースされたNOOBS 2.4.1以降では、Raspbianのkernelが4.9系列となり、書籍に記したコマンドではWiringPi2-Pythonが動作しなくなります。 そこで、p.193の7コマンドを下記に読み替えてください。(4)のダウンロードサイトが変更を受けています。
(1) $ sudo apt-get update
(2) $ sudo apt-get install python-dev python-setuptools
(3) $ sudo apt-get install python3-dev python3-setuptools
(4) $ git clone https://github.com/neuralassembly/WiringPi2-Python.git
(5) $ cd WiringPi2-Python
(6) $ sudo python setup.py install
(7) $ sudo python3 setup.py install
なお、一度インストールしたWiringPi2-Pythonを上書きインストールしたい場合、上記コマンドの実行前に、ホームディレクトリで下記のコマンドを実行して古いファイルを事前に実行しておきましょう。
$ sudo rm -rf WiringPi2-Python


p.199~201:タミヤの工作キットで作ったカメラ台のカラー画像

タミヤの工作キットで作るカメラ台の作成方法を示す図ですが、書籍では画像がやや小さく見にくいかもしれません。下記に、カラーで解像度の高い画像を貼り付けますので、ご活用ください。

画像をクリックすると画像が大きくなります。必要に応じて、大きくした画像上で右クリックして「名前を付けて保存」を選択して保存すると良いでしょう。

図6-7

図6-8

図6-9

p.205:カメラマウントA838を用いた場合のカメラ台のカラー画像

同様に、図6-12、図6-13のカラー画像も載せます。

図6-12

図6-13


p.209:半固定抵抗の回転の向きについて

本書は、Arduino Sidekick Basic Kit付属の半固定抵抗を用い、「右に回すとAD変換後の値が大きくなる」回路を組みました。この回転の向きは、下図のように「半固定抵抗の3.3VピンとGNDへの接続を入れ替える」ことで逆にすることができます。

お使いの半固定抵抗により回転の向きが異なることがありますので、配線の入れ替えにより好みの向きを選択してください。


p.222:長いコマンドの入力には注意

p.222からp.223で紹介したmjpg-streamerのインストール用のコマンドは少し長いものが多く、入力を間違うと正しく演習ができなくなってしまいます。

コピーできる形式で以下に再掲しますので、ブラウザで1行ずつコピーして、ターミナルで貼り付けて実行すると確実でしょう。その際、先頭の「(1)」や「$」などはコピーする必要はありませんのでご注意ください。

また、ブラウザでのコピーは「コピーしたい文字をなぞってから『右クリックしてコピー』または『Ctrl+c』」、ターミナルへの貼り付けは「ターミナル上でメニューから『編集→貼り付け』または『Shift+Ctrl+v』」です(ただし、キーボードのCtrlとCapslockを入れ替えている場合、ショートカットキーは効かないようです)。
(1) $ sudo apt-get update
(2) $ sudo apt-get install libjpeg8-dev cmake
(3) $ git clone https://github.com/jacksonliam/mjpg-streamer.git
(4) $ cd mjpg-streamer/mjpg-streamer-experimental
(5) $ make
(6) $ cd
(7) $ sudo mv mjpg-streamer/mjpg-streamer-experimental /opt/mjpg-streamer
なお、前著「Raspberry Piで学ぶ電子工作」をご利用いただいた方は、上記の7つのコマンドの実行前に、下記の2コマンドにより過去にインストールしたmjpg-streamerを一度削除した方が安全かもしれません。ターミナルLXTerminalを起動した直後の状態で順に実行してください。
(1) $ sudo rm -rf /opt/mjpg-streamer
(2) $ rm -rf mjpg-streamer

p.228:WebIOPiの起動に失敗する問題

WebIOPiからp.193でインストールしたWiringPi2-Pythonを呼び出すのですが、2016/2/12以降にダウンロードしたWiringPi2-Pythonを用いた場合、エラーが起きWebIOPiの起動に失敗します。「p.193:WiringPi2-Pythonのインストールコマンド」に記した手順で、エラーの起きないWiringPi2-Pythonをダウンロードしてインストールし直してください。

p.229:本章のプログラムを自動起動したい場合

本章のプログラムを、本書8.4.4で紹介した方法で自動起動し、さらにディスプレイやキーボードをRaspberry PIから外した状態で利用したい方がいらっしゃるかもしれません。

NOOBS 1.9.0までは問題なく動作したのですが、NOOBS 1.9.1以降は、「Raspbianが黒いコンソール画面で起動する状態」にしないと、ディスプレイを外した状態では正常動作しなくなりました。

それを実現したい場合、設定アプリケーションを起動し、「システム(System)」タブの「ブート(Boot)」項目にある「CLI(To CLI)」にチェックを入れ、再起動してください。画面が黒い「コンソール」状態でRaspbianが起動し、本章のプログラムが自動起動で正常動作するようになります。
なお、Raspbianが黒いコンソールで起動する状態から元に戻したい場合、コンソールで「startx」というコマンドを実行してデスクトップを起動してから、設定アプリケーションの「ブート(Boot)」項目で「デスクトップ(To Desktop)」を選択し、再起動してください。

第7章

p.239:NOOBS 1.4.2と1.5.0でOpenCVを用いた際のOpenGLに関するエラーについて

7章では画像処理のライブラリであるOpenCVを用います。NOOBS 1.4.2と1.5.0に含まれるRaspbian(Jessie)でプログラムを実行すると下記のエラーが出てプログラムが実行できませんでした。そのため、書籍ではエラーの出ない代替プログラムを用意し、NOOBS 1.4.2以前と以降とで使い分けました。
Windows system doesn't support OpenGL.
書籍刊行後、NOOBS 1.4.2以降のRaspbianで上記のエラーを抑制する方法が明らかになりましたので以下に記します。

まず、2016年2月にリリースされたNOOBS 1.6.0以降ではこの問題は解決されていますので、そもそも上記のエラーが出ません。この方法が一番簡単ですね。

NOOBS 1.4.2をお使いの方は、ターミナルソフトウェアLXTerminalを起動し、下記の2つのコマンドを順に実行し、必要なライブラリをインストールしてください。
sudo apt-get update
sudo apt-get install libgl1-mesa-dri
インストールが終わったら、Raspberry Piを再起動してください。それにより、代替プログラムではない通常のプログラムで7章の演習が実行できるようになります。

p.239:カメラモジュールv2について

2016年4月、Raspberry Piのカメラモジュールのバージョン2が発売になりました。こちらでも7章のプログラムは動作するのですが、NOOBS1.9.0までのRaspbianでは映像の向きが上下逆転してしまいますのでご注意ください。NOOBS 1.9.1に含まれるRaspbianでは正常動作します。

p.239:画像処理プログラムの画面のちらつきについて

7章で用いるプログラムは全てRaspberry PiのカメラモジュールをOpenCVで利用するものとなっています。このプログラムを使ってカメラ映像を表示すると、映像が時々ちらつく現象が見られることがあるかもしれません。その場合、プログラム中にある
camera.resolution = (320, 240)
という行を見つけ、その次に
camera.resolution = (320, 240)
camera.framerate = 15
という行を追加して保存してください。その際、先頭の空白の個数は上の行数に合わせることに注意してください。 フレームレート(1秒間の映像のコマ数)を15に減らすことでちらつきがなくなるのではないかと思います。

p.241:画像処理に影響を与えずに映像サイズを大きくする方法について

7章のプログラムでは、カメラから320x240のサイズの映像を取得し、何らかの画像処理を施して映像を表示しています。320x240という映像サイズは、画像処理の計算にかかる時間を考慮して決めています。大きくすると、計算に時間がかかり、映像が滑らかに表示されなくなるでしょう。

しかし、320x240という映像サイズは、表示してみると小さいと感じるのも事実です。ここでは、この映像サイズを大きくする方法を紹介します。

まず思いつくのは、カメラからの映像取得のサイズを大きくすることです(例えば640x480)。しかし、これは下記の理由によりお勧めできません。
  • 画像処理の計算に時間がかかるようになる
  • 画像処理の結果が変わる(円検出bb2-07-04-circle.pyの場合、最小半径5、最大半径100などと定めているが、映像サイズを変えると、これらの数字の意味が変わってくるため。顔検出bb2-07-05-face.pyも同様)
  • 追跡アプリケーションbb2-07-06-tracking-circle.pyとbb2-07-07-tracking-face.pyでは、映像サイズが320x240であることを前提としている部分が多い(映像の中心座標が(160,120)である、など)
そこで、「画像処理はサイズ320x240の映像に対して行うが、結果の映像は640x480に引き伸ばして表示する」方法を紹介します。

7章のプログラムの末尾付近には、下記の命令があります。
cv2.imshow('frame', stream.array)
という行があります。これは画像を画面に表示する命令なのですが、この命令を削除して下記の2行に置き換えると、320x240の画像が 640x480に引き伸ばして表示されます。(行頭のスペースの数は元の行と同じに統一してください)
dst = cv2.resize(stream.array, (640, 480))
cv2.imshow('frame', dst) 
映像を引き伸ばして表示しているだけなので、画質は良くありませんが、 デモなどで映像を大きく表示したいときは使えると思います。

p.241:7章のGUIプログラムを自動起動したい場合

7章のプログラムはGUIアプリケーションであり、/etc/rc.localに記述しても自動起動できません。 GUIアプリケーションを自動起動する方法を、「GUIアプリケーションの自動起動」にまとめました。

第8章

p.277:6脚ロボットのカラー画像について

6脚ロボットの作成方法を示す図ですが、書籍では画像がやや小さく見にくいかもしれません。下記に、カラーで解像度の高い画像を貼り付けますので、ご活用ください。

画像をクリックすると画像が大きくなります。必要に応じて、大きくした画像上で右クリックして「名前を付けて保存」を選択して保存すると良いでしょう。

図8-3

図8-12

図8-16

p.296:6脚ロボットの安定性について

ハンチング対策の解説において、サーボモーターSG90に与える電圧(乾電池の本数)によって6脚ロボットの挙動が異なることに触れました。サーボモーターの個体差などにもよりますが、6脚ロボットのモーターに与える電圧が大きく、その結果流れる電流が大きくなるとSG90の挙動が不安定になることがありました。
具体的には「モーターの角度が指定していない角度に動き、そこでロックしてしまう」という現象が起きました。もし、同様の現象に悩まされている方は、以下に記す解消方法を試してみて下さい。なお、書籍の中でサーボドライバの類似品は「Adafruitのものと挙動が異なる場合がある」と記しましたが、類似品の中にはこの「指定していない角度でモーターがロック」という現象が起こりやすいものもあり、そのため、類似品はサポート対象外としました。

対策1:モーターに与える電圧を小さくする
モーターに与える電圧を小さくすると、6脚ロボットが安定する傾向があります。簡単にこれを実現するは、乾電池1本の電圧(約1.5V)とエネループなどのニッケル水素充電池の電圧(約1.2V)が異なることを利用するのが簡単です。以下の様な電圧を簡単に作ることができます。
  • 約4.5V:乾電池3本
  • 約3.6V:エネループなどのニッケル水素充電池3本
もしエネループなどのニッケル水素充電池をお持ちの場合、試してみると良いかもしれません。ただし、乾電池や充電池2本まで電圧を下げると、6脚ロボットは動作しませんので注意してください。なお、乾電池とニッケル水素充電池を混ぜて用いるのはやめましょう。
また、乾電池を用いるにせよ、充電池を用いるにせよ、新品の乾電池あるいは充電直後の充電池は、使っているうちに徐々に電圧が小さくなっていきます(参考:Panasonic | エネループシリーズについて)。そのため、使っているうちに6脚ロボットの安定性が徐々に変化することはあり得ます。

対策2:ロボットの脚の振り幅を小さくする
6脚ロボットを安定させるもう一つの方法は、脚の振り幅を小さくすることです。脚の振り幅が小さいということは、モーターの回転する角度が小さいということなので、モーターに流れる電流が小さくなり、その結果6脚ロボットが安定して動作する傾向があります。ただし、ロボットの動きはややゆっくりになります。下記のファイルを変更することで実現できます。
カメラなし、ハードウェアPWMの場合:/usr/share/webiopi/htdocs/bb2/03/script.py
カメラなし、ソフトウェアPWMの場合:/usr/share/webiopi/htdocs/bb2/04/script.py
カメラあり、ハードウェアPWMの場合:/usr/share/webiopi/htdocs/bb2/05/script.py
これらのファイルの中で、下記の部分を見つけます。
LEG_F_R = NEUTRAL + 100
LEG_F_L = NEUTRAL - 100
LEG_B_R = NEUTRAL - 100
LEG_B_L = NEUTRAL + 100
4つある数字の100が、脚の振り幅(モーターの動く角度)に対応する数値です。これを小さめの値、例えば下記のように60に変更します。
LEG_F_R = NEUTRAL + 60
LEG_F_L = NEUTRAL - 60
LEG_B_R = NEUTRAL - 60
LEG_B_L = NEUTRAL + 60
変更して保存した後はWebIOPiを再起動する必要があります。WebIOPiが自動起動する設定になっている場合、Raspberry Piを再起動してしまうのが簡単でしょう。

p.296:サーボモーターの消耗について

本書ではSG-90というサーボモーターで6脚ロボットを作成しました。一般的に、サーボモーターは長く使っていると作成当初から挙動が変わり、交換が必要になる場合があります。そういう意味で、サーボモーターは消耗品と考えた方がよいかもしれません。

私の場合、6脚ロボットを初めて作成してから書籍が出版されるまでの約8ヶ月の間に、1つのサーボモーターを交換しました。具体的には、機体を持ったまま脚を動かした際、1つの脚だけ他の脚に比べて動きが遅くなったため交換しました。

p.308: LCDへのIPアドレスの表示について(1)

本書では、Raspberry Piにブラウザからアクセスする際にIPアドレスを用いました。そのため、Raspberry Piにルーターなどから割り振られたIPアドレスを知る目的で、LCDを回路に取り付けました。

しかし、本ページ下部の「p.335:IPアドレスでのURLの指定について」で記しますように、avahiという仕組みを用いると、IPアドレスではなく、下記のようなアドレスでのアクセスが可能になるのでした(ただし、p.335の注釈に示すように制限がありますので注意)。
  • http://raspberrypi.local:8000/bb2/03/
これを用いると、回路からLCDが不要になるなどのメリットがあります。具体的には下記の通りです。
  • p.309の図8-13やp.310の図8-14からLCDを取り外して良い
  • p.310での/etc/rc.localへの「python /home/pi/bb2-08-04-lcd.py $_IP &」の記述が不要
さらに、Raspberry PiのIPアドレスを固定する、という方法でも、毎回IPアドレスを調べる必要がなくなりますね。こちらについては前著サポートページ内の「Raspberry PiのIPアドレスを固定する」にまとめましたので、興味のある方は御覧ください

4章の補足で述べたように、LCDにはロットの問題によるトラブルが発生しているので、この方法を用いてLCDなしの回路とする方が良いかもしれませんね。

p.308:LCDへのIPアドレスの表示について(2)

6脚ロボットを制御するRaspberry PiのIPアドレスを知るため、LCDにIPアドレスを表示する方法を紹介しました。このとき、IPアドレスの取得に時間がかかるとIPアドレスではなく「Raspberry Pi」とLCDに表示されてしまいます。その様な場合、/etc/rc.localの適切な位置に「10秒待つ」ことを意味する「sleep 10」という命令を記述して対処する方法を紹介しました。

それでIPアドレスが表示できるようになれば問題ありませんが、OSとしてjessie (NOOBS 1.4.2以降に含まれるRaspbian)を用いている方は別の方法もありますのでそれを紹介します。

jessie以降に含まれる設定アプリケーションでは、下図(左)のように「Network at Boot」という項目があります。この「Wait for network」にチェックを入れて再起動すると、Raspberry Piのネットワークへの接続が完了してから起動が完了するようになります。その結果、「sleep 10」の記述なしでLCDにIPアドレスが表示されるようになる、というわけです。下図(右)のように以前からの設定アプリケーションraspi-configにも「Wait for Network at Boot」という項目が追加されており、「Slow Wait for network connection before completing boot」を選択することで、同様の効果が得られます。

もしこの設定をしてもIPアドレスではなく「Raspberry Pi」とLCDに表示される場合、書籍に書かれているように/etc/rc.localの適切な位置に「sleep 10」と記述する方法を試してみるとよいでしょう。


p.317:カメラモジュールv2について

2016年4月、Raspberry Piのカメラモジュールのバージョン2が発売になりました。こちらでも8章のプログラムは動作するのですが、NOOBS1.9.0までのRaspbianでは映像の向きが上下逆転してしまいますのでご注意ください。NOOBS 1.9.1に含まれるRaspbianでは正常動作します。

付録B

p.329:WebIOPiのインストールについて

現在、WebIOPiのサイトの上部に「Cayenne」というソフトへのリンクがありますが、「Cayenne」ではなく「WebIOPi 0.7.1」をダウンロードし、書籍のようにインストールしてください。

なお、WebIOPiをインストールするためのコマンドはやや長く、写し間違えると正しくインストールが行なわれません。下記にコピーできる形で再掲しますので、ブラウザで表示して1行ずつコピーし、ターミナルソフトウェアLXTerminalへ貼り付けて1つ1つ実行していけばトラブルが減るでしょう。コピーはブラウザ上でキーボードで「Ctrl+c」、貼り付けはLXTerminalのメニューから「編集」→「貼り付け」(またはCtrl+Shift+v)です。なお、行頭の「(1)」などの数字はコピーする必要はありませんのでご注意ください。なお、(1)のコマンドを実行する前に、p.329の指示に従ってWebIOPi-0.7.1.tar.gzをダウンロードし、ユーザーpiのホームに移動しておく必要がありますのでご注意ください。
(1) tar zxf WebIOPi-0.7.1.tar.gz
(2) cd WebIOPi-0.7.1/
(3) wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch
(4) patch -p1 -i webiopi-pi2bplus.patch
(5) sudo ./setup.sh
「Do you want to access WebIOPi over Internet ? [y/n]」という質問をされたときはキーボードで「n」を入力したあとEnterするのでした。

そして、引き続きp.331のコマンドを実行し、起動用ファイルを適切な位置に配置します。このコマンドもやや長いので、コピーできる形式で再掲します。
(1) wget https://raw.githubusercontent.com/neuralassembly/raspi/master/webiopi.service
(2) sudo mv webiopi.service /etc/systemd/system/
なお、上記の手順でWebIOPiをインストールしてもp.338の図B-3において「IN/OUT等が現れるはずのボタンに文字が現れず灰色のまま」という場合、まずはWebIOPiの再インストールを試してみましょう。そのためには、ターミナルを起動して下記のコマンドで過去のインストールファイルを一旦削除します。
sudo rm -rf WebIOPi-0.7.1
その後、もう一度上記のコマンドでWebIOPiをインストールします。

それでも症状が改善されない場合、原因はわかりませんが、OSであるRaspbianが壊れているという可能性もないとは言えません。余力があればOSを再インストールしてみることも検討してみると良いでしょう(私自身、OSの再インストールが必要だったことはないのですが、読者の方にはそれで改善したという方が複数名いらっしゃるようです)。

p.335:IPアドレスでのURLの指定について

本書では、ブラウザからRaspberry Piにアクセスする際に、ルーターなどからRaspberry Piに割り振られたIPアドレスを用いました。すなわち、IPアドレスが192.168.1.3の場合にブラウザから例えば下記のようにアクセスしました。
  • http://192.168.1.3:8000/bb2/01/
しかし、この方法はifconfigコマンドなどで事前にIPアドレスを調べておく必要があり、やや面倒でした。

NOOBS 1.4.2以降に含まれるRaspbian(Jessie)では、IPアドレスを用いずにRaspberry Piにアクセスできますのでその方法を紹介します。なお、この方法でRaspberry Piにアクセスできるのは下記のみです。
  • iTunesをインストールしたWindows(iTunesに含まれるBonjourというアプリケーションが必要なためです)
  • Mac OS X
  • iPhoneやiPad
Androidスマートフォンでは現時点ではこの方法ではRasbperry Piにはアクセスできないように思われます。

上記の条件が満たされれば方法は簡単で、ブラウザのアドレス欄に例えば下記のように入力すればOKです。
  • http://raspberrypi.local:8000/bb2/01/
すなわち、IPアドレス「192.168.1.3」などの代わりに「raspberrypi.local」という記法が使える、というわけです。これは、Jessie上で動作しているavahiというソフトウェアの働きによります。

なお、Jessie以前のWheezyで同じことを実現したい場合、LXTerminalを起動して下記のようにavahi-daemonをインストールする必要があります。
  • sudo apt-get update
  • sudo apt-get install avahi-daemon
インストール後に再起動すると、自動的にavahiが起動し、「raspberrypi.local」でのアクセスが可能になります。

なお、同じネットワーク内でavahiが起動したRaspberry Piが2台以上あると、同じ名前「raspberrypi」のマシンが2つ以上ある状態になり、名前の衝突が起こります。その場合、2台目以降のRaspberry Piには「raspberrypi-2.local」などの名前が自動的につけられますのでご注意ください。名前が衝突しないよう、あらかじめ「raspberrypi」というマシン名を変更しておく方法もありますが、ここでは省略します。

付録E(PDF)

PDF12:Chromiumブラウザについて

付録PDFにて、NOOBS 1.4.1 以前のRaspbian(wheezy)では、Google Chromeと同等のChromiumブラウザが利用可能だと述べました。そのインストールの際、下記のコマンドでインストールすると、メニュー等が日本語化された状態になります。
$ sudo apt-get install chromium-browser chromium-l10n
ただし、このChromiumはかなり古いため、Googleアカウントでログインしてブックマークを同期する、というChromiumの大きな特長を利用することができません。NOOBS 1.9.3以降のRaspbian(Jessie)では、デフォルトブラウザが新しいChromiumとなっていますので、こちらを利用することを検討するのが良いでしょう。


2017年3月20日月曜日

Raspberry Pi + Open JTalkによる音声合成で天気予報付き温度計に喋らせる

0. はじめに

前回の記事「Raspberry Pi + Julius + LIRC により家電製品を音声で操作する」では、Raspberry Piで音声認識を行いました。

今回はその逆、ということで音声合成を行ってみましょう。音声合成システムとしてはOpen JTalkを用います。

題材としては、本書第4章で作成した「天気予報付き温度計」に、「現在〇〇度」や「今日(明日)の天気は○○」のように音声合成により話す機能を追加してみます。

作成した「喋る天気予報付き温度計」の様子は下図のようになります。見やすいよう大きいLCDを使っていますが、回路自体は書籍第4章とほぼ同じです。唯一異なるのが、温度計に喋らせるためのタクトスイッチを1つ追加した点です。

喋る天気予報付き温度計

この喋る天気予報付温度計の動作の様子を示したのが下記の動画です。温度計以外にも、音声認識と組み合わせて「音声認識の結果をそのままオウム返しで喋る」というデモンストレーションの様子も示しています。



1. Raspberry Piでのスピーカー(イヤフォン)の利用

まずはRaspberry Piで音を鳴らせるようにしましょう。主に下記の3つの方法があります。
  1. Raspberry Pi本体のミニジャックにスピーカーやイヤフォンを接続する
  2. Raspberry PiとつながったHDMIディスプレイにスピーカーやイヤフォンを接続する
  3. USB接続のサウンドカードを利用する
それぞれの方法で音を鳴らす上での注意点を下記に記します。

Raspberry Pi本体のミニジャックを用いる場合

ターミナルを起動し、下記のコマンドを実行しておきます。末尾の「1」がミニジャックを利用することを表します。デフォルトは「0」(自動)です。
$ amixer cset numid=3 1

Raspberry Piに接続したHDMIディスプレイを用いる場合

ターミナルを起動し、下記のコマンドを実行しておきます。末尾の「2」がHDMI経由の音声出力を表します。デフォルトは「0」(自動)です。
$ amixer cset numid=3 2

USB接続のサウンドカードの場合

USB接続のサウンドカードとしては「Creative Sound Blaster Play!2 SB-PLAY2」でのみ動作確認をしており、それ以外のサウンドカードはサポートしませんのでご了承ください。
なお、USB接続サウンドカードの音声のボリュームを変更したい場合、ターミナルで例えば下記のようなコマンドを実行します。「10」の部分は0%~100%で表されたボリュームなので、適切な数値で読み替えます。特にイヤフォンを用いている場合、小さな値から試すのが無難です。
$ amixer -c 1 sset 'Speaker' 10


2. Open JTalkのインストール

まず音声合成システムOpen JTalkのインストール方法を紹介します。

ターミナルを起動して下記のコマンドを順に実行し、必要なソフトウェアをネットワークからインストールします。もちろんRaspberry Piがインターネットに接続されている必要があります。
$ sudo apt-get update
$ sudo apt-get install open-jtalk open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001
2 つ目のコマンド実行後に「続行しますか? [y/n]」などと聞かれた場合は、キーボードで「y」をタイプしてEnterキーを押して下さい。これらのインストールにより、「男性の声」での音声合成が可能になります。

さらに、女性の声で音声合成する際に必要になるファイルもインストールしておきましょう。こちらより、MMDAgent_Example-1.7.zipをブラウザでダウンロードしておきます。バージョンが新しくなっている場合、新しいもののダウンロードで問題ないと思います。 ダウンロードされたファイルはDownloadsディレクトリ(フォルダ)(/home/pi/Downloads)に格納されますので、本書p.322の図A-1のようにファイルマネージャを用いてユーザーpiのホーム(/home/pi)に移動しましょう。
その後、ターミナルで下記のコマンドを順に実行します。なお、MMDAgentの新しいバージョンがダウンロードされた場合、バージョン番号の部分(「1.7」)を適切に読み替えてください。
$ unzip MMDAgent_Example-1.7.zip
$ sudo cp -r  MMDAgent_Example-1.7/Voice/mei /usr/share/hts-voice/

最後に、実際にOpen JTalkを呼び出して発話をさせるプログラム (スクリプトといいます) をダウンロードして実行可能にしましょう。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/speech.sh
$ chmod a+x speech.sh
$ sudo mv speech.sh /usr/local/bin
以上でRaspberry Piに音声合成させるためのソフトウェアの準備ができました。

3. Open JTalkの動作確認

Open JTalkで音声合成を行う際、USB接続のサウンドカードを用いていないならば、そのまま実行が可能です。ターミナルを起動し、例えば下記のようなコマンドを実行します。
$ speech.sh ラズベリーパイ
「ラズベリーパイ」の部分は前回の記事「Raspberry Pi + Julius + LIRC により家電製品を音声で操作する」でインストールしたMozcにより日本語入力を行い実現します。ここまでの流れが間違いなく実行できていれば、男性の声で「ラズベリーパイ」と発声されます。想像がつくように、「ラズベリーパイ」の部分を変更すれば、合成される音声もかわりますので試してみて下さい。また、音声の指示に半角空白を含ませたい場合、「speech.sh 'ラズベリー パイ'」のように「'」でくくる必要があります。

なお、USB接続のサウンドカードを用いている場合、プログラム実行前にプログラムの変更が必要です。ターミナルを起動し、実行スクリプトを編集用に管理者権限のleafpadで開きます。
$ sudo leafpad /usr/local/bin/speech.sh
その中で下記の部分を見つけてください。
# for the device on Raspberry Pi
aplay -q $TMPVOICE

# for USB sound card
#aplay -D plughw:1,0 -q $TMPVOICE
「aplay」と書かれた行が2行ありますが、1つめが有効になっており、2つ目は先頭に「#」があるため無効になっています。USB接続のサウンドカードを用いる場合はこれを下記のように変更してください。
# for the device on Raspberry Pi
#aplay -q $TMPVOICE

# for USB sound card
aplay -D plughw:1,0 -q $TMPVOICE
すなわち、1つ目のaplayに「#」をつけて無効化し、2つ目のaplayから「#」を削除して有効化するわけです。「#」は半角文字で記述しましょう。編集が終わったらファイルを保存してleafpadを閉じて構いません。この編集が終わったら、 ターミナルで「speech.sh ラズベリーパイ」などと実行することで、USB接続のサウンドカードでも音声合成が行えるはずです。

4. 音声の変更(お好みで)

デフォルトでは男性の声で音声合成されますが、これを女性の声に変更したい場合は、下記の手順に従ってください。 まず、ターミナルで下記のコマンドを実行し、実行スクリプトspeech.shを編集用に管理者権限のleafpadで開きます。
$ sudo leafpad /usr/local/bin/speech.sh
その中で、下記の「HTSVOICE」で始まる部分に着目しましょう。
HTSVOICE=/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice
#HTSVOICE=/usr/share/hts-voice/mei/mei_happy.htsvoice
#HTSVOICE=/usr/share/hts-voice/mei/mei_angry.htsvoice
#HTSVOICE=/usr/share/hts-voice/mei/mei_bashful.htsvoice
#HTSVOICE=/usr/share/hts-voice/mei/mei_normal.htsvoice
#HTSVOICE=/usr/share/hts-voice/mei/mei_sad.htsvoice
この部分では、音声合成する際に用いる音声を選択しています。先頭に「#」がついている行はコメント文となっており、無効な行です。「#」がついていない 1 行のみが有効となっており、これが男性の声だったというわけです。

有効とする行を変更し(「#」のつかない有効な行を1行だけとする)、leafpadで保存してから、もう一度「speech.sh ラズベリーパイ」などと実行してみましょう。
その際、leafpadを起動したターミナルとは別に新たにターミナルを開いて実行するのが良いでしょう。声がかわるのが分かるはずです。なお、女性の声に変更するためには、インストール時にMMDAgent_Example-1.7.zipをダウンロードして、必要なファイルを適切な位置にコピーしていることが必要ですのでご注意ください。

5. 応用1:天気予報機能付き温度計に喋らせる

さて、以上により、Open JTalkとそれを呼び出すスクリプトにより音声合成ができることがわかりました。あとはこの機能をどう活用するかですが、まずは本書第4章で作成した「天気予報付き温度計」に発話機能を追加してみましょう。対象となるのは、本書第4章でこの温度計を作成した方となります。温度計とLCDの両方がI2C通信を行うものを用いますので、I2Cがあらかじめ有効にされている必要があります。

まず、必要な回路は下記のようになります。本書と同様にLCDとして横8文字x縦2文字のAQM0802を用いる場合は下図のようになります。GPIO 23に接続したタクトスイッチが一つ増えているだけです。ただし、最近はAQM0802を用いる際に、特殊な対処法が必要になることが多いです。本書補足ページ「本書発売後の追加情報」の「完成品のLCDを購入しても認識されない場合の暫定的な対処法」をご覧ください。


また、同じく「本書発売後の追加情報」の「4章全般:利用できるLCDについて」で紹介したストロベリーリナックスの横16文字x縦2文字のLCDを用いる場合の回路図はこちらです。LCDのピン配置が異なるだけで、基本的には同じ回路です。


これらの回路を動かすためのプログラムをダウンロードするため、ターミナルで下記のコマンドを実行してください。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/speech-weather.py
このプログラムは、書籍と同じくLCDとしてAQM0802を用いる場合のプログラムとなっています。 ストロベリーリナックスの横16文字x縦2文字のLCDを用いる場合、プログラムを少し変更する必要があります。そのためには、このプログラムを編集用にleafpadで開きます。ターミナルで下記のコマンドを実行しましょう。
$ leafpad speech-weather.py
プログラム中で、211行目にある下記の部分に着目します。横16文字のLCDを用いる場合はこのうちchars_per_lineの数値を8から16に変更してください。また、contrastの値は、文字が薄い場合に40程度に変更してください。変更が終わったら保存してleafpadを閉じて構いません。
contrast = 32 # 0から63のコントラスト。通常は32、文字が薄いときは40を推奨
chars_per_line = 8  # LCDの横方向の文字数
display_lines = 2   # LCDの行数
さて、プログラムを実行するには、ターミナル上で、プログラムspeech-weatherがあるディレクトリ(フォルダ)にて下記のコマンドを実行します。
$ python speech-weather.py
書籍第4章で必要な設定を済ませている方ならば、冒頭の動画のように「左のタクトスイッチで温度計のモード切替」、「右のタクトスイッチで音声合成」という動作が実現されるはずです。

このプログラム中で動作のポイントとなっているのは、81行目から始まる下記の部分です。modeというのは温度計の4つのモードを決める変数なのですが、その値に応じて、話す内容を場合分けしているのが見て取れます。
    elif channel==23:
        if mode==0:
            s = u('今日の天気は')+weather_kanji
            args = ['speech.sh', s]
            try:
                subprocess.Popen(args)
            except OSError:
                print('no speech.sh')
        elif mode==1 or mode==3:
            s = u('現在')+'{0:.1f}'.format(temperature)+u('度')
            args = ['speech.sh', s]
            try:
                subprocess.Popen(args)
            except OSError:
                print('no speech.sh')
        elif mode==2:
            s = u('明日の天気は')+weather2_kanji
            args = ['speech.sh', s]
            try:
                subprocess.Popen(args)
            except OSError:
                print('no speech.sh')


6. 応用2:音声認識と組み合わせてオウム返しで喋らせる

最後に、音声認識と組み合わせ、音声認識の結果をオウム返しで喋る、という例を試してみましょう。こちらも冒頭の動画にて例示されていましたね。 この例は音声認識にかなりの計算パワーを必要としますので、Raspberry Pi 3を用いることを推奨します。Raspberry Pi 3を用いても、認識から発声まで5秒程度の時間がかかることがあることが動画から見て取れるでしょう。 さらに、ここから先の内容は「Raspberry Pi + Julius + LIRC により家電製品を音声で操作する」を一通り終えた方を対象とします。

まず、音声認識を行う上で、どの辞書を用いるかに注意しておきましょう。「Raspberry Pi + Julius + LIRC により家電製品を音声で操作する」を終えた状態では「テレビ操作用の辞書」を用いる設定になっています。 一方、冒頭の動画では「Juliusのディクテーションキットのデフォルトの辞書」を用いました。どの辞書を用いても実行は可能ですが、もしデフォルトの辞書に戻したいならば、まずターミナルを起動して下記のように設定ファイルをleafpadで編集用に開きます。
$ leafpad dictation-kit-v4.4/main.jconf
この中で、辞書選択部分を下記のように「model/lang_m/bccwj.60k.htkdic」を用いるようにするのでした(先頭に「#」がない行のみが有効です)。
## 単語辞書ファイル
##
-v model/lang_m/bccwj.60k.htkdic
#-v ../remocon.dic
編集が終わったら保存してleafpadを閉じます。これにより、デフォルトの辞書が用いられるようになりました(ちなみに、自分でカスタマイズした辞書の方が単語数が少ないので認識速度は速いです)。

次に、必要なプログラムをダウンロードするため、ターミナルを起動して下記のコマンドを実行します。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/recog-speech.py
このプログラムを実行するためには、事前に音声認識エンジンJuliusをモジュールモードで起動しておく必要があります。 そのためには、ターミナルを起動して下記のコマンドを実行するのでした。
$ julius -C dictation-kit-v4.4/main.jconf -C dictation-kit-v4.4/am-gmm.jconf -demo -module
その状態で、もう一枚別のターミナルを起動し、その上で下記のコマンドでプログラムを実行します。
$ python recog-speech.py
あとはマイクに向かって話せば冒頭の動画のような動作が実現します。動画にも注釈がありますが、音声合成の結果の音声をマイクが拾わないように注意してください。そうしないと、「認識」→「合成」→「認識」→「合成」→…が無限に繰り返されます(この現象の原因に気づくまでちょっと悩みました)

さて、このプログラムrecog-speech.pyのポイントは、38行目から始まる下記の部分です。 認識された語は「''」→「語1」→「語2」→…「語n」→「'。'」という順で届くのですが、これをひとまとめに 「語1語2…語n。」と結合してからspeech.shに渡しています。
# 認識された単語wordの中に、u('...') という文字列が含まれるかどうかを
# チェックし、文字列に応じたアクションを記述します。
# u('...')でくくるのは、python2とpython3の互換性を保つためです。

if word != u(''):
    recognized_word += word

if u('。') in word: 
    print(recognized_word)
    args = ['speech.sh', recognized_word]
    subprocess.Popen(args).wait()
    recognized_word = u('')
以上、お疲れさまでした。

2017年3月15日水曜日

Raspberry Pi + Julius + LIRC により家電製品を音声で操作する

 0. はじめに

本書の第5章において、LIRC(Linux Infrared Remote Control) というソフトウェアを用いてRaspberry Piをテレビなどの家電製品のリモコンにする方法を紹介しました。

さらに、本ページの追加コンテンツ「Raspberry Pi上のLIRCでエアコンを操作する」において、書籍では触れられなかったエアコンの操作方法も紹介しました。

これらにおいて、家電製品へ命令を送信する方法として下記の3つを用いました。
  1. ターミナル上でのirsendコマンドによる送信
  2. タクトスイッチによる送信
  3. WebIOPiによるブラウザ経由の送信
本ページではこれらの3つに加え、「音声による命令の送信」の方法を紹介します。音声認識のためには音声認識エンジンであるJuliusを用います。

応用的なコンテンツとなりますので、本書第5章の「ターミナル上でのirsendコマンドによる送信(5.4.1章)」までの演習を終え、内容を理解している方を対象とします。

また、用いるOSはNOOBS 2.3.0に含まれるRaspbianとします。少なくとも、Jessie(NOOBS 1.4.2以降)であることを前提とした解説がありますので、なるべく新しいバージョンのOSを用いてください。

家電製品の操作に興味がないという方でも、本ページを読むことで「音声認識の結果を取得してその結果をもとに何らかのアクションを起こす」方法を知ることができます。

Raspberry PiにサンワプライのUSBマイクを接続した様子

また、リモコンで操作できるLED照明に対して本ページの内容を適用したデモンストレーションの動画が下記になります。


1. 音声認識を行うために必要な物品

音声認識を行うためにはマイクが必要ですが、Raspberry Piにはマイクを接続する端子がありません。マイクをRaspberry Piに接続するためには、外部機器を購入する必要があります。

本ページでは、マイクを接続するためのデバイスとして下記の2つを試しました。これ以外のデバイスはサポート対象外としますのでご了承ください。
どちらもUSBデバイスであり、USB端子に接続すれば使えるようになります。

ただし、SB-PLAY2を用いる場合、さらにミニジャック接続のPC用マイクも必要となります。これはどのようなマイクでも問題ないと思いますが、例えば「iBUFFALO マイクロフォン スタンドタイプ 3極プラグ搭載 ホワイト BSHSMPM01WH」のようなものがあります。

2. 日本語入力メソッド mozc のインストール

以下の手順において、Raspberry Pi 上で日本語を入力しなければならない箇所があります。Raspberry Pi用のOSであるRaspbian(Jessie以降)で日本語を入力するため、Googleが開発した日本語入力システムMozcをインストールします。「Google日本語入力」のもととなったソフトウェアです。

LXTerminalを起動し、下記の 2 つのコマンドを順に実行することで、ネットワークからMozcをダウンロードしてインストールします。なお、2 つ目のコマンドの実行後に「続行しますか? [y/n]」などと聞かれた場合は、キーボードで「y」をタイプしてEnterキーを押して下さい。
$ sudo apt-get update
$ sudo apt-get install ibus-mozc
なお、1 つ目のコマンドは、インストールできるアプリケーションのリストを更新するためのものです。1 分程度かかる場合あります。2 つ目のコマンドで、Mozcをインストールしています。

インストールが終った後はまずRaspberry Piを再起動します。その後、下図のように「US」と書かれた部分をマウスでクリックし「日本語 - Mozc」を選択してください。あとは「半角/全角」キーで日本語入力のオンオフを切り替えられます。
動作チェックとして、ブラウザでGoogleなどにアクセスし、日本語で検索してみると良いでしょう。

3. 音声認識エンジンJuliusのインストール

ここからは、Raspberry Pi上で音声認識を行うために用いるソフトウェアであるJuliusのインストール方法を解説します。

まず、こちらより julius-4.4.2.tar.gz をダウンロードしてください。ブラウザでダウンロードすると、デフォルトでユーザーpiのDownloadsディレクトリ(フォルダ)にダウンロードされます。

さらに、こちらより、Juliusディクテーションキットの最新版である dictation-kit-v4.4.zip をダウンロードしてください。こちらは400MB以上のサイズがあり、解凍するとさらに800MBの容量が必要となります。事前にRaspberry PiのOSを格納したSDカードの容量に余裕があることを確認した方がよいでしょう。

ターミナルを起動し、dfコマンドに-kオプションを付けて実行することで、SDカードの残り容量をKB単位で知ることができます。
$ df -k
ファイルシス   1K-ブロック    使用 使用可 使用% マウント位置
/dev/root          6154176 5625008 193504   97% /
(以下略)
上記の表示は、8GBのSDカードを用いてJuliusのインスト―ルを全て終えた状態でのSDカードの容量を示しています。使用率97%、残り容量193.504MBであることを示しますので、ほぼギリギリです。ですので、Juliusを用いる際は16GB以上のSDカードを用いることを推奨します。

さて、ダウンロードが終わったら、 julius-4.4.2.tar.gz および dictation-kit-v4.4.zip をDownloadsディレクトリ(フォルダ)(/home/pi/Downloads)からユーザーpiのホーム(/home/pi)に移動しましょう。本書p.322の図A-1のようにファイルマネージャを用いるのが良いでしょう。

次に、ターミナルを起動して下記のコマンドを順に実行し、Juliusのインストールに必要なライブラリをインストールします。
$ sudo apt-get update
$ sudo apt-get install libasound2-dev
上記のコマンドが終わったら、以下のコマンドでJuliusをインストールします。
$ tar zxf julius-4.4.2.tar.gz
$ cd julius-4.4.2
$ ./configure --enable-words-int --with-mictype=alsa
$ make
$ sudo make install
次に、 dictation-kit-v4.4.zip を下記のコマンドでユーザpiのホームに解凍します。これは解凍のみで構いません。
$ cd
$ unzip dictation-kit-v4.4.zip
以上でJuliusの準備は終了ですが、最後に、導入したマイクをJuliusで用いるための設定を行います。下記のコマンドにより、環境設定ファイル .bashrc テキストエディタ leafpadで開きましょう。
$ cd
$ leafpad .bashrc
このファイルには様々な設定が書き込まれていますが、それを壊さないように注意しながら、ファイル末尾に下記の1行を追加しましょう。
export ALSADEV=plughw:1,0
書き込みが終わったらファイルを保存してからleafpadを閉じます。

以上が終わったら、Raspberry Piを一旦再起動しましょう。再起動の前に、(もし接続していなかったら)Raspberry PiにUSB経由のマイクデバイスを接続しておきましょう。

4. Juliusの動作確認

インストールしたJuliusの動作チェックをしてみましょう。ターミナルを起動し、下記のコマンドを実行します。
$ julius -C dictation-kit-v4.4/main.jconf -C dictation-kit-v4.4/am-gmm.jconf -demo
長い命令ですので、本書p.344で解説した「TABキーによるファイル名の補完」をうまく活用しないと入力は大変です。それも難しい場合、上記コマンドのコピー&貼り付けで実行しても良いでしょう(個人的には、TABキーによる補完をマスターすることをお勧めします)。

また、juliusコマンドに与えるオプションは、用いるディクテーションキットのバージョンに依存します。本ページではv4.4を用いた解説になっていますのでご注意ください。

実行して数秒待つと、ターミナルに下記の表示が現れます。
(省略)
Stat: adin_alsa: device name from ALSADEV: "plughw:1,0"
Stat: capture audio at 16000Hz
Stat: adin_alsa: latency set to 32 msec (chunk = 512 bytes)
Stat: "plughw:1,0": Device [USB PnP Audio Device] device USB Audio [USB Audio] subdevice #0
STAT: AD-in thread created
<<< please speak >>>
「<<< please speak >>>」の表示が出たら、マイクに向かって何か話してください。認識結果がターミナルに表示されます。下記は、マイクに向かって「こんにちは」、「ラズベリーパイ」と話したときの表示です。
(省略)
pass1_best:  こんにちは 。
sentence1:  こんにちは 。
pass1_best:  ラズベリー 杯 、
sentence1:  ラズベリー パイ 。
<<< please speak >>>
認識に失敗することもありますが、必ずしも認識率が高いわけではありませんので、あまり気にしなくても良いでしょう。

認識動作を終了したい場合、ターミナル上で「Ctrl-c」(Ctrlキーを押しながらcキーを押す)を実行してJuliusを終了してください。

なお、マイクの感度を調整したい場合、下記のコマンドをあらかじめターミナルで実行しておきます。「50」の部分は0%~100%の感度に相当する数字なので、適切な数字をいれます。100に近付く程感度が高いはずです。
$ amixer -c 1 sset 'Mic' 50

5. Juliusの辞書作成

ここまでで、Raspberry PiとJuliusを用いた音声認識が実現しました。これを本書第5章の内容と組み合わせ、テレビのリモコン操作を音声で行ってみましょう。マイクに向かって「電源」と話すと、テレビの電源のオン・オフが切り替る、などの動作です。

そのためには、まず音声認識の認識率を向上させる必要があります。デフォルトでなぜ誤認識が多いかというと、Juliusが提示する認識語の候補が多すぎるからです。Juliusが認識に用いる辞書を、テレビ操作に必要な語句のみに限定すると、(当然ながら)認識率が向上します。今回の目的にはこれで十分ですので、試してみましょう。

まず、テレビの操作に必要な語句を、下記の通りとします。左が表記、右が読みとします。

電源 でんげん
入力 にゅうりょく
いち
さん
よん
ろく
なな
はち
きゅう
10 じゅう
11 じゅういち
12 じゅうに
ボリュームアップ ぼりゅーむあっぷ
ボリュームダウン ぼりゅーむだうん
チャンネルアップ ちゃんねるあっぷ
チャンネルダウン ちゃんねるだうん

この語句のみを記した辞書を作成するため、まずは上記の内容を記したテキストファイルを作成する必要があります。名前は任意ですが、ここでは remocon.yomi としましょう。

下記のコマンドでremocon.yomiファイルを新規作成します。
$ leafpad remocon.yomi
なお、leafpadを用いない方のために記しておくと、このファイルはUTF-8の文字コードで記述する必要があります。 このファイルには、下記のように「表記」と「読み」を列挙します。
電源 でんげん
入力 にゅうりょく
1 いち
2 に
3 さん
4 よん
5 ご
6 ろく
7 なな
8 はち
9 きゅう
10 じゅう
11 じゅういち
12 じゅうに
ボリュームアップ ぼりゅーむあっぷ
ボリュームダウン ぼりゅーむだうん
チャンネルアップ ちゃんねるあっぷ
チャンネルダウン ちゃんねるだうん
上記の内容を記述する際には注意がいくつかあります。

まず、「表記」と「読み」の間は「半角空白」か「TAB」などを区切り文字として記入します。 ただし、「半角空白」を区切り文字として用いる方針にすると、間違って「全角空白」を入力してしまうことがあり、トラブルの元です。 そのため、個人的には「TAB」を区切り文字とすることを推奨します。 具体的には例えば1行目の記述において下記のようにキーボードのTABキーを入力する、ということです。
電源[TABキー]でんげん
次に、上記の内容を記入する際、空行があってはいけません。典型的には、末尾に空行を入れてしまうことはしばしば起こりますので、注意しましょう。

記入が終わったら、ファイルを保存してleafpadを閉じます。

保存した remocon.yomi を元に、辞書ファイルを作成します。まずは、その際に用いる補助コマンドをダウンロードしましょう。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/addsil.pl
$ chmod a+x addsil.pl
上記2コマンドの実行が終わったら、下記のコマンドにより、読みファイル remocon.yomi から辞書ファイル remocon.dic を作成します。
$ iconv -f utf-8 -t euc-jp remocon.yomi | ./julius-4.4.2/gramtools/yomi2voca/yomi2voca.pl  | iconv -f euc-jp  -t utf-8 | ./addsil.pl > remocon.dic
非常に長いコマンドなので、コピー&貼り付けで実行するのが無難でしょう。具体的には「remocon.yomi の文字コードをEUP-JPに変換」→「yomi2voca.pl コマンドにより読みをローマ字に変換」→「文字コードをUTF-8に変換」 →「ファイル先頭に休止状態の情報2行を追加」→「remocon.dic を保存」という流れで処理が実行されます。

念のため、 remocon.dic の中身を確認しておきましょう。下記のコマンドで中身をleafpadで確認できます。UTF-8で記述されています。
$ leafpad remocon.dic
中身は下記のようになっているはずです。
<s>     []      silB
</s>    [。]    silE
電源    d e N g e N
入力    ny u u ry o k u
1      i ch i
2      n i
3      s a N
4      y o N
5      g o
6      r o k u
7      n a n a
8      h a ch i
9      ky u u
10    j u u
11    j u u i ch i
12    j u u n i
ボリュームアップ        b o ry u: m u a q p u
ボリュームダウン        b o ry u: m u d a u N
チャンネルアップ        ch a N n e r u a q p u
チャンネルダウン        ch a N n e r u d a u N
読みがローマ字に変換されているのが yomi2voca.pl の効果、先頭2行が追加されているのが addsil.pl の効果です。確認が終わったらleafpadを閉じて構いません。

なお、完成済みの辞書ファイル remocon.dic を下記のコマンドでダウンロードできますので、作成が面倒だという方はご活用ください。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/remocon.dic
なお、既に remocon.dic が存在する場所で上記コマンドを実行すると、ダウンロードされたファイルの名前は remocon.dic.1 などと自動的に変更されますのでご注意ください。

以上でテレビ操作用の辞書ファイルを用意できましたので、Juliusがこれを用いるよう変更してみましょう。そのためには、julius を実行する時に利用する設定ファイル dictation-kit-v4.4/main.jconf を編集する必要があります。

下記のコマンドで dictation-kit-v4.4/main.jconf を leafpadにより開きましょう。
$ leafpad dictation-kit-v4.4/main.jconf
この中に、辞書ファイルを指定している下記の場所があるので見つけてください。
## 単語辞書ファイル
##
-v model/lang_m/bccwj.60k.htkdic
これを下記のように編集してください。元からあった辞書指定行に「#」を追記して無効化し、新たに一行追加するわけです。全て半角で記述するよう注意しましょう。
## 単語辞書ファイル
##
#-v model/lang_m/bccwj.60k.htkdic
-v ../remocon.dic
なお、ここでの解説は、ディクテーションキットが /home/pi/dictation-kit-v4.4 に、作成した辞書ファイルが /home/pi/remocon.dic にあることを前提としています。追記した行にある「../」とは「一つ上の階層のディレクトリ(フォルダ)」を意味します。 ついでに、 dictation-kit-v4.4/main.jconf でもう一か所変更しておきましょう。下記の場所を見つけてください。
-rejectshort 800 # 指定ミリ秒以下の長さの入力を棄却する
これは、800ミリ秒以下の入力を無視する設定なのですが、この設定のままだと「に」や「ご」などのように短い音声の認識に失敗することが多くなります。 そこで、下記のようにこの数値を400に変更しましょう。半角で記述するよう注意しましょう。
-rejectshort 400 # 指定ミリ秒以下の長さの入力を棄却する
以上の変更が終わったら保存をしてからleafpadを閉じましょう。 そして、上と同様のjuliusコマンドで音声認識を試してみましょう。今度は上で列挙したテレビ操作用の単語しか認識されないはずです。 

下記は「でんげん」、「いち」、「ぼりゅーむあっぷ」と話したときの様子です。警告(WARNING)は出ていますが、正しく認識されていることがわかります。
pass1_best:  電源 。
WARNING: 00 _default: hypothesis stack exhausted, terminate search now
sentence1:  電源 。
pass1_best:  1 。
WARNING: 00 _default: hypothesis stack exhausted, terminate search now
sentence1:  1 。
pass1_best:  ボリュームアップ
WARNING: 00 _default: hypothesis stack exhausted, terminate search now
sentence1:  ボリュームアップ 。

6. moduleモードでのJuliusの実行

ここまででJuliusによる音声認識が実現できましたが、これを実現しているのは、配布されたファイルをインストールしてできたjuliusコマンドでした。

しかし、我々が実現したいのは、音声認識の結果を自分で作成したプログラムから利用することです。それができて初めて、「『電源』という音声が認識されたら、テレビの電源をオンするための命令を送信する」などの動作が可能になるのです。

そのためには、Juliusをmoduleモードと呼ばれるモードで動作させる必要があります。moduleモードの概念図を示したのが下図です。左側に描かれたmoduleモードで動作するjuliusがサーバーとなり、右側に描かれたクライアント(jcontrolコマンドや自作プログラム)からの認識の問い合わせに応答する、という仕組みです。


イメージをつかむために、moduleモードの動作を試してみましょう。まず、下記のコマンドでjuliusをmoduleモードで起動しましょう。これまでとの違いは、末尾に「-module」がつくだけです。
$ julius -C dictation-kit-v4.4/main.jconf -C dictation-kit-v4.4/am-gmm.jconf -demo -module
しばらく待つと、ターミナルに下記の表示が現れます。juliusがサーバーとして動作し、クライアントからの接続を待ち受けていることが記されています。
(省略)
Stat: server-client: socket ready as server
///////////////////////////////
///  Module mode ready
///  waiting client at 10500
///////////////////////////////
moduleモードのjuliusが動作するターミナルはそのままにしておき、 もう一つ別のターミナルを起動しましょう。そこで下記のコマンドを実行します。jcontrolはjuliusに付属するコマンドで、moduleモードのjuliusに接続し結果を表示することができます。「localhost」とはjuliusが動作しているRaspberry Piを表わすホスト名です。
$ jcontrol localhost
すると、そのターミナル上では下記のように表示されます。
connecting to localhost:10500...done
> <STARTPROC/>
> <INPUT STATUS="LISTEN" TIME="1489549742"/>
一方、moduleモードのjuliusが動作するターミナル上の表示は下記のように変化します。
(省略)
STAT: AD-in thread created
その状態で、これまで通りマイクに何か話してみましょう。先ほどと同様「でんげん」、
「いち」、「ぼりゅーむあっぷ」と話したとき、jcontrolコマンドを実行したターミナルには、例えば下記のように表示されます。
(省略)
>   <SHYPO RANK="1" SCORE="-2573.104004">
>     <WHYPO WORD="" CLASSID="<s>" PHONE="silB" CM="0.958"/>
>     <WHYPO WORD="電源" CLASSID="電源" PHONE="d e N g e N" CM="0.978"/>
>     <WHYPO WORD="。" CLASSID="</s>" PHONE="silE" CM="1.000"/>
>   </SHYPO>
(省略)
>   <SHYPO RANK="1" SCORE="-1995.357666">
>     <WHYPO WORD="" CLASSID="<s>" PHONE="silB" CM="0.927"/>
>     <WHYPO WORD="" CLASSID="1" PHONE="i ch i" CM="0.864"/>
>     <WHYPO WORD="。" CLASSID="</s>" PHONE="silE" CM="1.000"/>
>   </SHYPO>
(省略)
>   <SHYPO RANK="1" SCORE="-2783.654053">
>     <WHYPO WORD="" CLASSID="<s>" PHONE="silB" CM="0.953"/>
>     <WHYPO WORD="ボリュームアップ" CLASSID="ボリュームアップ" PHONE="b o ry u: m u a q p u" CM="0.967"/>
>     <WHYPO WORD="。" CLASSID="</s>" PHONE="silE" CM="1.000"/>
>   </SHYPO>
これまでとは形式がかなり異なりますが、「電源」、「1」、「ボリュームアップ」が認識されていることは見て取れるでしょう。 

jcontrolを終了するには、jcontrolを実行しているターミナルで「Ctrl-c」を実行します。そうすると、moduleモードのjuliusは再びクライアントからの接続を待機する状態に戻ります。 moduleモードのjuliusを終了するには、やはりそのターミナルで「Ctrl-c」を実行してください。

さて、以上の動作確認により、目指すべきことがわかりました。jcontrolのようにmoduleモードのjuliusに接続し、得られた認識結果に応じてアクションを起こすプログラムを書けば良いのです。

そのためのPythonプログラムを作成してみましたので、ダウンロードして試してみましょう。下記のコマンドで recog-TV.py をダウンロードできます。
$ wget https://raw.githubusercontent.com/neuralassembly/raspi/master/recog-TV.py
これを実行するため、あらかじめmoduleモードのjuliusを起動しておきます

そして、別のターミナルを開き、下記のコマンドでrecog-TV.pyを実行します。
$ python recog-TV.py
実行後にすぐ「socket error」と表示される場合はmoduleモードのjuliusが起動されていませんので注意してください。

エラーがでなければ、マイクに向かって話しかけてみましょう。

LIRCを既にインストール済みだが起動されていない方ならば下記のように表示されるでしょうし、
電源
irsend: could not connect to socket
irsend: No such file or directory
1
irsend: could not connect to socket
irsend: No such file or directory
ボリュームアップ
irsend: could not connect to socket
irsend: No such file or directory
LIRCをインストールされていない方ならば下記のように表示されるでしょう。
電源
command not found.
1
command not found.
ボリュームアップ
command not found.
いずれにせよ、音声認識結果「電源」、「1」、「ボリュームアップ」が表示されていることがわかります。 

このプログラム recog-TV.py は、音声が認識されたときに、テレビを操作する信号を出力するように作られています。 その準備ができていれば上記のエラーメッセージは出ないのですが、LIRCが起動していないときやLIRCがインストールされていない場合には 上記のようなメッセージが現れるというわけです。

LIRCの準備は本書第5章の5.4.1までを終えれば完了します。すなわち、「irsend SEND_ONCE TV power」などのコマンドでテレビが操作できるようになれば良いわけです。その状態で「moduleモードのjulius」および「recog-TV.py」が適切に起動されれば、エラーがでず、音声によりテレビを操作できるようになります。

もちろん、音声認識の結果をテレビの操作以外に用いることもできます。例えば、認識された言葉を合成音声でRaspnberry Piに発話させることも可能です。 その方法を、本ページの続編的な内容である「Raspberry Pi + Open JTalkによる音声合成で天気予報付き温度計に喋らせる」にて紹介しておりますので、是非ご覧ください。

7. 若干のコードの解説

サンプルファイル recog-TV.py を全て解説するのは難しいですが、このプログラムを
改造したいという方のために重要な部分のみを解説します。 

ポイントとなるのは以下の部分です。Web上での見やすさのためインデント(字下げ)は一部省略します。
# 認識された単語wordの中に、u('...') という文字列が含まれるかどうかを
# チェックし、文字列に応じたアクションを記述します。
# u('...')でくくるのは、python2とpython3の互換性を保つためです。
# 「対象となる文字が含まれているか」を調べていますので、
# 先に「『1』が含まれるか」をチェックすると
# 10~12がすべて「1」と判定されてしまいます。
# そのため、10~12のチェックを先に行っています。

if u('10') in word:
    print(word)
    args = ['irsend', '-#', '1', 'SEND_ONCE', 'TV', 'ch10']
    try:
        subprocess.Popen(args)
    except OSError:
        print('command not found.')
elif u('11') in word:
    print(word)
    args = ['irsend', '-#', '1', 'SEND_ONCE', 'TV', 'ch11']
    try:
        subprocess.Popen(args)
    except OSError:
        print('command not found.')
(以下略)
この部分ではwordという変数の中に、認識された語句が格納されています。それをif~elif文により分岐させ、認識された語句ごとに実行する処理を変えている、というわけです。

この部分をうまく書き換えることで、処理を色々と変えることができるでしょう。

8. 自動起動

最後に、ここで試したmoduleモードのjuliusとrecog-TV.pyを、Raspberry Pi起動時に自動で実行する方法を記しておきましょう。

自動起動用のファイル/etc/rc.localにコマンドを追記します。まず、管理者権限のleafpadで/etc/rc.localを編集用に開きます。
$ sudo leafpad /etc/rc.local
そして、末尾にある「exit 0」の手前に下記の3つのコマンドを記述し、保存します。
ALSADEV=plughw:1,0 julius -C /home/pi/dictation-kit-v4.4/main.jconf -C /home/pi/dictation-kit-v4.4/am-gmm.jconf -demo -module &

sleep 10

python /home/pi/recog-TV.py &

exit 0
ポイントは、下記の通りです。
  • .bashrcに書いたALSADEVについての設定は/etc/rc.localでは読み込まれないので、直に書く
  • main.jconfやam-gmm.jconfは「dictation-kit-v4.4/main.jconf」のような相対パスではなく「/home/pi/dictation-kit-v4.4/main.jconf」のような絶対パスで書く
  • juliusの起動が終了するのを待つため、sleep文を挿入する
  • recog-TV.pyも絶対パスで書く
保存したらleafpadを終了し、Raspberry Piを再起動してみてください。自動で音声入力を受け付けるモードになっているはずです。

 以上、お疲れさまでした。

2017年1月7日土曜日

GUIアプリケーションの自動起動

はじめに

Raspberry Piの起動時にアプリケーションを自動起動(自動実行)したい場合、設定ファイル /etc/rc.local に実行したいコマンドを記述する方法がよく知られています。 

しかし、この方法で自動起動できるのはターミナル上で実行するCUIアプリケーションのみであり、GUIアプリケーションの場合は別の方法を用いる必要があります。ここではその方法を紹介します。

本書の場合、7章「OpenCVによる画像処理と対象物追跡を行ってみよう」で紹介したプログラムが該当します。 なお、GUIアプリケーションであっても、ターミナルからどのようなコマンドで起動するかを知っておく必要があります。例えば、Chromiumブラウザなら「chromium-browser」などです。

方法

LXTerminalを起動し、下記のコマンドを実行します。テキストエディタleafpadにより、自動起動するアプリケーションが列挙されたファイルが開きます。
leafpad .config/lxsession/LXDE-pi/autostart
中身は下記のようになっているはずです(2016年11月にリリースされたNOOBS2.1.0の場合)。
@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xscreensaver -no-splash
@point-rpi 
この末尾に、起動したいアプリケーションのコマンドを追記します。例えば、本書7章で用いたbb2-07-01-preview.pyなら、下記のようになるでしょう。
@python /home/pi/bb2-07-01-preview.py
先頭に「@」つけることに注意してください。さらに、サンプルファイルの保存位置が異なるなら、適宜編集しましょう。

さらに、wiringpiを用いるbb2-07-06-tracking-circle.pyやbb2-07-06-tracking-face.pyなら先頭にsudoをつける必要があることにも注意してください。