JavaScript
node-red
ibmcloud
TJBot

自作AIロボットTJBot Zeroで遊んでみる


TJBot Zeroとは

 TJBotとは、レーザカットや3Dプリント用のデータがインターネット上に公開されており、自作できる人工知能ロボットです。これまでのTJBotは、Raspberry Pi 3 Model B+を搭載できる様になっていましたが、今回紹介するTJBot ZeroはRaspberry Pi Zero WHを搭載できる少し小さめのTJBotです。ラズパイを搭載しているため、Node-REDを用いて簡単にロボットを操作したり、人工知能APIと連携したりできます。

IMG_8110.jpg


TJBot Zeroの作り方

(1) レーザカットのデータをダウンロードし、ダンボールをレーザカット

https://www.ibm.com/developerworks/jp/code/open/projects/tjbot/downloads.html

(2) レーザカットした部品を以下の手順で組み立てる

https://public.dhe.ibm.com/software/dw/jp/2018/tjbot-zero/tjbot-zero-setup-guide.pdf

(3) 環境構築済イメージが入ったSDカードを用いてRaspberry Piを起動

(4) Node-REDによってTJBot Zeroを制御(本記事のメインの内容)


TJBot Zeroでできること

 TJBotはLED、マイク、スピーカ、カメラ、モータで動く腕が接続されているため、様々なイベントを契機に、多様な表現を行うことができます。以下でいくつかNode-REDを用いた開発の例を紹介します。

 各開発例を試すには、 Google Chromeを用いてhttp://<ラズパイのIPアドレス>:1880 からNode-REDフローエディタに入り、操作を行なってください。Node-REDフローエディタの右上のハンバーガーメニューから「読み込み」→「クリップボード」からフローデータを読み込むことができます。

※ 環境構築済のOSイメージには、あらかじめ動作確認用のサンプルとして「カメラで人の顔を認識し手を振るフロー」が入っています。サンプルフローを無効にするには、sampleタブをダプルクリックして、タブの状態を無効化します。最後に右上のデプロイボタンを押すと、サンプルフローが停止します。

2.PNG

sampleタブをダブルクリック

1.PNG

タブの状態を無効に変更


(1) 頭のLEDを点灯

 Node-REDのノードから頭についている7色のLEDを光らせることができます。TJBotの感情などの情報を表現したい際に使います。

IMG_8492.gif

 Node-REDのフローは以下の通りです。青色のinjectノード(フローを開始するノード)のボタンをクリックすると、指定した色でLEDが点灯します。

1.png

フローデータはこちら

 オレンジ色のtemplateノード(JSONデータを記載するノード)に、RGBのオンオフのデータが記載されており、本データをcontrol ledノード(LEDを制御するサブフロー)に送ることで、LEDを点灯させています。


(2) 手を上下に動かす

 モータに接続されている左腕を上下に動かすことができます。腕の動作により挨拶などの動作を表現できます。

IMG_8485.gif

 各injectノードのボタンをクリックすることで、「手を上げる」「手を水平に保つ」「手を下げる」の指示を出せるようになっています。

2.png

フローデータはこちら

 オレンジ色のtemplateノードには、モータに送る角度の数値データが記載されています。本数値データをcontrol armノードに送ることで、手を上下させています。


(3) 翻訳APIと連携

 TJBot Zeroがインターネットに接続されている場合は、翻訳APIにアクセスできます。

3.png

フローデータはこちら

 オレンジ色のtemplateノードには、翻訳したい文字列として「Hello World!」を記載してあります。本文字列を翻訳ノードに送ることで翻訳を行います。緑色のdebugノードは、翻訳ノードから受け取った翻訳結果の文字列を右側のデバックタブに出力します。日本語訳の「こんにちは世界!」が表示されていますね。

4.png

 Watsonの翻訳APIを用いる場合は、IBM CloudのポータルからAPIキーを取得し、翻訳ノードのプロパティの入力欄「API Key」に貼り付け、デプロイボタンを押すことで有効になります(IBM Cloudのライトアカウントがない場合は、こちらの手順で無料で作成できます)。プロパティ画面の入力欄「password」は何も入力しなくてOKです。


(4) 音声合成しスピーカで再生

 音声データをスピーカから再生できます。音声合成を連携させることで、会話をしてくれるTJBot Zeroを開発することもできます。

openjdk.png

