Arduinoとpythonで動かすロボット


##こんなロボットを作った
コンピュータビジョン勉強のネタが欲しくて、こんなロボットを作りました。
YouTube動画にリンクされてますので、ぜひとも画像をクリックしてみてください。どんな風に動くかが判ると思います。

[![https://www.youtube.com/watch?v=hIaIxOBjJzQ](http://img.youtube.com/vi/hIaIxOBjJzQ/0.jpg)](http://www.youtube.com/watch?v=hIaIxOBjJzQ)

* 仕様

    * 左右のモーターで前後左右回転
    * 5サーボを搭載したロボットアーム
    * ロボットアームの先端には直径8mmの小型カメラを搭載
    * 2サーボで首振りするPrimesense PS1080センサー (RGB-Dカメラ)
    * ハードウェア部分はArduino MEGA 2560で制御
    * Intel Atomプロセッサの小型PC(Windows 10)を搭載し、HTTPサーバが稼働
    * HTTPプロトコルを介して遠隔でロボットのコントロールが可能

このロボットを、Wi-Fi経由でpythonを使ってコントロールする。
カメラ画像、RGB-D画像などを獲得して、画像解析して動かそうという試みです。

##ロボット側詳細
ロボットを製作するにあたって、ベースとしてルンバのようなロボット掃除機を分解・改造して利用しました。ニトリで販売されている廉価のロボット掃除機です。これくらい安いものなら分解・改造しても惜しくはありませんｗ
そしてその上に、ロボットアームやArduino, RGB-Dカメラ, ロボットに搭載したハードウェアを制御するIntel Atomプロセッサ搭載の小型PCを載せています。
Arduinoは、大量のサーボをコントロールしたいため、MEGA 2560を採用しています。よく見るUNOでは少し足りませんし、将来の拡張も考えると心もとないかな、と。
小型PCは[DG-M01IW](http://www.dospara.co.jp/5shopping/detail_prime/2/149/5435/2090/)という型番で、なんと、文庫本サイズでありながら13時間持つバッテリーも内蔵しています。まさしく、このロボットでの利用にベストマッチで、2台も購入してしまいましたｗ

ロボット側のソフトウェアとしては、大別してArduinoに載せるファームウェア的なものと、PC(Windows 10)に載せるHTTPサーバを構成するサーバ的なものとがあります。

###Arduino
Arduinoにも電源が必要です。これにはラジコン用として流通している7.2Vバッテリーを使っています。

ロボットアームやRGB-Dカメラを支えるサーボのコントロールには、ArduinoによるPWM制御です。
ロボットの移動に使うモーターは、I2C制御のモーターコントローラを外付けし、I2C経由でロボット掃除機のモーターをコントロールするように回路を組みました。これでロボットが前後左右・回転移動可能になります。

PCとはUARTによるSerial通信を行います。
Arduino側では、以下のコントロールや情報獲得のためのプロトコルを用意しました。

* ロボットアーム, RGB-Dカメラを支えるサーボと、計7つのサーボのコントロール
* ロボットそのものの移動に使うモーターのコントロール
* 照度センサー、距離センサー、地軸センサーの情報獲得

上述のプロトコルをPCからSerialポートを通して発行することで、自在なサーボコントロールや情報獲得が可能になります。
例えば、`a0+90`と送信することで、サーボ#0を+90°の角度に動かしたり、`m+255+255`で左右の移動用モーターを前進方向に回す、など。無論、サーボのスピードコントロールなど、そういった細かいことはArduino側で行っています。

###PC (DG-M01IW)
PCは、内蔵のバッテリを持っているので、外部バッテリなしで稼働します。基本OSはプレインストールされていたWindows 10 Homeをそのまま利用しています。
Arduino, RGB-Dカメラ, ロボットアーム先端のカメラなどがUSBを介して接続されています。
また、Bluetoothや Wi-Fiなどは当然内蔵しているため、このPCがあってこそ、Wi-Fiベースのネットワークコントロールが可能になります。

Arduinoとの通信は、UART Serial通信を使って行います。
PC側では、以下の仕事がメインです。

* RGB-Dカメラの読み取り (カメラ＋距離データ)
* ロボットアーム先端に搭載したカメラの映像獲得
* HTTPサーバの搭載
* ArduinoにSerial通信してハードウェア側のコントロール

HTTPサーバ側で受け付けたURLに応じて、カメラ画像を返したり、サーボをArduino経由でコントロールします。
例えば、`http://..../sensor/color`に対するGET要求にはimage/jpegを返すとか、`http://..../arm0?cmd=...`に対するGET要求にはcmdパラメータに応じてロボットアームを動かすなど。

要するに、HTTPで受けた要求を解釈してその通りにArduinoに指令を送ったり画像・深度情報を返してやることがPC側の仕事です。このPCはロボットに搭載できるほど小型で、しかもバッテリ駆動ですので、CPU負荷が上がるような演算などは極力行いません。
この辺り、本当はRaspberry Pi程度でも実施できる仕事かと思いきや、意外とUSB周りの帯域が問題となり、特にRGB-DカメラあたりはRaspberry Piでは荷が重いです。

HTTPサーバは、いろいろ試行錯誤しましたが結局、C++で実装しました。理由は以下の通りです。

* RGB-DカメラのアクセスはOpenNI 2を利用しており、これはC/C++でのインタフェースが最も楽
* イメージの取り扱いにはOpenCV 2.4を利用しており、これもまたC/C++でのインタフェースが最も楽
* WindowsではHTTP.sysが用意されており、比較的楽にHTTPサーバを実装できた (あくまでも「比較的」。今更`socket()`とか`accept()`は駆使したくないものです)

本当は、OSをLinuxベースにすれば、C/C++ベースであろうとももっと楽にササッと作れたと思います。特にHTTP周り。
しかしながらIntel Atomプロセッサ搭載のミニPCにLinuxをインストールするのが少々厄介だった事(※)などあり、断念してWindows 10ベースで開発しました。(でもそのおかげで、デバッグ等はVisual Studioが活用できて結果的に楽だったかも)

※: 32bit版のEFIブートに対応したLinuxディストリビューションが見当たらなかったというだけの理由ｗ あんまりこの辺りで苦労したくないな、と...思ったのでした。本当はUbuntuとか入れたかった。

##画像解析ロジック
ここまでで、Wi-Fiネットワーク経由でロボットを完全ワイヤレスでコントロールできる状態になっており、画像解析してロボットをコントロールする側は、OS種にも言語にも何にも縛られることはありません。

個人的に使っているメインPCはMac Book Air Mid 2012ですので、この辺りは是非ともMacで行きたいところ。
ということで、pythonベースで numpy, OpenCV 2.x, (+  TensorFlow)などを駆使するように考えます。HTTP関係には[requests](http://docs.python-requests.org/en/latest/)が利用可能です。

現状は、[Qiita: "pythonで赤い物体を認識しよう"](http://qiita.com/odaman68000/items/ae28cf7bdaf4fa13a65b)に記載したような手法で、赤いオブジェクトを探索してそれを追いかけるようなロジックを作り込んでいます。ゆくゆくはロボットアームで自律的に掴むところまで持っていく予定です。

RGB-Dカメラから得た深度データを使って画像をクラスタリングする手法や、Point Cloud Libraryを使った点群処理なども駆使したいですね。この手のロジックはこれまで、C++/Objective-Cベースで色々実装していたのですが、python + numpyの破壊力に日々感動しています。もっと早くからpython + numpyに移行してれば良かったと思いますｗ

これから、これまで実装したロジックをpythonに移植しつつ、これらを活用してロボットのコントロールに深みを増していくつもりです。何か成果が出たら、それらの記事も書いていきたいと思います。