Browse over 10,000 Electronics Projects

An ARDUINO based JPEG Camera with IR and PIR

An ARDUINO based JPEG Camera with IR and PIR

 

 

Let’s equip Arduino with a serial-interface JPEG Camera with IR and try two applications: the first one saves shots (on a SD-card) at regular intervals while the second uses a PIR sensor to detect intrusions and photograph what happens.

 

Recently, miniaturized cameras with serial communication interface have been launched on the market. Compared to traditional cameras, they offer easier integration with Arduino or other microcontroller-based boards.

It is quite easy to understand that using a composite or USB interface camera requires a considerable effort, on both hardware and software sides. If you decide to bet on a serial interface camera, everything gets easier, because all the prototyping boards (Arduino in particular) and all microcontrollers (Microchip, Atmel etc.) have at least one serial port as a standard feature.

The basic concept of these cameras is that you can send all the setup commands, take screenshots and viewing images through appropriate bytes sequences via their serial port.

In our case, we will use a LinkSprite camera connected to Arduino Uno. Special feature of this camera is the ability to capture images even at night; in fact, it has a brightness sensor and infrared LEDs activated automatically when the detected light falls below a certain threshold (refer to the pictures in these pages to get an idea of how infrared LEDs work).

The camera is capable of capturing high-resolution images, sending them as JPEG through the serial port. It has a four-pin connector where two pins are for the power supply (+ 5V and GND) and two for the serial port (RX and TX).

 

figura B

 

This article will show how to use this camera in two different Arduino projects: the first creates a timing system to take pictures on specific intervals, storing them on the SD-card, while the second is an automatic surveillance system activated only if the special PIR sensor (Passive Infrared Radar) detects a warm object moving in the camera view field. In practice, this second application is a time-lapse video surveillance device that records what happens in a room, activated by the detection of moving people or vehicles. Of course, the PIR detection area must match the same camera angle so that the captured images effectively show the triggering “foe”.

Images will be saved on a Sd-card in JPEG format file and therefore we need a dedicated Sd-card shield (available on Futura Elettronica).

Finally, we will use software libraries (JPEGCamera) developed by us specifically for these camera usage examples.

 

figura C

 

SYSTEM HARDWARE

About the first application, the hardware consists of an Arduino Uno Rev 3 and a SD-card shield used to save images, all connected to the serial camera. The SD shield has four jumpers allowing us to choose which Arduino pin works as “chip select” (you can choose between D4, D8, D9 and D10); for “chip select” we mean the command line that enables the shield.

In our examples, we use D4 therefore we have to insert the corresponding jumper.

The camera has a four-pin connector used for both power and serial interface, and is supplied with a four wires cable (colors: red, brown, purple and gray) ending with female jumpers. Please note that for the serial communication between Arduino and the camera we decided not to use the hardware serial port, but we use the software one (mapped on Arduino D2 and D3 pins); in this way, the software library keeps the hardware port free for debugging.

To connect Arduino to the camera you need to connect the red wire (RXD) to Arduino D3 pin; the brown (TXD) to D2; the gray to the + 5V signal and finally the violet to ground (GND).

For the second application, we must add the PIR sensor to the hardware just described. What we used for our prototype is a device with a certain “intelligence” on-board, which implements two different trigger modes, providing a programmable delay time (between the motion detection and the signal trigger ) ranging from 0.3 to 180 seconds, has a 120 ° detection angle and  7 meters maximum range. The sensor has three pins (TTL 0V – 3.3V output and positive-negative power supply). To connect Arduino you must create a three-wire cable where the power supply positive and negative pins must be connected to Arduino +5V and GND while the TTL output to Arduino D5 pin. Through the output, the device sends the trigger signal caused by PIR sensor movement detection.

 

ARDUINO LIBRARY

JPEGCamera

figura A

 

To allow Arduino managing the JPEG camera we have developed a library (JPEGCamera) that offers all the LinkSprite camera functions: initialization, screenshots capturing and saving images.

The library provides an object called JPEGCamera you can call for complete hardware management.

Begin function initializes  the entire camera management system, a Reset physically resets the camera, a setImageSize  sets the captured image size (you can choose between 160 x 120, 320 x 280 and 640 x 480 pixels). Then there is the takePicture function , who commands the camera to capture the image currently framed (basically is the take screenshot function) and readJpegFileSize, which reads the size (in bytes) of the image file stored. Other functions include the readJpegFileContent, which deals with reading (a packet at a time) the image data and finally stopTakingPictures, which stops the screenshots capture.

 

figura 1

figura 2

 

The readJpegFileContent function deserves a special mention: the data reading process works with a packet (64 bytes, in our case) at a time. To do this it is necessary, each time you call the procedure, to indicate the starting address (the first time is equal to 0, the second 64, the third 128 and so on) and the packet size to be read (in our case, always 64; please note that it is not possible to exceed that value). The function requires as input a byte array where data will be saved; also returns the iSend output parameter, which indicates if the reading operation has been completed.

 

