2013年11月2日土曜日

Raspberry Pi用カメラモジュールおよび赤外線カメラPi NoIRの映像をandroidで表示してみた

0. はじめに

Raspberry Pi用の赤外線カメラPi NoIRが発売されました。
赤外線カメラは使ったことがないので興味があり、早速注文してみました。

既存のカメラと同じくraspistillコマンドなどで使えるのですが、
今回、その映像をmjpg-streamerで配信し、androidで見てみることにします。
なお、本ページの内容は、Pi NoIRだけでなく通常のRaspberry Pi用カメラでも全く同様に成り立ちます。

なお、2016年4月、Raspberry Piのカメラモジュールのバージョン2が発売になりました。こちらでも本ページのプログラムは動作するのですが、NOOBS1.9.0までのRaspbianでは映像の向きが上下逆転してしまいます。次のRaspbianが出るまで待つことをお勧めします。上級者の方には「sudo rpi-update」でカーネルを最新にすれば正常動作することをお知らせしておきます。


1. 新しい方法


ここから解説するのは、下記のサイトで紹介されている方法です。
解像度640x480、30fpsで高画質で動作するのでおすすめの方法です。

1.1 カメラモジュール対応のmjpg-streamerのインストール

まず、あらかじめraspi-config でカメラを有効にしておいてください。
そして、下記の要領で、カメラモジュール対応のmjpg-streamerをインストールします。


sudo apt-get update
sudo apt-get install libjpeg8-dev cmake
git clone https://github.com/jacksonliam/mjpg-streamer.git mjpg-streamer
cd mjpg-streamer/mjpg-streamer-experimental
make
cd
sudo mv mjpg-streamer/mjpg-streamer-experimental /opt/mjpg-streamer

インストールが完了したら、下記の内容をユーザーpiのホームディレクトリ/home/piにstart_steam.shという名前で保存します。なお、このスクリプトでは解像度640x480、フレームレート15fpsでmjpg-streamerを起動します。お好みで設定を変更してください(解像度640x480、30fpsまでは安定動作を確認しました)

#!/bin/bash
 
if pgrep mjpg_streamer > /dev/null
then
  echo "mjpg_streamer already running"
else
  LD_LIBRARY_PATH=/opt/mjpg-streamer/ /opt/mjpg-streamer/mjpg_streamer -i "input_raspicam.so -fps 15 -q 50 -x 640 -y 480" -o "output_http.so -p 9000 -w /opt/mjpg-streamer/www" > /dev/null 2>&1&
  echo "mjpg_streamer started"
fi

次に、このスクリプトを/etc/rc.localに記述することで、自動起動します。そのために、エディタで/etc/rc.localを編集するのですが、その際、管理者モードでないと保存できませんので注意してください。viで編集する場合は下記のようにsudoをつけて起動します。

sudo vi /etc/rc.local

もともと、「exit 0」という行が最後に記されているのですが、その手前に下記のように1行追記します。

(中略)

sh /home/pi/start_steam.sh

exit 0  # ←この行はもともとある行

以上でRaspberry Piを再起動すると、mjpg-streamerが自動で起動します。


1.2 android側アプリで閲覧

PCのブラウザで、Raspberry Piが動いているIPアドレスの9000ポートを見ると(http://xx.xx.xx.xx:9000/)、
映像が配信されていることがわかります。このポート番号は、上のスクリプトstart_stream.shの内部で決定されています。

この映像をandroidで受け取るには、手前味噌ですが簡単MJPEGビューアを使うと簡単です。
このアプリのソースはこちらにあります。

アプリを起動したら、メニューから「設定」を選択し、下図のように、解像度を640x480に、「ポート番号」を9000に(キーボードで記述)、コマンドを「?action=stream」に設定してください。


設定を保存すると下記のように、Raspberry Piのカメラから配信された映像がandroid上に表示されます。
なお、この映像は暗い部屋で人形にテレビのリモコンの赤外線を当てて撮影しました。


以上で目的は達成です。

冒頭で紹介した「Raspberry Piで学ぶ電子工作」ではこのRaspberry Piとカメラモジュールの組み合わせをキャタピラ式模型に搭載し、iPadなどのタブレットのウェブブラウザから映像を見ながら操作する、という演習を取り入れています。下記の内容紹介動画のおよそ1:38からその様子が示されています。



若干映像が詰まるところが見られますが(およそ1:57)、これはRaspberry Piと用いたWifiドングルの相性の問題と考えています。

「Raspberry Pi 2 + kernel 4.1 / 4.4 系列で5GHz対応WifiドングルGW-450Dを動かした」 を参考にGW-450Dを用いるとこの「映像の詰まり」は解消されるのですが、kernelの再構築が必要なので、書籍では紹介できませんでした。

以上です。


なお、以下に記すのは古い内容なので読み飛ばして頂いて構いません。


2. 古い方法

ここから先は、このエントリを執筆した2013年11月当時の古い方法です。今この方法を用いる必要性はないのですが、記録として残しておきます。

2.1Raspbian側の準備

まず、あらかじめraspi-config でカメラを有効にしておいてください。

次に、OSを最新にします。

sudo apt-get update
sudo apt-get upgrade

さらに、ファームウェアを最新にします。 これを実行しておかないと後でmjpg-streamerを起動するときに「ERROR opening V4L interface: Interrupted system call」というエラーがでます。
(2014.6.5追記:なお、2014.5.6のRaspbianを用いたところ、このプロセスは不要になっていました)

sudo rpi-update

なお、アップデートを実行すると、Raspberry Piの起動時の「Mounting local filesystems」の際にmmcblk0に関するエラーが出て起動しなくなる場合があります。その場合、こちらに関連情報がありますが、SDカードを変更すれば状況が改善する場合があります。

私の場合、Transcend SDHC 8GB(class 10)で起動しなくなったので、古いTranscend SDHC 8GB(class 2)に変更したところ、問題が解決しました。

2.2 Video4Linuxの有効化

次に、Rapsberry PiのカメラをVideo4Linuxで用いるために、こちらを参考にVideo4Linuxを有効にします。まず、以下を実行。

wget http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc && sudo apt-key add ./lrkey.asc

次に、/etc/apt/sources.listの末尾に下記の行を加えます。

deb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ wheezy main

そして、以下を実行します。

sudo apt-get update
sudo apt-get install uv4l uv4l-raspicam

2.3 mjpg-streamerのインストール

こちらを参考に、mjpg-streamerをインストールします。

まず、インストールに必要なライブラリやヘッダなどをインストールします。

sudo apt-get install libjpeg8-dev libv4l-dev
sudo apt-get install imagemagick

ヘッダにリンクを貼ります。

sudo ln -s /usr/include/linux/videodev2.h /usr/include/linux/videodev.h

次に、mjpg-streamerの最新のソースをダウンロードするため、subversionをインストールします。

sudo apt-get install subversion

そしてmjpg-streamerのソースをダウンロードします。

svn co https://svn.code.sf.net/p/mjpg-streamer/code/mjpg-streamer mjpg-streamer

そして、以下のようにmakeします。

cd mjpg-streamer
make

エラーが出ずにビルドが完了すれば次に進みます。

2.4 mjpg-streamerの起動

mjpg-streamerをビルドしたディレクトリで作業します。

まず、Video4Linuxを有効にします(このコマンドはどのディレクトリでもOK)。なお、無効にするには pkill uv4lを実行します。この例は解像度320x240、フレームレート10fpsです。

uv4l --driver raspicam --auto-video_nr --width 320 --height 240 --framerate 10

そして、mjpg-streamerを起動します。やはり解像度320x240、フレームレート10fpsを指定しています。

export LD_LIBRARY_PATH="$(pwd)"
LD_PRELOAD=/usr/lib/uv4l/uv4lext/armv6l/libuv4lext.so ./mjpg_streamer -i "input_uvc.so -d /dev/video0 -r 320x240 -f 10 -no_dynctrl" -o "output_http.so -w ./www"

色々試してみたところ、フレームレートを大きくすると不安定になるようで、mjpg-streamerが落ちます。私の環境では解像度320x240、フレームレート10fpsでは安定して動きますので、どこまでいけるか色々試してみてください。

2.5 android側アプリで閲覧

PCのブラウザで、Raspberry Piが動いているIPアドレスの8080ポートを見ると(http://xx.xx.xx.xx:8080/)、
映像が配信されていることがわかります。

この映像をandroidで受け取るには、手前味噌ですが簡単MJPEGビューアを使うと簡単です。
このアプリのソースはこちらにあります。

アプリを起動したら、メニューから「設定」を選択し、下図のように、解像度を320x240に、ポート番号を8080に設定します。

設定を保存すると下記のように、Raspberry Piのカメラから配信された映像がandroid上に表示されます。
なお、この映像は暗い部屋で人形にテレビのリモコンの赤外線を当てて撮影しました。




2.6  mjpg-streamerの自動起動

さて、動作が確認できたところで、必要な方はRaspberry Piが起動するときにmjpg-streamerが自動で起動するようにしておきましょう。以下、Raspberry Piでの操作です。

mjpg-streamerのディレクトリが/home/pi/mjpg-streamerであるという前提で話を進めます。

cd ~/mjpg-streamer

このディレクトリに、start-mjpg-streamer.shというファイルを作成し、下記の内容を記述します。エディタはviでもnanoでも、お好みのもので構いません。

#!/bin/sh

uv4l --driver raspicam --auto-video_nr --width 320 --height 240 --framerate 10

cd /home/pi/mjpg-streamer

export LD_LIBRARY_PATH="$(pwd)"

LD_PRELOAD=/usr/lib/uv4l/uv4lext/armv6l/libuv4lext.so ./mjpg_streamer -i "input_uvc.so -d /dev/video0 -r 320x240 -f 10 -no_dynctrl" -o "output_http.so -w ./www"

次に、このスクリプトを/etc/rc.localに記述することで、自動起動します。そのために、エディタで/etc/rc.localを編集するのですが、その際、管理者モードでないと保存できませんので注意してください。viで編集する場合は下記のようにsudoをつけて起動します。

sudo vi /etc/rc.local

もともと、「exit 0」という行が最後に記されているのですが、その手前に下記のように1行追記します。

(中略)

sh /home/pi/mjpg-streamer/start-mjpg-streamer.sh &

exit 0  # ←この行はもともとある行

保存したらRaspberry Piを再起動してみてください。mjpg-streamerが自動で起動しているはずです。お疲れ様でした。




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

2013年10月10日木曜日

enchantMOONで三輪オムニロボットを操作してみた

はじめに

enchantMOONで三輪オムニロボットを操作してみました。
動画はこちら。




経緯など

以前、「Firefox OSとRaspberry Piで三輪オムニホイールロボットを操作してみた」というエントリで、JavaScriptの勉強のために、Firefox OSで三輪ロボットを操作するという実験を行いました。

三輪ロボット側のRaspberry Piでnode.jsを動かし、websocket.ioを用いてFirefox OSと通信を行う、というものでした。

Firefox OS+JavaScriptという組み合わせで操作できるなら、enchantMOON+JavaScriptでもいけるのでは?というのが今回の着想です。

しかし、それほど簡単ではなかったので、以下に注意点をまとめます。

注意点

公式のsocket.io.jsでは通信ができませんでした。また、サーバーであるロボット側は前回はwebsocket.ioを用いましたが、enchantMOONに合わせてサーバー側もsocket.io.jsを用いるように変更しました(こちらは公式のものでOK)。
  • enchantMOONのバージョンはver.2.6.0 (r1880)以上を用いる
これより前のバージョンでは、つながったりつながらなかったりと、通信が不安定でしたが、ver.2.6.0では安定しています。その理由は「enchantMOONのXHRでresponseTextの末尾にゴミデータがつく」問題が、version 2.6.0で改善されたからだそうです。esmasuiさん、ありがとうございます。

ソースの構成など

enchantMOON側のソースの構成は下記のようにしました。

hack.js
main.js
lib/MOON.js
lib/socket.io.js  : esmasuiさんのもの
lib/enchant.js

タッチイベントを使いたかったので、parachesさんの『enchantMOONで「簡易版とことんぷよぷよ」を遊べるようにしてみた』を参考にenchant.jsを使ってみました。

hack.jsの内容
importJS(['lib/MOON.js', 'lib/enchant.js', "lib/socket.io.js"], function() {

    var sticker = Sticker.create();
    sticker.ontap = function() {
        var script=document.createElement('script');
        script.src="main.js";
        script.type='text/javascript';
        script.language='javascript';
        document.body.appendChild(script);
    };
    sticker.register();
});

main.jsの内容の一部
enchant();

var URL = 'http://192.168.1.5:8888'; // サーバーのアドレス
var width = 240
var height = 320
var socket;
var game = new Game(width,height);

game.onload = function () {
    socket = io.connect(URL, {'transports': ["xhr-polling"]});

    var touchPanel = new Sprite(width,height);
    touchPanel.x = 0;
    touchPanel.y = 0;
    touchPanel.addEventListener('touchstart', function(e) {
        moonTouched(e.x, e.y);
    });
    touchPanel.addEventListener('touchmove', function(e) {
        moonTouched(e.x, e.y);
    });
    touchPanel.addEventListener('touchend', function(e) {
        stopMotors();
    });

    game.rootScene.addChild(touchPanel);
}
game.start();

function moonTouched(keyx, keyy) {
    //ここにタッチエリアに応じた処理を書く。
    //上の動画では、4つのモーターにデータを送りたいので、
    //コンマ区切りの数値を送っている。

    //例えば以下のように
    //socket.send('90,0,0,0');
}
function stopMotors() {
    //例えば以下のようにモーターを停止させている
    //socket.send('90,0,0,0');
}

コントロール画面はこんな感じです。やっつけで書きました。絵心がある人だったら、面白いコントロール画面を描けると思います。


2013年10月8日火曜日

Xperia arc/rayとGalaxy S2/S3向けFirefox OS 1.1のビルド法を更新し、ビルド済みファイルを公開した話

はじめに

10/20(日)に東京電機大学で開催されるAndroid Bazaar and Coneference 2013 Autumnで展示するために、
安定して動作するFirefox OS端末が必要になったので、これまでビルド法を公開してきたGalaxy S2/S3、Xperia arc/ray へのビルドを試してみました。
ビルド法を公開した当時とは色々と状況が変わっているので、変更点などをメモ。
ついでにビルド済みファイルを公開。

これまでの経緯

2013年の6月に、下記の通りGalaxys S2/S3、Xperia arc/ray へのFirefox OSのビルド法を公開しました。

このビルド法は、下記の構成でソースを取得してビルドするようになっていました。
  • gaia:masterブランチの最新
  • gecko:gecko-18ブランチの最新
  • gonk:android 4.0 または cyanogenmod 9

しかし、7月以降、高解像度端末では上のままでは正しい解像度でのビルドができなくなっていました。


正しい解像度(6月頃) 正しくない解像度(7月以降)


このあたりのコミットとかこのあたりのコメントを追っていくと情報が得られますが、
gaiaでの簡易的な高解像度端末への対応を削除して、
gecko(masterとv1.1.0hdブランチ)の高解像度端末への対応度を高めていくということのようです。

Xperia arcとGalaxy S2への対応

ということで、まず、Xperia arcとGalaxy S2はビルド法を下記の構成に変更しました。
  • gaia:v1.1.0hdブランチの最新
  • gecko:v1.1.0hdブランチの最新(gecko 18.1)
  • gonk:android 4.0 または cyanogenmod 9

この2つは素直な端末なのか、トラブルは少ないです。Firefox OSのバージョンでいうと1.1ですね。

gaiaをmasterにしなかったのは、変更が頻繁すぎるため、
geckoをmasterにしなかったのは、gonkをcyanogenmod 9のままにしておきたかったからです。
(cyanogenmod 9のままgeckoをmasterにすると、WifiやSIMが使えなくなったりと、残念な感じになります)

Boot 2 JCROMの方は下記のようにしています。
  • gaia:master-jcブランチの最新
  • gecko:v1.1.0hdブランチの最新
  • gonk:android 4.0 または cyanogenmod 9

基本的には上記の方法でビルドするのですが、下記のように、端末ごとにいくつか例外があります。

Xperia rayへの対応

まず、Xperia rayではgecko v1.1.0hdでの解像度の取り扱いがうまくいっていないようなので、
geckoをgecko-18、gaiaを6月末の時点のものに固定していくつか修正を加えます。
  • gaia:masterブランチの6月末+いくつかの修正(ココ
  • gecko:gecko-18ブランチの最新
  • gonk:android 4.0 または cyanogenmod 9

Boot 2 JCROMは下記の通りです。
  • gaia:master-jcブランチの6月末+いくつかの修正(ココ
  • gecko:gecko-18ブランチの最新
  • gonk:android 4.0 または cyanogenmod 9

Galaxy S3への対応

この中では一番解像度が高い端末なのですが、Xperia ray同様、
gecko  v1.1.0hdでの解像度の取扱いがうまくいっておらず、さらに
gecko-18でも8月以降、起動が途中で止まってしまうコードが入っているようで、
gecko-18の7月末頃のコードを利用します。
  • gaia:masterブランチの6月末+いくつかの修正(ココ
  • gecko:gecko-18ブランチの7月末頃
  • gonk:android 4.0 または cyanogenmod 9

Boot 2 JCROMも同様です。
  • gaia:master-jcブランチの6月末+いくつかの修正(ココ
  • gecko:gecko-18ブランチの7月末頃
  • gonk:android 4.0 または cyanogenmod 9

ビルド済みパッケージ公開について

せっかくなので今日の時点でのビルド済みファイルをダウンロード可能にしました。
下記の各端末のページでダウンロード可能です。

なお、アップデートは無効にしてあるので、OTAアップデートは飛んできません。

これは、海外から「OTAアップデートしたらカメラが使えた!」というコメントが多くて困ったためです。
OTAアップデートすると解像度が狂ったり、こちらで修正した問題点が復活したりするのでOTAアップデートすべきではないです。
そもそも非公式端末にOTAアップデートが降ってきて適用できること自体問題だと思います。

おわりに

非公式端末へのインストールなので仕方ないのですが、特にXperia rayとGalaxy S3で
ビルド時のトラブルが多いです。

Galaxy S3の場合はgaiaとgeckoを両方masterにしてFirefox OS 1.2ベースにすると
状況は改善するようなのですが、gonkをJelly Beanベースにしなければいけないので、
作業に手を付けるのはいつになるか、わかりません。

Xperia rayについては、Firefox OS 1.2にするのは難しそうだし、このあたりが限界かも?
という気がしてきました。

というわけで、おしまい。