HOME | Raspberry Pi | ビジネス書籍紹介 | 2021-09-19 (Sun) Today's Access : 108 Total : 354102. Since 10 Sep. 2019

 画像処理 第5回自作デジカメ初号機完成
2020.10.27

YouTubeでポイントを説明しています。画像をクリックすると再生できます。

画像処理 第5回は、自作デジカメの組立てです。 第4回電源回路掲載後に、ArduCamカメラモジュールが初期不良を起こし、販売元で検証、交換してもらうのに2カ月半も 掛かってしまいました。
前回までに制作した、ArduCamカメラモジュール制御、SDカード制御、リアルタイムクロック制御 および電源モジュールからオリジナルのカメラを作っていきます。

■各回路のモジュール化
ブレッドボード上に配置した各回路をいきなり1つに纏めようとすると、気が滅入ってしまいますし、配線ミスの危険性があります。 そこで、機能ごとにモジュール化します。

画像処理 第2回カメラモジュール制御で制作した、ArduCamカメラ制御回路とmicroSDカード制御回路です。
まずは、ArduCamカメラ制御回路部分をモジュール化します。


さらに、第3回リアルタイムクロック制御回路とmicroSDカード制御回路を、1つのモジュールに纏めます。

基板の裏側に、電気二重層コンデンサーを取り付けています。

画像処理 第4回電源回路で制作した回路は、元々モジュール化していました。

昇圧した電源を、Arduino nano の Vin、GND端子に接続します。


Arduino Nano の MISO(D12)、MOSI(D11)、SCK(D13)はArduCamとマイクロSDカードモジュールで共通して使われるので、 2列15ピンのピンヘッダーを用いて分岐させています。また、5VとGNDも3分岐させています。
これらのモジュールを重ね合わせて、配線します。



■ソースコード
// ArduCAM demo (C)2017 Lee
// Web: http://www.ArduCAM.com
// This program is a demo of how to use most of the functions
// of the library with a supported camera modules, and can run on any Arduino platform.
//
// This demo was made for Omnivision 2MP/5MP sensor.
// It will run the ArduCAM 2MP/5MP as a real 2MP/5MP digital camera, provide both JPEG capture.
// The demo sketch will do the following tasks:
// 1. Set the sensor to JPEG mode.
// 2. Capture and buffer the image to FIFO every 5 seconds 
// 3. Store the image to Micro SD/TF card with JPEG format in sequential.
// 4. Resolution can be changed by myCAM.set_JPEG_size() function.
// This program requires the ArduCAM V4.0.0 (or later) library and ArduCAM 2MP/5MP shield
// and use Arduino IDE 1.6.8 compiler or above
#include <ArduCAM.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "memorysaver.h"
//This demo can only work on OV2640_MINI_2MP or OV5642_MINI_5MP or OV5642_MINI_5MP_BIT_ROTATION_FIXED platform.
#if !(defined OV5642_MINI_5MP || defined OV5642_MINI_5MP_BIT_ROTATION_FIXED || defined OV2640_MINI_2MP || defined OV3640_MINI_3MP)
  #error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
#define SD_CS 9
const int SPI_CS = 10;
ArduCAM myCAM( OV2640, SPI_CS );

// Realtime Clock
#define PIN_CE   2
#define PIN_IO   3
#define PIN_SCLK 4
static char clockTime[19]; // 時刻表示用文字列
static char shortTime[7];  // 撮影用文字列
static char dirTime[9];    // ディレクトリ用文字列

#define LED_PIN 8
#define BTN_PIN 7
boolean writeStatus=false;
String  recv;

//SPISettings settingsArduCam(2000000, MSBFIRST, SPI_MODE0);
//SPISettings settingsSDCard(250000, MSBFIRST, SPI_MODE0);
SPISettings settingsArduCam(500000, MSBFIRST, SPI_MODE0);
SPISettings settingsSDCard(4000000, MSBFIRST, SPI_MODE0);

#define LOCK_NONE    0
#define LOCK_ARDUCAM 1
#define LOCK_SDCARD  2

