Arduino Nano Motion Detection With OV7670 and Dual ESP8266 Setup

by Breadboard_tinker_2024_ in Circuits > Microcontrollers

193 Views, 1 Favorites, 0 Comments

Arduino Nano Motion Detection With OV7670 and Dual ESP8266 Setup

IMG_4732.JPG
IMG_4712 (2).JPG
IMG_4710.JPG
IMG_4711.JPG
IMG_4712 (2).JPG
IMG_4720.JPG

This project involves building a movement detection system using computer vision, powered by an Arduino Nano and two Node MCUs as microcontrollers. The system leverages basic computer vision techniques to detect motion in almost real-time, making it an ideal solution for small-scale monitoring or security applications. Despite using minimal hardware, it efficiently processes video data and communicates between the microcontrollers for accurate detection. The combination of the Arduino Nano and Node MCUs offers both simplicity and flexibility,

Supplies

IMG_4711 (1).JPG

1 x Arduino Nano

2 x Node MCU

1 x ov7670 camera(no FIFO)

1 x breadboard

1 x led

1 x TXSO108E level shifter(any high speed level shifter should work)

1 x normal level shifter(any thing would work)

Computer (with Arduino IDE installed)

jumper wire(male to male and female to female)

2 x 4.2k resistors

1 x USB cable for Nano

2 USB cables for Node MCU

Connection

connections


Connections for Arduino Uno/Nano

OV7670 connections:

VSYNC - PIN2

XCLCK - PIN3 (must be level shifted from 5V -> 3.3V)

PCLCK - PIN12

SIOD - A4 (I2C data) - 4.2K resistor to 3.3V

SIOC - A5 (I2C clock) - 4.2K resistor to 3.3V

D0..D3 - A0..A3 (pixel data bits 0..3)

D4..D7 - PIN4..PIN7 (pixel data bits 4..7)

3.3V - 3.3V

RESET - 3.3V

GND - GND

PWDN - GND


Connections between Arduino and Node MCU1

Arduino Node MCU1

TX (level shifter TXSO108E) RX

Ground (level shifter TXSO108E) Ground

5V (level shifter TXSO108E)

connections between Node MCU1 and Node MCU2

Node MCU1 Node MCU1

TX RX

Ground Ground

3.3v 3.3v


Camera to LED

Camera LED

HS(HREF) +


Arduino to LED

Arduino LED

G G

Libraries and Arduino IDE

