Turn on Peristaltic pump based on PH reading

I am completing a small project, where I take a PH reading and use that value to turn on one of two pumps.

So if PH reading is less than PH6 turn on a PH UP pump, and if reading is greater than PH6 turn on a PH DOWN pump with an allowable range of 1. So it can go to 5 and 7 before it turns on.

I am using two peristaltic pumps, connected to a 12v DC power source using an L298N driver.

The problem is I don’t know where to start to enter the code, I need to insert it in to the code I have for the PH probe.

Currently I have used the code with the probe and added an LCD, and all is good up to that point.

Would anyone have any advice on what the starting point is.

This is the probe I’m using:

I have to define the pins as an output, but then where do I go.

For now I want to get to a stage of where I can turn it on and off, then work from there.

I would greatly appreciate some help.

// PH Probe and LCD 
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

float calibration = 22.99;  //change this value to calibrate
const int analogInPin = A0;
int sensorValue = 0;
unsigned long int avgValue;
float b;
int buf[10], temp;

void setup() {
  lcd.begin(16, 2);
  lcd.print("PH Calibrating");
  delay(5000);
  lcd.clear();
  Serial.begin(9600);
}
void loop() {
  for (int i = 0; i < 10; i++) {
    buf[i] = analogRead(analogInPin);
    delay(30);
  }
  for (int i = 0; i < 9; i++) {
    for (int j = i + 1; j < 10; j++) {
      if (buf[i] > buf[j]) {
        temp = buf[i];
        buf[i] = buf[j];
        buf[j] = temp;
      }
    }
  }
  avgValue = 0;
  for (int i = 2; i < 8; i++)
    avgValue += buf[i];
  float pHVol = (float)avgValue * 5.0 / 1024 / 6;
  float phValue = -5.70 * pHVol + calibration;
  Serial.print("PH = ");
  Serial.println(phValue);
  delay(500);
lcd.begin(16, 2);
lcd.print("PH = ");
lcd.print(phValue);
}

I'm sure I don't see the problem.

It looks like you could do the turning off and on right when you shave figured out the pH.

  Serial.print("PH = ");
  Serial.println(phValue);

// so... 

  if (phValue > 7) {
    turnOnPump1();
    turnOffPump2();
  }

  if (phValue < 5) {
    turnOnPump2();
    turnOffPump1();
  }

This is probably not exactly why you want, as it implies one or the other pump will always be running. But that place in your program is a good insertion point for your logic and control statements for the pumps.

HTH

a7

the code collects 10 samples, sorts them and then uses the middle 6.

gotta wonder how much different that result is from a simple average? are grossly out of range values expected

Something like this, after calculating PH?

digitalWrite(PH_UP_Pin, phValue < 5.5);
digitalWrite(PH_DOWN_Pin, phValue > 6.5);

Pumps will be OFF between PH 5.5 and 6.5. You could "tighten it up" if you wish, say between 5.7 and 6.2.

Thanks Alto, you replied very quick, I will look at it later tomorrow, i didn't get a chance today, was trying to crimp custom length cables to attach to LCD, had a mare of a job, but all working now.
Again thanks for the pointers, I'm sure I will have more questions over the next day or two.

It's a cheap probe, and I got it for nothing of a friend, it's for a college project so I'm not overly worried. At the minute I have it in PH7 solution and it's around 6.99.

Are you saying increase the range number of samples to increase the accuracy.

I'm an older student and just want to get it working and out of the way. The last time I was in college there were none of these devices so readily or cheaply available, the internet was only starting off.

Thanks JCA34F. I am going to look at it later today, I didn't get a chance yet. Hopefully i can get it going.

no. i don't believe any of your averaging really does anything.

possibly use a simple running average

avg += (samp - avg) / N; // N > 1

@a1980 - the sketch below is a temperature control demo for a/c and heating.

It use hysteresis at both the cooling end and the heating end. Thus it is a variation and extension of @JCA34F's idea of turning on and off the pumps.

The slide fader is temperature. The red LED is heating, the blue LED is cooling. This seems analogous to you ability to raise or lower the pH.

The essential lines that do that are


  if (temperature  > 70) digitalWrite(coolingControl, HIGH);
  if (temperature  < 55) digitalWrite(coolingControl, LOW);

  if (temperature  < 50) digitalWrite(heatingControl, HIGH);
  if (temperature  > 65) digitalWrite(heatingControl, LOW);

I also added a "leaky integrator", an often used idea for smoothing data. The essential line is

//  averageTemp = 0.9 * averageTemp + 0.1 * temperature;

  averageTemp = 0.7 * averageTemp + 0.3 * temperature;

"The new average is mostly the old average, with a bit of the newest sample added."

The two constants 0.3 and 0.7 add to 1.0, as do 0.1 and 0.9 in the commented out version, which converges slower as it takes more of the old and less of the new. Just use constants that add to 1.0 and you can play with the convergence rate.


Here's the hole thing in the simulator. Play with the "temperature" slider and watch the heating and cooling react.

Wokwi_badge too hot, too cold


// https://wokwi.com/projects/369196030361510913
// https://forum.arduino.cc/t/turn-on-peristaltic-pump-based-on-ph-reading/1143658
    
# include <Adafruit_NeoPixel.h>
# define PIN A3       // the pin
# define NPIXELS 25

Adafruit_NeoPixel temperatureBar(NPIXELS, PIN, NEO_GRB + NEO_KHZ800); 

const byte coolingControl = 6;
const byte heatingControl = 7;

