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

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

Arduinoで遊ぼう - JPEGカメラで撮った写真をTwitPicにポストする

Posted by arms22 on 2010年01月09日 1  0

JPEGカメラモジュール+イーサーネットシールド /w Arduino
TwitPicに画像をポストするライブラリの応用編。JPEGカメラモジュールで撮った写真を直接TwitPicにポストしてみるよ。

接続する



c328r_2led_1sw.png
今回、JPEGカメラモジュールとの通信にはソフトウェアシリアルを使わず、ハードウェアシリアルを使います。ArduinoのTX、RX端子にJPEGカメラモジュールを接続します。JPEGカメラモジュールが接続されているとスケッチのアップロードに失敗するので、スケッチをアップロードする時はJPEGカメラモジュールを外して下さい。

ハードウェアシリアルをJPEGカメラモジュールとの通信に利用した為、処理中のメッセージを表示することができなくなりました。処理中を表すLEDとエラーを表すLEDを追加します。処理中は青色LED(digital 6番)を点灯させ、エラーが発生した場合(ポストに失敗など)には赤色LED(digital 5番)を点灯させます。

シャッターボタンをdigital 4番に接続します。ditital 4番の内蔵プルアップ機能を有効にします。スイッチを押した時のLOWレベルを検知して写真を撮影し、TwitPicにポストします。


ライブラリのインストール


次のライブラリをダウンロードし、Arduinoのlibrariesフォルダにコピーしてください(~/Documents/Arduino/libraries)。

画像サイズを取得できるよう改造したカメラライブラリ(CameraC328R)
http://arms22.googlecode.com/files/CameraC328R_002.zip

TwitPic-003.zip
http://code.google.com/p/arms22/downloads/detail?name=TwitPic-003.zip
TwitPicライブラリ
http://arms22.googlecode.com/files/TwitPic_002.zip


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


スケッチ


EthernetとSerialを初期化した後、シャッターボタンが押されるの待ちます。シャッターボタンのLOWレベルを検出したらJPEGカメラモジュールとの通信を開始し、スナップショットコマンドを送ります。
撮影に成功したら撮影した画像のサイズを取得し(camera.getJPEGPictureSize)、TwitPicへ画像のアップロードを開始します(twitpic.upload)。
upload関数に指定したc328rImageTransfer関数がコールされたら、撮影した画像の取得を開始します(camera.getJPEGPictureData)。撮影した1枚の画像はJPEGカメラモジュールから分割して送られてきます。分割された画像データが届く度にgetJPEGPicture_callbackがコールされるので、client->write関数を使ってTwitPicに分割された画像データを送信します。


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

#define SNAPSHOT     4
#define ERROR_LED    5
#define PROGRESS_LED 6

#define CAMERA_BAUD 57600

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 0, 0, 177 };

TwitPic twitpic("Yourname","Password");

CameraC328R camera;

uint16_t pictureSize = 0;
Client *targetClient;

/**
 * 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 )
{
  targetClient->write(package,packageSize);
}

uint32_t c328rImageTransfer(Client *client)
{
  if(client){
    targetClient = client;
    camera.getJPEGPictureData( &getJPEGPicture_callback );
  }
  return pictureSize;
}

void setup()
{
  Ethernet.begin(mac, ip);
  Serial.begin( CAMERA_BAUD );

  pinMode( PROGRESS_LED, OUTPUT );
  digitalWrite( PROGRESS_LED, HIGH );

  pinMode( ERROR_LED, OUTPUT );
  digitalWrite( ERROR_LED, HIGH );

  pinMode( SNAPSHOT, INPUT );
  digitalWrite( SNAPSHOT, HIGH ); // pull-up

  delay(10000);

  digitalWrite( PROGRESS_LED, LOW );
  digitalWrite( ERROR_LED, LOW );
}

void loop()
{
  do {
    if( digitalRead(SNAPSHOT) == LOW ){

      digitalWrite( PROGRESS_LED, HIGH );
      digitalWrite( ERROR_LED, LOW );

      if( !camera.sync() ){
        goto camera_error;
      }

      if( !camera.initial( CameraC328R::CT_JPEG, CameraC328R::PR_160x120, CameraC328R::JR_640x480 ) ){
        goto camera_error;
      }

      if( !camera.setPackageSize( 64 ) ){
        goto camera_error;
      }

      if( !camera.setLightFrequency( CameraC328R::FT_50Hz ) ){
        goto camera_error;    
      }

      if( !camera.snapshot( CameraC328R::ST_COMPRESSED, 0 ) ){
        goto camera_error;    
      }

      pictureSize = 0;
      if( !camera.getJPEGPictureSize( CameraC328R::PT_SNAPSHOT, PROCESS_DELAY, pictureSize) ){
        goto camera_error;    
      }

      if(twitpic.upload(&c328rImageTransfer) < 0){
        goto camera_error;
      }

      camera.powerOff();
      break;

camera_error:
      digitalWrite( ERROR_LED, HIGH );
    }

    digitalWrite( PROGRESS_LED, LOW );
    delay(100);
  }
  while(0);
}




Arduinoで遊ぼう - TwitPicに画像をポストするライブラリ(OAuth対応)
http://arms22.blog91.fc2.com/blog-entry-354.html
Arduinoで遊ぼう - TwitPicに画像をポストするライブラリ
http://arms22.blog91.fc2.com/blog-entry-287.html


Arduinoで遊ぼう - JPEGカメラモジュールで写真を撮る
http://arms22.blog91.fc2.com/blog-entry-261.html



Arduinoイーサネット・シールド
スイッチサイエンス
売り上げランキング: 3761



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



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

Posted by arms22 on 2009年10月13日 51  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



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