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

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カメラモジュールで写真を撮る

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



Ads by Google
最近の記事
カテゴリ
Arduino (114)
電子工作 (114)
スタバッテルミン (5)
スタバカップアンプ (18)
電光掲示板 (7)
イベント (59)
太陽電池 (12)
ニキシー管 (19)
ARM (8)
PIC (20)
USBデバイス (7)
V850 (17)
Xfind (6)
プログラミング (5)
Android (3)
未分類 (25)
カメラ (6)
本 (18)
mbed (2)
SoftModem (0)
3Dプリンタ (36)
Amazon.co.jp
最近のコメント
arms22:Arduinoで遊ぼう - SDメモリカードを読み書きする(廃止) (09/09)
nisi:Arduinoで遊ぼう - SDメモリカードを読み書きする(廃止) (09/04)
三ツ星トラフィック:MPPT太陽電池充電(7) (08/29)
nameless911:Ogaki Mini Maker Faire 2014に行ってきたよ。 (08/28)
claynets:オープンソースのPCBCAD「KiCad」。 (08/26)
arms22:Arduinoで遊ぼう-AVRライタを使わないBootloaderの書き込み (08/11)
Sekine:Arduinoで遊ぼう-AVRライタを使わないBootloaderの書き込み (08/10)
arms22:ArduinoでSDメモリカードを読み書きする (08/05)
arms22:ArduinoでSDメモリカードを読み書きする (07/24)
arms22:Arduinoで遊ぼう-AVRライタを使わないBootloaderの書き込み (07/22)
リンク
Ads by Google
以前の記事
プライバシーポリシー
当サイトでは、第三者配信による広告サービスを利用しています。このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 (氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、ここをクリックしてください。