フローデータはこちら


(5) カメラで撮影し、画像認識

 TJBot Zeroの右目にはカメラが搭載されています。本カメラで撮影した画像を画像認識APIに投げることができます。

6.jpg

 画像を撮影するにはカメラアイコンが付いているcamerapi takephotoノードを用います。injectノードから本ノードへイベントを送ることで撮影が実行され、画像のバイナリデータが後続のノードに渡されます。

5.png

フローデータはこちら

 まずは、ダッシュボード画面でカメラの撮影テストを行う「Camera test on dashboard」のフローを動かしてみます。ダッシュボードの画面に移動するには、http://<ラズパイのIPアドレス>:1880/uiにアクセスします。ダッシュボード画面にあるボタンをクリックすると、撮影した画像が上に表示されます。

avocado.png

 次に、撮影した画像の説明文を表示する「Generate caption from photo」というフローを動かしてみます。本フローでは、IBM MAXで提供されているImage Caption Generatorを用いて画像データから説明文を生成します。「generate caption」と書かれたinjectノードのボタンをクリックすると、撮影と画像認識が行われ、デバックタブに画像の説明文を出力します。それらしき結果が出力されていますね!

6.png

 最後に、画像のタグ付けを行う「Classify photo」というフローを動かしてみます。Watsonの画像認識APIを有効にするには、IBMクラウドのポータルからAPIキーを取得し、Visual Recognitionノードのプロパティ画面の入力欄に貼り付けます。デプロイボタンを押した後、classify photoと書かれたinjectノードをクリックすると、撮影と画像認識が実行されます。デバックタブには、workroomと出力されました(アボカドが入らなかったようです)。

7.png


フローをカスタマイズしてみよう


(6) 手を上下を1度に行うフローを作る

 injectノードのイベントを契機に手を上げ、すぐに下げるフローを開発します。イベントの遅延を実現するにはdelayノードを用います。新規に配置したinjectノードから、まずcreate up dataノードにワイヤーを繋ぎます。次に、injectノードからもう一つのワイヤーをdelayノードの左側の端子に繋ぎ、delayノードの右側の端子からはcreate down dataノードにワイヤーを繋ぎます。deleyノードをダブルクリックし、プロパティ設定画面にて遅延時間を500ミリ秒に設定します。デプロイボタンを押した後、injectノードをボタンをクリックすると、手を上下に動かすはずです。

10.png


(7) 画像認識を日本語で行う

 「Generate caption from photo」フローの認識結果は英語のため、日本語にしてみましょう。本フローのimage caption generatorノードとdebugノードの間にgoogle translateノードを挿入します(ワイヤーを削除するには、ワイヤーを選択後、Deleteキーを押します)。google translateノードをダブルクリックし、プロパティ設定画面にて翻訳先の言語としてJapaneseを選択します。

8.png

 デプロイボタンを押し、injectノードのボタンをクリックします。正しく動作すると部屋を撮影した画像から、それらしき結果が日本語で表示されます。

9.png


ツイートでTJBotを操作してみよう


(8) ツイートで手をあげたり、LEDを光らせたりする

 せっかくTJBot Zeroがインターネットに繋がっているため、TwitterからリモートからTJBot Zeroを操作してみます。下のフローは、ツイートによって手をあげたり、頭のLEDを光らせることができます。

armandledcontrolledbytweet.png

フローデータはこちら

フローを実行するには、その後、Twitterタブをダブルクリックし、フローを有効にします。デプロイボタンをクリックすれば、準備完了です。「#tjbot 手を上げて」とツイートすると手を挙げ、「#tjbot 頭のLEDをつけて」というとLEDが点灯します。フローの内部では、#tjbotのハッシュタグのツイートを取得し、「手」や「頭」という単語が含まれていると制御処理が動くようになっています。(ハッシュタグが他のツイートとかぶって、動作がよく分からない場合は、左端のWebSocketノードをTwitterノードに置き換え、ハッシュタグを#tjbot以外に変更してください)


(9) 画像付きツイートの解説を話す

次に画像付きツイートが投稿された際に、画像の解説を音声で喋るフローを動作させてみます。

explainphotointweet.png

フローデータはこちら

画像付きのツイートを投稿すると、TJBot Zeroが画像の説明を喋ってくれるはずです。


TJBot Zeroをシャットダウン