void spi_lock(int lock) {
	static int status = -1;
	if (lock==LOCK_NONE) {
		SPI.endTransaction();
		status = -1;
		return;
	}
	if (lock!=status) {
		SPI.endTransaction();
		if (lock==LOCK_ARDUCAM) {
			SPI.beginTransaction(settingsArduCam);
		} else if (lock==LOCK_SDCARD) {
			SPI.beginTransaction(settingsSDCard);
		}
		status = lock;
	}
}

void myCAMSaveToSDFile(){
	byte buf[256];
	static int pos = 0;
	char filename[20];
	char header[7];
	uint8_t prev = 0;
	uint32_t length = 0;
	uint32_t total  = 0;
	File outFile;

	//Flush the FIFO
	myCAM.flush_fifo();

	//Clear the capture done flag
	myCAM.clear_fifo_flag();

	//Start capture
	myCAM.start_capture();
	Serial.println(F("start Capture"));
	delay(50);
	while(!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));

	Serial.println(F("Capture Done."));  
	length = myCAM.read_fifo_length();

	Serial.print(F("The fifo length is :"));
	Serial.println(length, DEC);
	if (length >= MAX_FIFO_SIZE) //384K
	{
		myCAM.clear_fifo_flag();
		Serial.println(F("Over size."));
		return ;
	}
	if (length == 0 ) //0 kb
	{
		myCAM.clear_fifo_flag();
		Serial.println(F("Size is 0."));
		return ;
	}

	// JPEG FILE FFD8~FFD9
	// skip First Byte 0x00
	myCAM.CS_LOW();
	myCAM.set_fifo_burst();
	buf[0] =  SPI.transfer(0x00);
	buf[0] =  SPI.transfer(0x00);
	buf[1] =  SPI.transfer(0x00);
	myCAM.CS_HIGH();
	if ( (buf[0]!=0xFF)||(buf[1]!=0xD8) ) {
		Serial.println(F("Irregular JPEG Header"));
		sprintf(header,"%02x%02x",buf[0],buf[1]);
		Serial.println(header);
		return;
	}
	prev = buf[1];
	pos = 2;
	total=2;

	//ファイル名は8文字、拡張子は3文字までしか対応していない
	getDateBurst();
	if (!SD.exists(dirTime)) SD.mkdir(dirTime);
	sprintf(filename,"%s/%s.jpg",dirTime,shortTime);

	//Open the new file
	Serial.println(filename);
	outFile = SD.open(filename, O_WRITE | O_CREAT | O_TRUNC);
	if(!outFile){
		Serial.println(F("File open failed"));
		return;
	}

	spi_lock(LOCK_ARDUCAM);
	myCAM.CS_LOW();
	myCAM.set_fifo_burst();

	while ( true ) {
		while (true) {
			if (total>(length*2)) {
				myCAM.CS_HIGH();
				spi_lock(LOCK_NONE);
				Serial.print(F("Irregular Buffer Data : total size = "));
				Serial.println(total, DEC);
				sprintf(header,"%02x%02x",buf[pos-2],buf[pos-1]);
				Serial.println(header);
				return;
			}
			total++;
			buf[pos] =  SPI.transfer(0x00);
			if ((buf[pos]==0xD9)&&(prev==0xFF)) {
				myCAM.CS_HIGH();
				spi_lock(LOCK_NONE);
				spi_lock(LOCK_SDCARD);
				outFile.write(buf,(pos+1));
				//Close the file
				outFile.close();
				spi_lock(LOCK_NONE);
				Serial.println(F("Image save OK."));
				Serial.print(F("total bytes is :"));
				Serial.println((total-1), DEC);
				return;
			}
			prev = buf[pos];
			if (++pos==256) break;
		}
		myCAM.CS_HIGH();
		spi_lock(LOCK_SDCARD);
		outFile.write(buf, 256);
		pos = 0;
		spi_lock(LOCK_ARDUCAM);
		myCAM.CS_LOW();
		myCAM.set_fifo_burst();
	}
}

