まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを。参照していないものに関しては、コピペ改変まったく問いません

Mac版UnityでMMDモデルを使う

UnityでMMDを使う場合、「MMD4Mecanim」というアセットを使うのが一般的ですが、いかんせんWindows環境でしか動きません。
・・・が!MMD4Mecanimの前のバージョンと併用したら動きました。
こちらを参照させて頂きました。ありがとうございます。
qiita.com

女性キャラクター(というか低身長キャラ?)の場合、モデルによっては操作可能になったときに下に沈み込むようです。


■MMD4MecanimをダウンロードしてUnityで使えるようにする
1.こちらから最新版の「MMD4Mecanim」をダウンロードして解凍する
Stereoarts Homepage

2.こちらから「MMD4Mecanim」の少し前のバージョンをダウンロードして解凍する
www.shuwasystem.co.jp

3.Unityでプロジェクトを作り、1.でダウンロード&解凍した「MMD4Mecanim」の中にある「MMD4Mecanim.unitypackage」をダブルクリックする
4.「Import」ボタンを押してインポートする
5.2.でダウンロード&解凍した「MMD4Mecanim」の中にある「MMD4Mecanim.unitypackage」をダブルクリックする
6.このとき「PMX2FBX」のみ選択してImportする

MMDモデルをUnityにインポートする
1.「MMD4Mecanim」フォルダ→「歩き.vmd」をMMDモデルのフォルダにドラック&ドロップする
2.「Project」ビュー→「Assets」フォルダにモデルをフォルダごとドラック&ドロップする
3.「Project」ビュー→「Assets」フォルダ→モデルフォルダの中にできた「モデル名.MMD4Mecanim」をクリックする
4.規約をよく読み、チェックボックスをクリックして「同意する」ボタンを押す
5.「VMD」に「Project」ビュー→「Assets」フォルダ→モデルフォルダの中にある「歩き」をドラック&ドロップして「Process」を押す
6.少し時間がかかるので、待ちます
7.モデルフォルダの中に青い四角のアイコンが出来ていれば、ひとまずOK

■ベースになるモデルを用意する
1.Unityの「Assets」メニュー→「Import Package」→「Charactors」を選択して、Importを押す
2.「Project」ビュー→「Assets」フォルダ→「Standard Assets」フォルダ→「Charactors」フォルダ→「ThirdPersonCharactor」フォルダ→「Prefabs」フォルダ→「ThirdPersonController」を選択し、「Hierarchy」ビューにドラック&ドロップする
3.「Hierarchy」ビュー→「ThirdPersonController」の左の▼をクリックし、「EthanBody」「EthanGlasses」「EthanSkelton」をシフトキーを押して複数選択する
4.3.で複数選択した状態でマウスの右クリックを押し、「Delete」を選択して消す

■ベースモデルとMMDモデルを差し替える
1.「MMDモデルをUnityにインポートする」の7.でできた青いアイコンをクリックし、「Rig」タブ→「Animation Type」を「Humanoid」にして「Apply」を押す
※ここで赤い「エラー」が出た場合はそのモデルは使えません。黄色の「警告」ならOKです。ボーンなどに日本語名がある場合は読み込めないことがあります

2.「MMDモデルをUnityにインポートする」の7.でできた青いアイコンを「Hierarchy」ビュー→「ThirdPersonController」に重ねるようにドラック&ドロップする。これで親子関係になる
3.「Hierarchy」ビュー→「ThirdPersonController」をクリックし、「Animator」→「Avatar」の横の◯をクリックして、MMDモデル名Avatarをクリックする
4.赤いボタンを押してウィンドウを閉じ、Unity中央にある「プレイ」ボタンをクリックする
5.矢印キーを押すとキャラクターが走り出し、スペースキーを押すとジャンプする

Twitterにて@アカウントでポストして、GoogleHomeにしゃべらせる

こちらを参考にSlackでしゃべってもらおうとしたのですがどうも上手くいかなかったので、Twitterに「@アカウント名 しゃべらせたい内容」とツイートすることでしゃべってもらうようにしました。
engineer.muragon.com
残念ながら、ツイートしてすぐにはしゃべってくれないことが多いです。30秒から1分ほど待つ必要があるようです。

