1

I'm using a water level sensor with two outputs, a 5V fan and a water pump. Here's the wiring project.

What I want to do with this project is:

  1. When the water reaches 2 cm, then the water pump is on while the fan is off.
  2. When the water is less than 2 cm, then the water pump is off and fan is on.

The problem is, when the water is below the threshold, the sensor reading is quite unstable, thus making the relay switching too fast (see the video).

How to eliminate this problem?

#include <Wire.h>
#include <Blynk.h>
#include <LiquidCrystal_I2C.h>
#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

//Initialize the LCD display LiquidCrystal_I2C lcd(0x27, 16, 2); char auth[] = "xxx";//Enter your Auth token char ssid[] = "xxx";//Enter your WIFI name char pass[] = "xxx";//Enter your WIFI password BlynkTimer timer;

#define pinSensor A0 #define PIN_RELAY_1 D3 #define PIN_RELAY_2 D4 const int startThreshold = 2; // pumping shall start at startThreshold [cm] and above const int stopThreshold = 1; // pumping shall start at stopThreshold [cm] and below

int sensorValue = 0; // sensor reading integer float tinggiAir = 0; // height of water float sensorVoltage = 0; // voltage sensor int nilaiMax = 686; // max value of sensor after fully drowning it in water float panjangSensor = 4.0 ; // sensor's height in cm

enum StatusType {CHECKLEVEL, LEVELHIGH, PUMPING}; StatusType status = LEVELHIGH; // Let's start with LEVELHIGH to check level and set the display correctly

void setup() { Serial.begin(115200); lcd.begin(); Blynk.begin(auth, ssid, pass, "blynk.cloud", 80); lcd.backlight(); pinMode(PIN_RELAY_1, OUTPUT); pinMode(PIN_RELAY_2, OUTPUT); digitalWrite(PIN_RELAY_1, LOW); digitalWrite(PIN_RELAY_2, LOW); lcd.setCursor(0, 0); lcd.print("Water level"); lcd.setCursor(4, 1); lcd.print("Monitoring"); delay(1000); lcd.clear(); timer.setInterval(100L, wLevel); } void wLevel() { sensorValue = analogRead(pinSensor); tinggiAir = sensorValuepanjangSensor/nilaiMax; sensorVoltage = sensorValue5.0/686; }

void loop() { Blynk.run(); timer.run(); handleStatus(); }

void handleStatus() { switch (status) { case CHECKLEVEL: // Wait for level above threshold if (tinggiAir >= startThreshold) { // if wlevel more than startThreshold [cm], then status = LEVELHIGH; Serial.println("LEVELHIGH"); } break; case LEVELHIGH: levelIsHigh(); break; case PUMPING: if (tinggiAir < stopThreshold) { // if wlevel less than stopThreshold [cm] (use hysteresis!) then levelIsLowAgain(); status = CHECKLEVEL; Serial.println("CHECKLEVEL"); } break; } displayValues(); }

void displayValues() { static int oldSensorValue = -1; // variable untuk menampung nilai baca dari sensor dalam bentuk integer float oldTinggiAir = -1; // variabel untuk menampung ketinggian air float oldSensorVoltage = -1; // untuk menampung nilai ketinggian air

if (oldSensorValue != sensorValue || oldTinggiAir != tinggiAir || oldSensorVoltage != sensorVoltage) { Serial.print("Sensor Value = "); Serial.println(sensorValue); Serial.print("Sensor Voltage = "); Serial.println(sensorVoltage); Serial.print("Tinggi Air = "); Serial.println(tinggiAir); Serial.println(); // Display ke LCD lcd.setCursor(0, 0); lcd.print("WLevel:"); lcd.print(tinggiAir); lcd.setCursor(12, 0); lcd.print("cm"); oldSensorValue = sensorValue; oldTinggiAir = tinggiAir; oldSensorVoltage = sensorVoltage; Blynk.virtualWrite(V0, tinggiAir); } } void levelIsHigh() { digitalWrite(PIN_RELAY_1, HIGH); digitalWrite(PIN_RELAY_2, LOW); lcd.setCursor(0, 1); lcd.print("F:OFF P:ON"); Blynk.logEvent("wlevel", "wLevel more than 2cm"); status = PUMPING; Serial.println("PUMPING"); }

void levelIsLowAgain() { digitalWrite(PIN_RELAY_1, LOW); digitalWrite(PIN_RELAY_2, HIGH); lcd.setCursor(0, 1); lcd.print("F:ON P:OFF"); status = CHECKLEVEL; Serial.println("CHECKLEVEL"); }

jsotola
  • 1,554
  • 2
  • 12
  • 20
jeonsann
  • 11
  • 3

1 Answers1

5

The problem lies in the specification itself. According to your rules, what should the pump do if the water level is exactly 2 cm? Granted, there is no such thing as an exact physical measurement. But you have to realize that every measurement system is noisy. Noise is a fact of life you have to cope with when playing with hardware. You may try to make it smaller (by filtering), but it will always be there. Now the question is: what should the pump do if the difference between the water level and the required 2 cm is less than the noise amplitude?

The standard solution, as suggested by KIIV, is to implement some hysteresis. You define two thresholds: one for turning the pump on and another, lower threshold for turning it off. When the readings are in between these two thresholds, you live the pump alone, in whatever state it was before.

In pseudo-code:

const float low_threshold = 1.9;
const float high_threshold = 2.1;

void loop() { float water_level = get_level_reading(); if (water_level < low_threshold) turn_pump_off(); if (water_level > high_threshold) turn_pump_on(); }

If the difference between these thresholds is larger than the noise amplitude, noise will not disturb your system.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81