先日、特殊な用途向けに微速度撮影カメラが必要になり、Raspberry Piで急遽製作したものについて、技術的なメモを備忘録に残しておきます。
このカメラは、
- HD1080p画質で10秒〜1分ごとに自動で静止画撮影
- 壊れてもいいように安価である、1万円程度
- 簡易防水(防滴)
- 持ち運び可能なサイズである
- 充電式バッテリではなく二次電池が利用できる
- 連続稼働時間が長いこと、できれば半日以上
- exifにGPSタグをつけられる(トラッキング機能付き)
といった要件のもとで製作しました。
基板 - Raspberry Pi A+
プロトタイピングに使えるものは他にもArduinoやBeagleBone, mbed等がありますが、画像の取り扱いと性能と消費電力の兼ね合いからRaspberryPiを選択しました。
RaspberryPi基板はいくつかのバージョンがありますが、消費電力を重視してA+を利用しています。各バージョン(世代)間の消費電力の差は以下のページを参考にさせていただきました。
以降RasPiと略します。ながい。
開発用外部環境 - Motorola Lapdock for Atrix4G
ひとつの基板とはいえ立派にOSが動作するカードコンピュータですから、とりあえず最初はディスプレイとキーボードは必要です。
配線ごっちゃごちゃ化が嫌だったり、持ち歩いて作業もしたかったりしたので、画面とキーとマウスパッドとバッテリーが一体になったガジェットを利用しました。
MotorolaのスマホであるAtrix4Gを装着するために作られたLaptopなDockです。
こちらのページより知って利用させていただきました。
へぶらーい!なキーボードでした。
単体では脳みそがないので動作しませんが、知らない人からすればジョブズもびっくりの極薄ノートブックに見えて優越感かもですね〜。HDMIとUSBは変換ケーブルが必要で、かつLapdock側が端子が隣接してぎりぎりだったので削ってやる必要がありました。ちなみにUSBポートが一つしか無いA+にはハブ代わりにもなるので開発にはもってこいですね。こういう製品つくりたい。
OS - Arch Linux for ARM core
つづいてOSにはArch Linuxを採用しました。RasPiにはRaspbianとかPidoraとかがよく使われているように思いますが、ここでは出来うる限りソフトウェアを減らして、サービスも減らして、消費するエネルギーをなにがなんでも抑えたい、ということでミニマルなArchを選びました。
最初からデスクトップ環境が入っていないにも関わらずここまで使いやすいディストリも中々ありません。
というわけで、これまた同じArchインストール済みの中古ネットブックを使って、32GBのmicroSDにイメージ書き込みをしました。手順は公式が示してくれています。
気をつけるべきことは、これはモバイルPCではなくカメラとして運用させたいわけですので、microSDをうっかりMacのスロットに挿しちゃったりするとどういうわけか勝手にiPhotoが開いてくれちゃったりなんかしてほしいのです。
そのため、パーティションの切り方を以下のようにしました。
- パーティション1 : 起動ファイル用(boot), FAT32フォーマット, 容量100MB
- パーティション2 : ルートパーティション, ext4フォーマット, 容量約2GB
- パーティション3 : 写真保存用, FAT32フォーマット, 容量のこり全部おおよそ30GB
実際は8GぐらいのSDでも充分だとおもわれます。
このあと起動させて、rootで自動ログインするように設定しておきます。(参考)
そして/etc/fstabを編集して、パーティション3をルート直下に適当な名前でマウントするように設定します。今回は/piLapseに、fsckオプション無しでマウントしてもらうようにしました。後述する撮影用プログラムは、このpiLapse内にDCF規格として写真を保存するように設計します。つまりふつうのデジカメと若干の互換性をもたせたmicroSDにするわけです。
DCF規格について詳細はこちら(PDF)
DCIMみたいなフォルダを見たことがあれば多分それがこれです。
最後に、Archのリポジトリarmv6h/coreから最低限必要だと思われるvi, wpa_supplicantをいただいてSD内に保存しておき、ローカルでインストールしておきます。ネット環境の設定がすぐにできないならばほかにも先にいろいろ落としておくのが懸命ですね。
microSDカード周りに関してはいろいろ工夫が必要でしたので、それも後述することにします。
WiFi
Linuxではドライバの関係上、無線LANを利用するとなるとアダプタの種類によってはまったく対応してなかったり、自前でビルドしたりという面倒があります。
そこで、汎用なドライバrtl8192cuに対応していて、なおかつ小型なUSB無線アダプタとして知られているBuffaloのWLI-UC-GNM2を利用しました。
アマゾンで見ると、関連商品にめっちゃRasPiでてきます。よく使われるデバイスなんですねー。これはUSB口に挿して、シェルからiwconfigするだけで問題なく動作していることが確認できます。
wpa_supplicantでアクセスポイント名とパスワードをあらかじめ決めておき、外出先でスマホなどの無線LANルータをそのように設定させて起動すれば、電池駆動状態で無線操作できます。もちろんちゃんとsystemctl enableも実行して、起動時にこのサービスだけは立ち上がるようにしておきます。
このあたりを詳説されているページはこちら。
/etc/network/interfaces
の無線LANに相当するデバイスのところはStaticにしてしまいましょう。
IPアドレスを固定することで、外部からsshで操作できます。さらばLapdock。
これはお弁当箱に基板を詰めて完成してしまったあとも、内部にアクセスして操作するときに使うため必須です。サイズも小さく、1つだけのUSBポートを塞ぐ栓としてもふさわしいでしょう。ただし実際にカメラとして運用するときは、消費電力が大きすぎるため必ず外しておきます。
ソフトウェア(必要パッケージ)
ネット環境が整備されたところで、必要なパッケージをインストールしておきます。CUIで充分なのでXなどそのあたりは一切不要、またユーザはrootオンリーなのでsudoすら要りません。
パーミッション関係がうまくいかず動作が停止するよりはいいかなという判断ですが、企業のプロのSEが聞いたら卒倒するでしょうかね…
この段階でpacmanに捕ってきてもらったパッケージは以下の通りです。
- python2
- python2-pyserial
- cronie
- ntpdate
- unionfs-fuse
基本的な撮影プログラムはpythonで作成します。
必要な機能は ①撮影 ②GPSデータ読み込み&Exif書き込み そしてカードに保存、
の3つだけです。
これをcronieで毎分実行するようにします。もしも秒オーダーでインターバルしたい場合はスクリプト内で制御する必要がありますね。
さてpythonは2系と3系でかなり挙動が違うっぽいです。うしろに2とついてないのが3系??なんでこんなことになったんでしょう。実際のスクリプトは仕事関係のためここでは省略させてください。。。概要だけちょびっと、以降の項目で部分ごとに書きます。
カメラ - RasPi専用カメラ
カメラはRasPi純正のものを使いました。これもRasPiの強みで、自前のものを相性をたしかめながら選ぶ手間が無い上に高性能で、かつセットアップが恐ろしく簡単です。カメラモジュールから伸びるコネクタを、RasPi基板の"CAMERA"端子に挿すだけ。あとはRasPi用にビルドされたパッケージが多数用意されているため、シェルからコマンドひとつで写真が撮れてしまいます。
詳細を書かれていて参考にさせて頂いたのはこちら。設定による画像の違いサンプル付きで、とてもわかりやすいです。
プログラム機能①撮影 について
はじめにファイル名を決定します。DCF規格のWriter規定を満たせればよいのですが、だいたいのファイル構造さえ出来ていれば母艦PCは認識してくれます。
保存ディレクトリは /piLapse/DCIM/100RASPI
のようなところにすればOKです。
画像ファイルは PI000001.JPG
から始まるようにでもしておきます。ディレクトリ一覧を取得して名前降順にファイルを並べ替え、先頭ファイル名のインデックス2から7をint変換したものに1をたせば次のファイル名です。
がんばれば100万枚撮れますね。コブクロのあの曲だいすきです。
撮影はraspistillをpython内から使います。すなわち、
commands.getoutput("raspistill -w 1920 -h 1080 -n -o [ディレクトリ/ファイル名]")
となります。
これ、-xオプションで直接バイナリをいじらなくてもExif挿入できる素敵機能もあるので使わなければいけません。
GPS - 汎用シリアルGPSモジュールGMS6-CR6
秋月電子で2000円ちょっとで売られていたGPSモジュールで、Vcc,GNDとシリアルRX,TXの4線を備えた汎用的なものです。似た機種にGMS6-SR6があり、こちらはGLONASSも受信できるためとても使いたかった(海外用途でしたので)のですが、合計消費電力がかなり大きくなってしまい基板動作にも影響を与えかねないため断念しました。
また、信号線のロジックレベルにも注意が必要です。いろんなモジュールが使えると思いますが、3.3V駆動のためLVTTLで通信可能なものである必要があります。モジュール付属のケーブルは途中で切って基板にはんだづけしたのですが、あまりにも細くて悶えました。
GPIOピンにシリアルRXとTXがあるのでそこに接続してやります。
さて、初期設定ではこのシリアルポートはログインに使えるようにセットされているので、無効化してやらないと使えないそうです。
/boot/cmdline.txt と /etc/inittab をちょこちょこっと編集します。
このあたり参考にさせていただいたのはこちら。
GPSモジュールからは、電源を入れると共通フォーマットであるNMEAメッセージというものがドンドン送られてきます。この書式については、同じモジュールを採用されている先人様のページがあり非常に助かりました。
これが/dev/ttyAMA0として認識されるので、pySerialによって読み出して自作のパーサーに読み込ませてログ取りなりExif埋め込みなりの処理をしました。GPSモジュールとRasPiを組み合わせたものを作られている方は数少なく、これらの方法を教授いただくきっかけになったのは以下のページだけだったように思います。
Raspberry PiにGPSモジュールをつけてみた - meketenの趣味日記
プログラム機能②GPSデータ読み込み&Exif書き込み について
raspistillを実行する前に、pySerialによってシリアルポートから得られたメッセージを解析して変数につっこんでおかなければなりません。
ttyAMA0を4800bpsで開くと $GPGSV,3,1,12,24,89,098,19,12,47,352,
みたいなのがどんどん流れ込んできます。デフォルトでは毎秒送信ですが、こちらからNMEAを送ってやることで必要なメッセージの種類や間隔を調整できるそうです。が、何度やっても言うことをきいてくれなかったため、初期設定のまま仕方なく進めました。なぜできなかったかは未だに不明です。
GPS Exifとして欲しい情報は、緯度・経度・測位ステータス・移動ベクトル・捕捉衛星数、です。
これらに関する詳しい情報は以下のふたつを参考にさせていただきました。
Exif 2.1 GPS IFD tags
F6 Exif~EXIFの追加・修正・削除 手順~
測地系に関してはWGS84で固定、高度は誤差が大きく、かつ都市部のビルで使う用途ではないために後付けでJAXAとかの数値地表モデルから算出、でいいかなと思います。時刻は次の項で触れますが、ちゃんとしたOSがあるのでファイルシステム記録のものでも良かれと思われたため、Exifには記述しないことにしました。
必要な情報を切り出せたところでraspistillを行います。
-xオプションによって、GPS Exifを一項目ずつ GPS.GPSLatitude=-33/1,66/1,451/100
のように記述してやることで、うまく書き込んでくれました。この情報はこちらの掲示板から。
ちなみに何もしなくても"機種名"は埋め込まれるようになってるみたいです。
時刻関連 - ntpdate, RTCモジュール
電池駆動であってもGPSがあるために、時刻情報は電源が通っている限り最新のものが取得できます。
と思っていたのですが、屋内だったり電源投入直後だったりすると正確な時刻を得ることができません。そこでRasPi用RTCモジュールを利用することにしました。周辺機器の充実ぷりたるやすごいです。Arduinoなんかもそうですが、組み込みの革命だと思います。
参考ページはこちら。めちゃくちゃ簡単です。革命。
I2Cモジュールで、うまく整列されたRasPiのピンにぴったり収まります。そのままハードウェアクロックとして認識されるんですね。
さてさてこれで時刻リセットがないことは保証されましたが、基準時刻をはじめに教えてやらなくてはいけません。
そこでntpdateを使います。ntp.nict.jpにでもつないで手動で時刻補正してやります。大事なのは、常にはオンライン環境にないということです。動作としては、
- デバッグ / 調整時(WiFiアダプタ付き) : 起動 → ntpdateを実行し、成功すればRTCをシステムクロックに同期する。
- 運用時(WiFiアダプタが取り外されている) : 起動 → ntpdateを実行するが失敗、システムクロックをRTCから読み出した時刻に同期する。
というようになります。ntpdateの返り値でどちらをどちらと同期させるかを決めれば大丈夫ですねー。
シェルスクリプトとしてoptの下にでも保存し、ちゃんとsystemctlに登録しておきましょう。運用前にちゃんとオンライン状態にして同期させておくことが重要です。
最終的には、GPSの測位状態から受信された時刻に信頼性があるかないか調べ、信頼できるものであればシステム時刻を更新するようなスクリプトを書くつもりでしたが未完に終わっています。
表示 - 8×2LCD Breakout for Raspberry Pi
I2C controlled 8×2LCD Breakout for Raspberry Pi--販売終了www.switch-science.com
機器が動作しているかどうか知るには、インジケータLEDが一番便利です。しかしRasPi本体のものだけでは数ビットの情報量しかないうえとても眩しく、気分的にも電源食いに見えます。
そこでGPS以外のLEDは取っ払い、超小型の液晶をつけることにしました。
使い方はスイッチサイエンスさんが書かれています。
結果的には、RTCモジュールと同時に使用することができないという結論に至りました。
両方ともI2Cで、取り付けは簡単に問題無くできてバスアドレスの競合もないことを確認しました。
しかし液晶のほうだけコマンドに反応してくれない…
RTCを取り外すと正常に動いてくれたので、RTCのVccを電気的に切り離せば動作すんじゃないかとスクリプトを組むもダメ。
I2Cにお詳しい方、助言いただければ嬉しいです…m(._.)m
電源 - Eneloop Pro
ごくごくありふれた電源基板に、Eneloop Proの単3型を4本のせてRasPiの電源につなげただけです。直列なので容量そのまま2450mAh、全体の見込み平均消費電流が200mAほどなので、理論的には12時間持つ計算になります。
外装 - タッパー(¥100)
センスのなさを呪っています。利点はただ安いこと、意味も無く目立つ(?)ことです。雨の中使っても浸水はなかったので、防滴性能はありそうです。
その他 - RamDiskの利用
ほぼ完成してテストをしていたとき、電池の電源が切れて記録が途切れてしまいました。
使っていればなくなるのは当然のこと、新しいものに交換して電源を入れましたが、sshがつながりません。おっかしいなーと思い、一旦microSDを取り出して母艦で見ようとするとファイルシステムのエラーが…
正常にシャットダウンされないことで、やはりトんじゃったりするみたいですね。特にmicroSDから起動してるもんだから、書き込み回数もなかなか多いんじゃないでしょうか。それにこんな電池で駆動させていたら、書き込み最低電圧ギリギリでの動作とか可能性ありすぎ怖すぎホラーです。
ということで起動時にチェックディスクを行うように設定しましたが、効果無しでした。しかし改善策を調べていたら、同じようにRasPiをプチッと切ってしまいたい方はかなり多いようすです。
unionFSというファイルシステムを使い、起動中は仮想ディスクからの読み書きのみにするという仕組みのようで、Archリポジトリにもパッケージがあります。これらの例ではうまくいっているようですが、Archではpivot_rootがきちんと動作してくれませんでした。おそらく理解不足だと思われ、なかなかに情けないです。
このあたりで製作期間のリミットがやってきたため、unionFSは諦めました。
結局、単純にパーティション1(起動用)をRead onlyでマウント、2(ルート)はfsck付き、3(写真記録用)はR/Wでマウントして、システムのログやテンポラリフォルダはtmpfsにマウントされるように変更、さらにswapも作成させないようにします。
このあたりの参考はこちらから。
Raspberry Pi でRAMディスクを使う | よもやま雑記帳
最後にmicroSD全体のイメージコピーをとり、お弁当箱(タッパー)に詰めてなんとか完成としました。
結果
他の人が使うために作ったのですが、どうやら日本の反対側あたりでうまく活躍してくれたようで、予想外な写真を撮ってくれていました。一番の課題である電池持ちもよかったらしく、9〜10時間にわたり連続動作しました。
その時の写真も掲載はできないのですが、時間があるときに作り直せればまた自宅近くの景色でも微速度撮影してみようかと思う次第です。問題点は機体の物理的な脆さで、上には書かなかったのですが適当につけたスイッチが陥没して電源操作が一時的にできなったらしいです。手頃な外装部品をまた見つけないとなあ、というのが反省でした。