void setup(){
	uint8_t vid, pid;
	uint8_t temp;
	Wire.begin();
	Serial.begin(115200);
	Serial.println(F("ArduCAM Start!"));
	//set the CS as an output:
	pinMode(SPI_CS,OUTPUT);
	digitalWrite(SPI_CS, HIGH);
	// initialize SPI:
	SPI.begin();
  
	//Reset the CPLD
	myCAM.write_reg(0x07, 0x80);
	myCAM.write_reg(0x07, 0x00);
  
	while(1){
		//Check if the ArduCAM SPI bus is OK
		myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
		temp = myCAM.read_reg(ARDUCHIP_TEST1);
  
		if (temp != 0x55){
			Serial.println(F("SPI interface Error!"));
			delay(1000);continue;
		}else{
			Serial.println(F("SPI interface OK."));break;
		}
	}
	//Initialize SD Card
	while(!SD.begin(SD_CS)){
		Serial.println(F("SD Card Error!"));
	}
	Serial.println(F("SD Card detected."));

	while(1){
		//Check if the camera module type is OV2640
		myCAM.wrSensorReg8_8(0xff, 0x01);
		myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
		myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
		if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))){
			Serial.println(F("Can't find OV2640 module!"));
			delay(1000);continue;
		}
		else{
			Serial.println(F("OV2640 detected."));break;
		}
	}
	myCAM.set_format(JPEG);
	myCAM.InitCAM();
	//myCAM.OV2640_set_JPEG_size(OV2640_176x144);
	//myCAM.OV2640_set_JPEG_size(OV2640_352x288);
	//myCAM.OV2640_set_JPEG_size(OV2640_320x240);
	myCAM.OV2640_set_JPEG_size(OV2640_640x480);
	//myCAM.OV2640_set_JPEG_size(OV2640_800x600);
	//myCAM.OV2640_set_JPEG_size(OV2640_1600x1200);

	//myCAM.OV2640_set_Special_effects(BW);

	// Realtime Clock
	pinMode(PIN_SCLK,OUTPUT);
	pinMode(PIN_CE,  OUTPUT);

	pinMode(BTN_PIN, INPUT_PULLUP);
	pinMode(LED_PIN, OUTPUT);
}

void capture() {
	if ( !writeStatus ) {
		writeStatus = true;
		digitalWrite(LED_PIN, HIGH);

		myCAMSaveToSDFile();

		writeStatus = false;
		digitalWrite(LED_PIN, LOW);
	}
}

// 整数値をBCDに変換
byte dec2bcd(int x) {
  return ((x/10)<<4)+(x%10);
}

uint8_t bcd2dec(const uint8_t bcd) {
	return (10*((bcd&0xF0)>>4)+(bcd&0x0F));
}

uint8_t shiftInEx() {
	uint8_t input_value=0;
	uint8_t bit=0;
	pinMode(PIN_IO,INPUT);
	for (int i=0; i<8; ++i) {
		digitalWrite(PIN_SCLK,HIGH);
		delayMicroseconds(1);
		digitalWrite(PIN_SCLK,LOW);
		delayMicroseconds(1);

		bit = digitalRead(PIN_IO);
		input_value |= (bit<<i); // Bits are read LSB first.
	}
	return input_value;
}

void shiftOutEx(const uint8_t value) {
	bool pinModeFlag = false;
	pinMode(PIN_IO, OUTPUT);
	for (int i=0;i<8;++i) {
		digitalWrite(PIN_IO, (value>>i)&1);
		delayMicroseconds(1);
		digitalWrite(PIN_SCLK,HIGH);
		delayMicroseconds(1);

		// We're about to read data -- ensure the pin is back in input mode
		// before the clock is lowered
		if (i==7) {
			if (value==0xBF) pinModeFlag=true; // clock Burst Read
			if ((value>=0x80)&&(value<=0x8D)&&(value%2)) pinModeFlag=true;
		}
		if (pinModeFlag) {
			pinMode(PIN_IO,INPUT);
		} else {
			digitalWrite(PIN_SCLK,LOW);
			delayMicroseconds(1);
		}
	}
}

