Arduinoで遊ぼう - JPEGカメラで撮った写真をTwitPicにポストする
Posted by arms22 on 2010年01月09日

TwitPicに画像をポストするライブラリの応用編。JPEGカメラモジュールで撮った写真を直接TwitPicにポストしてみるよ。
接続する

今回、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
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
http://arms22.blog91.fc2.com/blog-entry-287.html
Arduinoで遊ぼう - JPEGカメラモジュールで写真を撮る
http://arms22.blog91.fc2.com/blog-entry-261.html
Arduinoで遊ぼう - JPEGカメラモジュールで写真を撮る
Posted by arms22 on 2009年10月13日

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

このモジュールの電源は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 ..." );
}
}
該当の記事は見つかりませんでした。