電子工作なし。幼稚園~小学生くらいの子供がいる家庭のリビングで使うRaspberry Pi(+ちょっとだけSlack)の後編。具体的にどうやって作るかの技術編です。黒い画面にアレルギーがない方が対象です。
今回はRaspberryPi2(OSはOSMCですが、Raspbianでも一緒だと思います)を使用していますが、Linux系であればどれでも良く似た感じだと思います。
実際の動きや概要は前編に。あわせて御覧ください。
ソースコード/GitHUB
説明ほとんど無いけど、使ってるスクリプトを下記に置きました。
毎日の記念撮影
デジタルカメラをUSB経由でRaspberryPiと接続し、コマンドラインから写真を撮ったりあれこれできるgphoto2を使って、cronで撮影します。撮影し終わったファイルは縮小して下記のslackerを使ってslackの#photoに投げています。詳細は下記の、1.一眼レフカメラをRaspberryPiからリモート制御する話 で。
- 一眼レフカメラをRaspberryPiからリモート制御する話 / もやし工房
一眼レフカメラをRaspberryPiからリモート制御する話デジタルカメラをUSB経由でRaspberryPiと接続し、コマンドラインから写真を撮ったりあれこれできるgphoto2の話。 - コマンドラインからSlackにメッセージや任意のファイルを送れるプログラム
https://github.com/os/slacker
https://github.com/juanpabloaj/slacker-cli - 実際のスクリプト
https://github.com/koike-moyashi/katei_raspi/tree/master/take_photo
写真からタイムラプス動画を作る
- 静止画を日付の古い順から0000-9999(存在するまで)の連番に変更
$ ls -r *.jpg | awk '{ printf "mv %s photo_%04d.jpg\n", $0, NR }' | sh
- ffmpegに食わせる(15フレーム/s, mp4)
$ ffmpeg -f image2 -r 15 -i photo_%04d.jpg -an -vcodec libx264 -pix_fmt yuv420p video.mp4
音楽再生をスマホで操作するのが面倒1(Kodi/OSMC)
Kodiの設定で外部からのコントロールを許可してから、下記のWebAPIをpythonスクリプトでたたきます。pip install xbmc-jsonしてから作ったスクリプトでよろしくしました。xbmc-jsonライブラリはhttp request時のタイムアウト設定が無かったので、3秒程度でタイムアウトする設定を加えました。
- APIドキュメント – JSON-RPC API
https://kodi.wiki/view/JSON-RPC_API - python用ライブラリ
https://pypi.python.org/pypi/xbmc-json/ - 実際のスクリプト
https://github.com/koike-moyashi/katei_raspi/tree/master/xbmc-json-script
音楽再生をスマホで操作するのが面倒2(音声認識/Julius)
インストール自体は(時間がかかりますが)色んな方がされているので問題なく済むと思います。全ての語句を認識させたいわけではないので辞書は小さく。若干ハマったのはマイクの音量と過剰マッチ。
音量はalsamixerを起動して、録音→該当マイクの音量?を最大値近くまであげました。過剰マッチに関しては、下記3の方を参考に、ダミーデータ&近い語句を沢山入れることによって少しマシになりました。2の方を参考に、ソケット通信で見に行く&任意のテキストが来た場合にシェルスクリプトを実行&Julius自体の自動起動しました。
- Julius
http://julius.osdn.jp/ - Raspberry Pi でライザップミクを作る@karaage
http://karaage.hatenadiary.jp/entry/2015/09/04/073000 - ルールベースの juliusと精度@お前の血は何色だ!! 4
http://d.hatena.ne.jp/rti7743/20120314/1331695203 - 実際のスクリプト
https://github.com/koike-moyashi/katei_raspi/tree/master/julius
ルーチン的な事に関して子どもに言うのが面倒くさい(喋らせる)
前準備(wavを適切なカードで鳴らす&同時に音を鳴らす)
最終的には できたwavを再生させるのでまずは音が鳴る環境を作ります(スピーカーから音がなるか確認します)。今回の場合はUSB外部オーディオに再生させたいのですが、ドライバー類は標準で認識していました。
またサウンドカードが複数つながっている関係で、そのままwavを再生しようとしても違うカードで鳴ってしまうため、カード番号XXで再生を設定しました。
aplay -l
とすると認識しているオーディオ機器を表示できるので、鳴らしたいカード番号とデバイスIDを確認します。
osmc@moyashi-osmc:~$ aplay -l **** ハードウェアデバイス PLAYBACK のリスト **** カード 0: 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 カード 0: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI] サブデバイス: 1/1 サブデバイス #0: subdevice #0 カード 1: Device [C-Media USB Audio Device], デバイス 0: USB Audio [USB Audio] サブデバイス: 1/1 サブデバイス #0: subdevice #0 カード 2: DAC [USB Audio DAC], デバイス 0: USB Audio [USB Audio] サブデバイス: 1/1 サブデバイス #0: subdevice #0
今回は [USB Audio DAC]で鳴らしたいので、カード2、デバイス0(数字は環境によって異なります)。
適当なwavファイルを転送し、
aplay -D hw:2,0 hoge.wav
で音が鳴ればOK。
Kodi側ではalsaの音量を100%にしたいのですが、音声再生時はこのままだとうるさいので喋らせている間はカード番号XXの音量を絞る設定を入れました。
amixer -q -c 2 set PCM 60% aplay --quiet ${TMPFILE} amixer -q -c 2 set PCM 100%
あと、そのままだとLinux(alsa?)の制限でKodiで音楽が流れている&停止直後だと、aplayでwavを再生しても「audio open error: Device or resource busy」と言うエラーで再生できなかったので、alsaでミキサーとやらを作成し、複数の音源が同時になってもエラーとならないようにしました。
~/.asoundrc pcm.!default { type plug slave.pcm "dmixer" } pcm.dmixer { type dmix ipc_key 1024 slave { pcm "hw:2,0" period_time 0 period_size 1024 buffer_size 4096 channels 2 #rate 44100 } bindings { 0 0 1 1 } }
環境によって”hw:2,0″の部分をaplay -l等でhw番号を調べ、鳴らしたいカードにする必要があります。
お話させる(OpenJtalkのインストール)
OpenJtalkと言うオープンソース・ソフトウェアを使うと、テキスト文字(漢字可)から辞書等を使いつつ良い感じに音声wavファイルを作ってくれます。
基本は下記ページを参考にしましたが、ページ中のスクリプトはバージョン変わってるので異なります。
- Raspberry Piに喋らせる / 橋本商会
http://shokai.org/blog/archives/6893 - Open JTalk
http://open-jtalk.sourceforge.net/
$ sudo apt-get install open-jtalk open-jtalk-mecab-naist-jdic htsengine libhtsengine-dev hts-voice-nitech-jp-atr503-m001
確認
$ echo "こんにちは" | open_jtalk -x /var/lib/mecab/dic/open-jtalk/naist-jdic -m /usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice -ow ~/test.wav $ aplay -D hw:2,0 ~/test.wav
うーん。喋るけどロボロボしい声。
声データ(音響モデル)の変更
今回は上記ページにあるメイさんを使用しましたが、「htsvoice」や「音響モデル」で検索すると、色んなモデルデータがダウンロード/使用可能です。音響モデルの指定は先程の”-m”で指定しているだけなので、内容によって声を変えても楽しそうです。
- 音声合成ソフトSHABERUで使用できる音響モデル
http://akihiro0105.web.fc2.com/Downloads/Downloads-htsvoice.html
wget http://downloads.sourceforge.net/project/mmdagent/MMDAgent_Example/MMDAgent_Example-1.6/MMDAgent_Example-1.6.zip unzip MMDAgent_Example-1.6.zip sudo cp -R MMDAgent_Example-1.6/Voice/* /usr/share/hts-voice/
確認
$ echo "こんにちは" | open_jtalk -x /var/lib/mecab/dic/open-jtalk/naist-jdic -m /usr/share/hts-voice/mei/mei_normal.htsvoice -ow ~/test.wav $ aplay -D hw:2,0 ~/test.wav
うん。可愛くなった。
簡単なコマンドでお話できるようスクリプトを作っておく
上記のブログを参考に簡単にお喋りできるようにスクリプトを作りました。RaspberryPiではメディアプレーヤーKodiを動かして音楽聞いている関係で、喋らせるときはamixerでボリュームを一時的に絞っています。
osmc@moyashi-osmc:~$ jsay こんにちは オハナシシタヨ cron用(/usr/local/bin/jsay_cron) 喋る前にピン・ポーン・パン・ポーン音を入れる+平日のみ動く。
チャイム音は下記の素材を使わせてもらいました。
決まった時間にお話させる
cronへ登録します。
# # 朝 # 15 06 * * * /usr/local/bin/jsay_cron 家族の時間だよ。家族の時間だよ。おうちのことをする時間だよ。 30 07 * * 1,2,3,4,5 /usr/local/bin/jsay_cron XXちゃん。そろそろ学校へ行く時間だよ。XXちゃん。そろそろ学校へ行く時間だよ。気を付けて行ってきてね。 20 08 * * 1,2,3,4,5 /usr/local/bin/jsay_cron XXくん。そろそろ保育園の時間だよ。XXくん。そろそろ保育園の時間だよ。今日も元気にいってらっしゃい。 # # 夜 # 15 17 * * * /usr/local/bin/jsay_cron 家族の時間だよ。家族の時間だよ。おうちのことをする時間だよ。
子どもに直接注意するのはエネルギー使う(Slackから喋らせる)
Slackの特定のroomに文字列を投げると、常駐しているボットがテキストをひろって、上記の喋らせるスクリプトに内容をなげ、スピーカーから声がでるみたいな流れ。
Hubotのインストール
Slackと連携させる為にHubotと言うNode.jsで動くボット用フレームワークを入れます。
基本下記のページを参考にしてましたが、調べているとnode.jsやhubotのバージョン等によって入れ方が色々あるっぽいので最新の情報を調べてみることをおすすめします。ちなみに名前はroboにしました。
- Raspberry PiにNode.jsを入れる / Installing Node.js via package manager | Node.js
https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions - Raspberry Pi | 自作Slackボットを作ろう / たぷん日記
http://www.tapun.net/raspi/raspberry-pi-raspberry-pi-slack-hubot-install
Slackのメッセージで喋らせる
Slackに投稿すると先ほど入れたOpenJtalkでおしゃべりさせます。
Hubotを利用したスクリプトでローカルの任意をシェルを実行できるのでそれを利用します。
と言っても結構簡単で、hubotを作成したscriptsディレクトリに下記のファイルを入れて(部屋と実行したいスクリプトを指定して)node.jsを再起動するだけ。
- SlackからHubot経由で 、サーバのシェルを実行してみよう! / Sanwa Systems Tech Blog
http://tech.sanwasystem.com/entry/2015/04/30/213521 - 実際のスクリプト
https://github.com/koike-moyashi/katei_raspi/tree/master/slack_bot
hubotを入れたディレクトリに移動し、bin/hubotを起動して、単体(slack経由では無い)で動くかを確認したのち、Slack経由で動くかを確認します。下記のSLACK_TOKENはSlackでHubotの連携をするともらえます。
#!/bin/sh export HUBOT_SLACK_TOKEN=XXXX-XXXXXX-XXXXXXXX bin/hubot --adapter slack
カワイイ。
ボットの常駐化
上記のスクリプトを常駐化させるためにforeverと言うのを入れます。
- node.jsスクリプトをforeverでデーモン化する / DegiWiki
hubotを入れたディレクトリでこんな感じで起動。
#!/bin/sh export HUBOT_SLACK_TOKEN=xxxx-XXXXXXX-XXXXXXXX forever start -l /var/log/nodejs/logfile.log -a -c coffee node_modules/.bin/hubot -a slack
スケジュールをいちいちスマホで見るのが面倒
GoogleAPIでカレンダーAPIを登録してから、公式のClient Libraryを利用して今日の予定だけテキストで吐くスクリプトを作りました(下記1に詳細が書いてあります)。
出てきたテキストを、上記の喋らせるスクリプト(jsay)に投げるとしゃべります。
- Google Calendar API / PHP Client Library
https://developers.google.com/google-apps/calendar/quickstart/php - Google Calendar / Slack App Directory
https://slack.com/apps/A0F8149ED-google-calendar - 実際のスクリプト
https://github.com/koike-moyashi/katei_raspi/tree/master/get_calender
最後に
ある程度上手く動くことが確認できたら、miniSDの中身をイメージ化してファイルにし、何処かに保存しておくことがおすすめです。上記環境をもう一度作るのはどう考えても辛い。
- Windows で Raspberry Pi のバックアップを取る方法
http://www.moonmile.net/blog/archives/6878
コメント
[…] もやし工房さんの子どもがいる家庭で使うRaspberryPi&Slack(技術編)のまんまやればいいだけ。 […]