void getDateBurst() {
	digitalWrite(PIN_SCLK,LOW);
	digitalWrite(PIN_CE,HIGH);
	delayMicroseconds(4);
	shiftOutEx(0xBF); //clock Burst Read
	uint8_t ss  = bcd2dec(shiftInEx() & 0x7F);
	uint8_t ii  = bcd2dec(shiftInEx());
	uint8_t hh  = bcd2dec(shiftInEx());
	uint8_t dd  = bcd2dec(shiftInEx());
	uint8_t mm  = bcd2dec(shiftInEx());
	uint8_t day = bcd2dec(shiftInEx());
	uint8_t yy  = bcd2dec(shiftInEx());
	digitalWrite(PIN_CE, LOW);
	delayMicroseconds(4);
	sprintf(clockTime,"%02d%02d%02d%02d%02d%02d",yy,mm,dd,hh,ii,ss);
	sprintf(shortTime,"%02d%02d%02d",hh,ii,ss);
	sprintf(dirTime,  "20%02d%02d%02d",yy,mm,dd);
}

void loop(){

	while (Serial.available())  {
		char data = Serial.read();
		if (data == '\n') {
			if (recv.substring(0, 2) == "on")  {
				capture();
			} else if (recv.substring(0, 4) == "time")  {
				getDateBurst();
				Serial.println("$ time");
				Serial.println(clockTime);
			}
			recv = "";
		} else {
			recv += data;
		}
	}

	if ( digitalRead(BTN_PIN)==LOW ) {
		capture();
	}
}

$ pio run -t upload
→ Ref.Arduino開発環境構築 PlatformIO

■動作確認

ニッケル水素電池からの電源供給により、Arduino nanoを起動し、シャーターボタンを押しても撮影されませんでした。 そこで、電圧・消費電流を計測してみます。
→ Ref.電流計測モジュール INA219


電源回路にニッケル水素電池1.2Vを取り付け、5Vに昇圧して給電した場合
BUS電圧は、3.67Vまで降下し、電流は87.9mAとなり、カメラ撮影に必要な電圧(5V)を確保できていません。


電源回路のニッケル水素電池をリチウムポリマー電池3.7Vに交換してみました。
BUS電圧5.09V、電流139.6mAと十分な出力を発揮し、正常に撮影できました。


作成済みの電源回路には、ニッケル水素電池充電用のモジュールを取り付けてあるので、リチウム電池用の充電回路に仕様変更します。

LiPoバッテリー充電コントローラ(TP4056)
使用するバッテリーに保護回路が付属しない、有無が不明の場合には、保護遮断機能付きの基板を選びましょう。
Ref.LiPoバッテリー充電コントローラ



3.7Vのリチウムポリマー電池を使用するので、稼働表示用の昇圧回路付きLEDは不要となり、また充電用電源供給端子も充電コントローラ基板に付いているので、 電源回路基板にスペースが空いたため、基板左側に電源スイッチを取り付けました。


また、左下にリチウムポリマー電池用に、PHコネクタを取り付けています。

■自作デジカメ 初号機完成

自作カメラ前面

右側の長いコードになっている部分は、シャッターボタンです。 ボタンを押すと、撮影が行われ、画像データをmicroSDカードに保存しおわるまで、左側の赤のLEDが点灯します。

自作カメラ上面

画像中央のType-Cは Arduino nano のUSB端子です。撮影時には不要ですが、プログラムの更新時に使用します。

自作カメラ左側面

各モジュールを Arduino nanoと接続するための、ワイヤーが並んでいます。 端子から外れないように、ワイヤーも自作しています。

自作カメラ右側面

電源オフ時に、クロックモジュールへ電力を供給するための電気二重層コンデンサと、メイン電源のリチウムポリマー電池が収められています。

自作カメラ背面

上部の電源スイッチを押すと、スイッチ右側の緑のLEDが点灯します。

■焦点補正

