ラベル arduino の投稿を表示しています。 すべての投稿を表示
ラベル arduino の投稿を表示しています。 すべての投稿を表示

2014年11月2日日曜日

Raspberry PiとArduinoで16x32 RGB LEDパネルにカメラモジュールの映像を表示してみた

はじめに

5月頃に秋月で「RGBフルカラードットマトリクスLEDパネル 16x32ドット」を購入し、長いこと放置していたのですが、少し時間ができたので試してみることにしました。

最近ずっと仕事で使っていたRaspberry Piで試すことにします。ただし、Raspberry Piに直接接続するわけではなく、

RaspberryPi―(シリアル通信)→Arduino→RGB LEDパネル

という構成にしました。そうすることで、Adafruitで公開されているArduino用のライブラリを流用することができます。

なお、この構成で始めた後に、やはりAdafruitでRaspberry Pi用のチュートリアルが出てることを知りました。そちらのチュートリアルでは画像ファイルをスクロールする例を取り扱っていますが、本ページでは、それとは異なる構成でRaspberry Piのカメラモジュールの映像をRGB LEDパネルに表示するところまでを試してみます(下図)。


準備

まず、AdafruitのArduino用のチュートリアルを元に、Arduinoで動作することを確かめてください。ArduinoのIDEでFile→Examples→RGBmatrixPanelとたどった時に「16x32」が含まれているサンプルは動作します。

用いるArduinoはチュートリアルにあるようにArduino Unoで良いですが、私は「Arduino Pro Mini 328 5V 16MHz」+「FT232RL搭載小型USB-シリアルアダプタ 5V」の組み合わせを用いました。ソースを少し変更するだけでArduino Megaでもいけるようですが、こちらでは試していません。

C++ & OpenCVの場合

それでは、Raspberry Piでの準備に入っていきます。Raspberry Piのカメラモジュールの映像を取得し、それをRGB LEDパネルに表示することを目指しますが、そのためにC++とOpenCVの組み合わせを用いることにします。

最初はPythonと画像処理ライブラリのPillowの組み合わせで試していたのですが、思った速度が出なかったので、C++とOpenCVの組み合わせに切り替えました。Python+Pillow版についてはページ末尾にメモを残しますので、興味のある方はどうぞ。

さて、Raspberry Pi、Arduino、RGB LEDパネルを下記のように接続しておきます。この場合、Arduinoの電源はRaspberry PiのUSBから供給されます。



さらに、Raspberry Piではカメラモジュールを使えるようにしておきましょう。「sudo raspi-config」で設定を起動し、「5. Enable Camera」→「Enable」とたどれば良いのでした。

次に、Raspberry PiでOpenCV、および後に必要なcmakeをインストールします。

sudo apt-get update
sudo apt-get install libopencv-dev cmake

次に、このRaspberry Piのカメラモジュールに対してOpenCVを用いることができるよう、「RaspiCam : C++ API for using Raspberry camera with/without OpenCv」をインストールします。まず、SourceForgeからraspicam-0.1.1.zip (129.5 kB)をダウンロードし、下記のコマンドでインストールします。

unzip raspicam-0.1.1.zip
cd raspicam-0.1.1
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig

このRaspiCamを用いると、Raspberry Piのカメラモジュールで取得した画像に対してOpenCVを利用できるので良さそうです。私は普段OpenCVを使っているわけではなく、RaspiCamも今回初めて触ったので、「良さそう」という程度しか言えないのですが。

次に、RGB LEDパネル用に私が用意したファイルを準備します。

cd
git clone https://github.com/neuralassembly/raspi_16x32RGBLED
cd raspi_16x32RGBLED
make

makeを実行した後、しばらく待つとビルドが完了します。画像ファイル表示用のimage2LEDmatrix、カメラモジュール表示用のcamera2LEDmatrixの2つの実行ファイルができています。 

さらに、Arduino用のserial2LEDmatrix.inoというC言語ファイルが存在します。このserial2LEDmatrix.inoをWindowsなどであらかじめArduinoに書き込んでおきましょう。 

このスケッチは、下図のように16x32x3バイトの階調(各階調は0~Fで表示)をシリアル通信で受け取り、「.」(ピリオド)を受け取ったタイミングでLEDパネルの内容を更新するように記述されています。



