FinePixデジタルカメラを使ったコマ撮り(微速度)カメラの製作 2012.8.24


    1.はじめに

     FujiFilmのFinePixシリーズのデジタルカメラの一部の機種には、PCカメラ(Webカメラ)機能が備わっているものがある。これらのカメラは、Windowsパソコンに専用のドライバーソフトをインストールし、パソコンとカメラを付属のUSBケーブルで接続すれば、Webカメラとして使える。製品に添付されているWindows用のドライバーだけでなく、Linux専用のドライバーも、有志の手により既に開発されており、Linuxでも使える。

     ちなみに、ジャンク品のF401とF410の2個のデジタルカメラを入手し、Linuxに接続してみた所、簡単に接続できてしまった。カメラメーカーのデジタルカメラによるWebカメラなので、さぞかし画像品質は良いだろうと期待していたのだが、そこはそれ、おまけの機能という扱いのようで今ひとつである。

     画像サイズは、320x240ピクセルのQVGAサイズ固定であり、露出やホワイトバランスの画質調整は一切できない。ズーム機能も働かない。出力される画像フォーマットは、JPEGのみである。出力されてくるファイルのサイズは20Kバイト程度と小さく高圧縮しているので画質は今ひとつだ。ただし、自動露出、ホワイトバランス自動調整なので画質の点に目をつぶれば、使い易いともいえる。

     入手したカメラを自宅のLinuxサーバーに接続して暫くライブカメラとして使ってみたのだが、USB接続だけにサーバーからUSBケーブルの届く範囲でしかカメラを設置することが出来ない。そこで、ライブカメラとしての使用は諦めて別の使い道を模索し、コマ撮り用のカメラ(微速度カメラ)としての応用を考えて見た。

     USBインタフェースとSDカードを持ったマイコンシステムにこのカメラを接続し、一分間隔あるいは、数分間隔毎に画像データを取得しSDカードに記録する。一定の時間動作させた後、SDカードに記録された画像データをパソコンで読み取って、動画処理を施せば、微速度カメラが出来上がる。


    2. 回路設計

     USBインタフェース付きのPICマイコンとして、「PIC24FJ64GB002」を採用した。このマイコンのUSBインタフェースは、USBホスト、USBデバイスのどちらにも対応している。そこで、カメラを接続している時は、USBホストとして動作させ、パソコンと接続する時は、USBデバイス(パソコンからは、SDカードリーダーに見える)として動作させるようにした。こうすれば、SDカードの抜き差しのわずらわしさを避けることが出来る。また、USBデバイスとして動作する時は、パソコンからのUSBバスパワーのみで動作できるようにした。


    図1:微速度カメラ制御回路

     製作した回路の回路図を、左図1に示す。 

     USBコネクタは、ホスト用としてAコネクタ、デバイス用としてBコネクタの2つが必要だ。AコネクタのVBUS端子には、電源のACアダプターからの+5Vをポリスィッチを通して接続している。BコネクタのVBUS端子は、バスパワーとしてPCから+5Vの供給を受けるもので、ACアダプタからの+5VとダイオードORを取って、3.3Vレギュレータの電源としている。

     USBコネクタの信号ラインD+とD-は、リレー接点を通してマイコンに接続している。これは、Aコネクタ、BコネクタにカメラとPCを同時に差し込んだ時の信号の競合を避けるためであり、リレーのコイル電源は、ACアダプタ側の+5Vから取っており、Bコネクタからのバスパワーのみで動作している時は、リレーはオフとなり、マイコンのUSB端子が、Aコネクタ(カメラ)に接続されることはない。

     ACアダプタを接続するDC-Jackを2個設けているが、一つは、デジタルカメラ用の電源出力である。FinePixのデジタルカメラは、USBのバスパワーでは動作出来ず、ACアダプタによる+5Vが必要となる。本装置のACアダプタとカメラ専用のACアダプタでACコンセントを2個占有するのはもったいなくてこのような構造とした。なお、F410は、ACアダプタの仕様が、+3V仕様となっており、この方法を使うことはできない。+5V仕様のF401で運用をすることにしている。

     カメラとPCの接続切り替えは、USBケーブルの抜き差しをソフトウェアーで検出し自動で行うようにしているが、強制的に切り替えることもできるようにスィッチを設けた。またホストモード、デバイスモードの動作モードを示すLEDをコネクタの傍に設置した。

     SDカード用のSDカードスロットとマイコンの接続は、SPIインタフェース接続とした。SDカードは、運用中取り外すことも無いので、カードスロットのWriteEnable端子やCardDetect端子は、接続しなくても構わないのだが、一応セオリー通りに接続しておいた。

     その他、PICマイコンのファーム書き換え用端子とデバッグ用のRS-232出力端子を9ピンのピンヘッダーに設けておいた。


    ホストモードで動作中。Aコネクタ側のLEDが点滅/点灯
    FinePixデジカメを接続。
    カメラの電源も本装置から供給。

    内部回路。SDカードは右側の基板の裏に実装
    カメラを外してPCを接続。Bコネクタ側のLEDが点灯
    PCでは、Gドライブとして見える。DATAフォルダに画像ファイルが出来ている


    3. ソフトウェアの作成

    3-1 FinePixデジカメの制御方法

     FinePixデジカメの制御方法が判らなければどうにもならない。また、非力なPICで制御できるのかどうか。これらを見極めるためにLinuxのfinpix用のドライバーを調べて見た。

     ドライバーソフトは、gspca のメインドライバと finepix のサブドライバーから構成されているが、今回の目的に必要なのは、finepixだけである。このソースファイルを読む限り、FinePixの制御に必要なのは、次の赤字で示す部分のみのようである。


    static int command(struct gspca_dev *gspca_dev, int order)	/* 0: reset, 1: frame request */
    {
    	static u8 order_values[2][12] = {
    		{0xc6, 0, 0, 0, 0, 0, 0,    0, 0x20, 0, 0, 0},	/* reset */
    		{0xd3, 0, 0, 0, 0, 0, 0, 0x01,    0, 0, 0, 0},	/* frame request */
    	};
    
    	memcpy(gspca_dev->usb_buf, order_values[order], 12);
    	return usb_control_msg(gspca_dev->dev,
    		usb_sndctrlpipe(gspca_dev->dev, 0),
    		USB_REQ_GET_STATUS,
    		USB_DIR_OUT | USB_TYPE_CLASS |
    		USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
    		12, FPIX_TIMEOUT);
    }
    
    
    static void dostream(struct work_struct *work)
    {
    	struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
    	struct gspca_dev *gspca_dev = &dev->gspca_dev;
    	struct urb *urb = gspca_dev->urb[0];
    	u8 *data = urb->transfer_buffer;
    	int ret = 0;
    	int len;
    
    	/* synchronize with the main driver */
    	mutex_lock(&gspca_dev->usb_lock);
    	mutex_unlock(&gspca_dev->usb_lock);
    	PDEBUG(D_STREAM, "dostream started");
    
    	/* loop reading a frame */
        again:
    	while (gspca_dev->present && gspca_dev->streaming) {
    		/* request a frame */
    		mutex_lock(&gspca_dev->usb_lock);
    		ret = command(gspca_dev, 1);
    		mutex_unlock(&gspca_dev->usb_lock);
    		if (ret < 0) break;
    		if (!gspca_dev->present || !gspca_dev->streaming)  break;
    		/* the frame comes in parts */
    		for (;;) {
    			ret = usb_bulk_msg(gspca_dev->dev,
    				urb->pipe,
    				data,
    				FPIX_MAX_TRANSFER,
    				&len, FPIX_TIMEOUT);
    			if (ret < 0) {
    				/* Most of the time we get a timeout
    				 * error. Just restart. */
    				goto again;
    			}
    			if (!gspca_dev->present || !gspca_dev->streaming)  goto out;
    			if (len < FPIX_MAX_TRANSFER || 
    				(data[len - 2] == 0xff && data[len - 1] == 0xd9)) {
    				/* If the result is less than what was asked
    				 * for, then it's the end of the
    				 * frame. Sometimes the jpeg is not complete,
    				 * but there's nothing we can do. We also end
    				 * here if the the jpeg ends right at the end
    				 * of the frame. */
    				gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
    				break;
    			}
    			/* got a partial image */
    			gspca_frame_add(gspca_dev,
    				gspca_dev->last_packet_type == LAST_PACKET ?  FIRST_PACKET: NTER_PACKET,
    				data, len);
    		}
    		/* We must wait before trying reading the next
    	 	 * frame. If we don't, or if the delay is too short,
    		 * the camera will disconnect. */
    		msleep(NEXT_FRAME_DELAY);
    	}
       out:
    	PDEBUG(D_STREAM, "dostream stopped");
    }
    
    

     上記のソースファイルを読み解くと、カメラの制御は次のようになる。

      ・ order_value で示されるフレームリクエスト用の12バイトのデータ列を、エンドポイント0のコントロール転送を使ってカメラに送信すれば、カメラは画像データを送信できるようになる。

      ・ 続いて、バルク転送用のエンドポイントを使って画像データを受信用バッファに受信する。受信データの大きさがバッファの大きさよりも小さい場合や、画像データの末尾がjpegファイルの終了マーク(0xffd9)に一致していれば、受信完了となる。

     非常に簡単な手順でカメラが制御できるわけで、これなら非力なPICでも十分にカメラから画像を読みだすことができる。jpeg形式で送信してくるので、後処理も不要で、そのまま画像データを一つのファイルとしてSDカードに書き込めば良い。

     また、バルク転送を使っていることから、画像データの読み出し要求を出すタイミングはシビアに考える必要もなく、SDカードへのデータ書き込み時間も気にする必要はなさそうである。


    3-2 PICのソフトウェア

     PICのUSBソフトウエアの作成に関しては、Microchip社からアプリケーションフレームワークとしてサンプルプログラムが提供されている。USBホストモードとして必要なソースファイルは、 usb_host.c と usb_host_generic.c だ。usb_host_generic.c は、 f inepix の制御用に少し修正が必要だ。

     USBデバイスモードとして必要なソースファイルは、usb_device.c , usb_function_msd.c, SD-SPI.c だ。これでSDカードをPC側から、メモリディスクとして読み取ることが出来るようになる。その他、 usb_config.c や usb_descriptors.c などの関連ファイルも環境に合わせて適宜修正をしておく。

     カメラを接続してホストモードで動作している時は、 カメラから取得した画像データをSDカードに書き込むために、ファイルシステムソフトウエアが必要であるが、これもMicrochip社から提供されている FSIO.c を使った。FSIO.c は FATファイルシステムを提供するもので、4GB以上のSDカードを使いたくて、config オプションで FAT32のサポートを有りに設定したが、ロングファイルネームはサポート無しにした。このため、SDカードに書き込むファイル名は、8.3形式のファイル名に限定され、「IMGXXXXX.JPG」のファイル名を使うことにした。


    4 動作概要

     本装置の動作は次のようになる。

    4-1 「ホストモード動作」

     (1)デジタルカメラ、PCのどちらも本装置に接続していない状態で、ACアダプタを接続すると装置が起動する。
     (2)起動直後は、ホストモードとなっており、Aコネクタ横に設けたLEDが点滅している。
     (3)ここで、カメラをAコネクタに接続すると、自動的にUSBのエヌメレーション処理が行われ、カメラの接続が確認され、LEDが点滅から点灯に変わる。
     (4)カメラの接続を確認した後、SDカード内に予め書き込まれている CAMERA.INI ファイルの中の画像読み取り間隔の指示に従って、カメラからの画像を読み取り、SDカードに書き込みを行う。カメラを外さない限り、この動作を永遠に繰り返すこととなる。
     (5)カメラが接続されてホストモードで動作している時に、PCからのUSBケーブルをBコネクタに接続しても、モードは変わらずに、ホストモードとしての動作を継続する。

    4-2 「デバイスモード動作」

     (1)デジタルカメラ、PCのどちらも本装置に接続していない状態で、ACアダプタを接続すると装置が起動する。
     (2)起動直後は、ホストモードとなっており、Aコネクタ横に設けたLEDが点滅している。
     (3)ここで、PCからのUSBケーブルをBコネクタに接続すると、ホストモードからデバイスモードへと直ちに移行し、PCと接続を行う。Bコネクタ横のLEDが点灯状態となり、それまで点滅していたAコネクタ横のLEDは消灯する。
     (4)PCからは、USBメモリディスクとして見えるので、ディスク内のDATAフォルダを開けば、記録された画像ファイル(「IMGXXXX.JPG」)を読みだすことが出来る。
     (5)PCが接続されてデバイスモードで動作している時に、カメラをAコネクタに接続しても、モードは変わらずに、デバイスモードとしての動作を継続する。

    4-3 「モード自動切り替え」

     (1)カメラとPCが共に接続された状態にあり、モードがホストモードにある時、カメラからのケーブルを抜くと、直ちにデバイスモードに移行し、PCと接続を行う。
     (2)カメラとPCが共に接続された状態にあり、モードがデバイスモードにある時、PCからのケーブルを抜くと、直ちにホストモードに移行し、カメラと接続を行う。

     以上のように、カメラ、PCともに接続していない状態にある時に、カメラを先に接続するとホストモードに、PCを先に接続するとデバイスモードになる。接続された機器に応じて動作する。


    5 SDカードのファイル作成

     SDカードは、4GBのSDHCカードを採用した。予めSDカードリーダー等を使ってPCに接続し、FAT32でフォーマットをしておく。このフォーマット済みのSDカードをマイコンシステムに組み込んでから、「4-2 デバイスモード動作」で示したような手順でPCと接続する。

     PCからは、SDカードがメモリディスクとして見えるので、ディスクフォルダを開いて、ルートディレクトリに、CAMERA.INI ファイルと、DATAフォルダを作成する。

     CAMERA.INIファイルはテキストファイルであり、先頭の一行に、現在日時と、画像取得間隔を次のように書いておく。

      2012/07/16 20:12:35 300  (現在日時が、2012年7月16日20時12分35秒で、5分間隔で画像を取得する場合)

     この後、PCとの接続を切って、カメラを接続すると、5分間隔で、画像を取得し、DATAフォルダ内に IMGXXXX.JPG のファイル名で画像データの記録を行う。CAMERA.INIファイルに書いておいた日時は、マイコンシステム内の時計の初期値となり、以降この時刻を元にファイルの作成時刻が生成される。


    6 ソースファイル

    main.c finepixカメラの制御と画像取得
    Descriptor.txt finepixカメラのUSBディスクリプタ
    MPLAB Project File MPLAB C30 プロジェクトファイル一式


    7 使ってみて

     右の動画ファイルは、自宅の西側の道路を5分間隔で10日間余りに渡ってコマ撮り撮影した画像を動画に変換したものです。 日が昇につれて、住宅の影や樹木の影が動いていく所や、南の空の雲が西から東に流れて行く様子が良く分かります。屋外撮影なので、夜間は撮影しないようにプログラムしています。

     午後になると強い西日により、窓ガラスに白いレースのカーテンが写りこんでしまっています。少し見難いですが、コマ撮りの面白さは十分に感じられかと思います。
     撮影間隔を30秒ぐらいにして記録すれば、防犯カメラとしても十分に活用できるのではないかと思いました。
    コマ撮り画像からの動画
    (fpix.avi 63MB)