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

コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: No title

C328Rのソースコードのライセンスは
Apache License, Version 2.0 なので
特に問題はないと思います。
私が改変した部分もオリジナルのライセンスに従います。

NewSoftSerialはLGPLになります。
ソースコードで添付するなら特に問題にならないと思います。

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: No title

こちらの環境はMacOSX 10.6でProcessingのバージョンは
1.0.9 です。コンパイルが通ることを確認できております。
一度、Processingのバージョンを確認してみてください。

※あとinportではなくimportですね。
これが原因ではないですよね?

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: No title

arduino-0018はArduinoというマイコン上で動作させるプログラムを書く為のソフトです。
Processingはパソコン上で動作するソフトです。
つまり今回のサンプルを動作させるにはarduino-0018+ArduinoとProcessingの1つのハードウェアと2つのソフトウェアが必要になります。

1つ目のサンプルコードはarduino-0018を使ってコンパイル&Arduinoにアップロードします。
2つ目のサンプルコードはProcessingで使います。

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: 新しいカメラとの相換性。非常に困っています。

従来のカメラモジュールとの差異はこちらにまとめられている通りで、
初期化時のシリアル通信の速度が固定になっているようですね。

http://www.silentsystem.jp/c1098soft.htm

CameraC328R::sync()
CameraC328R::initial()
このへんをうまく変更すればいけると思います。
とりあえず動かせればいいというのであれば、カメラモジュールとの通信速度を14400bpsに固定して、
CameraC328R::initial()のcreateCommandの0のところを14400に相当する値を設定すれば14400bpsで通信できると思います。

がんばってください。

No title