ポストする先の「@アカウント名」は使用するアカウントが@アカウント名に承認されていれば、鍵つきアカウントでもOKです。
なのでGoogleHome専用のアカウントを作っておくといいかもしれません。

※仕様上「https://xxxxx.ngrok.io/google-home-notifier」のxxxxがgoogle-home-notifierを立ち上げるたびに異なります。
下記では現状、google-home-notifierを立ち上げるたびにwebhooksの「URL」の項目を書き直す必要があります。
マシンを立ち上げっぱなしにしておくならまだ良いかもですが、書き直さなくて良いよう改良中です。


●準備:リクエスト用のURLを作る
Googlehomeをしゃべらせるために必要なgoogle-home-notifierはngrokのサーバーを立ち上げてしゃべらせているようなので、そのURLをまず知る必要があります。

1.ターミナルを起動して、ユーザ名$ の後に「cd_」と入力する(「_」はスペース)
2.「google-home-notifier」フォルダを見つけ(おそらくHome→「node_modules」フォルダの中にある)、「cd_」の後ろにドラッグする
3.そうすると「google-home-notifier」のパスを自動的に入力してくれるので、そのままエンターキーを押す
4.ユーザ名$ の後に「node example.js」と入力してエンターキーを押す
5.すると下記のように表示されるので、https:以下をコピーしておく(「xxxx」はダミーです)

curl -X POST -d "text=Hello Google Home" https://xxxxx.ngrok.io/google-home-notifier

google-home-notifier.jsに書き加える

1.スマホのGoogleHomeアプリを立ち上げ、右上のアイコンをタップする
2.「デバイス」と出てくるので、「PINXXXX」と書いてあるところの右にある「⋯」をタップする
3.「設定」をタップし、いちばん下に書いてある「IPアドレス」の数字をメモする
4.PCで「google-home-notifier.js」という名前のファイルを探し、エディタで開く
5.おそらく8行目と20行目が「en」または「us」となっているので、ここを「ja」にする
6.下記のように付け加える。「var ip」のところは3.の数値にする

var deviceAddress;
var language;

//追加
var deviceName = 'Google Home';
var ip = '192.168.x.x';
//ここまで

7.6.を保存する


●IFTTTでレシピを作る
レシピはこちらを参考にさせて頂きました。
kotodama.today

1.IFTTTにログインして、右上の自分のアカウント名の横にある三角アイコンから「New Applet」を選択する。
※このとき認証しているTwitterアカウントはしゃべらせたいアカウント(「@アカウント」の「アカウント」。GoogleHome用にアカウントを作っていればそのアカウントのほうがベターか)であること
例:しゃべらせたいアカウント:@hogegooglehome
自分が使っているアカウント:@hoge
の場合、認証するのは@hogegooglehome
2.「+This」をクリックして「Twitter」をクリックする
3.「New mention of you」をクリックする
4.「+That」をクリックして「webhooks」を選択する
5.「Make a web request」をクリックして、下記のようにする
・「URL」に「準備:リクエスト用のURLを作る」5.でコピーしたURLを入力
・「Method」は「POST」を選択
・「Content Type」は「application/x-www-form-urlencoded」を選択
・「Body」は「text=” {{UserName}} さんから {{Text}}”」と入力
※この「UserName」は自分が使用しているアカウント名になる。しゃべらせたいアカウント名ではない
例:しゃべらせたいアカウント:@hogegooglehome
自分が使っているアカウント:@hoge
の場合、「UserName」は@hoge
6.「Create action」をクリックする
7.「@アカウント しゃべらせたいこと」でツイートすると、GoogleHomeがキェェェシャベッタァァァ!

Googlehomeで好きな言葉をしゃべらせる その1

IFTTTで出力の部分をGoogleアシスタントにできないので、現状Dialogflow(GoogleBot制作サービス)を使わない限りコードを書かずにしゃべらせるということはできません。
ここではサーバーサイドのjavascriptと言われるnode.jsのお勉強も兼ねて、node.jsのライブラリである「google-home-notifier」を使って何かしゃべってもらおうと思います。
node.jsなにそれおいしいの?レベルでも大丈夫です。
なおラズパイではなくMac+Atomを使用しています。