カメラモジュールの ArduCam Mini 2MP は、M12マウントでレンズの交換も可能です。 レンズはネジ式なので、ネジを左右に回して焦点を補正することができます。
撮影した画像を確認しながら、補正するのは面倒です。 device monitor で撮影画像サイズを確認しながら、補正しましょう。

$ platformio device monitor -p /dev/ttyUSB0 -b 115200
ArduCAM Start!
SPI interface OK.
SD Card detected.
OV2640 detected.

ここで、シャッターボタンを押すか、デバイスモニター上で、"on"[Return]で撮影が行われます。
Capture Done.
The fifo length is :11268
20201026/114302.jpg
Image save OK.
total bytes is :10758

被写体がピンぼけしていると画像サイズは小さく、レンズを回して焦点が合ってくると、画像サイズが増加していきます。
画像サイズがピークになるように調整しましょう。

■撮影

それでは撮影に出掛けましょう。
microSDカードは、16GBや32GBだと機能しない場合もあります。8GBくらいのSDカードを用意するとよいでしょう。


でも、その前に・・・落として壊れたら大変です。ナイロン製のスペーサーに穴を空けて、ストラップ取り付け用にチャームを結びつけています。


ハロウィーン間近のショッピングモールを散策してみました。電球直視は苦手かもしれません。


日没後の微かな街路灯に照らされた世界は得意のようです。


ショーウィンドウの中を撮影してみました。トイカメラ風の柔らかな映像になっています。

 Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
2020.05.28 画像処理 第1回トイカメラ
2020.06.09 画像処理 第2回カメラモジュール制御
2020.06.28 画像処理 第3回リアルタイムクロック
2020.07.08 画像処理 第4回電源回路
2020.10.27 画像処理 第5回自作デジカメ初号機完成
2020.11.10 画像処理 第6回ドーナツデジカメ
2021.05.16 画像処理・基本変換
2021.06.26 Unexpected Maker TinyS2
2021.07.10 M5Stackアプリの移植
2021.09.18 FeatherS2 ESP32-S2


ニーア オートマタ PLAY ARTS改 <ヨルハ 二号 B型 DX版> PVC製 塗装済み可動フィギュア
「NieR:Automata」より、ヨルハ二号B型こと2BがPLAY ARTS改に新たに登場! 高級感の感じられるコスチュームや髪の質感、洗練されたボディバランス、細かなデティールに至るまでこだわり抜かれた逸品。 DX版には通常版のラインナップに加え2Bの随行支援ユニット ポッド042などをはじめ“純白の美しい太刀"白の約定やエフェクトパーツ、自爆モードを再現できる換装用ボディパーツ、シーンに合わせて変えられる顔パーツ2種も付属する豪華な仕様に。 作中のあらゆるシーンを再現することが可能なファン必見の一品となっている。

DIPスイッチで動作電圧を3.3Vと5Vに切り替えられるUNO互換ボード
KEYESTUDIO Plus Board for Arduino UNO R3 with Type-C USB Cable, 3.3V 5V 1.5A Output Current, More Powerful Controller Board USB-シリアルチップ:CP2102 / 動作電圧:5Vまたは3.3V(DIPスイッチ制御)/ 外部電源:DC 6-15V(9V推奨)/ デジタルI / Oピン:14(D0〜D13)/ PWMチャネル:6(D3 D5 D6 D9 D10 D11)/ アナログ入力チャネル(ADC):8(A0-A7)/ DC出力機能の各I / Oポート:20 mA / 3.3Vポートの出力能力:50 mA / フラッシュメモリ:32 KB(うち0.5 KBはブートローダーによって使用されます)/ SRAM:2 KB(ATMEGA328P-AU)/ EEPROM:1 KB(ATMEGA328P-AU)/ クロック速度:16MHz / オンボードLEDピン:D13

エレクトロクッキー Leonardo R3 ATmega32u4 ボード DIY Arduino工作用 - ピンクエディション


