Let's 顔面製造!第二弾! 歌うサンタ顔面ロボットを作ろう
みなさん、こんにちは!へっぽこまるこです!
今回は、クリスマスをいい感じに盛り上げてくれるサンタ(っぽい)ロボットを obnizとgoogle home miniでつくってみました!
少し遅めの(めっちゃ早めの)サンタクロースをご覧あれ〜!
以前に「Let’s 顔面製造!ダンボールとサーボモータで喋る顔面ロボットを作ろう」でつくった顔面ロボット(的なもの)を改造して作ってみます!
完成イメージ
※LEDが結構強めに光っているので閲覧にはご注意ください
obnizでgoogle-home-notifierを使ってgoogle home miniから音源を再生します。 google-home-notifierは、スキル開発なしでgoogle homeにテキストを読ませたり、MP3などの音源が再生できたりするnode.jsのライブラリです。
再生された曲に連動して下唇に仕込んだサーボモータを動かして、 歌ってる感じにしてみます。
つくってみよう
### + obniz + sg90(顔面ロボの流用) + LED(顔面ロボの流用) + 顔デバイス(顔面ロボの流用) + ジャンパワイヤー(顔面ロボの流用) + 切ないクリスマスソングの音源 + 白のファー生地や赤いフェルトなど(デバイス装飾用)
macOS High Sierraの環境で進めます。
サンタデバイス準備
顔面デバイスをデコります。 毛足10cm程度のファー生地を裂いたものと、 赤いフェルトで適当につくった帽子をくっつけます。
サーボモータとLEDをobnizに接続します。
ライブラリやら準備
node.jsがインストールされてる前提で進めます。
ターミナルで以下のコマンドを叩きます。
//ディレクトリ作成&移動
$ mkdir santa
$ cd santa
//google-home-notifierとobnizのライブラリをインストール
$ npm install google-home-notifier
$ npm install obniz
//メインのプログラムファイルを作成
$ touch face.js
//音源格納用ディレクトリを作成
$ mkdir audio
audioフォルダには音源のkurisumasusong.mp3を格納しておきます。
音源準備
google-home-notifierを使って簡単に曲を再生するには、 クリスマスソングが入ったMP3をネットにアップして、 URLを取得する必要があります。
今回は、n0bisuk先生のハンズオンで教えてもらった ngork+pythonを使った方法でホスティングします。
santa ディレクトリ配下で作業します。
$ python -m SimpleHTTPServer 8080
別タブで以下を実行します。
$ cd santa
$ ngrok http 8080
実行結果です。
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account nougami (Plan: Free)
Version 2.2.8
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://84019d5b.ngrok.io -> localhost:8080
Forwarding https://84019d5b.ngrok.io -> localhost:8080
Connections ttl opn rt1 rt5 p50 p90
57 0 0.00 0.00 6.51 8.91
HTTP Requests
https://84019d5b.ngrok.io/audio/kurisumasusong.mp3 が音源ファイルのURLになります。
へっぽこプログラム
node.jsでプログラムを書きます。 (async/awaitはまだ勉強中・・・)
const googlehome = require('google-home-notifier');
const language = 'ja';
const Obniz = require("obniz");
const obniz = new Obniz("××××-××××");
obniz.onconnect = async function () {
var mouth = obniz.wired("ServoMotor", {signal:0, vcc:1, gnd:2});
var leftLed = obniz.wired("LED", { anode:3, cathode:4 });
var rigthLed = obniz.wired("LED", { anode:5, cathode:6 });
mouthMove = async function (maxDeg, maxDegWait, minDeg, minDegWait) {
await mouth.angle(maxDeg);
await obniz.wait(maxDegWait);
await mouth.angle(minDeg);
await obniz.wait(minDegWait);
}
singMouth = async function () {
//init
await mouthMove(0.0, 1300, 0.0, 0);
//く
await mouthMove(40.0, 400, 0.0, 100);
//り
await mouthMove(40.0, 400, 0.0, 100);
//す
await mouthMove(40.0, 400, 0.0, 100);
//ま
await mouthMove(30.0, 80, 0.0, 100);
//す
await mouthMove(30.0, 80, 0.0, 100);
//きゃ
await mouthMove(50.0, 100, 0.0, 100);
//ろ
await mouthMove(30.0, 100, 0.0, 100);
//る
await mouthMove(30.0, 120, 0.0, 100);
//が
await mouthMove(40.0, 900, 0.0, 500);
//な
await mouthMove(40.0, 400, 0.0, 100);
//が
await mouthMove(40.0, 400, 0.0, 100);
//れ
await mouthMove(40.0, 400, 0.0, 100);
//る
await mouthMove(40.0, 400, 0.0, 100);
//こ
await mouthMove(40.0, 100, 0.0, 100);
//ろ
await mouthMove(40.0, 100, 0.0, 100);
//に
await mouthMove(40.0, 100, 0.0, 100);
//は
await mouthMove(50.0, 1300, 0.0, 500);
//き
await mouthMove(40.0, 100, 0.0, 100);
//い
await mouthMove(40.0, 100, 0.0, 100);
//と
await mouthMove(40.0, 200, 0.0, 100);
//ぼ
await mouthMove(40.0, 100, 0.0, 100);
//く
await mouthMove(40.0, 100, 0.0, 100);
//の
await mouthMove(40.0, 100, 0.0, 100);
//こ
await mouthMove(40.0, 170, 0.0, 100);
//た
await mouthMove(40.0, 170, 0.0, 100);
//え
await mouthMove(40.0, 170, 0.0, 100);
//も
await mouthMove(30.0, 1000, 0.0, 500);
//き
await mouthMove(40.0, 100, 0.0, 100);
//い
await mouthMove(40.0, 100, 0.0, 100);
//と
await mouthMove(40.0, 500, 0.0, 100);
//で
await mouthMove(40.0, 100, 0.0, 100);
//て
await mouthMove(40.0, 100, 0.0, 100);
//い
await mouthMove(40.0, 100, 0.0, 100);
//る
await mouthMove(40.0, 100, 0.0, 100);
//だ
await mouthMove(40.0, 100, 0.0, 100);
//あ
await mouthMove(40.0, 100, 0.0, 100);
//ろ
await mouthMove(40.0, 800, 5.0, 600);
//く
await mouthMove(40.0, 400, 0.0, 100);
//り
await mouthMove(40.0, 400, 0.0, 100);
//す
await mouthMove(40.0, 400, 0.0, 100);
//ま
await mouthMove(30.0, 80, 0.0, 100);
//す
await mouthMove(30.0, 80, 0.0, 100);
//きゃ
await mouthMove(50.0, 100, 0.0, 100);
//ろ
await mouthMove(30.0, 100, 0.0, 100);
//る
await mouthMove(30.0, 120, 0.0, 100);
//が
await mouthMove(40.0, 900, 0.0, 500);
//な
await mouthMove(40.0, 400, 0.0, 100);
//が
await mouthMove(40.0, 400, 0.0, 100);
//れ
await mouthMove(40.0, 400, 0.0, 100);
//る
await mouthMove(40.0, 400, 0.0, 100);
//こ
await mouthMove(40.0, 100, 0.0, 100);
//ろ
await mouthMove(40.0, 100, 0.0, 100);
//に
await mouthMove(40.0, 100, 0.0, 100);
//は
await mouthMove(50.0, 1300, 0.0, 500);
//だ
await mouthMove(40.0, 100, 0.0, 100);
//れ
await mouthMove(40.0, 100, 0.0, 100);
//を
await mouthMove(40.0, 400, 0.0, 100);
//あ
await mouthMove(40.0, 100, 0.0, 100);
//い
await mouthMove(30.0, 100, 0.0, 100);
//し
await mouthMove(30.0, 100, 0.0, 100);
//て
await mouthMove(30.0, 100, 0.0, 100);
//る
await mouthMove(30.0, 100, 0.0, 100);
//の
await mouthMove(40.0, 100, 0.0, 100);
//か
await mouthMove(30.0, 1000, 0.0, 500);
//い
await mouthMove(40.0, 100, 0.0, 100);
//ま
await mouthMove(40.0, 100, 0.0, 100);
//は
await mouthMove(40.0, 500, 0.0, 100);
//み
await mouthMove(40.0, 100, 0.0, 100);
//え
await mouthMove(40.0, 100, 0.0, 100);
//な
await mouthMove(20.0, 100, 0.0, 100);
//く
await mouthMove(20.0, 100, 0.0, 100);
//て
await mouthMove(40.0, 100, 0.0, 100);
//も
await mouthMove(40.0, 100, 0.0, 100);
//お
await mouthMove(50.0, 5000, 50.0, 0);
for (i=49; i>=0; i--){
await mouth.angle(i);
await obniz.wait(80);
}
}
google_home = async function() {
googlehome.device('Google-Home', language);
await googlehome.play('http://×××××.ngrok.io/audio/kurisumasusong.mp3', function(res) {
console.log(res);
leftLed.on();
rigthLed.on();
singMouth();
});
}
await google_home();
}
for (i=49; i>=0; i–){ await mouth.angle(i); await obniz.wait(80); } ↑はこだわった部分なので、 注目してみてもらえると嬉しいです。
実行
サンタデバイスにgoogle home miniをそっと添えて、 以下のコマンドで実行します。
$ node face.js
サンタが歌ってる感じになります。
まとめ
哀愁漂うサンタクロースができたのではないでしょうか。
私にとって、スマートスピーカーは電子部品的存在なので、 今後も色々な作品に仕込んで、へっぽこなモノづくりに一役買ってもらおうと思っています。
よかったら是非「スマスピ + デバイス」挑戦してみてください!