●node.jsのインストール
1.こちら
Node.js
にアクセスして、自分に合った環境のnode.jsをダウンロード+インストール
2.ちゃんとインストールされているか確認するために、ターミナルで「ユーザー名$」の後に「node -v」と入力してエンターキーを押す。バージョン名が表示されればOK

ユーザー名$ node -v

3.同様にターミナルで「ユーザー名$」の後に「npm -v」と入力してエンターキーを押す。バージョン名が表示されればOK

ユーザー名$ npm -v

google-home-notifierのインストール
1.「ユーザ名$」の後に「npm install google-home-notifier」と入力してエンターキーを押す

●エディタ「Atom」でnode.jsを動かすテスト
ターミナルでやるのが定石なのでしょうが、個人的にはエディタでやりたい派なのでAtomを使ってみました。
1.Atomをインストールする
atom.io
2.「Atom」メニュー→「Prefernces」→「+ Install」をクリックし、「atom-beautify」と入力して「Packages」をクリックする。ソースコードを見やすくしてくれるパッケージです
3.「atom-beautify」の「Install」をクリックする
4.2-3と同じ方法で、下記のパッケージをインストールします
・script いろんな言語を実行する。Macの場合はCommand+iで実行
atom-ternjs javascript補完ツール
・platformio-ide-terminal ターミナルが使える。+アイコンで起動
・autoclose-html HTMLで閉じたタグを自動で入力
5.「File」メニュー→「Save As」をクリックし、名前は英字で拡張子「.js」をつけて保存。ここでは「index.js」として保存する
6.「index.js」に下記を入力する。こちら
www.youtube.com
の映像を参考にさせて頂きました(英語)。

var array = ['おはよう','こんにちは','こんばんわ'];

for (var i = 0; i < array.length; i++) {
  console.log(array[i]);
}

7.「File」メニュー→「Save」で保存する
8.「platformio-ide-terminal」がインストールされていれば左下に「+」アイコンが出てくるので、それを押してターミナルを起動
9.「Macの名前:5のファイルがある場所 ユーザ名$」と出てくるので、「ユーザ名$」の後に「node 5.のファイル名」と入力してエンターキーを押す
例:My-iMac:nodejsTestFolder MYUSER$ node index.js
10.下記のような結果になればOK
おはよう
こんにちは
こんばんわ

●Googlehomeにしゃべらせる
ようやくgoogle-home-notifierでしゃべらせることができます。
google-home-notifierのGithubに書かれているものを日本語用に改良しています。
googlehome.deviceのところはサンプル通り'Google Home'でもいけるのですが、出てきたデバイス名が"Google-Home-ID名"なっていたのでGoogle-Homeとしています。

1.Atomの「File」メニュー→「New File」を選択して新しいファイルを作る
2.「File」メニュー→「Save As」をクリックし、名前は英字で拡張子「.js」をつけて保存。ここでは「ghtalktest1.js」として保存する
3.下記を入力する。日本語の文字列「'ハローワールド、私はグーグルホームです。'」のところはお好きな言葉でOKです。

var googlehome = require('google-home-notifier');
var language = 'ja'; 

googlehome.device('Google-Home', language); 
googlehome.notify('ハローワールド、私はグーグルホームです。', function(res) {
  console.log(res);
});

4.「File」メニュー→「Save」で保存する
5.「platformio-ide-terminal」がインストールされていれば左下に「+」アイコンが出てくるので、それを押してターミナルを起動。
すでに起動している場合は何もせず6.を行う
6.「Macの名前:5のファイルがある場所 ユーザ名$」と出てくるので、「ユーザ名$」の後に「node 2.のファイル名」と入力してエンターキーを押す
例:My-iMac:nodejsTestFolder MYUSER$ node ghtalktest1.js
7.キェェェシャベッタァァァ!

GoogleHome+IFTTTでtwitterやSlackにメモをする

本家のメモでは3件までしか記憶できないようなので、GoogleHomeに話した内容をTwitterやSlackにポストできるようにしました。
長文は難しいっぽいので、短めかつ少しゆっくり目に話しかけるのがポイントのようです。
ただTwitterにしろSlackにしろ、不自然に単語と単語の間に半角スペースが入ります。これは音声認識というか自然言語処理の仕様上のことですが、メモをそのままテキストとして使いたい場合はちと不便ですね。