TJBot Zeroをシャットダウンするには、まずsampleタブを有効にした後、デプロイボタンを押します。その後「(4) Shutdown Raspberry Pi」のフローのinjectノードのボタンをクリックすると、シャットダウンが開始されます。1分ほど経過しシャットダウンが完了すれば、電源を抜いてもOKです。

poweroff.png

フローデータはこちら


最後に

 工夫次第で自作スマートスピーカや、ホームオートメーションシステムを作れそうです。他のWatsonのAPIはもちろん、GCPのCloud Vision、AzureのCognitive Servicesも使えるため、様々な人工知能APIを組合せてオリジナルTJBot Zeroを開発してみてください。


フローデータ


(1) 頭のLEDを点灯

[{"id":"e2d5a234.d2c46","type":"subflow","name":"control led","info":"","category":"Raspberry Pi","in":[{"x":40,"y":100,"wires":[{"id":"b0d11225.80d6d"},{"id":"dd44f6be.0cf958"},{"id":"2e6176b3.9ce01a"}]}],"out":[],"icon":"node-red/rpi.png"},{"id":"4be72e9c.9970c","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin15: red","pin":"15","set":true,"level":"0","freq":"","out":"out","x":410,"y":40,"wires":[]},{"id":"18584bb5.b68834","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin16: green","pin":"16","set":true,"level":"0","freq":"","out":"out","x":410,"y":100,"wires":[]},{"id":"3395242d.5654cc","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin18: blue","pin":"18","set":true,"level":"0","freq":"","out":"out","x":410,"y":160,"wires":[]},{"id":"b0d11225.80d6d","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.r","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.r","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":40,"wires":[["4be72e9c.9970c"]]},{"id":"dd44f6be.0cf958","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.g","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.g","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":100,"wires":[["18584bb5.b68834"]]},{"id":"2e6176b3.9ce01a","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.b","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.b","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":160,"wires":[["3395242d.5654cc"]]},{"id":"a510bc6c.f4801","type":"tab","label":"led","disabled":false,"info":""},{"id":"8da20197.bb186","type":"subflow:e2d5a234.d2c46","z":"a510bc6c.f4801","name":"","x":670,"y":220,"wires":[]},{"id":"58fd8d26.ee8b94","type":"template","z":"a510bc6c.f4801","name":"create red data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": true,\n    \"g\": false,\n    \"b\": false\n}","output":"json","x":440,"y":80,"wires":[["8da20197.bb186"]]},{"id":"c66c5df3.3603f","type":"template","z":"a510bc6c.f4801","name":"create green data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": false,\n    \"g\": true,\n    \"b\": false\n}","output":"json","x":450,"y":160,"wires":[["8da20197.bb186"]]},{"id":"33db2d88.675772","type":"template","z":"a510bc6c.f4801","name":"create blue data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": false,\n    \"g\": false,\n    \"b\": true\n}","output":"json","x":440,"y":240,"wires":[["8da20197.bb186"]]},{"id":"8601621c.ca283","type":"template","z":"a510bc6c.f4801","name":"create aqua data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": false,\n    \"g\": true,\n    \"b\": true\n}","output":"json","x":450,"y":400,"wires":[["8da20197.bb186"]]},{"id":"acaec9d.55fa338","type":"template","z":"a510bc6c.f4801","name":"create yellow data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": true,\n    \"g\": true,\n    \"b\": false\n}","output":"json","x":450,"y":320,"wires":[["8da20197.bb186"]]},{"id":"bfb3a970.c53168","type":"template","z":"a510bc6c.f4801","name":"create pink data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": true,\n    \"g\": false,\n    \"b\": true\n}","output":"json","x":440,"y":480,"wires":[["8da20197.bb186"]]},{"id":"3d0dc6f1.2e515a","type":"template","z":"a510bc6c.f4801","name":"create white data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": true,\n    \"g\": true,\n    \"b\": true\n}","output":"json","x":450,"y":560,"wires":[["8da20197.bb186"]]},{"id":"6a663a2d.915094","type":"template","z":"a510bc6c.f4801","name":"create off data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": false,\n    \"g\": false,\n    \"b\": false\n}","output":"json","x":440,"y":640,"wires":[["8da20197.bb186"]]},{"id":"8b5d4f3e.e94ec","type":"inject","z":"a510bc6c.f4801","name":"red","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":80,"wires":[["58fd8d26.ee8b94"]]},{"id":"e211b47f.5ed1d8","type":"inject","z":"a510bc6c.f4801","name":"green","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":160,"wires":[["c66c5df3.3603f"]]},{"id":"902b6ab7.9a0428","type":"inject","z":"a510bc6c.f4801","name":"blue","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":240,"wires":[["33db2d88.675772"]]},{"id":"9b31221d.9b0ce","type":"inject","z":"a510bc6c.f4801","name":"yellow","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":320,"wires":[["acaec9d.55fa338"]]},{"id":"5576838c.7f9f4c","type":"inject","z":"a510bc6c.f4801","name":"aqua","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":400,"wires":[["8601621c.ca283"]]},{"id":"9da9ea9.6ee9e18","type":"inject","z":"a510bc6c.f4801","name":"pink","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":480,"wires":[["bfb3a970.c53168"]]},{"id":"69657865.3f6918","type":"inject","z":"a510bc6c.f4801","name":"white","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":560,"wires":[["3d0dc6f1.2e515a"]]},{"id":"e27634f9.b699c8","type":"inject","z":"a510bc6c.f4801","name":"off","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":640,"wires":[["6a663a2d.915094"]]}]


