3Dプリンタ 監視編(6) サウンド設定

3Dプリンター

サウンド設定

OctoPrintはラズベリーパイであり、動いているOSはraspbian(Jessie)だ。手元にはUSB-DACがあるので、 これを繋いで音を出す様にしてみる。

USB-DACは秋月電子のAKI.DAC-U2704。 USB接続だが、USBコネクタがMicroUSBではなくMiniUSBとなかなか厄介なシロモノ。いまどきは見なくなったMiniUSBコネクタなので、 ケーブルを探すのが大変。100均でも今は売ってない。

これに小型アンプと100均のスピーカーを繋いで、 単体で音が出るようにした。

USB-DAC接続

まずはUSBを繋いで、認識状況の確認。

$ lsusb

Bus 001 Device 006: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
Bus 001 Device 007: ID 08bb:2704 Texas Instruments Audio Codec  #これっぽい
Bus 001 Device 004: ID 0411:0261 BUFFALO INC. (formerly MelCo., Inc.)
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

2番めに「Texas Instruments Audio Codec」として認識されている。問題なさそうだ。
次にサウンドカードとしての認識確認。

$ cat /proc/asound/cards

 0 [ALSA           ]: bcm2835 - bcm2835 ALSA
                      bcm2835 ALSA
 1 [Camera         ]: USB-Audio - BUFFALO BSW20KM15 USB Camera
                      Novatek BUFFALO BSW20KM15 USB Camera at usb-3f980000.usb-1.3, high speed
 2 [DAC            ]: USB-Audio - USB Audio DAC
                      Burr-Brown from TI USB Audio DAC at usb-3f980000.usb-1.4, full speed

なるほど2番めにはWebカメラが認識されており、3番めとして「TI USB Audio DAC」として認識されている。
次に優先順位の確認

$ cat /proc/asound/modules

 0 snd_bcm2835
 1 snd_usb_audio
 2 snd_usb_audio

まだ何もしてないので、内蔵音源のbcm2835が優先となっている。USB-DACは3番めと思われる。
では、ここから、USB-DACの優先順位を上げていく。 「/usr/share/alsa/alsa.conf」の編集。 ディレクトリを移動して
cd /usr/share/alsa
まずは元のファイルをバックアップ。
sudo cp -p alsa.conf alsa.conf_org
その後、内容編集
sudo nano alsa.conf
最初のページの以下の箇所をコメントアウト。

~
# pre-load the configuration files
 
@hooks [
        {
                func load
                files [
                        {
                                @func concat
                                strings [
                                        { @func datadir }
                                        "/alsa.conf.d/"
                                ]
                        }
                        "/etc /asound.conf"
#                       "~/.asoundrc"
                ]
                errors false
        }
]
~

次に2ページくらい下のページの以下の箇所を「0」から「2」に修正。

~
defaults.ctl.card 2
defaults.pcm.card 2
~

これでalsa.confの修正は完了。ctrl+oとctrl+xでnanoを終了する。

では、一旦このままリブートを行う。
sudo reboot
再起動後、音を出してみる。ちゃんとUSB-DAC経由のスピーカから音が出ればOK。
aplay /usr/share/sounds/alsa/Front_Center.wav
alsaの設定は不明点多く、うまくいかないときは何が悪いかわからないので、諦める他無い。 今回はうまく音が出てくれた。よかった。

OpenJTalk設定

音が出るようになったので、音声合成が出来るようにOpenJTalkを入れる。 まずはapt-getでインストール実施。
sudo apt-get install -y open-jtalk open-jtalk-mecab-naist-jdic hts-voice-nitech-jp-atr503-m001 libhtsengine1
終了したら、喋らせるスクリプトを準備。
nano jtalk.sh

#!/bin/bash
HV=/usr/share/hts-voice/nitech-jp-atr503-m001/nitech_jp_atr503_m001.htsvoice
 
tempfile=`tempfile`
option="-m $HV \
  -s 16000 \
  -p 100 \
  -a 0.03 \
  -u 0.0 \
  -jm 1.0 \
  -jf 1.0 \
  -x /var/lib/mecab/dic/open-jtalk/naist-jdic \
  -ow $tempfile"
 