Twitterに関してはこちら
yuki-no-yabo.com
を参照させて頂きました。


0.準備
Googleアシスタント・Twitter・SlackのアカウントをIFTTTと紐付けておきます。
すべてやり方は同じなので、Googleアシスタントを例にします。
0-1.Slackにチャンネルをあらかじめ作っておく
0-2.IFTTTにログインし、searchをクリック
0-3.「Google Assistant」と入力して、出てきたアイコンをクリック
0-4.右上にあるSettingsをクリックしてアカウント名とパスワードを入力する

1.IFTTTにおけるGoogleアシスタントの処理をつくる
1-1.ユーザ名からNew Appletを選択
1-2.+thenアイコンをクリックして「Google Assistant」と入力
1-3.出てきたアイコンをクリックしてから「Say a phrase with a text ingredient」を選択する
1-4.下記のように入力して「Create Trriger」をクリックする
Twitterの場合はこちら
f:id:prince9:20171206024639p:plain
・Slackの場合はこちら
f:id:prince9:20171206023453p:plain

2.ポストする側(TwitterまたはSlack)の処理をつくる
2-1.+thatをクリックして「slack」または「twitter」を選択する
2-2.twitterの場合は「Post a tweet」、slackの場合は「Post to channel」を選択する
2-3.twitterの場合はそのまま「Create Action」をクリック、slackの場合は「Which channel?」の上を「channels」・下を0-1.で作ったチャンネル名にしてそのまま「Create Action」をクリックする
Twitterの場合はこちら
f:id:prince9:20171206024802p:plain
・Slackの場合はこちら
f:id:prince9:20171206024835p:plain

 

0からMacでChainerを使う(準備編)

Pythonをほんの少しだけしか触ったことがない、Pythonなにそれおいしいのレベルから始める機械学習です。
MacでChainerって機械学習をしていきます。
まずは準備編。やることだけ分かりやすく箇条書きにしてあります。

ここqiita.com
を参考にさせて頂いて、下記の手順でChainerをインストールします。

1.パッケージマネージャー「Homebrew」をインストール
ここbrew.sh
へアクセスし、表示されているスクリプトをコピーする
2.Macの「ターミナル」アプリ(ユーティリティの中にあり)を立ち上げ、先ほどコピーしたスクリプトをペーストしてEnterを押す
3.「Press RETURN to continue〜」と出るので、returnキーを押す
4.パスワードの入力を求められるので、Chainerをインストールするマシンのログインパスワードを入力してreturnキーを押す
5.Python3をインストールする
ユーザ名$となっている後ろに「brew install python3」をコピペしてreturnキーを押す
例:
ユーザー名$ brew install python3
6.Python3のライブラリをインストールする
ユーザ名$となっている後ろに「pip3 install numpy」「pip3 install scipy」「pip3 install matplotlib」「pip3 install pandas」「pip3 install scikit-learn」「pip3 install chainer」「pip3 install jupyter」を入力し、それぞれreturnキーを押す。
ユーザ名$の後ろに「pip3 install numpy」と入力しreturnキーを押す。次にユーザ名$の後ろに「pip3 install scipy」と入力しreturnキーを押す・・・というように、ひとつずつ入力しreturnキーを押す。
例:
ユーザ名$ pip3 install numpy
ユーザ名$ pip3 install scipy
ユーザ名$ pip3 install matplotlib
ユーザ名$ pip3 install pandas
ユーザ名$ pip3 install scikit-learn
ユーザ名$ pip3 install chainer
ユーザ名$ pip3 install jupiter

7.exitを入力し、returnキーを押して終了する
ユーザ名$ exit

これで準備完了。今後Python3のライブラリをインストールするときは「pip3 install〜」を使えばうまくいくようです。

MESHのデータをProcessingに送ってアニメーションさせる

Bluetooth通信でスマホタブレットにセンサーのデータを簡単に送れるSonyのMESH。
このセンサーのデータをIFTTT+Googleスプレッドシート経由でProcessingに送って、アニメーションの速度と色を変えてみました。
APIを使っていないので、Googleスプレッドシートにどれだけの回数アクセスしても大丈夫か判断がつかなかったため、データのローディングはかなりゆっくりです。
テストなので見た目関係なしのシンプルなコードです。