(2) 手を上下に動かす

[{"id":"251f4adb.2bd746","type":"subflow","name":"control arm","info":"","category":"Raspberry Pi","in":[{"x":60,"y":100,"wires":[{"id":"44476a97.062544"},{"id":"659774de.295cdc"}]}],"out":[],"icon":"node-red/rpi.png"},{"id":"659774de.295cdc","type":"rpi-gpio out","z":"251f4adb.2bd746","name":"Pin26: servo","pin":"26","set":"","level":"0","freq":"50","out":"pwm","x":430,"y":100,"wires":[]},{"id":"44476a97.062544","type":"delay","z":"251f4adb.2bd746","name":"","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":150,"y":180,"wires":[["c09265bf.b87078"]]},{"id":"c09265bf.b87078","type":"template","z":"251f4adb.2bd746","name":"create stop data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"0","output":"str","x":340,"y":180,"wires":[["659774de.295cdc"]]},{"id":"78220013.3b614","type":"tab","label":"arm","disabled":false,"info":""},{"id":"f439ba41.7c4648","type":"template","z":"78220013.3b614","name":"create up data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"3","output":"str","x":360,"y":60,"wires":[["1a4e4ec6.81f511"]]},{"id":"9c91bff4.80512","type":"template","z":"78220013.3b614","name":"create middle data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"7","output":"str","x":370,"y":120,"wires":[["1a4e4ec6.81f511"]]},{"id":"4e6fd4da.26e92c","type":"template","z":"78220013.3b614","name":"create down data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"11","output":"str","x":370,"y":180,"wires":[["1a4e4ec6.81f511"]]},{"id":"811d3634.2855a8","type":"inject","z":"78220013.3b614","name":"up","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":60,"wires":[["f439ba41.7c4648"]]},{"id":"22a73f17.972e4","type":"inject","z":"78220013.3b614","name":"middle","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":120,"wires":[["9c91bff4.80512"]]},{"id":"b8033614.e66ba8","type":"inject","z":"78220013.3b614","name":"down","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":180,"wires":[["4e6fd4da.26e92c"]]},{"id":"1a4e4ec6.81f511","type":"subflow:251f4adb.2bd746","z":"78220013.3b614","name":"","x":630,"y":120,"wires":[]}]


(3) 翻訳APIと連携