void setup()
{
  Serial.begin(115200);
  Serial.println("\ntoo hot, too cold...\n");

  temperatureBar.begin();

  pinMode(coolingControl, OUTPUT);
  pinMode(heatingControl, OUTPUT);
}
  
unsigned long now;
# define RATE 20   // every N millisocends

void loop()
{
  static unsigned long lastTime;

  now = millis();
  if (now - lastTime < RATE) return;
  lastTime = now;

  int temperature = map(analogRead(A0), 0, 1023, 20, 100);
  static float averageTemp;

//  averageTemp = 0.9 * averageTemp + 0.1 * temperature;

  averageTemp = 0.7 * averageTemp + 0.3 * temperature;

  temperature = averageTemp;

  temperatureBar.clear();
  temperatureBar.setPixelColor(map(temperature, 20, 100, 0, NPIXELS), 0xff0000);    
  temperatureBar.show();

  if (temperature  > 70) digitalWrite(coolingControl, HIGH);
  if (temperature  < 55) digitalWrite(coolingControl, LOW);

  if (temperature  < 50) digitalWrite(heatingControl, HIGH);
  if (temperature  > 65) digitalWrite(heatingControl, LOW);

  if (digitalRead(heatingControl) && digitalRead(coolingControl)) {
    Serial.println("heating and cooling logic error"); Serial.flush();
    while (1);
  }
}

HTH

a7

If you want to add L298 to your project, you need to declare 3 digital pins as output. You have to declare that in the setup function. You have to connect Input1, Input2 and ENA pins to the Arduino's 3 digital pins. If you want to add speed control, you'll need to connect ENA to a PWM pin of the Arduino.

I have tried this so far, and using an LED on a breadboard to see does it light up and turn off.

 Serial.println(phValue);
  if (phValue > 7) {
    digitalWrite(A7, HIGH);
  }
  if (phValue < 7) {
    digitalWrite (A7, LOW);
  }

How ever when the LED comes on there is a drop of a value of about 1 from the PH probe.
So if it reads PH7, and the LED comes on, the value drops to about PH6 and LED goes off, then PH goes back to about PH7 maybe PH6.94.

Would you have any idea on why this drop occurs.

I have an L298N wired to the pump, I think I should be able to get it working, I just have no experience with coding, trying to bluff my way though it and figure out what goes where as I go along.

I didn't write the code, this is what I found for this model of probe online. So I don't fully understand all the in's and outs, but would have some grasp on what it's doing.

Sounds like inadequate power or a wiring issue.

Post a schematic, hand drawn is easiest and fastest. Show all your components and how they are connected, with attention to where power comes from and how it is provided to the parts that need power.

If you've never, google electronics schematic, choose "images" and look at a few, then fake it as best you can. More information is better, usually.

Maybe snap a photo of your setup and post that.

And it wouldn't hurt to always post a full working sketch, as code matters and we can't be sure of the experiment or your reported results if we don't see the code, too.

a7

Here are some sample codes. I think you'll find these helpful.

Thank You

// PH Probe and LCD 
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

float calibration = 22.99;  //change this value to calibrate
const int analogInPin = A0;
int sensorValue = 0;
unsigned long int avgValue;
float b;
int buf[10], temp;

void setup() {
  lcd.begin(16, 2);
  lcd.print("PH Calibrating");
  delay(5000);
  lcd.clear();
  pinMode(A7, OUTPUT);
  Serial.begin(9600);
}
void loop() {
  for (int i = 0; i < 10; i++) {
    buf[i] = analogRead(analogInPin);
    delay(30);
  }
  for (int i = 0; i < 9; i++) {
    for (int j = i + 1; j < 10; j++) {
      if (buf[i] > buf[j]) {
        temp = buf[i];
        buf[i] = buf[j];
        buf[j] = temp;
      }
    }
  }
  avgValue = 0;
  for (int i = 2; i < 8; i++)
    avgValue += buf[i];
  float pHVol = (float)avgValue * 5.0 / 1024 / 6;
  float phValue = -5.70 * pHVol + calibration;
  Serial.print("PH = ");
  Serial.println(phValue);//This is what i added from here
  if (phValue > 7) {
    digitalWrite(A7, HIGH);//If PH is greater than 7, A7 goes high, turns on LED
  }
  if (phValue < 7) {
    digitalWrite (A7, LOW);//If PH is less than 7, A7 goes low, turns off LED
  }
  delay(2000);
lcd.begin(16, 2);
lcd.print("PH = ");
lcd.print(phValue);
}

I hope the picture is OK, I will try and do out a schematic also.
The problem is when A7 goes high, the PH value immediately drops by about a value of one.
If I disconnect A7, PH goes back to original reading.
I'm not sure if it also has something to do with how quick it's reading the PH probe.
EG PH reads 7.03, A7 goes high, PH reading drops to PH6, then after the delay of 2000 it reads again at PH7.03, then after delay 2000 it reads again at PH6, when I disconnect A7 the PH reading goes back to it's original 7.03.
Also I think that is a 5k resistor across the LED.

When the LED turns on, the current flowing through the wiring/breadboard causes the voltage at the pH probe's GND pin to change by a few millivolts. This is what causes the reading to change.

The problem should be solved by connecting the pH sensor to it's own separate GND pin on the Arduino.

Hi John,

You may be right, it seems I had to connect both ground to the Arduino for it not to it drop, but the LCD is gone very dim, I'll work on it a bit more. I'm going to try and do a schematic on tinkercad.
Would the grounding issue still be a problem connecting to the driver L298N, or will it resolve itself once connected to the driver.
I thought it would be ok to have all the grounds from the Arduino connected to one line, what do I do if I need more ground points.