For this we will be using Arduino ide 1.8.18 (I get what you are probably thinking right now) but this is for a reason. since we are using the Live Ov7670 library which was created by Indrek Luuk and the good thing about this library is that the creator of the library also made a tool which can take advantage of the library. So basically this tool allows you to display the captured images on the screen (although this feature wont be used in the movement detection project its still petty cool to play around with and most importantly for debugging. But Arduino discontinued the functionality of custom libraries over time. So we have to stick to a old ide version for now.


Get Arduino ide 1.8.18 from here


Download the libraries

The library used in this project was made by Indrekluuk.

In order to download the Live OV7670 library you have to visit here then


step1

visit the GitHub page i gave.

Step2



Download ZIP.

Step3



extract the ZIP

Step4

copy the libraries and past them in the Arduino libraries folder

Step5

open the Live ov7670 file

got to src

then click the Arduino file

The Code of Arduino

Screenshot (4).png

Step1

click on ExampleUart.cpp file in the ide"

Step2

Change UART mode to 2

Step 3

open step.h


Look at the comment section for instructions

replace #if UART_MODE==2
const uint16_t lineLength = 160;
const uint16_t lineCount = 120;
const uint32_t baud = 115200;
const ProcessFrameData processFrameData = processGrayscaleFrameBuffered;
const uint16_t lineBufferLength = lineLength;
const bool isSendWhileBuffering = true;
const uint8_t uartPixelFormat = UART_PIXEL_FORMAT_GRAYSCALE;
CameraOV7670 camera(CameraOV7670::RESOLUTION_QQVGA_160x120, CameraOV7670::PIXEL_YUV422, 17);
#endif


with


#if UART_MODE==2
const uint16_t lineLength = 40;
const uint16_t lineCount = 40;
const uint32_t baud = 31250;
const ProcessFrameData processFrameData = processGrayscaleFrameBuffered;
const uint16_t lineBufferLength = lineLength;
const bool isSendWhileBuffering = true;
const uint8_t uartPixelFormat = UART_PIXEL_FORMAT_GRAYSCALE;
CameraOV7670 camera(CameraOV7670::RESOLUTION_QQVGA_160x120, CameraOV7670::PIXEL_YUV422, 17);
#endif

Code for Node MCU 1

This Code handles the data for noise reduction.

Step1

Download the file attached and upload it to a Node MCU.


Note: make sure to disconnect the RX and TX pins before uploading and then reconnecting them.


Note: if you have a question feel free to ask it in the comments.


The code



#define UART_MODE 2 // Ensure this matches the transmitter configuration

#if UART_MODE == 2
const uint32_t baud = 31250; // Set baud rate to match transmitter
#endif

const uint16_t lineLength = 40;
const uint16_t lineCount = 40;
const uint32_t frameBufferSize = lineLength * lineCount; // Frame size (40x40 = 1600 bytes)

uint8_t frameBuffer[frameBufferSize]; // Buffer to store frame data
uint32_t frameSums[frameBufferSize] = {0}; // Array to hold sum of pixel values
uint8_t frameCount = 0; // Counter for the number of frames received
uint8_t averageAverages[frameBufferSize] = {0}; // Array to store average averages
uint8_t averageAverageCount = 0; // Counter for average averages

void setup() {
// Initialize serial communication
Serial.begin(baud); // Use the correct baud rate for the external device
Serial.setTimeout(200); // Optional: Set a timeout for serial read operations

Serial.println("Receiver ready.");
}

void loop() {
static uint32_t byteIndex = 0; // Index to track received bytes

// Check if there is available data to read
while (Serial.available()) {
uint8_t rawByte = Serial.read(); // Read incoming byte

// Decode the pixel byte by discarding the last bit
uint8_t pixelValue = rawByte >> 1;

// Store the decoded pixel value in the frame buffer
frameBuffer[byteIndex] = pixelValue;
byteIndex++;

// If the full frame is received
if (byteIndex >= frameBufferSize) {
// Process the received frame data
Serial.println("Frame received:");

// Update frame sums
for (uint32_t i = 0; i < frameBufferSize; i++) {
frameSums[i] += frameBuffer[i];
}
frameCount++;

// If four frames have been received, calculate and store averages
if (frameCount >= 4) {
calculateAndStoreAverage();
// Reset frame sums for the next batch
memset(frameSums, 0, sizeof(frameSums));
frameCount = 0;
}

// Reset byteIndex for the next frame
byteIndex = 0;
}
}
}

// Function to calculate and store average pixel values
void calculateAndStoreAverage() {
Serial.println("Average pixel values for the current batch:");
for (uint32_t i = 0; i < frameBufferSize; i++) {
uint8_t averageValue = frameSums[i] / 4; // Calculate average for the current batch
Serial.print(averageValue, DEC); // Print average pixel value in decimal
Serial.print(" ");
averageAverages[i] += averageValue; // Store the average value for this pixel
if ((i + 1) % lineLength == 0) {
Serial.println(); // Newline after each row
}
}
averageAverageCount++; // Increment the average average count

// If two average averages have been calculated, print the final average
if (averageAverageCount >= 2) {
printFinalAverages();
// Reset average averages for the next set
memset(averageAverages, 0, sizeof(averageAverages));
averageAverageCount = 0;
}
}

// Function to print the final average of averages
void printFinalAverages() {
Serial.println("Final average of averages:");
for (uint32_t i = 0; i < frameBufferSize; i++) {
uint8_t finalAverage = averageAverages[i] / 2; // Calculate final average
Serial.print(finalAverage, DEC); // Print final average pixel value in decimal
Serial.print(" ");
if ((i + 1) % lineLength == 0) {
Serial.println(); // Newline after each row
}
}
}


Node MCU 2 Code

This MCU handles the actual motion detection task


This code works by substracting a frame from another frame the farer the result is to 0 the higher the movement is.

currently if the difference is over 40 the program will count it as movement which you can adjust with



const uint8_t movementThreshold = 40


The code


#define UART_MODE 2 // Ensure this matches the transmitter configuration

#if UART_MODE == 2
const uint32_t baud = 31250; // Set baud rate to match transmitter
#endif

const uint16_t lineLength = 40;
const uint16_t lineCount = 40;
const uint32_t frameBufferSize = lineLength * lineCount; // Frame size (40x40 = 1600 bytes)

uint8_t frameBuffer[frameBufferSize]; // Buffer to store current frame data
uint8_t previousFrameBuffer[frameBufferSize]; // Buffer to store previous frame data
uint32_t frameSums[frameBufferSize] = {0}; // Array to hold sum of pixel values
uint8_t frameCount = 0; // Counter for the number of frames received
uint8_t averageAverages[frameBufferSize] = {0}; // Array to store average averages
uint8_t averageAverageCount = 0; // Counter for average averages
const uint8_t movementThreshold = 40; // Threshold to detect movement (you can adjust this)

void setup() {
// Initialize serial communication
Serial.begin(baud); // Use the correct baud rate for the external device
Serial.setTimeout(200); // Optional: Set a timeout for serial read operations

Serial.println("Receiver ready.");
}

void loop() {
static uint32_t byteIndex = 0; // Index to track received bytes

// Check if there is available data to read
while (Serial.available()) {
uint8_t rawByte = Serial.read(); // Read incoming byte

// Decode the pixel byte by discarding the last bit
uint8_t pixelValue = rawByte >> 1;

// Store the decoded pixel value in the frame buffer
frameBuffer[byteIndex] = pixelValue;
byteIndex++;

// If the full frame is received
if (byteIndex >= frameBufferSize) {
// Process the received frame data
Serial.println("Frame received:");

// Detect movement by comparing with the previous frame
detectMovement();

// Store current frame as previous for the next iteration
memcpy(previousFrameBuffer, frameBuffer, frameBufferSize);

// Reset byteIndex for the next frame
byteIndex = 0;
}
}
}

// Function to detect movement by comparing the current frame to the previous frame
void detectMovement() {
Serial.println("Movement detected at positions:");

bool movementDetected = false;
for (uint32_t i = 0; i < frameBufferSize; i++) {
// Calculate the absolute difference between the current and previous frame
uint8_t diff = abs(frameBuffer[i] - previousFrameBuffer[i]);

// If the difference exceeds the threshold, consider it as movement
if (diff > movementThreshold) {
Serial.print(i); // Print the index of the pixel with detected movement
//Serial.print(" ");
movementDetected = true;

// You can also print the difference value if needed
Serial.print("(Diff: ");
Serial.print(diff, DEC);
//Serial.print(") ");
}

// Optional: Print newline after each row for clarity
if ((i + 1) % lineLength == 0) {
Serial.println();
}
}

if (!movementDetected) {
Serial.println("No significant movement detected.");
}
}



Step1

Download the file attached and upload it to a Node MCU.

Note: make sure to disconnect the RX and TX pins before uploading and then reconnecting them.


Note: if you have a question feel free to ask it in the comments.

Finalizing

Step2

plug in everything except Node MCU1(because it receives power via Node MCU 2)


Step1

open the serial monitor on Node MCU2 (the first few statement may not be correct because the camera take time to adjust ) Wait until you get 3 - 4 outputs typically 1 minute - 2 minute then you should see a reliable output.

if there is noise(the outputs going crazy while nothing is moving o the camera is still and even after 3 minutes if this

check for loose connections still if the issue persists move on to step3.

Step 3(debugging)

disconnect Node MCU 2 and connect Node MCU 1 to the Seria1 monitor then u should be seeing that the a string or a 40x40 array being printed on the same frequency the led turns on and off if it is so then use shorter wires and if this doesn't fix it then move on to step 4.


if you don't see the led blink at the rate the serial monitor prints then use shorter wires with the Arduino.

if you see no led blinks recheck the wiring of the camera or tighten it

if you see nothing in the serial monitor move on to step4

Step4(even more debugging)

if you are here then comment the error and the symptoms in the comment section.

I will try by best to help you.



Finalizing

IMG_4713.JPG
IMG_4713.JPG
IMG_4714.JPG