なんでも作っちゃう、かも。

Arduino/Make/フィジカルコンピューティング/電子工作あたりで活動しています。スタバの空きカップを使ったスタバカップアンプなど製作。最近はもっぱらArduinoと3Dプリンタの自作に興味があります。

Arduinoで遊ぼう - JPEGカメラモジュールで写真を撮る

Posted by arms22 on 2009年10月13日 57  0

JPEGカメラモジュールとArduino

SparkFunで取り扱っているJPEGカメラモジュール(C328-7640)は解像度640x480のカラー静止画をJPEG圧縮して出力するモジュールだ。マイコンとの接続はシリアルでたった4本のワイヤでArduinoと接続、制御することができる。スナップショットコマンドを送ると撮影した画像をJPEGで圧縮してシリアルで送信する。日本だとスイッチサイエンスさん、ストロベリーリナックスさんで買える。今回はこのJPEGカメラモジュールを使って静止画を撮影し、Processingの画面に撮影した画像を表示してみよう。

jpeg_camera_snapshot_sample.jpg
※夜に撮影したのでちょっと画像が荒い感じ。昼に撮ればもう少し綺麗になると思う。

SparkFun Electronics - JPEG Color Camera - UART Interface
http://www.sparkfun.com/commerce/product_info.php?products_id=9334

スイッチサイエンス - シリアル接続JPEGカラーカメラ
http://www.switch-science.com/products/detail.php?product_id=219

Strawberry Linux - シリアル出力JPEGカラーカメラ(640x480)
http://strawberry-linux.com/catalog/items?code=18104

このモジュールの仕様は次の通り。

  • サイズ:20x28mm
  • 解像度:640x480, 320x240, 160x128, 80x60
  • 電源:3.3V, 60mA
  • 通信速度:115.2Kbps(自動速度検出付)


Arduinoと接続する


JPEGカメラモジュール接続図
このモジュールの電源は3.3Vなので5VのArduinoと直結してしまうとポートが壊れてしまう。その為、ArduinoのTxD信号を5Vから3Vに抵抗で分圧(100K/200K)してモジュールに入力する。またArduinoのハードウェアシリアル(0番と1番)はPCとの通信に利用するのでモジュールとの通信にはソフトウェアシリアル(2番と3番)を使う。


ライブラリをダウンロードする


次のサイトでJPEGカメラモジュール(C328-7640)用のライブラリが公開されている。

gizmologi.st - Taking Pictures with Arduino
http://gizmologi.st/2009/04/taking-pictures-with-arduino/

しかし、上記ライブラリはモジュールとの通信にハードウェアシリアルを使っている。ハードウェアシリアルはPCとの通信に利用したいので、ソフトウェアシリアルを使うようにライブラリを変更した。

ソフトウェアシリアルを使うように改造したライブラリ(CameraC328R)
http://arms22.googlecode.com/files/CameraC328R.zip

ソフトウェアシリアルはNewSoftSerialというライブラリを使う。Arduino IDEにはソフトウェアシリアルライブラリ(SoftwareSerial)が標準で付属しているがavailable関数が使えない。NewSoftSerialは次のサイトからダウンロードできる。

Arduiniana - NewSoftSerial
http://arduiniana.org/libraries/newsoftserial/

ダウンロードしたライブラリはSKETCHBOOK/librariesにコピーする。


スケッチ


最初のスケッチはArduino。ハードウェアシリアル、ソフトウェアシリアルの初期化を行って(setup)、PCから1byte、データが送られてくるのを待つ(loop)。データを受信(撮影のトリガー)したらJPEGカメラモジュールとの通信を開始し、スナップショットコマンド(snapshot)を送る。そして撮影した画像をJPEGカメラモジュールから受け取りPCに送信する(getJPEGPicture_callback)。

#include <CameraC328R.h>
#include <NewSoftSerial.h>

#define LED_PIN 13
#define PAGE_SIZE 64
#define USB_BAUD 115200
#define CAMERA_BAUD 14400