SKETCH EXAMPLE 1

Starting from the beginning, we analyze the first JPEG camera example code, the continuous saving images application (Listing 1).

We include the necessary libraries (JPEGCamera.h, SoftwareSerial.h – since we will use a software serial interface – and SD.h, to save images on the SD-card) and define the size (in bytes) of a single data packet stored (chunk_size; 64 bytes).

Subsequently we define the Arduino pin (D4) we will use as SD-card chip select and some variables that we will use in the program (in particular jpegCamera, used for camera management). Inside the setup function we initialize the board and we call the camera begin command; later we initialize the SD  library indicating that we want to use D4 pin as chip select.



Advertisement1


In the loop function, we manage the real images capture and saving; first we set to capture 320 x 280 pixels pictures and through jpegCamera.takePicture we start capturing the single screenshot.

Afterwards we can define the “save as” filename (e.g. imageXX.jpg where XX ranges from 00 to 99) and through SD.open we can create and open the file in writing mode on the SD-card. Then, through a while loop we handle the image reading and saving process. With jpegCamera.readJpegFileContent we read one jpeg data packet at a time and we can save it by using the File object write function.

When the while loop ends, all the picture bytes have been read and saved; then we execute the File object close  function to close the file handler and jpegCamera.stopTakingPictures to tell the camera to stop capturing images.

Before ending the loop, let’s wait one second and increase the variable that counts the number of pictures taken.

 

 /*********************************************************************
* Inclusione librerie *
*********************************************************************/
#include <JPEGCamera.h>
#include “SoftwareSerial.h”
#include <SD.h>
// Chunk size per salvataggio immagine
#define CHUNK_SIZE 64
/*********************************************************************
* Definizione pin I/O Arduino *
*********************************************************************/
// Led scheda Arduino
const int pinBoardLed = 13;
// Pin Arduino Chip Select SD
const int pinSDChipSelect = 4;
/*********************************************************************
* Variabili programma *
*********************************************************************/
// Oggetto JPEG Camera
JPEGCamera jpegCamera;
// JPEG file
File jpegFile;
// Contatore immagine
byte i = 0;
/*********************************************************************
* Codice programma *
*********************************************************************/
// Inizializzazione Scheda
void setup() {
// Inizializzo I/O
pinMode(pinBoardLed, OUTPUT);
pinMode(pinSDChipSelect, OUTPUT);
// Accendo led Arduino
digitalWrite(pinBoardLed, HIGH);
// Inizializzo JPEG Camera
jpegCamera.begin();
// Init SD
pinMode(10, OUTPUT);
if (!SD.begin(pinSDChipSelect)) {
// Lampeggio led Arduino
for (;;) {
digitalWrite(pinBoardLed, HIGH);
delay(500);
digitalWrite(pinBoardLed, LOW);
delay(500);
}
}
// Spengo led Arduino
digitalWrite(pinBoardLed, LOW);
} // Chiusura funzione setup
// Programma Principale
void loop() {
boolean isEnd = false;
uint16_t address = 0x0000;
uint16_t chunkSize = CHUNK_SIZE;
byte body[CHUNK_SIZE];
// Imposto dimensione immagine
jpegCamera.setImageSize(jpegCamera.ImageSize320x280);
// Reset JPEG Camera
jpegCamera.reset();
// Scatto immagine
jpegCamera.takePicture();
// Identifico nome file
char fileName[12] = “image00.jpg”;
fileName[5] = ((i / 10) + 0x30);
fileName[6] = ((i % 10) + 0x30);
// Apro file
jpegFile = SD.open(fileName, FILE_WRITE);
// Leggo/salvo i dati immagine
isEnd = false;
while(isEnd == false) {
jpegCamera.readJpegFileContent(address, chunkSize, body, &isEnd);
address += chunkSize;
// Salvo i dati sul file
jpegFile.write(body, chunkSize);
}
// Chiudo file
jpegFile.close();
// Fermo immagine
jpegCamera.stopTakingPictures();
// Attesa
delay(1000);
// Prossimo file
i = ((i + 1) % 100);
} // Chiusura funzione loop

 

SKETCH EXAMPLE 2

The second example, besides implementing the functions explained in the previous example, manages a PIR sensor too and therefore can be used as an anti-intrusion detection system prototype.

The algorithm works as follows: cyclically Arduino saves images (max. 5 – image01.jpg, …, image05.jpg – overwriting the oldest cyclically) in a SD-card folder (DIR000, …., DIR999); when it detects an alarm condition the cyclical saving process continues but changing the filename to image06.jpg, …., image10.jpg and increasing the folder name number. Then, everything goes on as before.

The first lines of this software are the same as the previous sketch (libraries inclusion, saving process, Arduino pins definition and variables declaration).

The setup function is similar to that in Listing 1, modified to identify the first free directory (the folder number is indicated by the dirCount variable). Even the loop cycle is quite similar to the previous example; different parts are needed to handle the different folder and file naming during intrusion detection. 

