The last exercise of the semester regarding the integration of technology was the development of the Serendipity Camera, one of the main elements of The Secret Garden Toolkit. Called this way because of the intentional randomness I wanted to give to the pictures, the camera is composed of a Arduino Uno, an SD shield from Snootlab and a TTL serial JPG camera from Adafruit. Designed to be used in security systems, the camera streams video but it can also take snapshots of that video in color and transmit them over the TTL serial link to the SD card, which is actually what it is programed to do in the present example. The maximum resolution of the pictures is 640x480, which is quite low, and the accuracy of the color rather poor. However, it was the most suitable and affordable small camera I could find in order to construct the system myself, which was the real objective.
It takes a picture every 30 seconds, helping children to randomly document their explorations. The intention was to offer them also a shutter button so they could take voluntary pictures (as explained in the flow chart). Nevertheless, when I built the camera and found out that it took up to 15 seconds to save a single picture, I decided to skip this option and stick to the automatic ones. Clearly something to look at in an eventual second version of the design.
As for the code, it is made to have the camera first take a snapshot test, giving you information through the serial port about wether or not the camera has been found, the size of the picture that is going to be taken and the absence of the SD card (in case you have forgotten to put it in). After that and having defined a subroutine (a sequence of program instructions, packaged as a unit, that take the actual snapshot) it enters in a loop of 1 picture every 30 seconds by calculating the elapsed time since the last show. Pictures are saved in the memory card with names created by a piece of code that works as an incremental filename generator.
The TTL camera
The SD shield
Flow chart representing the original intentions for the camera
Layout of the current circuit
Code with self explanations:
#include <Adafruit_VC0706.h>
#include <SD.h>
#include <SoftwareSerial.h>
#define chipSelect 10
// Using SoftwareSerial (Arduino 1.0+) or NewSoftSerial (Arduino 0023 & prior):
#if ARDUINO >= 100
// On Uno: camera TX connected to pin 2, camera RX to pin 3:
SoftwareSerial cameraconnection = SoftwareSerial(2, 3);
#else
NewSoftSerial cameraconnection = NewSoftSerial(2, 3);
#endif
Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection);
unsigned long timeLastShot; //extended size variables for number storage, so it can store the number of miliseconds that passed since it took last picture
void setup() {
Serial.begin(9600);
Serial.println("VC0706 Camera snapshot test");
// See if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
// Try to locate the camera
if (cam.begin()) {
Serial.println("Camera Found:");
} else {
Serial.println("No camera found?");
return;
}
// Print out the camera version information
char *reply = cam.getVersion();
if (reply == 0) {
Serial.print("Failed to get version");
} else {
Serial.println("-----------------");
Serial.print(reply);
Serial.println("-----------------");
}
// Set the picture size - you can choose one of 640x480, 320x240 or 160x120
// Remember that bigger pictures take longer to transmit!
cam.setImageSize(VC0706_640x480); // biggest
//cam.setImageSize(VC0706_320x240); // medium
//cam.setImageSize(VC0706_160x120); // small
// read the size back from the camera
uint8_t imgsize = cam.getImageSize();
Serial.print("Image size: ");
if (imgsize == VC0706_640x480) Serial.println("640x480");
if (imgsize == VC0706_320x240) Serial.println("320x240");
if (imgsize == VC0706_160x120) Serial.println("160x120");
take_save_photo(); //take photo for the first time.
}
void loop() {
if(millis()- timeLastShot > 30000 ){ // if 30 seconds passed since last shot...
take_save_photo(); //take interval photo.
}
}
void take_save_photo() { //subfunction
timeLastShot = millis(); // remember when it took photo last time
// Try to locate the camera
if (cam.begin()) {
Serial.println("Camera Found:");
} else {
Serial.println("No camera found?");
return;
}
// Set the picture size
cam.setImageSize(VC0706_640x480); // biggest
//cam.setImageSize(VC0706_320x240); // medium
//cam.setImageSize(VC0706_160x120); // small
Serial.println("Snap in 3 secs...");
delay(3000);
if (! cam.takePicture())
Serial.println("Failed to snap!");
else
Serial.println("Picture taken!");
char filename[13];
strcpy(filename, "IMAGE00.JPG");
for (int i = 0; i < 100; i++) {
filename[5] = '0' + i/10;
filename[6] = '0' + i%10;
//filename[7] = '0' + i%100;
//filename[8] = '0' + i%1000;
// create if does not exist, do not open existing, write, sync after write
if (! SD.exists(filename)) {
break;
}
}
// Open the file for writing
File imgFile = SD.open(filename, FILE_WRITE);
// Get the size of the image (frame) taken
uint16_t jpglen = cam.frameLength();
Serial.print("Storing ");
Serial.print(jpglen, DEC);
Serial.print(" byte image.");
int32_t time = millis();
pinMode(8, OUTPUT); //snootlab SD shield: pin 8
// Read all the data up to number of bytes!
byte wCount = 0; // For counting number of writes
while (jpglen > 0) {
// read 32 bytes at a time;
uint8_t *buffer;
uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups! -----> it didn't really work
buffer = cam.readPicture(bytesToRead);
imgFile.write(buffer, bytesToRead);
if(++wCount >= 64) { // Every 2K, give a little feedback so it doesn't appear locked up -------> incremental ellipsis (puntos suspensivos)
Serial.print('.');
wCount = 0;
}
//Serial.print("Read "); Serial.print(bytesToRead, DEC); Serial.println(" bytes");
jpglen -= bytesToRead;
}
imgFile.close();
time = millis() - time;
Serial.println("done!");
Serial.print(time); Serial.println(" ms elapsed"); //time it took to save the picture
}
Añadir un comentario