以下、image2LEDmatrixとcamera2LEDmatrixの使用法を解説してきます。

画像ファイルの表示 

image2LEDmatrixはSDカード上の画像をRGB LEDパネルに表示するプログラムです。練習兼動作検証用に書きました。

任意サイズの画像を与えることができます。画像の形式は、JPEGやPNGなど、OpenCVが読み込みに対応しているものです。動作モードは下記の2モードあります。

./image2LEDmatrix filename 0

末尾の0は省略することができます。こちらは下図のように画像の全体をスケーリングして表示します。なお、このページの画像は、見やすくするために全てRGB LEDパネルに紙をかぶせて撮影しています。


一方、下記の用に末尾に1をつけて起動すると、下図のように画像の左右または上下を捨て、なるべく画像を大きく表示します。

./image2LEDmatrix filename 1


Raspberry Piのカメラモジュールの映像の表示

カメラモジュールの映像を表示するには、下記のコマンドを実行します。

./camera2LEDmatrix

すると、下図のようにカメラモジュールの映像がRGB LEDパネルに表示されます。真面目に計測していませんが、体感で5fps以上は出ているのではないかと思います。

なお、フレームレートが低いのは、動作の安定化のためにwhileループ内でusleep関数によるウェイトを入れているためです。RaspiCam自体は約30fpsで映像を取得する能力がありますのでご注意ください。


やってみるとわかりますが(いや、やる前にわかるか)、解像度があまりにも小さいことと、LEDが明るすぎることとがあいまって、何が映っているかわからないことが多く、ちょっと厳しいです。

普通に周囲の映像を映すと、ほとんどのLEDがかなりの輝度で輝くので、1.0A以上の電流がパネルに流れてしまいます。

そのため、使いこなすには何らかの画像処理が必要そうです。せっかくOpenCVを使っているので、エッジ抽出、ビット反転、時間差分などを試したのですが、解像度の小ささから、何が起こっているのかわからず、イマイチでした。

何か面白い応用があれば、お知らせ頂ければ幸いです。

(おまけ)Pythonの場合

上で、C++とOpenCVでの例を紹介しましたが、その前にはPython + Pillowで試していました。この方法にはいくつか欠点があったため途中でやめてしまったのですが、メモとして記録を残しておきます。

準備

まず回路ですが、Python用いてArduinoとシリアル通信する場合は、こちらのstackoverflowにかかれているように、ArduinoのRESETとGNDの間に220μF程度のコンデンサを挟む必要があります。ただし、このコンデンサはスケッチ書き込み時は外してください。
(追記:すいません、コンデンサなしでも問題なく動くかもしれません。追試の必要あり)


次に、Raspberry Piでpipとpython-devとlibjpeg8-devをインストールします。

sudo apt-get update
sudo apt-get install python-pip python-dev libjpeg8-dev

次に、Pillow をインストールします。

sudo pip install pillow

以上の準備のもと、次に、RGB LEDパネル用に私が用意したファイルを準備します。

git clone https://github.com/neuralassembly/raspi_16x32RGBLED_Python

raspi_16x32RGBLED_Pythonの中に、画像ファイル表示用のimage2LEDmatrix.pyとカメラモジュールの映像表示用のcamera2LEDmatrix.pyとが入っています。

これらを用いるのは、C++版でも用いたserial2LEDmatrix.inoをArduinoに書き込んでおいてください。これは https://github.com/neuralassembly/raspi_16x32RGBLED に含まれています。

画像ファイルの表示

C++版と同様に、画像全体表示

python image2LEDmatrix.py filename 0

および、画像の切り出し表示

python image2LEDmatrix.py filename 1

に対応しています(末尾の0は省略できます)。画像ファイルのサイズも任意ですが、画像リサイズのアルゴリズム(PIL.Image.NEAREST、PIL.Image.BILINEAR、PIL.Image.BICUBIC、PIL.Image.ANTIALIAS)がイマイチなため、縮小後の画像があまり綺麗に表示されないことがあるのが欠点です(OpenCV版ではINTER_AREAを用いました)。