NewSoftSerial mySerial(2, 3);
CameraC328R camera(&mySerial);

uint16_t pictureSizeCount = 0;

/**
 * This callback is called EVERY time a JPEG data packet is received.
 */
void getJPEGPicture_callback( uint16_t pictureSize, uint16_t packageSize, uint16_t packageCount, byte* package )
{
  // packageSize is the size of the picture part of the package
  pictureSizeCount += packageSize;

  Serial.write(package,packageSize);

  if( pictureSizeCount >= pictureSize )
  {
    digitalWrite( LED_PIN, LOW );
    Serial.flush();
  }
}

void setup()
{
  Serial.begin( USB_BAUD );
  mySerial.begin(CAMERA_BAUD);

  pinMode( LED_PIN, OUTPUT );
  digitalWrite( LED_PIN, LOW );
}

void loop()
{
  if( Serial.available() ){

    while(Serial.read() != -1);

    digitalWrite( LED_PIN, HIGH );

    if( !camera.sync() )
    {
      Serial.println( "Sync failed." );
      return;
    }

    if( !camera.initial( CameraC328R::CT_JPEG, CameraC328R::PR_160x120, CameraC328R::JR_640x480 ) )
    {
      Serial.println( "Initial failed." );
      return;
    }

    if( !camera.setPackageSize( 64 ) )
    {
      Serial.println( "Package size failed." );
      return;
    }

    if( !camera.setLightFrequency( CameraC328R::FT_50Hz ) )
    {
      Serial.println( "Light frequency failed." );
      return;
    }

    if( !camera.snapshot( CameraC328R::ST_COMPRESSED, 0 ) )
    {
      Serial.println( "Snapshot failed." );
      return;
    }

    pictureSizeCount = 0;
    if( !camera.getJPEGPicture( CameraC328R::PT_JPEG, PROCESS_DELAY, &getJPEGPicture_callback ) )
    {
      Serial.println( "Get JPEG failed." );
      return;
    }
  }
}



次のスケッチはProcessing。Arduino IDEのシリアルモニタを閉じ、アプリを起動する。画面が開いたら適当なキーを押すと撮影が開始され、Arduinoから撮影された画像が送られてくる。データの転送中、ArduinoのLEDが点灯している。このLEDが消えたら再度、適当なキーを押すと画面に撮影した画像が表示される。撮影された画像はスケッチと同じフォルダに保存される。
import processing.serial.*;

Serial myPort;
String filename = "photo.jpg";
byte[] photo = {
};
Boolean readData = false;
PImage captureImage;

void setup()
{
  size(640,480);
  println( Serial.list() );
  myPort = new Serial( this, Serial.list()[3], 115200 ); //Serial.list()[3]は環境に合わせて変更すること。
}

void draw()
{
  byte[] buffer = new byte[64];
  if( readData )
  {
    while( myPort.available() > 0 )
    {
      int readBytes = myPort.readBytes( buffer );
      print( "Read " );
      print( readBytes );
      println( " bytes ..." );
      for( int i = 0; i < readBytes; i++ )
      {
        photo = append( photo, buffer[i] );
      }
    }
  }
  else
  {
    while( myPort.available() > 0 )
    {
      print( "COM Data: " );
      println( myPort.readString() );
    }
  }
}

void keyPressed()
{
  if( photo.length > 0 ) {
    readData = false;
    print( "Writing to disk " );
    print( photo.length );
    println( " bytes ..." );
    saveBytes( filename, photo );
    println( "DONE!" );
    photo = new byte[0];

    captureImage = loadImage(filename);
    image(captureImage, 0, 0);
  }
  else {
    readData = true;
    myPort.write(0);
    println( "Waiting for data ..." );
  }
}



Arduino Uno SMD
Arduino Uno SMD
posted with amazlet at 11.02.02
スイッチサイエンス
売り上げランキング: 23827



Arduinoをはじめようキット
スイッチサイエンス
売り上げランキング: 1910



該当の記事は見つかりませんでした。