アドバイス助かります。
自分の変更点として
.hの125行目を
bool initial( BaudRate, ColorType, PreviewResolution, JPEGResolution );
とし
.cppの118行目を
bool CameraC328R::initial( BaudRate baudRate, ColorType colorType, PreviewResolution previewResolution, JPEGResolution jpegResolution )
{
createCommand( CMD_INITIAL, 0x07, colorType, previewResolution, jpegResolution );
としました。

.ccpの70行目の
createCommand( CMD_SYNC, 0, 0, 0, 0 );
も色々と変更してみましたが上手くいきませんでした。

Re: No title

syncコマンドに対して、ACKは返ってきてますか?
ACKが返ってきているのであれば、その後のINITIALでうまくいっていなさそうですね。
INITIALに対してはACKは返ってきてますか?

横レス失礼いたします

 いつも参考にさせていただいております。
 以前、C328をつかった方式でここを参考にさせていただきました。感謝です。
 つい最近、C1098へ切り替わり328が入手困難となりやもう得ず、C1098を購入いたしました。
 すでに、質問もあることなのですが、伺わせていただきたい内容が質問と上がっていたので、重ねての質問になることをお許しください。
 Rioさんと同じく変更を加え、

ここのサイトを参考にさせていただいた形で
if( !camera.initial( CameraC328R::BAUD14400,CameraC328R::CT_JPEG, CameraC328R::PR_160x120, CameraC328R::JR_640x480 ) ) {
Serial.println( "Initial failed." );
return; }
と記述しコンパイルは成功しました。

実行結果としては
if( !camera.sync() ) {
Serial.println( "Sync failed." );
return;
}
の部分でのエラーで止まっている状態です。

何分、電子工作一年生なのでオシロなどの設備が乏しいため、通常起動状態での信号を見たりできないのですが、同期信号を得ることができていないようです。

Re: 横レス失礼いたします

カメラとの通信速度は14400bpsにして、
CameraC328R.cppの次の行を

createCommand( CMD_INITIAL, 0, colorType, previewResolution, jpegResolution );

次のように書き換えてためしてみてください。

createCommand( CMD_INITIAL, 0x07, 0x07, 0x00, jpegResolution ); // jpegResolutionは 0x05 か 0x07

新設計の画像処理チップって書いてあるし、C328Rのコマンドあんまり対応してないのかな。。

No title

早速の対応ありがとうございます。


>>createCommand( CMD_INITIAL, 0x07, 0x07, 0x00, jpegResolution ); // jpegResolutionは 0x05 か 0x07

を試しましたが。
Sync failed.
と表示が相変わらずの状態です。

販売元のHPではコマンドは同じと記述されていますけど、違うと考えるほうが良いのかもしれませんね。

.ccpの464~477行の
sendACK( cmd, 0 );

createCommand( CMD_ACK, cmd,0, (byte)(packageId & 0xFF), (byte)(packageId >> 8) );

などの’0’も気になったので、いじってみましたが、やはりダメでした。

Re: No title

カメラのとの通信速度を14400bpsにして、
最初のsyncが通らないのはたぶんハードの問題のような気がします。
まずは結線を確認して、RX/TXが逆になっていないか確認してください。

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

オシロスコープで

 短時間使わせていただいて、328と1098を同じ接続で状態を見ましたが、やはり1098は返答がありませんでした。
 スケッチは、同じものを使用しました。

Re: オシロスコープで

syncにたいしてACKが返ってこないのですね。。
うーん、、ボーレートが間違ってるか、RX/TXが間違ってるか、電源電圧を間違ってるか、カメラが壊れているか。。その辺ですね。。

確認として

Mini USB Adapter で、C328とC1098を接続してテストしてみましたが、1098では全く無反応のようです。

  これはもう、ハード的に故障だという結論に達したようです。
 何かわかりましたら、また書き込みさせていただきます。
 
 これからも、参考のHPとして活用させていただきますので、よろしくお願いします。

追記

 販売元から、ソフトをダウンロードして行いました。
 禁止ワードにひっかかて、名前が書けません

Re: 確認として

C1098はC328より多く電流を消費するようですが、
USBアダプタの3.3Vで動作させている場合、
C1098が動作しない可能性がありますね。

9Vの箱電池で

AdruinioのVinに接続し、エラー毎でLEDを表示するようにして、タックスイッチを押すことで開始するように回路を組んで、スケッチして再度オシロで反応を見ましたが、やはり、反応なしでした。

Re: 9Vの箱電池で

カメラにつなぐ3.3Vの電源に余裕は十分ありますか?
レギュレータは別途繋いでいる?

回路として

 ご指摘通り、ただ箱電池を9VをArduinoに繋げているだけでした。
 USBからとっても、Vinにつないでもこれだと、FTDI232を経由した、電源供給になるので変わらないんですね。
 TOSHIBAのTA48033Sという3端子レギュレーターを貰えたので、入力ーGNDにセラミックコンデンサ0.47μF、GND-出力に電解コンデンサ100μFを接続し、入力からARDUINO Vinに、出力(3.3V)はカメラ側へ接続しています。
 結果として、それでも反応なしでした。
 

Re: 回路として

電流消費が大きい件、LinkSpriteのカメラと勘違いしてました。。すみません。
レギュレータ別にしても動かないとなるとやっぱり故障なのかな。うーむ。

度々、申し訳ありません。

まだ、C1098には苦戦していますが、とりあえず動く方のC328を使って、作ってしまって。
C1098をあと乗せしようと思います。

 そこで質問なのですが、MegaでSerial1~3へNewserialを使ったようにカメラを接続するのはどうすればよいでしょうか?

class NewSoftSerial;

CameraC328R(NewSoftSerial *softSerial = NULL);

NewSoftSerial *_serialPort;

の3行を変更すればいいのかな?程度はわかるのですが・・・。

Re: 度々、申し訳ありません。

んー。結構改造しないとだめかも。
とりあえず、オリジナルのCameraC328Rのコード使ったほうが早いかな。
ぼくならStreamクラスに対応して、NewSoftSerialでもHardwareSerialどちらにも対応すると思う。

なるほど

 久々に作業してます。
 いろいろ手を加える必要が在るという事ですね。

 オリジナルの方を試していますが、サンプルスケッチでSPI_PINの設定がなかったりで、何が何やらわからない状態で嵌ってます。
 こうしてみると、ずいぶん管理人さんのライブラリーで楽をさせていただいていたのだと痛感しています。
 ソフトとハードの両立(一度に覚えよう)するのは至難ですね・・・。

Re: なるほど

>  ソフトとハードの両立(一度に覚えよう)するのは至難ですね・・・。
少しずつやっていきましょうー

そうそうスイッチサイエンスで新しいJPEGカメラの取り扱いがはじまてます。
今、動作確認中ですがうまくいったらまた記事にするので、参考にしてみてください。

http://www.switch-science.com/products/detail.php?product_id=453

参考にさせていただきます

 記事公開されたら参考にさせていただきます。
 ハード的にC1098の動かない理由が何となくわかったような気がします。
 同じ回路でC328とC1098の受け取り電圧に差があるのでC1098では信号が来ているのに信号が来ていないような処理をしている感じがします。
 
 MEGAでいろいろ接続計画頑張ってますが、C328をTX/RX接続いまだに出来てないです。
 先は長いなぁ…他は、TX1~で接続しました。
 とりあえず、C328がうまく繋がらないと、C1098へマラソン移行できないですから、う~ん、ライブラリ改造の底なし沼へ足を一歩二歩・・・。

Re: 参考にさせていただきます


オリジナルのC328ライブラリはシリアルポート0(TX0/RX0)を使っていますね。
シリアルの関数呼び出しを、

Serial.flush();
Serial.print( _command[i], BYTE );
Serial.available()
Serial.read()

次のように使いたいシリアルポート(1~3)に変更すればそのポートで動くと思いますよ。

Serial1.flush();
Serial1.print( _command[i], BYTE );
Serial1.available()
Serial1.read()

早速試しました

 コンパイルもちゃんと通りました。
 このページのサンプルを一部変更した形で、processingからの読み込みができるかを確認するために、IDEのシリアルモニターで1キャラ送信し返答を見ましたが、どうも、if( Serial.available() ){での、シリアルバッファのチェックでPC側からの通信が得られていないような状態になっています。謎です。
 
 結果として、タックスイッチで撮影開始トリガーにしてやってみました。 成功です。
 あとは、C1098を組み込んだ形にするのと、Serialの問題を解決です。
 ありがとうございました。

No title

 MEGAに取り付けたC1098で撮影できました。
 if( !camera.setLightFrequency( CameraC328R::FT_50Hz ) ) の部分で、エラーを起こしましたが。この部分をすっ飛ばした形でうまくいけました。
 山を一つ越えた感じです。
 ありがとう、ございました。

Arduinoの質問

初めまして。
このカメラはPCと切り離して
(つまりArduino単体で)
使用すること可能なのでしょうか?
データはイーサネットシールドをつけたmicroSDに格納したいと思っています。
よろしくお願いします。

Re: Arduinoの質問

わりと簡単だと思います。
http://arms22.blog91.fc2.com/blog-entry-320.html

No title

はじめまして、私はArduino初心者で、
電子回路の初歩しかわからないド素人ですが、
C1098でSyncが取れない原因に2日ほど悩んでいたところ、
arms22さんの分圧回路そのまま使ってて、
もしかしたら必要電流量が足りてないのかと思ったので、
抵抗を100k/200kから10k/20kにしたらSyncがとれました。

素人考えですが、このまま使用を続けても良いのでしょうか?

Re: No title

こんにちは。
100k/200kだと波形がなまってsyncがとれなかったのかもしれません。
10k/20kで問題ないと思います。

ダイレクト

はじめまして、このプログラムを参考にさせてもらっているものです。
画像取得時に、processing画面で適当なキーを押す作業をせず、ダイレクトに画像を取得(ようはカメラからの片方向通信)したいのですが、その場合プログラムのどこをどういじればいいのでしょうか?

Re: ダイレクト

Arduinoのスケッチを画像を繰り返し撮影して、送信するように改造。
Processing側はJPEGのSOI(FFD8)を受信したらデータの書き込みを開始、
EOI(FFD9)を受信したら書き込み終了ってすればいいんじゃないかな?

http://siisise.net/jpeg.html

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: No title

ごめんなさい。
リンク先のファイルは持っていません。

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: No title

WProgram.hとWConstants.hのインクルードを削除して、
Arduino.hをインクルードしてください。
NewSoftSerialのかわりにSoftwareSerial使ってみてください。
Secret

Ads by Google
最近の記事
カテゴリ
Arduino (114)
電子工作 (112)
スタバッテルミン (5)
スタバカップアンプ (17)
電光掲示板 (7)
イベント (58)
太陽電池 (12)
ニキシー管 (19)
ARM (8)
PIC (20)
USBデバイス (7)
V850 (17)
Xfind (6)
プログラミング (5)
Android (3)
未分類 (25)
カメラ (6)
本 (18)
mbed (2)
SoftModem (0)
3Dプリンタ (31)
Amazon.co.jp
最近のコメント
arms22:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/17)
arms22:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/17)
radical bird:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/17)
arms22:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/17)
radical bird:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/15)
arms22:ABSプリント時の反り対策 (04/08)
質問です!:ABSプリント時の反り対策 (04/08)
arms22:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/08)
radical bird:Arduinoで遊ぼう - iPhoneのオーディオ端子を使って通信をする (04/08)
ぼおん:ABSプリント時の反り対策 (04/01)
リンク
Ads by Google
以前の記事
プライバシーポリシー
当サイトでは、第三者配信による広告サービスを利用しています。このような広告配信事業者は、ユーザーの興味に応じた商品やサービスの広告を表示するため、当サイトや他サイトへのアクセスに関する情報 (氏名、住所、メール アドレス、電話番号は含まれません) を使用することがあります。このプロセスの詳細やこのような情報が広告配信事業者に使用されないようにする方法については、ここをクリックしてください。