そのため、Python版ではWindowsのgimpなどで事前に画像を横32x縦16にリサイズしておいた方が良い場合があります。

Raspberry Piのカメラモジュールの映像の表示

カメラモジュールの映像を表示するには、下記のコマンドを用います。この辺りを参考にしました。

python camera2LEDmatrix.py

残念ながら、こちらはでは、2秒に1回程度しか映像が更新されません。そのため、Pythonをあきらめ、C++とOpenCVによる方法に移行したのでした。




「ラズパイ4対応 カラー図解 最新 Raspberry Piで学ぶ電子工作」、「実例で学ぶRaspberry Pi電子工作」、「Raspberry Piではじめる機械学習」を執筆しました。

2013年8月27日火曜日

Firefox OSとRaspberry Piで三輪オムニホイールロボットを操作してみた

Firefox OSを載せたXperia arcと、node.jsが動作するRaspberry Piで三輪オムニホイールロボットを操作してみました。動画はこちら。



以下、動画について解説していきます。

はじめに

最近、Google Glass、Firefox OS、Windows ストアアプリ、enchantMOONのようにJavaScriptを用いて開発する環境が増えています。

私のWeb関係の知識ははHTML3.2時代で止まっていて、このままではとてもこれらの流れについていけそうにないので、少し知識をアップデートすることにしました。

また、別ジャンルで名刺サイズの小型PCであるRaspberry Piが去年から流行っていますが、この流行にも乗り遅れた感があるので、合わせて触ってみようと思い立ちました。

というわけで、これらを満たす目標として
  • Firefox OSでnode.jsが動作するRaspberry PiとWebSocket通信し、ロボットを動かす
ことを目指してみます。

動かすロボットは、
で用いた三輪オムニホイールロボットとします。こちらはandroidアプリでbluetooth通信してロボットを動かしていましたが、こちらと同じ動作を目指します。

なお、androidでは画像処理による対象物追跡を行いましたが、さすがにJavaScriptで画像処理はキツイ気がするので今回は割愛しました。

システム

こんな感じのシステムとしました。Firefox OSを載せた端末としては、「Xperia arcとXperia ray向けにFirefox OSをビルドしてみた」で紹介したXperia arcを用います。

基本的に、Android上のChromeやFirefoxでも動作するように作成しているので、自前ビルド端末を使ったことによる影響は多分ないと思います。


node.jsを動かしてモーターを動かすなら、こちらでやられているようにmbedを用いた方がスマートな気がしますが、mbedは未体験ということもあり今回は見送りました。

方針が決まれば、あとは様々な方の成果を活用させて頂くだけ、ということで、以下でそれらへのポインタを示したいと思います。


Raspberry Pi上のnode.js

Raspberry Piにnode.jsをインストールし、Firefox OS(というよりブラウザ)からの指令を受け取れるようにする方法はInterface誌2013年9月号の記事「ARMコンピュータRaspberryPi×HTML5でスマートI/O」に書いてあります。

この例では、指令に基づいてRaspberry Piのピンに接続したLEDを点灯させていましたが、その部分をシリアル通信でのaruduinoへの指令に変更します。

Raspberry Piからのシリアル通信は、こちらのページのC言語のプログラムを用いました。リンク先の例ではRaspberry Pi上のピンでシリアル通信しているので/dev/ttyAMA0を用いていますが、今回私はUSBシリアルアダプタを用いたので/dev/ttyUSB0を指定します。(3.3V←→5Vのレベル変換が面倒だったので)

また、送る文字列ですが、コマンドラインの引数で与えた文字列をそのままaruduinoに送りたかったので、以下のようにしました。

