先週試したAdafruit製の「小型TTLシリアルjpegカメラ」での間欠撮影。先週はどうしたわけか同じ画像ばかり撮れてしまい、失敗である。
(チナミに、このカメラのメーカーの「Adafruit」という会社、有名なマッシモ・バンジのTEDの中で紹介されていたことに気付いた。)
https://youtube.com/watch?v=UoBUXOOdLXY%3Ft%3D5m50s
気を取り直して、スケッチを直す。撮影時のカメラのステータスを確認し、撮れていなければ何回でも撮り続ける。
「while(撮れてない)撮る;」
……というわけだ。まあ、万が一ハードウェアエラーなどがあるとループが回り続けるので良くないが、ループが回り続けようが結局のところはモノとしては電源を入れ直す他にどうしようもないので、こんなものだろう。
それと、撮影が終わったらカメラをそのつどリセットすることにした。また、既に存在するファイル名は避けるようにした。こういう時、Arduinoには書式文字列付きの「sprintf」がないので、少し不便だなと思う。
夜明けから日没までの一日の空の雲を撮りたいので、天気予報を見て雨が降らぬ確信を持ってから、昨夜寝る前にベランダにカメラをセットしておいた。朝早く起きるより楽だからだ。夜のうちに1000枚くらい写真が撮れてしまうが、SDカードには余裕があるので大丈夫である。
昼間は用事があるのでカメラの面倒は見れないが、放置しておけば淡々と写真は撮れていく。
で、撮れた写真をWindows Movie Makerに流し込むと、微速撮影動画の一丁上がりだ。
スケッチは次のとおりである。
//
// camera2Web.ino
// 27.07.20(月) 0850~
// 佐藤俊夫
// Adafruit製小型TTLシリアルJPEGカメラ+ETHERNET SHIELD 2で
// 間欠撮影をし、Webでダウンロードできるようにする。
//
#include <Adafruit_VC0706.h>
#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include <Ethernet2.h>
#define CHIPSELECT 4
SoftwareSerial CAMCONNECTION(2, 3);
Adafruit_VC0706 CAM = Adafruit_VC0706(&CAMCONNECTION);
const unsigned long int INTERVAL = 30L * 1000L;
byte MAC[] = { 0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74 };
IPAddress IP(192, 168, 1, 129);
EthernetServer SERVER(80);
EthernetClient CLIENT;
void setup() {
pinMode(10, OUTPUT);
if(!SD.begin(CHIPSELECT)) return;
if(!CAM.begin()) return;
CAM.setImageSize(VC0706_320x240);
Ethernet.begin(MAC, IP);
SERVER.begin();
delay(1000);
}
void loop() {
static unsigned long int prevtime = 0;
char c;
String rstr = "";
// INTERVALおきに写真を撮る
if(millis() >= prevtime + INTERVAL){
prevtime = millis();
takePicture();
}
// Webサーバ
CLIENT = SERVER.available();
if(CLIENT) {
while(CLIENT.connected()) {
if(CLIENT.available()) {
c = CLIENT.read();
rstr += c;
if(rstr.endsWith("\r\n")){
break;
}
}
}
if(rstr.indexOf("IMG") >= 0){
String filename = "DCIM/";
char cfilename[17];
filename.concat(rstr.substring(rstr.indexOf("IMG"), rstr.indexOf("JPG") + 3));
filename.toCharArray(cfilename, 17);
CLIENT.println("HTTP/1.1 200 OK");
CLIENT.println("Content-Type: image/jpg");
CLIENT.println("Connection: close");
CLIENT.println();
File img = SD.open(cfilename);
while(img.available()){
CLIENT.write(img.read());
}
img.close();
}else{
sendform();
}
rstr = "";
delay(1);
// close the connection:
CLIENT.stop();
}
delay(20);
}
void sendform(){
// フォームを送る。
CLIENT.println("HTTP/1.1 200 OK");
CLIENT.println("Content-Type: text/html");
CLIENT.println("Connection: close");
CLIENT.println();
CLIENT.println("<!DOCTYPE HTML>");
CLIENT.println("<html><head></head><body><center>");
File dcim = SD.open("/DCIM");
while(true) {
File imgfile = dcim.openNextFile();
if(!imgfile){
dcim.rewindDirectory();
break;
}
CLIENT.write("<a href=\"");
CLIENT.write(imgfile.name());
CLIENT.write("\">");
CLIENT.write(imgfile.name());
CLIENT.println("</a><br>");
imgfile.close();
}
dcim.close();
CLIENT.println("</center></body></html>");
}
void takePicture(){
static unsigned int pnum = 0;
char filename[] = "DCIM/img0000.jpg";
while(!CAM.takePicture());
do{
filename[8] = '0' + pnum / 1000;
filename[9] = '0' + (pnum / 100) % 10;
filename[10] = '0' + (pnum / 10) % 10;
filename[11] = '0' + pnum % 10;
pnum ++;
}while(SD.exists(filename));
if(pnum > 9999) pnum = 0;
File imgFile = SD.open(filename, FILE_WRITE);
uint16_t jpglen = CAM.frameLength();
pinMode(8, OUTPUT);
while (jpglen > 0) {
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpglen);
buffer = CAM.readPicture(bytesToRead);
imgFile.write(buffer, bytesToRead);
jpglen -= bytesToRead;
}
while(!CAM.reset());
imgFile.close();
}