ずーっと気になってたロボット「RAPIRO」、ラピロって読みます。このロボットの最大の特徴は、ラズベリーパイを内蔵して、ラピロを動作させることができることです。おもちゃにしては高いので、ラズパイを使いこなせるようになるまでは買わないって決めてたけど、箱型AIロボット「BB-2」を完成させることができたので、ついにオンラインショッピングでぽちっとしました。翌日には届いちゃう凄い時代です。早速、ロボットを組み立てますが、ついでにAIロボットとして完成させるためにカスタマイズ改造もしちゃいます。
この説明には、RAPIROの標準キットに無いカスタマイズ改造をしているのでご注意を。
ロボット胸部分にArduino互換の基盤をネジで取り付け、サーボモータには右足や左手など稼働部分のシールを貼るなど各モジュールを作っていきます。
腕や足などの関節部分にサーボモーターを取り付けます。RAPIROは部品点数が少なく、すごく単純化されているので、組み立ては少しコツがいるかも。
なんだかこわい図になってしまった。この後、サーボモーターのコネクタをRapiroのArduino基盤に接続する。配線が多いのでコンパクトにキレイに配線しないと胸の上側パーツがはまらないので根気よくやりましょう。
Drスランプ・アラレちゃんが誕生する時を思い出しますね。ラピロ標準キットに無い、ラズパイとスピーカーを頭部分に内蔵します。スピーカーはアンプをハンダ付けしたり、コネクタを接続するなど電子工作しています。
電子工作実験の時に、台湾製の小型USBマイクだと声を認識できなかったので、もったいないけれど、マイク内蔵USBカメラをロボット本体のスカート内に取り付けした。このマイクとラズパイの相性はバッチリです。
人工知能(AI)ロボットに仕上げるための改造です。喋るための「スピーカー」は50mmでジャストフィットするよう設計されています。見るための「カメラ」は、Raspberry Pi3専用カメラモジュールを取り付け出来ます。聞くための「マイク」は体の中を通ってスカート内に設置しました。
ここで問題が発生。ラピロは元々、Raspberry Pi2を前後方向に実装できるよう設計されていたらしく、Raspberry Pi3になると変換アダプタを挟んで、図のように左右方向に設置するように変更になっており、USBコネクタを接続するスペースが凄く狭くなっています。USBカメラのケーブルコネクタをそのままでは接続できないため、180度折り返すことができる「USB変換コネクタ」を買ってきて、図のように頭に収めることが出来ました。
ラピロの頭の中でスピーカーの音がこもってしまったので、ドリルを使って耳の穴を大きくしました。とてもキレイに音が聞こえるようになりました。
部品 | 主な仕様 |
---|---|
(ロボット本体)RAPIRO | Arduino基盤を搭載、サーボモーター12個搭載 |
(頭脳)Raspberry Pi3 Model B | CPUはクアッドコア1.2GHz(つまり4コア)、無線LAN搭載 |
(聞く)マイク内蔵USBカメラ | Baffaro BSWHD06M |
(話す)スピーカー | サイズ50mm + 超小型BTLアンプ8Ω, 1.5V, ROHM製BU7150 |
(見る)カメラ基盤 | Raspberry Pi Video Module Camera Board 775-7731 |
(感じる)温度計 | DS18B20使用温度センサモジュール |
(食べる:自宅)AC-DC電源 | Input: 100V, Output: 12V, 5A |
(食べる:外出時)充電式電池 | eneloop pro 単三型 5本、 |
ラピロの組み立てとラズパイ搭載などの改造を行いました。この後、Arduinoの初期設定を行うのですが、最終的にはプログラミングして、ダンスをさせるところまで出来ました。ラピロは標準キットでも動きますが、ラズパイを載せたり、カメラを取り付けたり、カスタマイズしてロボットの電子工作やプログラミングを勉強するのにとっても良いロボットです。値段も42,000円程度であり、けっして安くはないですが、他のロボットは高級すぎてとても手が出ないので予算面ではぎりぎりでしょうか。とか言って、改造費が追加で10,000円くらいかかってしまいましたけど。次は、ラピロの初期設定を行います。
こちらは、ラピロが自分で音楽を流して踊ってみた動画です。
自作したpythonプログラムと同じディレクトリにmp3ファイルがあります。Raspberry Pi3からラピロのArduino基盤へひたすらコマンドを送信しています。
#!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import string import traceback import serial import time import subprocess # RAPIROと通信するための初期設定 glbCom = serial.Serial('/dev/ttyAMA0', 57600, timeout = 10) if __name__ == '__main__': try: # mp3音楽を鳴らす(スピーカー出力、ボリューム1000)。 cmd = "omxplayer -o local --vol -1000 song01miku.mp3" # mp3音楽を鳴らすが、後で音楽を途中停止できるようにsubprocessを使う。 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE) # ラピロへ動作コマンドを送信します。 glbCom.write( "#M0" ) time.sleep(1) glbCom.write( "#PS00A130T005" ) #頭左 time.sleep(1) glbCom.write( "#PS00A090T005" ) #頭init time.sleep(0.5) glbCom.write( "#PS00A050T005" ) #頭右 time.sleep(1) glbCom.write( "#PS00A090T005" ) #頭init time.sleep(1) glbCom.write( "#PS00A050S01A130T010" ) #胸左 time.sleep(1) glbCom.write( "#PS00A130S01A050T010" ) #胸右 time.sleep(1) glbCom.write( "#PS00A090S01A090T010" ) #胸init time.sleep(1) glbCom.write( "#PS02A040S05A130T005" ) #両手ちょい前 time.sleep(0.5) glbCom.write( "#PS02A000S05A180T005" ) #両手init time.sleep(1) glbCom.write( "#PS02A040S05A130T005" ) #両手ちょい前 time.sleep(0.5) glbCom.write( "#PS02A000S05A180T005" ) #両手init time.sleep(2) glbCom.write( "#PS00A040S02A090S03A040S09A110T010" ) #右見て、手を伸ばす time.sleep(2) glbCom.write( "#PS00A090S02A000S03A130S09A090T010" ) #init time.sleep(2) glbCom.write( "#PS00A140S05A090S06A140S11A110T010" ) #左見て、手を伸ばす time.sleep(2) glbCom.write( "#PS00A090S05A180S06A050S11A090T010" ) #init time.sleep(2) glbCom.write( "#PS08A100S10A080T003" ) #足開く time.sleep(0.3) glbCom.write( "#PS08A090S10A090T003" ) #足init time.sleep(0.3) glbCom.write( "#PS08A100S10A080T003" ) #足開く time.sleep(0.3) glbCom.write( "#PS08A090S10A090T003" ) #足init time.sleep(2) glbCom.write( "#PS00A050S01A130S02A090S05A130S09A070S11A090T001" ) #体左ひねり・ポ time.sleep(1) glbCom.write( "#PS02A040S05A090T003" ) #コ time.sleep(0.3) glbCom.write( "#PS02A090S05A130T003" ) #ポ time.sleep(0.3) glbCom.write( "#PS02A040S05A090T003" ) #コ time.sleep(0.3) glbCom.write( "#PS02A090S05A130T003" ) #ポ time.sleep(0.3) glbCom.write( "#M0" ) time.sleep(1) glbCom.write( "#PS00A130S01A050S02A040S05A090S11A110T001" ) #体右ひねり・ポ time.sleep(1) glbCom.write( "#PS02A090S05A130T003" ) #コ time.sleep(0.3) glbCom.write( "#PS02A040S05A090T003" ) #ポ time.sleep(0.3) glbCom.write( "#PS02A090S05A130T003" ) #コ time.sleep(0.3) glbCom.write( "#PS02A040S05A090T003" ) #ポ time.sleep(0.3) glbCom.write( "#M0" ) time.sleep(0.5) glbCom.write( "#PR000G000B000T003" ) #LED-黒 time.sleep(0.5) glbCom.write( "#PR000G000B255T003" ) #LED-あお time.sleep(0.5) glbCom.write( "#PR000G000B000T003" ) #LED-黒 time.sleep(0.5) glbCom.write( "#PR000G000B255T003" ) #LED-あお time.sleep(0.5) glbCom.write( "#PR000G000B000T003" ) #LED-黒 time.sleep(0.5) glbCom.write( "#PR255G000B000T010" ) #LED-赤 time.sleep(0.5) glbCom.write( "#PS00A130S01A050S02A130S05A130S08A070S10A050T003" ) #両足-左 time.sleep(0.7) glbCom.write( "#PS00A090S01A090S02A090S05A090S08A090S10A090T003" ) #両足init time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A040S05A040S08A130S10A110T003" ) #両足-右 time.sleep(0.7) glbCom.write( "#PS00A090S01A090S02A090S05A090S08A090S10A090T003" ) #両足init time.sleep(0.7) glbCom.write( "#PS02A090S04A070S05A090S07A110T003" ) #両手つかむ time.sleep(0.5) glbCom.write( "#PS02A090S04A110S05A090S07A070T003" ) #両手離す time.sleep(0.5) glbCom.write( "#PS02A090S04A070S05A090S07A110T003" ) #両手つかむ time.sleep(0.5) glbCom.write( "#PS02A090S04A110S05A090S07A070T003" ) #両手離す time.sleep(0.5) glbCom.write( "#PS02A180S03A040S05A000S06A140T010" ) #万歳 time.sleep(0.7) glbCom.write( "#PS02A180S03A040S05A000S06A060T005" ) #左手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A120S05A000S06A140T005" ) #右手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A040S05A000S06A060T005" ) #左手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A120S05A000S06A140T005" ) #右手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A040S05A000S06A060T005" ) #左手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A120S05A000S06A140T005" ) #右手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A040S05A000S06A060T005" ) #左手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A120S05A000S06A140T005" ) #右手上げて time.sleep(0.7) glbCom.write( "#PS02A180S03A040S05A000S06A140T005" ) #万歳 time.sleep(0.7) glbCom.write( "#PS00A160S01A020S02A090S03A040S05A130S06A100T005" ) #右パンチ time.sleep(1) glbCom.write( "#PS00A020S01A160S02A040S03A070S05A090S06A140T005" ) #左パンチ time.sleep(1) glbCom.write( "#PS00A160S01A020S02A090S03A040S05A130S06A100T005" ) #右パンチ time.sleep(1) glbCom.write( "#PS00A020S01A160S02A040S03A070S05A090S06A140T005" ) #左パンチ time.sleep(1) glbCom.write( "#PS00A160S01A020S02A090S03A040S05A130S06A100T005" ) #右パンチ time.sleep(1) glbCom.write( "#PS00A020S01A160S02A040S03A070S05A090S06A140T005" ) #左パンチ time.sleep(1) glbCom.write( "#PS00A160S01A020S02A090S03A040S05A130S06A100T005" ) #右パンチ time.sleep(1) glbCom.write( "#PS00A090S01A090S02A040S03A130S05A130S06A050T010" ) #左パンチ time.sleep(1) glbCom.write( "#PS02A180S03A040S05A000S06A140S09A030S11A140T010" ) #のびー time.sleep(3) glbCom.write( "#PS01A090S02A040S03A070S05A130S06A100S09A085S11A085T007" ) #戻る time.sleep(2) glbCom.write( "#PS00A130S01A050S02A130S05A090T005" ) #右1 time.sleep(0.7) glbCom.write( "#PS00A130S01A050S02A040S05A040T005" ) #右2 time.sleep(0.7) glbCom.write( "#PS00A130S01A050S02A130S05A090T005" ) #右1 time.sleep(0.7) glbCom.write( "#PS00A130S01A050S02A040S05A040T005" ) #右2 time.sleep(0.7) glbCom.write( "#PS00A130S01A050S02A130S05A090T005" ) #右1 time.sleep(0.7) glbCom.write( "#PS00A130S01A050S02A040S05A040T005" ) #右2 time.sleep(0.7) glbCom.write( "#PS00A090S01A090S02A040S03A070S05A130S06A100T005" ) #正面 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A130S03A070S05A130S06A100T005" ) #左1 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A040S03A070S05A040S06A100T005" ) #左2 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A130S03A070S05A130S06A100T005" ) #左1 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A040S03A070S05A040S06A100T005" ) #左2 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A130S03A070S05A130S06A100T005" ) #左1 time.sleep(0.7) glbCom.write( "#PS00A050S01A130S02A040S03A070S05A040S06A100T005" ) #左2 time.sleep(0.7) glbCom.write( "#PS00A090S01A090S02A040S03A070S05A130S06A100T005" ) #正面 time.sleep(0.7) glbCom.write( "#PS00A050S01A050S02A090S03A070S06A100S10A050T005" ) #右1 time.sleep(1) glbCom.write( "#PS00A050S01A050S02A000S03A070S05A130S06A100S10A050T003" ) #右2 time.sleep(0.8) glbCom.write( "#PS00A050S01A050S02A090S03A070S05A040S06A100S10A050T003" ) #右3 time.sleep(0.8) glbCom.write( "#PS00A050S01A050S02A180S03A070S05A090S06A100S10A050T003" ) #右4 time.sleep(0.8) glbCom.write( "#PS00A050S01A050S02A000S03A070S05A130S06A100S10A050T003" ) #右2 time.sleep(0.8) glbCom.write( "#PS00A050S01A050S02A090S03A070S05A040S06A100S10A050T003" ) #右3 time.sleep(0.8) glbCom.write( "#PS00A050S01A050S02A180S03A070S05A090S06A100S10A050T003" ) #右4 time.sleep(0.8) glbCom.write( "#PS00A090S01A090S02A040S05A130S08A090S10A090T005" ) #初期 time.sleep(1) glbCom.write( "#PS00A130S01A130S02A090S03A070S05A040S06A100T003" ) #左1 time.sleep(0.7) glbCom.write( "#PS00A130S01A130S02A130S03A040S05A130S06A050T003" ) #左2 time.sleep(0.7) glbCom.write( "#PS00A130S01A130S02A040S03A130S05A040S06A100T003" ) #左3 time.sleep(0.7) glbCom.write( "#PS00A130S01A130S02A090S03A070S05A040S06A100T003" ) #左1 time.sleep(0.7) glbCom.write( "#PS00A130S01A130S02A130S03A040S05A130S06A050T003" ) #左2 time.sleep(0.7) glbCom.write( "#PS00A130S01A130S02A040S03A130S05A040S06A100T003" ) #左3 time.sleep(0.7) glbCom.write( "#PS00A090S01A090S02A040S05A130S08A090S10A090T005" ) #初期 time.sleep(1) glbCom.write( "#M8" ) #さよなら time.sleep(8) proc.stdin.write("q") #音楽停止 except: print ('--------------------------------------------') print ('[rapiro_dance.py]') print ('--------------------------------------------') print ( traceback.format_exc(sys.exc_info()[2]) ) print ('--------------------------------------------') finally: time.sleep(2) glbCom.write( "#M0" ) print("(^_^)> 完了!\n")
ラピロが正常に動かない時のチェックリストを作りました。
[ ]PC - Raprio間の通信(ファームウェアのインストール)
[ ]PC - Raprio間の通信(ラピロ動作する)
[ ]PC - Raprio間のUSBケーブル(USBケーブルはデータ通信用か[充電専用USBケーブルはNG])
[ ]シリアルコンソールのdisable(無効化)
[ ]PCとラズパイは、競合するのでPCと接続するケーブルは外す
[ ]ラズパイ - Rapiro間の通信速度が一致しているか(例:serial.Serial('/dev/ttyAMA0', 57600, timeout = 10))
[ ]ラズパイ - Rapiro間の通信(ただしエラーは出ない)
[ ]ラズパイ - Rapiro間の配線が正しい端子に繋がっているか
[ ]電源配線が正しい端子に繋がっているか