身近な現実問題にAIやデータサイエンスの適用を試してみる新連載。今回は「ミニぷぱ」というラズパイベースの小型ロボット犬を製作し、OAK-D-LITEカメラを搭載することで物体検知して自動的に目で追うようにしてみる。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
AI/機械学習/データサイエンスをある程度学んできて、Kaggleにも挑戦してちょっとずつ実践を試してきたら、もっと身近な現実問題にAIやデータサイエンスの適用を試したくなってきますよね。そこで本連載では、AIやデータサイエンス、場合によってはもっと広げてPythonなどの幅広い技術を活用して、業務データの利活用や日常作業の効率化、身の回りの趣味や遊びの高度化などを試していきたいと思っています。
ちなみに、コンペティションでの挑戦をつづる『僕たちのKaggle挑戦記』という連載も現在展開中ですが、本連載はその姉妹版であり現実問題版のような立ち位置という想定です。連載タイトルも姉妹連載に似せて『僕たちのAI・データサイエンス実践記』のようにしてもよかったのですが、「実践してみた」のように肩肘を張るような堅い内容ではなく「ちょっと試して遊んでみた」のように気楽な内容にしたかったので、『AI・データサイエンスで遊ぼう』としました。
筆者らが試したことを、読者の皆さんが追体験/疑似体験して楽しめることを目標に執筆していきたいと思います。そこでは、成功例や楽しさだけでなく、筆者らの失敗や苦しんだ部分なども共有していく予定です。この連載が、筆者らだけでなく読者の皆さんにとっても「AIやデータサイエンスを現実問題でどうやって使えばよいのか?」を考えるヒントや練習にもなるとよいなと考えています。もちろん余裕があれば、ぜひ読者自身の手でも試してみてください。
当面の執筆予定者は2人です。2人とも教科書的なデータを使ったディープラーニングやKaggleに挑戦した経験はありますが、現実的な身の回りのデータを使うのはこれがほぼ初めてとなります。内容で「それ、おかしいだろう」と思うことがあればお手柔らかにSNSコメントなどで教えてもらえるとうれしいです。まずは自己紹介として、それぞれの予定や意気込みを短くコメントしておきます。
どうもどうも。かわさきです。あれこれやろうとして、いろいろと悪戦苦闘しているうちに、この連載でも一色さんに先行されてしまいました。この世の中、成功することはそれほど多くはないでしょうが、人はきっと失敗から学ぶこともあるはずです。とはいえ、何か形になるような(オチが付けられるような)結果を得てから、今回の連載の原稿執筆に取り組む所存です(笑)。
今回の記事を執筆している一色(いっしき)です。現実データを使ったAI/データサイエンスの実践としては、「Jigsaw」というレコメンデーションエンジンのメンテナンスをしていることや、ログイン認証で提示されるアイコンを画像認識して自動選択するC#のプログラム(「やっていいのか、それ?」というのはあるんだけど、作れちゃったんだもの)とかは過去にやったことがあります。とはいえ、現実問題の経験は圧倒的に少ないので、この連載をきっかけに頑張ろうと思っています。よろしくお願いします。
さて、連載紹介と自己紹介が終わったところで本題に入りましょう。
Boston Dynamics(ボストン・ダイナミクス)社の「Spot」って知っていますよね? 黄色くて、くの字の足がピョコピョコと動いて歩いたりできるロボット犬です(図1)。
Spotの挙動が「すごい」と、何年か前にSNSなどで話題になりました。「へぇ、欲しい」と思った筆者ですが、Spotは意外に体が大きく家で手軽に所有できるサイズではないし、そもそも価格が(ネット検索すると)800万円以上らしく、とても個人が趣味で持つようなものではありません。それから数年がたち、2021年の冬、ある小型ロボット犬に出会いました。それがMangDang Technology(マンダン・テクノロジー)社の「Mini Pupper」(ミニ・パッパー、日本名「ミニぷぱ」)です(図2)。
「Pupper」と聞いて思い出したのは、ルーディ・ラッカーのSF小説「ソフトウェア」「ウェットウェア」「フリーウェア」でした。が、あちらで出てくるのは「バッパー」でした。ただし、つづりは「bopper」なのでPupperという名前の元ネタってことはなさそうです。買って読んだはずなのに見つからないから、何とか買い直したいなぁ。
それはともかく、かわいいですね。
Pupperは「子犬、わんちゃん、わんこ」を意味する俗語らしいです。
ミニぷぱの詳しい説明は公式Makuakeサイトに任せますが、サイズは肩幅11センチ×胴体21センチ×高さ約17センチの超小型で机の上に乗せられ、価格も自作するなら約5万円と格安です(※基本部品のみのリサーチキットの場合)。これを見たとき、次のことを強く思いました。
「妻の帰宅時に出迎えをするペット犬を作りたい」
それが目標、お題になります。が、最初からそこに到達するにはあまりに長い道のりでした。まずは、ミニぷぱをチュートリアル通りに動かし、画像認識して物体に追従して動くところまでを、今回はやってみようと思います。
ミニぷぱのハードウェア組み立て部分は、ソフトウェアであるAIではないので、本稿では説明上の必要最小限で簡単に紹介するだけとします。
ちなみに、ミニぷぱは日本ではクラウドファンディングサイト「Makuake」のプロジェクトとして始動した段階であり、まだ一般販売されていません。よって、執筆時点(2022年4月25日)での新たな入手は難しいです。今後、Amazon.co.jpでの一般販売が計画されているようです(執筆時点ではまだページがありません)。Amazon.co.jpでも一般販売が開始されたようです(2022年5月27日追記/修正、リサーチ・キット/コンプリート・キット/四足組立完成版/その他)。※なお、筆者自身はMangDang社と全く関係がなく、本稿も宣伝ではありません。AIの実装体験を解説するために、筆者がやったことをつづっているだけです(念のため)。
組み立ては公式ドキュメントに従うだけです。とはいうものの、筆者が自作した段階ではドキュメントの情報や丁寧さが不足していることもあって、パーツの組み立て順序や向き、配線などあらゆる場面で何度も間違えてかなり苦労しました(図3)。「製作目安:初心者なら約2〜3日、上級者なら約2〜3時間」とアナウンスされていますが、私の場合は2週間かかりました。逆に何度も分解しては組み立て直したおかげで、慣れたところはあるかもしれません。今なら1日以内に組み立て可能と思います。なお、公式ドキュメントは写真が多数追加されるなどアップデートされ続けており、情報は充実してきているようです。また、今後の組み立てはもっと簡単になることが公式ドキュメントに書かれています。
筆者の一番複雑な自作物はDeAGOSTINI(デアゴスティーニ・ジャパンディ)社の「週刊 マイ3Dプリンター」だったけど、ここまで間違えなかったので、ミニぷぱの組み立て難易度はかなり高いと思います。最悪なのは、足の基本位置を調整するキャリブレーション(Calibration)で、サーボモーター(=姿勢を制御するモーター)を2つ壊してしまったことです。幸いなことにサーボモーターが1つ予備で付属していました。1つはギアが、もう1つはモーターが壊れたと想定して、2つのサーボモーターを分解して1つに組み立て直したところ何とかなりました。このサーボモーターはMangDang社の特注品で、一般販売されていません。もしこれから作る人はサーボモーターとキャリブレーションの取り扱いは優しく丁寧に、キャリブレーションの最初は足が急に動くので全4足を外しておくことをお勧めします。AIとは全く関係ないけど。
ちなみに、基本部品の他に、電子工作で広く使われている基盤「Raspberry Pi 4 Model B / 2GB」(以下では「ラズパイ」と表記。※現在、半導体不足の影響で価格高騰の上に入手困難)と、32GB以上のmicroSDカードが最低限必要です。また、ラズパイを使うために、キーボードとマウス(EwinミニキーボードをUSB無線ドングルで使うのがお勧め)、モニター、HDMIケーブル(Type-A ― micro Type-D)なども当然必要です。
ミニぷぱを動かすためのソフトウェアには、下記の2つのエディションがあります(※エディションの命名は筆者が便宜的に行ったものであり、公式ドキュメントには記載されていません)。
PS4版はPS4コントローラーでラジコン風に遊ぶだけのエディションです。他には顔の表情をカスタマイズできます。ミニぷぱは元々、スタンフォード大学の学生グループ(Stanford Student Robotics)が中心に開発したもので、最初にこのエディションが開発されたようです(※PS4版からROS版への開発経緯はこちらの記事で紹介されています)。PS4版では内部で「Stanford Pupper」という四足ロボット用ソフトウェアが使われています。PS4コントローラーとミニぷぱをBluetooth接続してから、PS4コントローラーの[L1]ボタンでミニぷぱ本体をアクティブにした後、[R1]ボタンでRest(休憩)モードからTrot(足踏み)モードに切り替えることで足踏みが始まります(※詳しくは公式ドキュメントを参照)。この状態で左スティックで前後左右に動かせ、右スティックで向きを変えられます(図4)。
一方のROS版はカスタマイズ開発用のエディションです。Trot(足踏み)モードのようなものはなく、静止した状態から動かすことが可能です。手動による操作は、PS4コントローラーの他、PCからのキーボードでも可能です(図5は[i]キーを長押して前に進めているところ)。AIなどでの自動操縦をしたい場合にも、このエディションを使います。
さらに、本稿で試すような画像認識などを行いたい場合は、ミニぷぱが正式対応しているOAK-D-LITEというAIカメラが便利です。本稿でもOAK-D-LITEを用います(詳細後述)。なお、OAK-D-LITEとラズパイを接続するには、USBケーブル(Type-C ― Type-A。お勧めはL字型のこちら)が必要です。OAK-D-LITEの土台となるパーツが付属していないので、パーツを自作するために3Dプリンターもあるとよりよいです(※土台の3Dモデルを一般の方が作成し公開してくれていましたので、これを利用しました。いつの間にか公式でも土台の3Dモデルが公開されていました。ただし土台を付けると、ねじの長さが微妙に足りなくなるんですよね……)。
また、AIではないので筆者は試していませんが、周辺の物理環境を光から3Dでセンシングするデバイス「LiDAR」(Light Detection And Ranging、ライダー)にもROS版で対応しており、自己位置推定と環境地図作成を同時に行う技術「SLAM(Simultaneous Localization and Mapping)」を使ってロボット犬を部屋の中で自由に移動させることもできます(※詳細は公式ドキュメントを参照)。
このようにミニぷぱを本気で使うのであれば、ROS版を利用することになります。PS4版は親しみやすくできており、起動時にピャーと鳴き声を発したり、バッテリーが減ったらジギジギと苦しい声を出したりします。これらの機能は、ROS版にも移植可能だったので筆者は個人的に移植しました(※その方法についてはマニアックすぎるので割愛します)。
上記のようにPS4版とROS版の違いがあることも、コードを読み進めるなどしてようやく気付くことができました。バッテリーの電池が1時間で切れてしまうこともあり、ソフトウェアコードを読んで仕組みを理解するのに2〜3週間を費やしてしまい、製作から本稿を執筆するまでに約1カ月がかかってしまいました。始める前は「2週間ぐらいでいけるかな」となめていました。ぐぬぬ……。
先人の苦労のおかげで、後の人は楽できるのです。
前掲の図5では、キーボードでミニぷぱを操作していました。ROSを動かすために、ミニぷぱのラズパイにはOSとしてUbuntu 20.04 LTSがインストールされています(※ROSがUbuntuのLTSにしか対応しない方針なので必ずしも最新OSではありません)。公式ドキュメントによれば、ミニぷぱをリモートから動かすためのPCのOSも基本的に同じUbuntu 20.04 LTSにして、これにROS Noeticをインストールする必要があります。しかし筆者が試した範囲では、PS4コントローラーや、PCからのキーボード、OAK-D-LITEによる操作/作業などはWindowsやmacOSからも可能でした(※ただし、筆者自身がROSを使うのが初めてであり、人に教えられるほどの知識はまだない上での発言ですのでご了承ください)。
前掲の図5のように動かすには、リモートにあるPC上でターミナルを3つ開いて、リスト1〜3のコマンドを実行するだけです(※前述の通り、WindowsやmacOSでリスト1は実行しなくても動作はしました)。
roscore
ssh ubuntu@192.168.1.83 -p 22
ubuntu@mini-pupper-ros:~$ roslaunch mini_pupper bringup.launch
ssh ubuntu@192.168.1.83 -p 22
ubuntu@mini-pupper-ros:~$ roslaunch champ_teleop teleop.launch
3つ目のコマンドをroslaunch ps4_interface ps4_interface.launchに変えると、PS4コントローラーによる操作が可能です(図6)。
ピョコピョコした動作はほんとにかわいらしいですね。こんな子が出迎えに出てくれると、確かにうれしいかもしれません。
基本的には3つ目以降のコマンドを別のものに変えることで、さまざまな挙動が可能になっています。
試行錯誤の連続で苦労しましたが、ここまで動かせると後述の作業も含めて次々と成功しました。
ちなみに、筆者はPS4版とROS版のコードを比較しながら「両者で何が違うか」「どのような仕組みで動くのか」を理解しようとしましたが、最初からそこまでする必要はないかもしれません。MangDang社が公開しているROS版OSの.imgファイルを使えば、基本的なものはインストールされているので少し設定を変えるだけですぐに動く状態です。筆者が失敗した例では、間違ってラズパイ側UbuntuへROSをインストールしたりしてしまっていましたが、そんな作業は不要でした。これからROS版を試す人は、取りあえず動かしてみるところから始めた方がよいです。公式ドキュメントには、PC側の作業とラズパイ側の作業の2種類があるので、両者を混同しないようにご注意ください。
いよいよ今回の目的です。OAK-D-LITEカメラで画像認識をして物体検知し、その物体を視線で追うようにミニぷぱの姿勢を動かします。
そもそもOAK-D-LITE(OpenCV AI Kit - Depth - Lite)とは、Luxonis(ルクソニス)社とコンピュータビジョン用ライブラリー「OpenCV」が共同で販売しているAIカメラ「OpenCV AI Kit」シリーズの中の一製品です(※日本ではスイッチサイエンスで販売されています)。3つのカメラが内蔵されており、深度(Depth)も認識可能なのが特徴です。Luxonis社から公開されているDepthAI APIを使うことで、本稿で行う物体検知だけでなく、姿勢推定や、セマンティック・セグメンテーションなどなどさまざまなAI(画像認識)を簡単に実現可能です(※「何ができるか」はOAK-D-LITEのKickstarterページが分かりやすいです)。
そのDepthAI APIを使って、例えばMobileNetモデルによる物体検知が可能です。ミニぷぱROS版のGitHubリポジトリ「minipupper_ros」には、実際にドリンクボトルを検知してミニぷぱの姿勢を動かすデモチュートリアルが掲載されています。今回はここまでを実践してみようと思います。
動かし方は、リスト4〜6で先ほどとほぼ同じです(※こちらのチュートリアルにはroscoreコマンドの実行は記載されていませんでした)。
ssh ubuntu@192.168.1.83 -p 22
ubuntu@mini-pupper-ros:~$ roslaunch mini_pupper bringup.launch
ssh ubuntu@192.168.1.83 -p 22
ubuntu@mini-pupper-ros:~$ roslaunch depthai_examples mobile_publisher.launch
ssh ubuntu@192.168.1.83 -p 22
ubuntu@mini-pupper-ros:~$ rosrun mini_pupper_detect oak_detect.py
ROSにはROS 1とROS 2があり、DepthAIのROSエコシステム「depthai-ros」ではその両方に対応していますが、ここで使われているのはROS 1です。ROS 1では、実行プログラムをNode(ノード)という単位で扱います。リスト5ではMobileNetモデル用のノード「mobile_publisher」を起動し、リスト6ではドリンクボトル検知時にミニぷぱの姿勢変更を行うためのノード「oak_detect」を起動しているというわけです。
上記の3つのコマンドを実行後に、ミニぷぱの前にドリンクボトルを掲げて位置を動かすと、確かに図7のように視線で追いかけるように動きました。
MobileNetモデルでどんな物体を検知するかは、oak_detect.pyファイル(ラズパイ側の/home/ubuntu/catkin_ws/src/minipupper_ros/mini_pupper_detect/scripts/oak_detect.pyファイル)にPythonコードで記載されています。リスト7に、少し長いですがその全コードを掲載しました。コメントの#mobilenet object listに検知可能な物体の種類と番号が記載されています。
#!/usr/bin/env python3
import rospy
#from darknet_ros_msgs.msg import BoundingBoxes
from geometry_msgs.msg import Twist
from geometry_msgs.msg import Pose
from vision_msgs.msg import Detection2DArray
import math
height = 300
width = 300
roll=0
pitch=0
yaw = 0
yaw_increment=0
pitch_increment=0
pose = Pose()
#mobilenet object list
#0: background
#1: aeroplane
#2: bicycle
#3: bird
#4: boat
#5: bottle
#6: bus
#7: car
#8: cat
#9: chair
#10: cow
#11: diningtable
#12: dog
#13: horse
#14: motorbike
#15: person
#16: pottedplant
#17: sheep
#18: sofa
#19: train
#20: tvmonitor
def toward_obj(obj_class,obj_list):
global pose,roll,pitch,yaw,yaw_increment,pitch_increment
rate = rospy.Rate(200) # 200hz
yaw_increment = 0
pitch_increment = 0
for i in obj_list:
bb = i.bbox #BoundingBoxes
si = i.source_img #SourceImage
r = i.results #Results
rr = r[0] #RealResults
#print(rr.id)
if(rr.id == obj_class):
print(11111)
yaw_increment=(width/2-bb.center.x)*0.0002
pitch_increment=-(height/2-bb.center.y)*0.0002
#else:
#yaw_increment=0
yaw = yaw+yaw_increment
#print(yaw_increment)
pitch = pitch+pitch_increment
cy=math.cos(yaw*0.5)
sy=math.sin(yaw*0.5)
cp=math.cos(pitch*0.5)
sp=math.sin(pitch*0.5)
cr =math.cos(roll * 0.5)
sr =math.sin(roll * 0.5)
pose.orientation.w= cy * cp * cr + sy * sp * sr
pose.orientation.x = cy * cp * sr - sy * sp * cr
pose.orientation.y = sy * cp * sr + cy * sp * cr
pose.orientation.z = sy * cp * cr - cy * sp * sr
pub_pose.publish(pose)
rate.sleep()
def callback(data):
bounding_boxes = data
detections = bounding_boxes.detections
toward_obj(5,detections)
#toward_obj('cup',a)
#print(a[0])
def listener():
rospy.init_node('yolo_detect', anonymous=True)
rospy.Subscriber("/mobilenet_publisher/color/mobilenet_detections", Detection2DArray, callback)
rospy.spin()
if __name__ == '__main__':
pub_pose = rospy.Publisher('/body_pose', Pose, queue_size=10)
listener()
今回は5番の「bottle」が使われているはずです。確かにtoward_obj(5,detections)というコードで5が指定されていますね。
def toward_obj(obj_class,obj_list):という関数定義で、引数obj_classが宣言されています。その関数定義内にif(rr.id == obj_class):という条件判定が行われ、条件に合致する場合には11111という数値を出力し、3次元ベクトルの回転であるヨー(yaw)とピッチ(pitch)と呼ばれる数値を計算しています(参考:「ロール・ピッチ・ヨー ― Kinectで学ぶ数学 - Build Insider」)。
計算した数値は、最終的にpose.orientationオブジェクトに格納され、pub_pose.publish(pose)メソッドによりbody_poseトピックに対応するPublisherからpublishすることで、四足歩行制御を行うノード(上記のコードには記載されていませんが、リスト4のコマンドにより起動済みのquadruped_controller_node型のノード「champ_controller」)に渡されています。これによりミニぷぱ本体の姿勢が動くようです。このようにROS 1ではPublisher(発行者)とSubscriber(講読者)という仕組みを採用しており、ノード間でのデータ(Message)のやり取りは同名のTopic(トピック)に対応するPublisherとSubscriberを通じて行われます。
なおリスト7で、「物体検知時の姿勢変更プログラムのROSノード」の名前がyolo_detectとなっているのは恐らく誤記で、本来はoak_detectと記述したかったのではないかと思います。
AI処理部分のコード内容が少し分かってきたので、最終的な目標である「妻を出迎えるミニぷぱ」も実現できそうな気がしてきました(……たぶん前途多難)。
最終的には、一色さんが黄色い犬になってお出迎えをするという方法も……。
なるほど、それだ!(違う)
今回はここまでですが、最後にミニぷぱの開発環境についても言及しておきます。ミニぷぱをカスタマイズする開発関連の作業は、リモートPC(筆者の場合はWindows)にVisual Studio CodeをインストールしてSSH経由で接続するのが非常に快適でした(図8)。
今回は、少しコード内容も見てみましたが、ほぼチュートリアル通りの作業でした。次回は、頑張ってAI処理のカスタマイズに手を出します。お楽しみに。
Copyright© Digital Advantage Corp. All Rights Reserved.