In addition, the last function commands added, check if there is an alarm signal coming from the PIR sensor: if yes, the file saving mechanism explained above is executed.

The sketch of the application is in Listing 2.

/******************************************************************************
* Inclusione librerie *
******************************************************************************/
#include <JPEGCamera.h>
#include “SoftwareSerial.h”
#include <SD.h>
// Chunk size per salvataggio immagine
#define CHUNK_SIZE 64
/******************************************************************************
* Definizione pin I/O Arduino *
******************************************************************************/
// Led scheda Arduino
const int pinBoardLed = 13;
// Pin Arduino Chip Select SD
const int pinSDChipSelect = 4;
// Sensore PIR scheda Arduino
const int pinPIRSensor = 5;
/******************************************************************************
* Variabili programma *
******************************************************************************/
// Oggetto JPEG Camera
JPEGCamera jpegCamera;
// JPEG file
File jpegFile;
// Contatore directory
int dirCount = 0;
// Contatore immagine
byte fileCount = 1;
boolean flagSensorePIR = false;
/******************************************************************************
* Codice programma *
******************************************************************************/
// Inizializzazione Scheda
void setup() {
// Inizializzo I/O
pinMode(pinBoardLed, OUTPUT);
pinMode(pinSDChipSelect, OUTPUT);
pinMode(pinPIRSensor, INPUT);
// Accendo led Arduino
digitalWrite(pinBoardLed, HIGH);
// Inizializzo JPEG Camera
jpegCamera.begin();
// Init SD
pinMode(10, OUTPUT);
if (!SD.begin(pinSDChipSelect)) {
// Lampeggio led Arduino
for (;;) {
digitalWrite(pinBoardLed, HIGH);
delay(500);
digitalWrite(pinBoardLed, LOW);
delay(500);
}
}
// Identifico prima directory libera
for (;;) {
char dirName[7] = “DIR000”;
dirName[3] = ((dirCount / 100) + 0x30);
dirName[4] = (((dirCount % 100) / 10) + 0x30);
dirName[5] = ((dirCount % 10) + 0x30);
// Se directory non esiste
if (SD.exists(dirName) == false)
break;
// Prossima directory
dirCount++;
}
// Spengo led Arduino
digitalWrite(pinBoardLed, LOW);
} // Chiusura funzione setup
// Programma Principale
void loop() {
boolean isEnd = false;
uint16_t address = 0x0000;
uint16_t chunkSize = CHUNK_SIZE;
byte body[CHUNK_SIZE];
// Imposto dimensione immagine
jpegCamera.setImageSize(jpegCamera.ImageSize320x280);
// Reset JPEG Camera
jpegCamera.reset();
// Scatto immagine
jpegCamera.takePicture();
// Identifico prima directory libera
char dirName[7] = “DIR000”;
dirName[3] = ((dirCount / 100) + 0x30);
dirName[4] = (((dirCount % 100) / 10) + 0x30);
dirName[5] = ((dirCount % 10) + 0x30);
// Se directory non esiste
if (SD.exists(dirName) == false)
// Creo directory
SD.mkdir(dirName);
// Identifico nome file
char pathComplete[22] = “DIR000/image00.jpg”;
pathComplete[3] = ((dirCount / 100) + 0x30);
pathComplete[4] = (((dirCount % 100) / 10) + 0x30);
pathComplete[5] = ((dirCount % 10) + 0x30);
pathComplete[12] = ((fileCount / 10) + 0x30);
pathComplete[13] = ((fileCount % 10) + 0x30);
// Apro file
jpegFile = SD.open(pathComplete, FILE_WRITE);
// Leggo/salvo i dati immagine
isEnd = false;
while(isEnd == false) {
jpegCamera.readJpegFileContent(address, chunkSize, body, &isEnd);
address += chunkSize;
// Salvo i dati sul file
jpegFile.write(body, chunkSize);
// Se sensore PIR non rilevato
if (flagSensorePIR == false) {
// Se sensore PIR attivo
if (digitalRead(pinPIRSensor) == HIGH) {
// Prossimo file è il 6 (verrà incrementato in seguito)
fileCount = 5;
flagSensorePIR = true;
}
}
}
// Chiudo file
jpegFile.close();
// Fermo immagine
jpegCamera.stopTakingPictures();
// Attesa
delay(100);
// Se sensore PIR non rilevato
if (flagSensorePIR == false) {
// Se sensore PIR attivo
if (digitalRead(pinPIRSensor) == HIGH) {
// Prossimo file è il 6
fileCount = 6;
flagSensorePIR = true;
}
// Se sensore PIR non attivo
else {
// Prossimo file number
if (fileCount == 5)
fileCount = 1;
else
fileCount++;
}
}
// Se sensore PIR rilevato
else {
// Se salvati 5 file
if (fileCount == 10) {
// Resetto file
fileCount = 1;
// Prossima directory
dirCount++;
// Indico reset PIR
flagSensorePIR = false;
}
else
fileCount++;
}
} // Chiusura funzione loop

 

 


Top