[{"id":"517a466.35e3db8","type":"tab","label":"translation","disabled":false,"info":""},{"id":"1940100a.3b92f","type":"debug","z":"517a466.35e3db8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":120,"wires":[]},{"id":"dfb8a763.0e5b88","type":"template","z":"517a466.35e3db8","name":"create text","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Hello world!","output":"str","x":270,"y":120,"wires":[["d6fa9f81.a1c6a"]]},{"id":"aaa07631.98a7c8","type":"inject","z":"517a466.35e3db8","name":"translate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":120,"wires":[["dfb8a763.0e5b88"]]},{"id":"3918375d.c6af18","type":"comment","z":"517a466.35e3db8","name":"(1) Google translate","info":"","x":130,"y":80,"wires":[]},{"id":"6cdaa822.7b6f38","type":"watson-translator","z":"517a466.35e3db8","name":"","action":"translate","basemodel":"en-tr","domain":"general","srclang":"en","destlang":"ja","password":"","apikey":"","custom":"","domainhidden":"general","srclanghidden":"en","destlanghidden":"ja","basemodelhidden":"en-tr","customhidden":"","filetype":"forcedglossary","trainid":"","lgparams2":true,"neural":false,"default-endpoint":true,"service-endpoint":"https://gateway.watsonplatform.net/language-translator/api","x":350,"y":340,"wires":[["c988431b.639e8"]]},{"id":"ae6b14ed.370358","type":"comment","z":"517a466.35e3db8","name":"(2) Watson Language Translator","info":"","x":170,"y":220,"wires":[]},{"id":"c988431b.639e8","type":"debug","z":"517a466.35e3db8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":530,"y":340,"wires":[]},{"id":"c11d01c2.fb9b3","type":"template","z":"517a466.35e3db8","name":"create text","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Hello world!","output":"str","x":270,"y":260,"wires":[["6cdaa822.7b6f38"]]},{"id":"f22a5211.15b35","type":"inject","z":"517a466.35e3db8","name":"translate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":260,"wires":[["c11d01c2.fb9b3"]]},{"id":"d6fa9f81.a1c6a","type":"google-translate","z":"517a466.35e3db8","name":"","to":"ja","x":440,"y":120,"wires":[["1940100a.3b92f"]]},{"id":"87d5d575.c14848","type":"comment","z":"517a466.35e3db8","name":"paste API key ->","info":"","x":140,"y":340,"wires":[]}]


(4) 音声合成しスピーカで再生

