Arduino UNO-Based Water Detection and Motor Control System with SD Logging
View and Edit Project In Cirkit Designer
Circuit Documentation
Summary
This circuit is designed to monitor water levels using multiple water sensors and to take action based on the sensor readings. It includes an Arduino UNO microcontroller for processing sensor data and controlling other components. The circuit features a power management system using a TP4056 charger module, a DC-DC boost converter, and an 18650 Li-Ion battery. It also includes a motor driver (L298N) to control two DC motors, piezo speakers for audible alerts, and an SD module for data logging. The system is designed to be responsive to water detection and to manage power effectively.
Component List
Microcontroller
- Arduino UNO: A microcontroller board based on the ATmega328P, with digital and analog I/O pins.
Power Sources
- 18650 Li-Ion Battery: A rechargeable battery providing power to the circuit.
- TP4056: A lithium battery charger module with battery protection.
- DC-DC Boost Converter: Steps up voltage from the battery to a higher level required by certain components.
Sensors
- Water Sensors: Detect the presence of water and provide a signal to the Arduino.
Actuators
- DC Motors: Perform mechanical actions in response to control signals from the motor driver.
- Piezo Speakers: Emit audible tones when activated by the Arduino.
Motor Driver
- L298N DC Motor Driver: Controls the direction and speed of the DC motors.
Storage
- SD Module: Used for data logging onto an SD card.
Protection and Filtering
- Diodes: Prevent reverse current flow and protect the circuit.
- Ceramic Capacitor: Filters out voltage spikes and noise.
Wiring Details
Arduino UNO
- GND: Connected to the ground plane of the circuit.
- 5V: Powers the SD module.
- Vin: Receives power from the battery through the TP4056 and diodes.
- A0, A1, A2: Connected to water sensors for analog signal reading.
- A3: Connected to a ceramic capacitor for voltage sensing.
- D2 - D13: Control signals for the SD module, piezo speakers, and motor driver.
18650 Li-Ion Battery
- Positive: Connected to the TP4056 module, DC-DC boost converter, and Arduino Vin through diodes.
- Negative: Connected to the ground plane.
TP4056
- B+ and B-: Connected to the battery.
- OUT+ and OUT-: Power output to the Arduino and SD module.
DC-DC Boost Converter
- VIN+ and VIN-: Input from the battery.
- VOUT+ and VOUT-: Output to the motor driver and ground plane.
Water Sensors
- Signal: Connected to Arduino analog pins (A0, A1, A2).
- VCC: Powered by Arduino digital pins (D7, D6, D5).
- GND: Connected to the ground plane.
DC Motors
- Pin 1 and Pin 2: Controlled by the L298N motor driver.
Piezo Speakers
- Pin1: Connected to Arduino digital pins (D8, D4, D13) for tone generation.
- Pin2: Connected to the ground plane.
L298N DC Motor Driver
- GND: Connected to the ground plane.
- 5V: Powered by the DC-DC boost converter.
- IN1 - IN4: Control signals from Arduino digital pins (D9 - D12).
- OUT1 - OUT4: Outputs to DC motors and ground plane.
SD Module
- CS, SCK, MOSI, MISO: SPI interface connected to Arduino digital pins (D5, D3, D2, D4).
- VCC: Powered by the Arduino 5V pin.
- GND: Connected to the ground plane.
Diodes
- Cathode: Connected to the positive terminal of the battery.
- Anode: Connected to the Arduino Vin and motor driver 5V input.
Ceramic Capacitor
- Pin0: Connected to the ground plane.
- Pin1: Connected to Arduino analog pin A3 for voltage sensing.
Documented Code
#include <SD.h>
const int waterSensorPins[3] = {A0, A1, A2};
const int piezoPins[3] = {8, 4, 13};
const int motor1Pin1 = 9;
const int motor1Pin2 = 10;
const int motor2Pin1 = 11;
const int motor2Pin2 = 12;
const int waterSensorPowerPins[3] = {7, 6, 5};
const int voltageCapPin = A3;
const int sdChipSelect = 5;
const int waterThreshold = 500;
const int debounceDelay = 200;
const int hysteresis = 20;
unsigned long lastDebounceTime[3] = {0, 0, 0};
int lastSensorState[3] = {LOW, LOW, LOW};
unsigned long lastActivityTime = 0;
const unsigned long idleTimeLimit = 8000; // 8 seconds to simulate watchdog timer
void setup() {
for (int i = 0; i < 3; i++) {
pinMode(waterSensorPins[i], INPUT);
pinMode(waterSensorPowerPins[i], OUTPUT);
digitalWrite(waterSensorPowerPins[i], HIGH);
pinMode(piezoPins[i], OUTPUT);
}
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(motor2Pin1, OUTPUT);
pinMode(motor2Pin2, OUTPUT);
pinMode(voltageCapPin, INPUT);
Serial.begin(9600);
digitalWrite(sdChipSelect, LOW);
if (!SD.begin(sdChipSelect)) {
Serial.println("Error initializing SD card!");
logError("SD card initialization failed");
}
digitalWrite(sdChipSelect, HIGH);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - lastActivityTime >= idleTimeLimit) {
resetSystem(); // Simulate watchdog reset if idle for too long
lastActivityTime = currentMillis;
}
lastActivityTime = currentMillis;
int waterDetectedCount = 0;
for (int i = 0; i < 3; i++) {
int reading = digitalRead(waterSensorPins[i]);
if (reading != lastSensorState[i]) {
lastDebounceTime[i] = currentMillis;
}
if ((currentMillis - lastDebounceTime[i]) > debounceDelay) {
if (reading == HIGH) {
int waterValue = analogRead(waterSensorPins[i]);
if (waterValue > waterThreshold) {
waterDetectedCount++;
}
}
}
lastSensorState[i] = reading;
}
int toneFrequency = 0;
switch (waterDetectedCount) {
case 1:
toneFrequency = 1000;
break;
case 2:
toneFrequency = 1500;
break;
case 3:
toneFrequency = 2000;
break;
default:
toneFrequency = 0;
break;
}
for (int i = 0; i < 3; i++) {
if (toneFrequency > 0) {
tone(piezoPins[i], toneFrequency);
} else {
noTone(piezoPins[i]);
}
}
int voltageCapValue = analogRead(voltageCapPin);
if (voltageCapValue > 512 + hysteresis) {
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
} else if (voltageCapValue < 512 - hysteresis) {
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
delay(1000); // To simulate low-power mode by slowing down the loop
}
void logError(const char* errorMsg) {
Serial.print("Persistent Error: ");
Serial.println(errorMsg);
digitalWrite(sdChipSelect, LOW);
File logFile = SD.open("error_log.txt", FILE_WRITE);
if (logFile) {
logFile.print("Error: ");
logFile.println(errorMsg);
logFile.close();
Serial.println("Error logged to SD card.");
} else {
Serial.println("Failed to write to SD card.");
}
digitalWrite(sdChipSelect, HIGH);
}
void takeCorrectiveAction(const char* errorType) {
Serial.print("Taking corrective action for ");
Serial.println(errorType);
if (strcmp(errorType, "voltage") == 0) {
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
} else if (strcmp(errorType, "sensor") == 0) {
for (int i = 0; i < 3;