子どもがいる家庭で使うRaspberryPi&Slack(技術編)

電子工作なし。幼稚園~小学生くらいの子供がいる家庭のリビングで使うRaspberry Pi(+ちょっとだけSlack)の後編。具体的にどうやって作るかの技術編です。黒い画面にアレルギーがない方が対象です。

今回はRaspberryPi2(OSはOSMCですが、Raspbianでも一緒だと思います)を使用していますが、Linux系であればどれでも良く似た感じだと思います。

実際の動きや概要は前編に。あわせて御覧ください。

ソースコード/GitHUB

説明ほとんど無いけど、使ってるスクリプトを下記に置きました。

毎日の記念撮影

デジタルカメラをUSB経由でRaspberryPiと接続し、コマンドラインから写真を撮ったりあれこれできるgphoto2を使って、cronで撮影します。撮影し終わったファイルは縮小して下記のslackerを使ってslackの#photoに投げています。詳細は下記の、1.一眼レフカメラをRaspberryPiからリモート制御する話 で。

  1. 一眼レフカメラをRaspberryPiからリモート制御する話 / もやし工房
    http://www.moyashi-koubou.com/blog/dslr_camera_raspberrypi/
  2. コマンドラインからSlackにメッセージや任意のファイルを送れるプログラム
    https://github.com/os/slacker
  3. 実際のスクリプト
    https://github.com/koike-moyashi/kaitei_raspi/tree/master/take_photo

音楽再生をスマホで操作するのが面倒1(Kodi/OSMC)

Kodiの設定で外部からのコントロールを許可してから、下記のWebAPIをpythonスクリプトでたたきます。pip install xbmc-jsonしてから作ったスクリプトでよろしくしました。xbmc-jsonライブラリはhttp request時のタイムアウト設定が無かったので、3秒程度でタイムアウトする設定を加えました。

  1. APIドキュメント – JSON-RPC API/v6
    http://kodi.wiki/view/JSON-RPC_API/v6
  2. python用ライブラリ
    https://pypi.python.org/pypi/xbmc-json/
  3. 実際のスクリプト
    https://github.com/koike-moyashi/kaitei_raspi/tree/master/xbmc-json-script

音楽再生をスマホで操作するのが面倒2(音声認識/Julius)

インストール自体は(時間がかかりますが)色んな方がされているので問題なく済むと思います。全ての語句を認識させたいわけではないので辞書は小さく。若干ハマったのはマイクの音量と過剰マッチ。

音量はalsamixerを起動して、録音→該当マイクの音量?を最大値近くまであげました。過剰マッチに関しては、下記3の方を参考に、ダミーデータ&近い語句を沢山入れることによって少しマシになりました。2の方を参考に、ソケット通信で見に行く&任意のテキストが来た場合にシェルスクリプトを実行&Julius自体の自動起動しました。

  1. Julius
    http://julius.osdn.jp/
  2. Raspberry Pi でライザップミクを作る@karaage
    http://karaage.hatenadiary.jp/entry/2015/09/04/073000
  3. ルールベースの juliusと精度@お前の血は何色だ!! 4
    http://d.hatena.ne.jp/rti7743/20120314/1331695203
  4. 実際のスクリプト
    https://github.com/koike-moyashi/kaitei_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ファイルを作ってくれます。

基本は下記ページを参考にしましたが、ページ中のスクリプトはバージョン変わってるので異なります。

  1. Raspberry Piに喋らせる / 橋本商会
    http://shokai.org/blog/archives/6893
  2. 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」や「音響モデル」で検索すると、色んなモデルデータがダウンロード/使用可能です。


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にしました。

Slackのメッセージで喋らせる

Slackに投稿すると先ほど入れたOpenJtalkでおしゃべりさせます。

Hubotを利用したスクリプトでローカルの任意をシェルを実行できるのでそれを利用します。

と言っても結構簡単で、hubotを作成したscriptsディレクトリに下記のファイルを入れて(部屋と実行したいスクリプトを指定して)node.jsを再起動するだけ。

hubotを入れたディレクトリに移動し、bin/hubotを起動して、単体(slack経由では無い)で動くかを確認したのち、Slack経由で動くかを確認します。下記のSLACK_TOKENはSlackでHubotの連携をするともらえます。


#!/bin/sh
export HUBOT_SLACK_TOKEN=XXXX-XXXXXX-XXXXXXXX
bin/hubot --adapter slack

カワイイ。

ボットの常駐化

上記のスクリプトを常駐化させるためにforeverと言うのを入れます。

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)に投げるとしゃべります。

  1. Google Calendar API / PHP Client Library
    https://developers.google.com/google-apps/calendar/quickstart/php
  2. Google Calendar / Slack App Directory
    https://slack.com/apps/A0F8149ED-google-calendar
  3. 実際のスクリプト
    https://github.com/koike-moyashi/kaitei_raspi/tree/master/get_calender

最後に

ある程度上手く動くことが確認できたら、miniSDの中身をイメージ化してファイルにし、何処かに保存しておくことがおすすめです。上記環境をもう一度作るのはどう考えても辛い。

このエントリーをはてなブックマークに追加

同一タグの最新記事:

同一カテゴリ(IT)の最新記事:

最近投稿された記事:

他のカテゴリの記事も読んでみる: