Network Cameraを作ってみよう(3) Webサーバとカメラを結合
ここまでくればあと一息である。最終目的である、撮影した画像をWebサーバ経由で配信、というシステムに仕立て上げてみよう。
配線は図4の様に、単に図1と図3を組み合わせただけである。もちろんパルストランス無しでよければ図2と図3を組み合わせればよいので配線は更に楽だろう。
さてプログラムの方だが、Ilya I氏作のpub_iva2k_ethrpcを流用させていただいた。mbedのcookbookにも様々なWebサーバが載っているが、敢えてこちらを使ったのは
- 当初から内蔵メモリをサポート
- 画像転送などもサポート
- 比較的構造が簡単で手を入れやすい
- DHCPで立ち上がる
というあたりである。またSDカードをサポートしており、ソースを見る限り☆board Orangeと組み合わせればそのまま利用できそうなのも便利だ(pub_iva2k_ethrpc自身は、mbed-BoB2というベースボードでの動作を想定しているようだが)。変わったところでは、Dynamic HTMLをサポートしているのもちょっと将来の拡張に便利そうだ、と思える。
さて手順であるが、
- SummaryページでImport this programを使い、プログラムをまるごと自分のワークスペースに取り込む(ついでにこの際、名前も変えておく)
- Camera_LS_Y201のライブラリを取り込む(先の「カメラのハンドリング」で説明した通りだ)
- main.cppを書き換える
- コンパイル・リンクを行い、mbedにコピーする
- mbedをリセットする
という手順で完了である。再起動後、http://192.168.1.126/picture.jpg (←IPアドレスは各々の環境によって異なる)にアクセスすれば、こんな具合にカメラ映像が表示される筈だ(Photo37)。
もうちょっとソフィストケイトしたものを…というのであれば、List 2の様なファイルをindex.htmという名前でmbedにコピーすればhttp://192.168.1.126/ (←IPアドレスは各々の環境によって異なる)にアクセスするだけで画像が表示されるし、しかも自動的に一定期間(List 2の場合は5分間)で画面が更新されるようになる。
さて、ではmain.cppをどう書き換えるかという話である。書き換えた後のソースをList 3に示すので見比べていただきたい。ポイントとしては
- カメラの画像取り込み用にcaptureImage()とcamera_callback()を追加
- main()の最後、while(1)でメインループに入る直前で、カメラの初期化処理を追加
- main()のループの中で、一定期間(今回の場合は約60秒)ごとに1回ずつ画像をカメラから取り込み、それを"/local/picture.jpg"という名前で上書き保存する
といったあたりとなる。この「60秒」をどうやって設定するかだが、プログラムを見ていただくとお分かりだが、元のhttpサーバのプログラムでは、http.poll()という、HTTPリクエストが来ているかどうかの判断を5msごとに行っている。もっと正確に書けば、http.poll()を呼び出して、何もないと判断したら5msの間wait()で待機し、再びhttp.poll()を呼び出すという仕組みである。そこで12000回http.poll()を呼び出したら(つまり5ms×12000回=60秒wait()で待機したら)、カメラからの画像取得を1回行うという、割とベタな実装になっている。
ちなみにコンソールにはこんな具合(Photo38)にカメラ関係のデバッグメッセージが表示されるようになっている。ただしこれはmain.cppの冒頭で
int gDebug=1;
となっている部分を
int gDebug=0;
にすると、いきなり出なくなるように配慮している。gDebug自身は元々pubiva2kethrpcの中で利用されているデバッグレベルの値で、これにあわせてメッセージの出方を変えるようにしている。
余談になるが、今回利用したシリアルカメラは、(通信がシリアルだけあって)かなり通信が遅い。カメラの解像度は160x120、320x240、640x480の3種類が選べるが、実際に撮影した結果(Photo39~41)では、撮影後のデータ転送時間が
160×120ピクセル:2秒程度 320×240ピクセル:7秒程度 640×480ピクセル:25秒程度
となっている。ほぼファイルサイズに比例、という感じであるが問題なのはこのファイル転送中はWebサーバとして反応できないことで、このあたりの改善は今後の課題かもしれない。設定はmain()の中のカメラの初期化の部分で、cam.setImageSize()の引数で決まる(更に余談だが、Camera_LS_Y201ライブラリでは、なぜか320x240ピクセルの指定が"ImageSize320x280"になっている。撮影した画像はちゃんと320x240ピクセルなので、これは純粋にラベル名だけの問題である)が、テストした感触では320x240ピクセルがちょうど手ごろ、という感じである(7秒くらいならブラウザがタイムアウトすることはまずないため)。