Newtonライト2.0 ベイズ統計
ベイズ統計は,結果から原因を推定する統計学です。AIや医療などの幅広い分野で応用されています。その基礎となるのは18世紀に考えだされた「ベイズの定理」です。 この本では,ベイズ統計学のきほんをやさしく紹介していきます。

Interface 2021年10月号
☆特集:~ 格好良さアップ! 機能&信頼性アップ ! ~「 3Dプリンタ & メカ設計入門 」
☆特集2:Pico達人への道…「 C/C++でMicroPython拡張 」


トランジスタ技術 2021年9月号
☆特集:~ 直流・交流・非接触・センサ微小電流の測定ノウハウ ~「電流を正しく測る技術」

トランジスタ技術スペシャル 2021年7月号 宇宙ロケット開発入門
これから開発・活用が進むと期待されている宇宙空間への交通・物流インフラとして、小型・低価格ロケットが注目を集めています。本書では、基本構造から制御メカニズムまで、小型宇宙ロケット開発の基礎知識を実例を交えて解説します。

日経Linux 2021年9月号
【特集1】おうち時間をLinuxデスクトップで楽しむ! Linux環境を作るワザ
【特集2】徹底図解で丸わかり! 「WSL2」入門   Windows 11の新機能を速報!
【特集3】IT自動化ツール AnsibleでWeb導入を自動化
【特集4】ラズパイで楽しむLinuxライフ 「今、会議中」と家族に伝えるプレートをPythonで作ろう


ラズパイマガジン2021年秋号
特集1 サクッと動くパーツ&ライブラリ総覧
特集2 ArduinoライブラリでラズパイPicoを動かす
特集3 古いラズパイをフル活用! Node-REDで 楽しい電子工作
特集4 空気の汚れをラズパイで検知しよう
特集5 ラズパイで楽しむLinuxライフ
特集6 NVIDIAのAIボードが6000円台に!
特集7 M5StickCで始める電子工作 iPhoneからサーボモーターを制御しよう


トランジスタ技術スペシャル 2021年 4月号 No.154「達人への道 電子回路のツボ」
初学者が実用的な電子回路を設計できるようになるためのポイントをまとめました。学校の教科書だけではつかめない基本電子回路やOPアンプ/トランジスタの使い方の実際を、いろいろな視点から解説しています。


Raspberry Pi 3 Model B V1.2 (日本製) 国内正規代理店品
【仕様概要】CPU:ARM 1.2GHz 4コア、GPU:2コア 3D・動画支援、RAM:1GB、ネットワーク:LAN/Wi-Fi/Bluetooth、インターフェース:USB/HDMI/オーディオ/GPIO(UART/I2C/I2S/SPI...)。

ELEGOO Arduino用 Nanoボード V3.0 CH340/ATmega328P、Nano V3.0互換 (3)


ESPr Developer 32
スイッチサイエンス(Switch Science)

協和ハーモネット UL1007 AWG24 耐熱ビニル絶縁電線 リール巻 100m 黒


白光(HAKKO) ダイヤル式温度制御はんだ吸取器 ハンディタイプ FR301-81


サンハヤト TTW-203 テストワイヤ
ブレッドボードとスルーホール間の接続に便利なワイヤですブレッドボード用のオスピンと基板のスルーホール用のバネ性のある端子を組み合わせたテストワイヤです

無水エタノールP 500mlx2個パック(掃除)


ケイバ(KEIBA) マイクロニッパー MN-A04


熱収縮チューブφ1.5
印字無しで綺麗☆ シュリンクチューブ 絶縁チューブ 防水 高難燃性 収縮チューブ (2m, ブラック(黒))


サンハヤト SAD-101 ニューブレッドボード


白光(HAKKO) HEXSOL 巻はんだ 精密プリント基板用 150g FS402-02


【Amazon.co.jp限定】エーモン 電工ペンチ 全長約255mm (1452)


[Amazon限定ブランド]【指定第2類医薬品】PHARMA CHOICE 解熱鎮痛薬 解熱鎮痛錠IP 100錠


Copyright © 2011-2022 Sarako Tsukiyono All rights reserved®.