if [ -z "$1" ] ; then
  open_jtalk $option
else
  if [ -f "$1" ] ; then
    open_jtalk $option $1
  else
    echo "$1" | open_jtalk $option
  fi
fi
 
aplay -q $tempfile
rm $tempfile

作成したら保存して実行してみよう。
echo “只今の時刻は、`date +%k`時`date +%-M`分です” | sudo sh ./jtalk.sh
うまく男の声で今の時刻を喋ってくれた。 若干音量小さめなので、少し大きくしておこう。
sudo alsamixer
ゲイン-8くらいが、妥当なところだろうか。

では、もう少しいい声にするために、音声データをダウンロードする。
wget http://sourceforge.net/projects/mmdagent/files/MMDAgent_Example/MMDAgent_Example-1.4/MMDAgent_Example-1.4.zip
ファイルがダウンロードできたら、解凍。
unzip MMDAgent_Example-1.4.zip
その後、ボイスデータの場所にコピーしてやる。
sudo cp -R MMDAgent_Example-1.4/Voice/* /usr/share/hts-voice/
これで、MMDAgentの声色が使用できる。

では、新しい声色を使用するためにスクリプトを修正しよう。(2行目を修正)

#!/bin/bash
HV=/usr/share/hts-voice/mei/mei_happy.htsvoice
 
tempfile=`tempfile`
option="-m $HV \
  -s 16000 \
  -p 100 \
  -a 0.03 \
  -u 0.0 \
  -jm 1.0 \
  -jf 1.0 \
  -x /var/lib/mecab/dic/open-jtalk/naist-jdic \
  -ow $tempfile"
 
if [ -z "$1" ] ; then
  open_jtalk $option
else
  if [ -f "$1" ] ; then
    open_jtalk $option $1
  else
    echo "$1" | open_jtalk $option
  fi
fi
 
aplay -q $tempfile
rm $tempfile

作成したら保存して実行してみよう。
echo “只今の時刻は、`date +%k`時`date +%-M`分です” | sudo sh ./jtalk.sh
声色が変わったのが確認できた。

ケース準備

USB-DACとアンプのケースを準備する。 Fusion360でなんとなく作成。USB-DACにはネジ止め穴が開いているので、そこだけ計測して位置合わせを実施。 あとは適当な箱にした。高さも適当だったけど、コンデンサの背が高くてギリギリだった。

これを印刷して作成。ケースとフタが準備できた。

できあがったらUSB-DACとアンプをケースにしまう。USB-DACはネジ穴だけ合わせて差し込み棒を用意したけど、 それ以外の固定具はないので、不安定。アンプ側は全くなにもないので、もっと不安定。 でも動かすものじゃないからフタして隠せばなんとかなるか。

USBを繋いだスピーカーキットをX-ONE2の中の奥の方に配置。プリンタヘッドのじゃまにならない位置なので、問題ないはず。 ここで何か喋らせるようにしよう。 しかし、スピーカ丸出しは何とかしなくちゃだな。

しゃべり

では、OctoPrintからのイベントで喋ってもらおう。 OctoPrintoのイベントと言えば、設定の中に何かあったはず。画面のスパナマークをクリックしてみると、 「GCODE Scripts」にイベントごとの設定エリアがあった。でもこれGcode飛ばすやつだな。 GCodeではしゃべってくれず、シェルコマンドを飛ばしてくれないと、何も出来ない。違ったようだ。

もう少し調べてみると、OctoPrintのGithubのWikiに答えがあった。

OctoPrint wiki

OctoPrintの設定ファイルであるconfig.yamlファイルをカスタマイズすると、色々と出来る様子。 少し以下を参考に試してみよう。

プリント状況を音声で実況する3Dプリンター

記事だと音声合成にAquesTalkを使用しているが、こちらはOpenjTalk。まあ似たようなもんだから問題ないだろう。

まずは、config.yamlの編集
cd ~/.octoprint
うまく移動できたら、ファイルが有るか見てみる。

$ ls -al
合計 60
drwxr-xr-x 13 pi pi 4096 11月 16 23:27 .
drwxr-xr-x 9 pi pi 4096 11月 19 12:39 ..
-rw-r--r-- 1 pi pi 1562 11月 16 23:27 config.yaml
drwxr-xr-x 6 pi pi 4096 11月 19 09:02 data
drwxr-xr-x 4 pi pi 4096 11月 18 23:49 generated
drwxr-xr-x 2 pi pi 4096 11月 15 22:30 logs
drwxr-xr-x 2 pi pi 4096 6月 21 18:49 plugins
drwxr-xr-x 2 pi pi 4096 10月 29 10:47 printerProfiles
drwxr-xr-x 2 pi pi 4096 6月 21 18:49 scripts
drwxr-xr-x 3 pi pi 4096 9月 27 20:49 slicingProfiles
drwxr-xr-x 3 pi pi 4096 11月 19 11:16 timelapse
drwxr-xr-x 2 pi pi 4096 6月 21 18:49 translations
drwxr-xr-x 2 pi pi 4096 11月 19 11:16 uploads
-rw------- 1 pi pi 218 9月 27 20:50 users.yaml
drwxr-xr-x 2 pi pi 4096 9月 27 20:43 watched

問題なく存在していた。まあ当たり前か。では、編集をする前にバックアップしておこう。
cp -p config.yaml config_org.yaml
では編集開始。
nano config.yaml
編集としては最終行に移動して、内容を書き加える。何を記述すればよいかは、こちらのドキュメントが良さそうだ。

Events@OctoPrint’s documentation

では、まずは簡単そうなのを作成してみる。 基本的にはイベントを拾って何かを行うこととなる。簡単に起こせそうなイベントとして、接続イベントを拾って喋ってみよう。 では、config.yamlの最後に以下を書き加えてみる。

events:
  enabled: True
  subscriptions:
  - event: Connected
    command: echo "こんにちは。`date +%k`時`date +%-M`分、3Dプリンタに接続しました" | sudo sh ~/jtalk.sh
    type: system

これで、一度OctoPrintを再起動させる。再起動はweb画面の電源マークを押すと出てくる「Restart OctoPrint」を実行してやれば、 OctoPrintのアプリだけ再起動がかかる。1分程度で再接続可能になる。

接続イベントでしゃべりを入れたので、再起動後自動接続時でもしゃべってくれた。いい感じに動作した。

拾えるイベントはかなり多岐にわたる。いろんなことができそうだ。 必要そうなイベントを拾い出して、しゃべらせてみよう。

events:
  enabled: True
  subscriptions:
  - event: Startup
    command: echo "こんにちは。`date +%k`時`date +%-M`分、3Dプリンタを起動しました。" | sudo sh ~/jtalk.sh
    type: system
  - event: Shutdown
    command: echo "シャットダウンします。さようなら" | sudo sh ~/jtalk.sh
    type: system
  - event: PrintStarted
    command: echo "3Dプリンタの印刷を開始します。" | sudo sh ~/jtalk.sh
    type: system
  - event: PrintFailed
    command: echo "3Dプリンタの印刷に失敗しました。" | sudo sh ~/jtalk.sh
    type: system
  - event: PrintDone
    command: echo "3Dプリンタの印刷が終了しました。" | sudo sh ~/jtalk.sh
    type: system
  - event: PrintCancelled
    command: echo "3Dプリンタの印刷を中止しました。" | sudo sh ~/jtalk.sh
    type: system

とりあえずこんなところだろうか。

wikiを見ていると、Payloadというパラメータが有り、どうやらこれが動的な情報が入っている変数の様子。 サンプルを探してみると、{}で囲んだら使えそうな雰囲気。 印刷終了時に、印刷時間でもしゃべらせてみよう。

印刷時間は

time: the time needed for the print, in seconds (float)

といった形で返ってくるらしく、小数点有りの秒数。これをそのまま説明されてもわかりづらいので、 やはり○時間○分○秒という形に直したい。しかしシェルで1行では書けそうにないので、 ちょっとC言語を借りよう。

#include <stdio.h>
int main(int argc, char **argv) {
    int in;
    int h,m,s;
 
    if (argc > 1) {
        in = atoi(argv[1]);
    } else {
        in = 0;
    }
 
    h = in / 3600;
    in %= 3600;
 
    m = in / 60;
    in %= 60;
 
    s = in;
 
    if (h > 0)
        printf("%d時間%d分%d秒",h,m,s);
    else if (m > 0)
        printf("%d分%d秒",m,s);
    else
        printf("%d秒",s);
}

秒を時間に直すコードを作成。 ではこれをOctoPrintのスクリプトに利用してみよう。 印刷終了イベントを下記のように書き直す。

- event: PrintDone
  command: echo "3Dプリンタの印刷が終了しました。印刷時間は `~/.octoprint/sec2time {time}`です。" | sudo sh ~/jtalk.sh
  type: system

これで、印刷終了時に経過時間も一緒に教えてくれるようになった。

お知らせ

OctoPrintのwikiのCookbookを見ると、スクリプトのサンプルがある。 この中には、メールを飛ばしたりするものがあり、なるほど便利そう。

Cookbook: Useful Eventhooks@OctoPrint

確かに、長い印刷を仕掛けて終了をメールで知らせてくれると、便利かも。 そして、どうせならお知らせはLINEで飛ばそう。

ということで、終了時にLINEを飛ばす。LINEだとメッセージに加えて絵も飛ばせるので、 終了時のスナップショットも送るようにしてみよう。(要LINE Notify)

jtalk.shも.octoprint下に移動し、config.yamlは以下のように修正。

events:
  enabled: True
  subscriptions:
  - event: Startup
    command: echo "こんにちは。`date +%k`時`date +%-M`分、3Dプリンタを起動しました。" | sudo sh ~/.octoprint/jtalk.sh
    type: system
  - event: Shutdown
    command: echo "シャットダウンします。さようなら" | sudo sh ~/.octoprint/jtalk.sh
    type: system
  - event: PrintStarted
    command: echo "3Dプリンタの印刷を開始します。" | sudo sh ~/.octoprint/jtalk.sh
    type: system
  - event: PrintFailed
    command: echo "3Dプリンタの印刷に失敗しました。" | sudo sh ~/.octoprint/jtalk.sh
    type: system
  - event: PrintDone
    command: sudo sh ~/.octoprint/PrintDone.sh {time} {file}
    type: system
  - event: PrintCancelled
    command: echo "3Dプリンタの印刷を中止しました。" | sudo sh ~/.octoprint/jtalk.sh
    type: system
  - event: Error
    command: echo "エラーが発生しました。エラー内容は {error} です" | sudo sh ~/.octoprint/jtalk.sh
    type: system

また、呼び出されるシェル側は、以下のようにした。

# save picture
curl -o /tmp/printDone.jpg "http://localhost:8080/?action=snapshot"
# speak message
TM=$(/home/pi/.octoprint/sec2time $1)
MES="3Dプリンタの印刷が終了しました。印刷時間は$TMです。"
sudo sh /home/pi/.octoprint/jtalk.sh $MES
# send message
curl -X POST -H 'Authorization: Bearer *****'\
 -F "message=$MES"\
 -F 'imageFile=@/tmp/printDone.jpg'\
   https://notify-api.line.me/api/notify

これで印刷終了後にメッセージと終了直後の画像が届く。

なんだか、LINE Notifyは改行ができない。仕様かな?

3Dプリンタ 監視編

3Dプリンタ 監視編(1) カメラ監視
3Dプリンタの監視について
3Dプリンタ 監視編(2) OctoPi設定
3Dプリンタの管理ツールOctoPiを使う
3Dプリンタ 監視編(3) OctoPi設置
3Dプリンタの管理ツールOctoPiを使って運用開始
3Dプリンタ 監視編(4) Webカメラ
3Dプリンタの管理ツールOctoPiにつなぐWebカメラ
3Dプリンタ 監視編(5) OctoPi-Plugin
3Dプリンタの管理ツールOctoPiへのプラグインについて
3Dプリンタ 監視編(6) サウンド設定
3Dプリンタの管理ツールOctoPiを使って運用開始
3Dプリンタ 監視編(7) 操作端末
3Dプリンタの管理ツールOctoPi用操作端末を作成
3Dプリンタ 監視編(8) OctoPi更新
3Dプリンタの管理ツールOctoPiをjessie版からbuster版にする