[{"id":"f701c6de.999808","type":"openjtalk","z":"c14f1d3a.bff39","name":"","x":540,"y":60,"wires":[]},{"id":"ea44b681.13a6e8","type":"inject","z":"c14f1d3a.bff39","name":"greeting","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":60,"wires":[["9ea07db5.78218"]]},{"id":"9ea07db5.78218","type":"template","z":"c14f1d3a.bff39","name":"create sentence","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"こんにちは、僕の名前はTJボットです!","output":"str","x":360,"y":60,"wires":[["f701c6de.999808"]]}]


(5) カメラで撮影し、画像認識

[{"id":"6f5931a8.20f79","type":"debug","z":"93900994.16dbb8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":120,"wires":[]},{"id":"b7cea0e3.0778f","type":"template","z":"93900994.16dbb8","name":"create text","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Hello world!","output":"str","x":270,"y":120,"wires":[["73d74c90.718ab4"]]},{"id":"f4372a59.4d77c8","type":"inject","z":"93900994.16dbb8","name":"translate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":120,"wires":[["b7cea0e3.0778f"]]},{"id":"464d240c.22d1bc","type":"comment","z":"93900994.16dbb8","name":"(1) Google translate","info":"","x":130,"y":80,"wires":[]},{"id":"4f930128.396be","type":"comment","z":"93900994.16dbb8","name":"(2) Watson Language Translator","info":"","x":170,"y":220,"wires":[]},{"id":"38314bdc.37f7a4","type":"debug","z":"93900994.16dbb8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":530,"y":340,"wires":[]},{"id":"a7443ba2.2550c8","type":"template","z":"93900994.16dbb8","name":"create text","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Hello world!","output":"str","x":270,"y":260,"wires":[["9a1a3451.26ac18"]]},{"id":"9361dc18.9666","type":"inject","z":"93900994.16dbb8","name":"translate","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":260,"wires":[["a7443ba2.2550c8"]]},{"id":"31b16fa2.dd6d7","type":"comment","z":"93900994.16dbb8","name":"paste API key ->","info":"","x":140,"y":340,"wires":[]},{"id":"73d74c90.718ab4","type":"google-translate","z":"93900994.16dbb8","name":"","to":"ja","x":440,"y":120,"wires":[["6f5931a8.20f79"]]},{"id":"9a1a3451.26ac18","type":"watson-translator","z":"93900994.16dbb8","name":"","action":"translate","basemodel":"en-tr","domain":"general","srclang":"en","destlang":"ja","password":"","apikey":"","custom":"","domainhidden":"general","srclanghidden":"en","destlanghidden":"ja","basemodelhidden":"en-tr","customhidden":"","filetype":"forcedglossary","trainid":"","lgparams2":true,"neural":false,"default-endpoint":true,"service-endpoint":"https://gateway.watsonplatform.net/language-translator/api","x":350,"y":340,"wires":[["38314bdc.37f7a4"]]}]


(8) ツイートで手をあげたり、LEDを光らせたりする

[{"id":"e2d5a234.d2c46","type":"subflow","name":"control led","info":"","category":"Raspberry Pi","in":[{"x":40,"y":100,"wires":[{"id":"b0d11225.80d6d"},{"id":"dd44f6be.0cf958"},{"id":"2e6176b3.9ce01a"}]}],"out":[],"icon":"node-red/rpi.png"},{"id":"4be72e9c.9970c","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin15: red","pin":"15","set":true,"level":"0","freq":"","out":"out","x":410,"y":40,"wires":[]},{"id":"18584bb5.b68834","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin16: green","pin":"16","set":true,"level":"0","freq":"","out":"out","x":410,"y":100,"wires":[]},{"id":"3395242d.5654cc","type":"rpi-gpio out","z":"e2d5a234.d2c46","name":"Pin18: blue","pin":"18","set":true,"level":"0","freq":"","out":"out","x":410,"y":160,"wires":[]},{"id":"b0d11225.80d6d","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.r","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.r","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":40,"wires":[["4be72e9c.9970c"]]},{"id":"dd44f6be.0cf958","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.g","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.g","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":100,"wires":[["18584bb5.b68834"]]},{"id":"2e6176b3.9ce01a","type":"change","z":"e2d5a234.d2c46","name":"payload = payload.b","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.b","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":160,"wires":[["3395242d.5654cc"]]},{"id":"251f4adb.2bd746","type":"subflow","name":"control arm","info":"","category":"Raspberry Pi","in":[{"x":60,"y":100,"wires":[{"id":"44476a97.062544"},{"id":"659774de.295cdc"}]}],"out":[],"icon":"node-red/rpi.png"},{"id":"659774de.295cdc","type":"rpi-gpio out","z":"251f4adb.2bd746","name":"Pin26: servo","pin":"26","set":"","level":"0","freq":"50","out":"pwm","x":430,"y":100,"wires":[]},{"id":"44476a97.062544","type":"delay","z":"251f4adb.2bd746","name":"","pauseType":"delay","timeout":"200","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":150,"y":180,"wires":[["c09265bf.b87078"]]},{"id":"c09265bf.b87078","type":"template","z":"251f4adb.2bd746","name":"create stop data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"0","output":"str","x":340,"y":180,"wires":[["659774de.295cdc"]]},{"id":"7187e081.a70dc","type":"switch","z":"ef7b8d90.83f31","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"手","vt":"str"},{"t":"cont","v":"頭","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":3,"x":270,"y":220,"wires":[["8d3d41d5.0f6f9","9986fdb8.f02be"],["cd4cdd05.2800b","f3822478.1a6c78"],["3d6dd38a.5d551c"]]},{"id":"3d6dd38a.5d551c","type":"debug","z":"ef7b8d90.83f31","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":470,"y":340,"wires":[]},{"id":"fa8d5002.a6241","type":"comment","z":"ef7b8d90.83f31","name":"Set credentials->","info":"","x":100,"y":140,"wires":[]},{"id":"5b62a74.11cf358","type":"twitter in","z":"ef7b8d90.83f31","twitter":"","tags":"#tjbot","user":"false","name":"","inputs":0,"x":250,"y":140,"wires":[["7187e081.a70dc"]]},{"id":"9986fdb8.f02be","type":"template","z":"ef7b8d90.83f31","name":"create up data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"3","output":"str","x":480,"y":60,"wires":[["2f852fcc.8b733"]]},{"id":"c8c152a7.f44c5","type":"template","z":"ef7b8d90.83f31","name":"create down data","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"11","output":"str","x":490,"y":160,"wires":[["2f852fcc.8b733"]]},{"id":"2f852fcc.8b733","type":"subflow:251f4adb.2bd746","z":"ef7b8d90.83f31","name":"","x":690,"y":100,"wires":[]},{"id":"8d3d41d5.0f6f9","type":"delay","z":"ef7b8d90.83f31","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":470,"y":100,"wires":[["c8c152a7.f44c5"]]},{"id":"749e0cac.c536a4","type":"subflow:e2d5a234.d2c46","z":"ef7b8d90.83f31","name":"","x":670,"y":240,"wires":[]},{"id":"f3822478.1a6c78","type":"template","z":"ef7b8d90.83f31","name":"create red data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": true,\n    \"g\": false,\n    \"b\": false\n}","output":"json","x":480,"y":200,"wires":[["749e0cac.c536a4"]]},{"id":"ec5b454a.559568","type":"template","z":"ef7b8d90.83f31","name":"create off data","field":"payload","fieldType":"msg","format":"json","syntax":"plain","template":"{\n    \"r\": false,\n    \"g\": false,\n    \"b\": false\n}","output":"json","x":480,"y":300,"wires":[["749e0cac.c536a4"]]},{"id":"cd4cdd05.2800b","type":"delay","z":"ef7b8d90.83f31","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":460,"y":240,"wires":[["ec5b454a.559568"]]},{"id":"97c80acb.6e03c8","type":"comment","z":"ef7b8d90.83f31","name":"(1) Control by tweet","info":"","x":110,"y":60,"wires":[]}]


(9) 画像付きツイートの解説を話す

[{"id":"562b17a8.765728","type":"http request","z":"9ff48d4c.1257f","name":"get image data","method":"GET","ret":"bin","url":"","tls":"","x":320,"y":180,"wires":[["5af436e4.a1cf98"]]},{"id":"b57c6ab0.7a59a8","type":"debug","z":"9ff48d4c.1257f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":280,"wires":[]},{"id":"32c78fa3.ee3ed","type":"change","z":"9ff48d4c.1257f","name":"set image url","rules":[{"t":"set","p":"url","pt":"msg","to":"tweet.entities.media[0].media_url_https","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":120,"wires":[["158246d3.a66ee9"]]},{"id":"4e180f93.f93a9","type":"openjtalk","z":"9ff48d4c.1257f","name":"","x":540,"y":240,"wires":[]},{"id":"158246d3.a66ee9","type":"switch","z":"9ff48d4c.1257f","name":"filter null url","property":"url","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":590,"y":120,"wires":[["562b17a8.765728"]]},{"id":"a07fdff8.2af71","type":"comment","z":"9ff48d4c.1257f","name":"Set credentials->","info":"","x":140,"y":120,"wires":[]},{"id":"32e7c70f.012228","type":"twitter in","z":"9ff48d4c.1257f","twitter":"","tags":"#tjbot","user":"false","name":"","inputs":0,"x":290,"y":120,"wires":[["32c78fa3.ee3ed"]]},{"id":"d2e9b881.10e8b8","type":"comment","z":"9ff48d4c.1257f","name":"(2) Explain about image in tweet","info":"","x":190,"y":80,"wires":[]},{"id":"f9e3fa33.e20718","type":"google-translate","z":"9ff48d4c.1257f","name":"","to":"ja","x":340,"y":240,"wires":[["b57c6ab0.7a59a8","4e180f93.f93a9"]]},{"id":"5af436e4.a1cf98","type":"image-caption-generator","z":"9ff48d4c.1257f","service":"476e6b66.75e1c4","method":"predict","predict_body":"","predict_bodyType":"str","name":"","x":530,"y":180,"wires":[["f9e3fa33.e20718"]]},{"id":"476e6b66.75e1c4","type":"image-caption-generator-service","z":"","host":"https://max-image-caption-generator.max.us-south.containers.appdomain.cloud","name":"cloud"}]


TJBot Zeroをシャットダウン

[{"id":"c16ef4e0.5b20c8","type":"comment","z":"f7e611e7.f7e29","name":"(4) Shutdown Raspberry Pi","info":"","x":150,"y":1280,"wires":[]},{"id":"45ba9275.beb5cc","type":"inject","z":"f7e611e7.f7e29","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":1340,"wires":[["3f52d111.d601de"]]},{"id":"f262b2ed.7ac95","type":"debug","z":"f7e611e7.f7e29","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":1340,"wires":[]},{"id":"3f52d111.d601de","type":"exec","z":"f7e611e7.f7e29","command":"sudo poweroff","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":330,"y":1340,"wires":[["f262b2ed.7ac95"],[],[]]}]


使用したノード


おまけ1: 環境構築済のOSイメージのセットアップ方法

 TJBot Zero向けの環境構築済のOSイメージは、以下のURLからダウンロードできます。ダウンロードしたイメージは、Etcher等のSDカード書き込みソフトウェアを用いて16GB以上のSDカードに書き込んでください。

https://github.com/tjbotfan/tjbotzero-raspbian/releases

 初回はディスプレイ(ミニHDMI<->HDMI変換アダプタが必要)とキーボード、マウスをつないで起動し、以下のコマンドを用いてwifi設定を行う必要があります。

sudo sh -c 'wpa_passphrase SSID PASSPHRASE >> /etc/wpa_supplicant/wpa_supplicant.conf'

sudo reboot

 再起動後は、PCのブラウザから http://raspberrypi.local:1880 にアクセスすると、Node-REDフローエディタにアクセスできます(シャットダウンはSSHで入り、sudo poweroffを実行すればOKです)。


おまけ2: 自分で環境構築する手順

 新しいOSイメージやNode-REDがリリースされた際など、もし初めから環境構築を行いたい場合は、下記の手順を行なってください。


  • Raspbian NOOBSからダウンロードしたzipファイル内のファイルを、FAT32でフォーマットしたSDカードに書き込み


  • ラズパイにキーボードとマウス、ディスプレイをつなぎ、SDカードを入れたラズパイを起動


  • コマンドラインからWifi設定

    sudo raspi-config nonint do_wifi_country JP

    sudo sh -c 'wpa_passphrase SSID PASSPHRASE >> /etc/wpa_supplicant/wpa_supplicant.conf'

    sudo reboot


  • 設定やソフトウェアのインストールを行う下記URLにあるシェスクリプトを実行(メモリを使用するChromium等は終了して実行してください)


https://raw.githubusercontent.com/tjbotfan/tjbotzero-raspbian/master/install.sh


  • sudo rebootで再起動

-> サンプルとして、LED点灯のフロー、顔を認識して手を振るフロー、IPアドレスを音声で伝えるフローが動作


おまけ3: ハンズオン向けTJBot Zeroを自宅で使う

 TJBotハンズオンで作成したTJBot Zeroを自宅で使うには、以下を行います。



  • セットアップに必要な部品を接続し、Raspberry Piを起動

    以下の部品のうちUSB給電用ACアダプタ以外を接続した後、最後にUSB給電用ACアダプタに接続して起動してください。


    • HDMI接続のディスプレイ

    • HDMIケーブル

    • mini-HDMI〜HDMI変換アダプタ

    • USBキーボード

    • USBマウス

    • USBハブ(USBマイクを外してUSBハブを接続し、USBハブにマイク、キーボード、マウスを接続)

    • USB給電用ACアダプタ(2A以上)

    ディスプレイにデスクトップが表示されれば起動完了です。



  • wifi設定

    まず右上にあるwifiアイコンをクリックします。すると、アクセスポイント一覧が表示されるため、自身のものを選択し、パスワードを入力します。以降は自動的にwifiに接続できるようになるはずです。

    wifi.png


  • Node-REDへアクセス、開発

    PCのブラウザから http://raspberrypi.local:1880 にアクセスすると、Node-REDフローエディタにアクセスできます(Raspberry Pi上のChromiumはメモリ不足でフリーズすることがあるため使わない方が良いです)。


  • シャットダウン(SSHから行う方法)

    Google ChromeのアドオンのSecure Shell Extensionを用いて、SSH経由でRaspberry Piへログインします。ユーザ名は「pi」、ホスト名は「raspberrypi.local」、パスワードは「raspberry」です。

    ssh.png

    もし接続ボタンをクリックした後、「Are you sure you want to continue connecting (yes/no)?」と表示された場合は「yes」と入力してください。ログインした後は、「sudo poweroff」を入力してエンターを押せばシャットダウンが開始します。

    poweroff.png

    Raspberry Piの基盤の上にある緑色のLEDが消えれば電源のUSBを抜いてもOKです。


  • シャットダウン(VNCから行う方法)

    Google ChromeのアドオンのVNC Viewer for Google Chromeを用いて、Raspberry PiのGUIにログインします。Addressは「raspberrypi.local」、User nameは「pi」、Passwordは「raspberry」です。

    vnc.png

    ログイン後は左上のメニューからShutdownを選択します。

    vnc2.png


  • TJBotコミュニティへ参加

    FacebookのTJBotコミュニティに参加し、開発したものをシェアしてみてください。