main関数の引数部
int main(int argc, char *argv[]){

送信文字列の定義部
  p_tx_buffer = &tx_buffer[0];
  char *num_buffer = argv[1];

  while(*num_buffer != '\0')
  {
     *p_tx_buffer++ = *num_buffer++;
  }
  *p_tx_buffer++ = '\0';


なお、このシリアル通信プログラムを起動する部分のJavaScriptは以下のような感じです。「[value]」の部分がブラウザから送られる文字列で、serialtestという名前をつけた上のシリアル通信用プログラムの引数となります。

server.on('connection', function(socket) {
        socket.on('message', function(data){
                console.log('Receive: ' + data);
                send_to_arduino(data);
        });
});

var send_to_arduino = function (value){
        var spawn = require('child_process').spawn;
        var sendexec = spawn('./serialtest', [value]);
        sendexec.stdout.on('data', function(data){});
}

なお、「Raspberry PiとNode.jsで作る独立稼働モバイルサーバ (Think IT)」によると、node-serialportを用いるとnode.jsを通してRaspberry Pi/arduino間でJavaScriptで通信できるそうなので、そちらでもよさそうですね。

Firefox OSアプリ

Firefox OSアプリは実質Webアプリなので、HTML/CSS/JavaScriptで記述します。
  • Raspberry PiにSSHでログインしてエディタでJavaScriptを編集
  • Android上のChromeとFirefoxで動作確認
という手順で開発しました。ブラウザのリロードでアプリのアップデートが完了するのは、当たり前といえ新鮮な体験です。

AndroidのFirefoxで動作確認するとFirefox OSでもほぼ同じ動作をするので、あまりFirefox OSの出番はなく開発を進められました(Firefox OSの存在意義は…)。

今回は小さなアプリなのでそれほど苦労する部分はありませんでしたが、端末の画面の回転の検出にChromeとFirefoxで違いがあったので注意が必要でした。

  var mqOrientation = window.matchMedia("(orientation: portrait)");

  mqOrientation.addListener(function() {
    // 画面回転検出時の処理
  });
によってChromeとFirefox両方で画面回転を検出できます。

また、IP Webcamからの画像取得ですが、今回は簡易的に済まそうということで、IP Webcamのスナップショット画像を得る機能をひたすら呼び出してcanvasに描画し続けるという方法を取っています。


Firefox OSアプリのpackaged app化

Firefox OSでは、通常ブラウザ上で動作するWeb アプリを、zipで固めたpackaged appとして端末にインストールすることができます。

packaged appを作成するためのテンプレートとして今回はkassy-kzさんのFirefoxOS_Templateを用いました。

packaged appをインストールする方法としては
  1. マーケットからインストール
  2. Firefox OSシミュレーターからインストール
  3. ローカルネットワーク上のサーバーからのインストール
などがあります。私は公式端末であるKeonやPeakを購入しておらず、Nexus SやGalaxy S2などといった端末に自分でビルドしたFirefox OSをインストールするという方法でFirefox OSを試しています。

この自前ビルドの端末ですが、上記の2の方法でのインストールがうまくいきませんでした。Remote Debuggingを有効にしてはいるのですが。

仕方ないので、3の方法でインストールしました。リンク先の解説の通りですが、package.manifest は、アプリのmanifest.webappをコピーして、package_pathの行を追加するだけで良さそうでした。インストール後、「XXXX downloading...」という通知が、端末を再起動するまで消えないのですが、気にしないことにします。



感想など

Androidアプリで行っていたbluetoothでのロボット操作を、Firefox OSでも実現できました。ただし、いくつか気になる点もありました。

まず、モーターへ指令が到達するまでのステップ数がかなり増えているので若干遅延が発生することがあります。Wifiを利用しているので、Wifiの干渉が大きい場所ではこの遅延がより大きくなることが予想されます。

また、タッチイベントを全て送ると処理が追いつかなくなり、やはり遅延が大きくなるので、指令を送信する回数を減らすなどの工夫が必要な場面がありました。

一方、良い面ですが、Firefox OS用に作成したアプリはWebアプリなので、androidでもiOSデバイスでも動作する(はず)というのはなかなか魅力的に思えました。

ただ、どうしても機能が最大公約数的になりますし、結局各端末でデバッグしなければいけないということも起こりがちなので良し悪しかなあと思います。なんだかこの辺はJavaが出てきたときに言われたことの繰り返しですね。

あと個人的には、ビルドだけして放っておいたFirefox OS端末の使いみちができてよかったな、と。

そんな感じで今回は以上です。

こちらもどうぞ




「ラズパイ4対応 カラー図解 最新 Raspberry Piで学ぶ電子工作」、「実例で学ぶRaspberry Pi電子工作」、「Raspberry Piではじめる機械学習」を執筆しました。