f:id:prince9:20171026023211g:plain

テキストプログラミングさえいらず、ブロックをつなげていくことでプログラミングをするのでIoTデバイスの試作に便利です。
成人男性の親指くらいの大きさに電池・センサー・通信できるチップが入っていて、小さくて良いですね。
MESHは専用のスマホタブレットアプリをプログラミングをして動作させますが、複数のWebサービスを連携させる「IFTTT」を使えばGoogleスプレッドシート経由で他の開発環境にデータを送ることができます。
GoogleスプレッドシートのデータをJSONXML化して、それをProcessingなりUnityなりで読み込みます。

またGPIOというタグを使って、Arduinoやラズパイ経由でMESHにないセンサーや出力を使うことができます。
Bluetoothのパケットを解析して公式アプリを介さずに自作アプリでデータを直接やりとりする方法もあるようです(公式からのアナウンスはなし)。

ひとまずいちばん楽なIFTTTを使ってProcessingに「動きタグ」のデータを送ってみます。
まず大まかな流れとしては、

  1. IFTTTのアカウント作成を行い、MESHアプリのIFTTTタグでアカウントの紐付けを行う
  2. IFTTTにログインした状態で、アプレットを作成する
  3. GoogleドライブからGoogleスプレッドシートを作成し、スクリプトエディタでスクリプトを入力する
  4. MESHアプリで動きタグを振るとGoogleスプレッドシートにそのデータが記録される
  5. GoogleスプレッドシートのIDを確認し、「https://spreadsheets.google.com/feeds/list/GoogleスプレッドシートのID/od6/public/basic?alt=rss」をメモしておく
  6. https://spreadsheets.google.com/feeds/list/GoogleスプレッドシートのID/od6/public/basic?alt=rss」がXMLのアドレスになるので、ProcessingやUnityなどで読み込んで使う

なぜかGoogleスプレッドシートJSONをProcessingで読み込んで使おうとするとnull(空)になってしまうので、今回はXMLでやってみました(原因追求中。Googleスプレッドシート以外のJSONはOKでした。JSON自体は読み込めているのですが、各要素にアクセスできない)。

では細かく手順を追っていきます。

1.PCからhttps://ifttt.com/にアクセスし、Email adressにメールアドレスを入力してアカウントを作成する
2.https://ifttt.com/session/new?wp_=1 から作成したアカウント名とパスワードを入力してログインする
3.MESHアプリを立ち上げ、連携タグの+をタップして出てきたIFTTT Keyをメモっておく(初回のみ)
※IFTTT Keyが見つからない場合はMESHアプリのSettings→IFTTT設定でキーを確認してください
4.PCでIFTTTにログインした状態で、Searchをクリックし「MESH」と入力してリターンキーを押す
5.Settings→Edit connectionをクリックし、メモったキーを入力する
f:id:prince9:20171026025241p:plain
6.https://ifttt.com/my_applets のNew Appletをクリックしてアプレットを作成する
7.ifの後ろの+アイコンをクリックして、Search serviceに「MESH」と入力する
8.Event from MESH~をクリックし、EventIDに英語で分かりやすいIDを入力する 例:check1 など
9.Create triggerをクリックする
10.thenの後ろの+をクリックして、Search serviceに「Google Drive」と入力する
11.Connectをクリックし、Googleのアカウントとパスワードを入力してログインする
12.許可をクリックする
13.Add row to spreadsheetをクリックし、Spreadsheet nameに英語で名前をつける。Drive Folder Pathも設定しておく

f:id:prince9:20171026025331p:plain

14.Create actionをクリックする
15.Finishをクリックする
16.Googleドライブにアクセスして新規からフォルダを作成し、Drive Folder Pathで入力したフォルダ名でフォルダを作る
17.新規からGoogleスプレッドシートを選択し、Add row to spreadsheetでつけた名前で新しいスプレッドシートを作成する

f:id:prince9:20171026032702p:plain

18.「ツール」メニュー→スクリプトエディタを選択し、下記を入力する
今回はテストなので下記
recipe.meshprj.com
を参照させて頂きました。

function myFunction() {
 
}


