Network Cameraを作ってみよう(2) カメラのハンドリング

Ethernetが動き出したら、これはいったん脇においておき、次はカメラのハンドリングである。話は再び、先ほど紹介したLS_Y201のページに戻る。さて、このカメラそのものをまず入手する必要がある。こちら、国内の場合だとスイッチサイエンスで"LinkSpriteシリアル接続JPEGカラーカメラ"という名称で販売されており、筆者もスイッチサイエンスから通販で入手した。

問題はこのカメラ、LS_Y201のページの写真と異なり、5pinのコネクタがついていることだ(Photo25~27)。かなり珍しいタイプなので、秋葉原のショップあたりでも手に入るかどうか怪しいところ。あきらめてはんだで配線を引っ張り出そうとおもったのだが、試しに身の回りを探したところ、なぜか5pin→4pinのUSBケーブルを発見した(Photo28)。

Photo25:これはレンズキャップがまだ被せてある状態

Photo26:古いモデルの中には信号の電圧レベルが合ってないものもあるが、こちらはTTLレベルの信号が出力される新しいモデル

Photo27:問題のコネクタ。5pinタイプはちょっと珍しい

Photo28:どうもマザーボード側に5pinコネクタがついているという珍しいモデル用のものらしい(もうどのマザーボードにこれがついていたのか、筆者にもさっぱりわからない)

ためしに接続してみるとコネクタもぴったりあう(Photo29)。また端子は5pinなのだが、実はこのカメラで使っているのは4pinのみ(1pinは未使用の模様)ということで、ちょうど配線もぴったりだったため、そのまま流用してしまった。とはいえこれは一般的ではないので、コネクタの取り付け部にリード線をつけて配線を引っ張り出すのが現実的な案だと思う。

Photo29:この通りぴったり装着できた

さて、配線は図3の様になる。これが準備できたら、プログラムに取り掛かろう。まず先ほどのコンパイラの画面で、左上の"New"ボタンを押すと、新しいプログラムの作成メニューが出てくるので、適当な名前を入れる(Photo30)。

Photo30:カメラのテストプログラムということで、捻りの無い名前を

図3 カメラの5pinコネクタとmbedとの配線図

ついでCamera_LS_Y201のSummaryページに移動し、ここで"Import this library into a program"をクリックし、Import画面で今作成したプログラムを指定する(Photo32)。

Photo31:こちらはライブラリのみの提供で、プログラムは自分で作ることになる

Photo32:Target Pathのところを"CameraTest"に指定すると、このプログラムでライブラリが使えるようになる

これにより、CameraTestでカメラ用ライブラリが利用できるようになった(Photo33)。もっとも、肝心のプログラムがまだである。Newで作ると、main.cppの中身はごらんの通りでしかない(Photo34)。

Photo33:CameraTestの中に、"Camera_LS_Y201"のライブラリアイコンが出現することで、利用可能になったことが判る

Photo34:無条件でHello World!が記述されている。まぁ消して自分のプログラムを入れろ、という事なのだが

幸いにも先ほどのページにサンプルプログラムが掲載されているので、これをコピーしてmain.cppの中身を上書きしてしまえばいいのだが、どうもサンプルプログラムの開発にあたっては☆board Orangeを前提にしているようで

  • ディレイなしでひたすら画像を撮影、書き出しを行う
  • 撮影した画像はSDカードに書き出す
  • LCDに撮影状態を表示する

といった仕様になっており、このままだとちょっとうまくない。そこで

  • 撮影を100秒おきにするように変更
  • 撮影した画像は内蔵メモリ(/localfile)に書き出す
  • コンソールにのみ撮影状態を表示する

と手直しをしたのがList 1である。ちなみに何で100秒おきかというと、先にも書いたとおり内蔵メモリは2MB弱しかないので、連続撮影をするとすぐ一杯になってしまうこと、それとこれは内蔵メモリをmbedから使う場合の制約なのだが、mbedが内蔵メモリをアクセスしている間は、外部(例えばPC)からアクセスすることができないという問題がある。つまり連続撮影をされると、その画像を取り出すことができなくなってしまうわけで、あえて100秒という長めの時間設定をしている。まぁ、あくまで動作確認なので、使い勝手が悪いのはご容赦いただきたい。

コンパイル後にダウンロード、mbedにコピーしてリセットという一連の処理を行うと、コンソールにはこんな具合に撮影状態が表示され(Photo35)、IMG_0000.JPG、IMG_0001.JPG、…という具合に自動的に撮影したファイルがたまってゆく筈だ。撮影した画像は?というとこんな具合(Photo36)。まぁまぁの画質であった。

Photo35:別にファイル名を変える必要もないのだが、そこまでやると変更が大きくなるので、このあたりは元のサンプルのままとさせていただいた。出てくる数字はこのファイルのファイル名である

Photo36:とりあえず天井に向けて撮影してみました

List 1:
#include "mbed.h"
#include "Camera_LS_Y201.h"

LocalFileSystem local("local");
Camera_LS_Y201 cam1(p13, p14);

FILE *fp = NULL;
int datcnt = 0;

/**
 * Callback function for readJpegFileContent.
 *
 * @param buf A pointer to a buffer.
 * @param siz A size of the buffer.
void callback_func(int done, int total, uint8_t *buf, size_t siz) {
    fwrite(buf, siz, 1, fp);

    static int n = 0;
    int tmp = done * 100 / total;
 */
void callback_func(int done, int total, uint8_t *buf, size_t siz) {
    fwrite(buf, siz, 1, fp);

    static int n = 0;
    int tmp = done * 100 / total;
    if (n != tmp) {
        n = tmp;
        // You can print the progress to LCD here.
    }
}

int capture(int n) {
    /*
     * Take a picture.(L)
     */
    if (cam1.takePicture() != 0) {
        return -1;
    }
    printf("Captured.\r\n");

    char fname[64];

    /*
     * Open file.
     * Read the content.
     */
    snprintf(fname, sizeof(fname) - 1, "/local/IMG_%04d.jpg", n);
    fp = fopen(fname, "wb");
    if (fp == NULL) {
        return -2;
    }
    printf("Capture: %04d", n);
    datcnt = 0;
    if (cam1.readJpegFileContent(callback_func) != 0) {
        fclose(fp);
        return -3;
    }
    fclose(fp);

    /*
     * Stop taking pictures.
     */
    cam1.stopTakingPictures();

    return 0;
}

/**
 * Entry point.
 */
int main(void) {
    wait(1);

    if (cam1.reset() == 0) {
        printf("Reset OK.\r\n");
    }
    wait(1);

    int cnt = 0;
    // for (int i = 0; i < 10; i++) {
    while (1) {
        int r = capture(cnt);
        if (r == 0) {
            printf("[%04d]:OK.\r\n", cnt);
        } else {
            printf("[%04d]:NG. (code=%d)\n\n", cnt, r);
        }
        cnt++;
        wait(30);
    }

    return 0;
}