function onEdit(event) {
 var Spreadsheet = SpreadsheetApp.getSctiveSpreadsheet();
 var Sheet = Spreadsheet.getSheetByName("シート1");
 var LastRow = Sheet.getLastRow();
 var value = Sheet.getRange(LastRow,2).getValue();

 //openByIDはスプレッドシートのURLである「https://docs.google.com/spreadsheets/d/abcd/edit#gid=0」の abcdの部分
var MESH = SpreadsheetApp.openByID('abcd');
 var MESH_Sheet = MESH.getSheetByName("シート1");
 
 var d = new Date();
 MESH_Sheet.getRange(4,2).setValue(Utilities.formatData(d,'JST','yyyy年M月d日 HH:MM:SS'));
 MESH_Sheet.getRange(4,3).setValue(value);
  
 
}




function reset(event) {
 var sheet = SpreadsheetApp.getActiveSheet();
 sheet.clear();
 
}

19.スクリプトを保存する
20.MESHアプリを立ち上げて動きタグを準備した状態で下記のように接続する。スピーカーはセンサー動作確認用
f:id:prince9:20171026030715p:plain
21.IFTTTのアイコンをタップし、イベントIDにIFTTTで設定したEventIDを入力する
22.「送信する」を選択して「データを追加」をタップする
23.今回は「振られた強さ」をタップしてOKを押す
24.この状態で動きタグを振るとGoogleスプレッドシートにデータが書き込まれる

■ここから開発環境「Processing」の場合

25.Processingを立ち上げ、下記のコードを入力する。動きタグのデータが大きいほどスピードが上がり、色が変化します
XMLの部分はこちら
memorandums.hatenablog.com
を参考にさせて頂きました。
一定時間ごとにスプレッドシートを見に行ってます。どうも見に行った瞬間アニメーションが固まってしまうみたいなので、そこが要修正ですが・・・

float[] numberArray = {};

int acc1,acc2;
float acc3;   
float Max = 10;       
float X;             
float Spx;        
float Acx;    

void setup() {
size(600,600);
colorMode(HSB, 360, 100, 100);
  background(0,0,99);
  
  X = 0;
  Spx = 0;
  Acx =  0.25;
  
}


void draw() {

  if( frameCount%250 == 0){
        readXML();
  }
  
   fadeToWhite();

   for (int i = 0; i < numberArray.length; i++) {
Acx = numberArray[i];
}

   Spx = Spx + Acx;            


  if (Spx > Max) {
Spx = Max; 
}

  X = X + Spx;        
  
//もし、xの値が画面の幅以上になったら、xを0に戻す
  if (X >= width) {    
    X = 0;
  }
  noStroke();

fill(acc2,100,100);
  rectMode(CENTER);
  rect(X, height/2, 10, 10);
  
  
}

//list/abcd/の「abcd」はスプレッドシートのURLである「https://docs.google.com/spreadsheets/d/abcd/edit#gid=0」の abcdの部分

void readXML() {
  XML xml = loadXML("https://spreadsheets.google.com/feeds/list/abcd/od6/public/basic?alt=rss");
XML[] items = xml.getChild("channel").getChildren("item");



for (XML item : items) {
    String data = item.getChild("description").getContent();

//「data:_10」という形の文字列で出力されるので、スペースで区切る
String[] q = splitTokens(data, " ");
//「10」だけ取り出して整数に変換
acc1 = new Integer(q[1]);
acc2 = acc1 *10;
acc3 = acc1/100.0;
}

numberArray = append(numberArray,acc3);
  

println(numberArray);
}

void fadeToWhite() { 
  noStroke();
  fill(acc2,0,100);
  rectMode(CORNER);
  rect(0, 0, width, height);
}

Processingで曲線を描くときに楽できるツール

Processingで思ったような曲線を描くのがめんどいのーと検索してたところ、こんなツールがあったのでご紹介です。
Illustratorのようにハンドルを動かすと、自動的にvertexとbezierVertexの座標を出してくれます。

www.khanacademy.org

こんな感じです。

f:id:prince9:20170901053601p:plain

void setup() {
  size(600,600);
 noLoop();
}

void draw() {
  background(255);
  fill(0);
 beginShape();
vertex(150,43);
bezierVertex(220,107,224,173,156,252);
bezierVertex(204,166,200,102,150,43);
endShape();
}