Also, the Voltage variable in this code I stole from another working sensor. (TDS Sensor)
So the calibration step finds the voltage for ph(7)
If we start with a wild guess of vref/2.0
Vref=5
VcalInMV= 2500
VreadingInMV = reading * Vref/4096 * 1000
phPerMV = 1.0/59.6
PH = 7 - ((VreadingInMV - VcalInMV) * phPerMV)
I’ll have to look at this later when I have some pH 7 solution handy. That looks like a great starting point.
Thanks for your input!!
I would guess tap water to be close, no?
Guess not: EPA guidelines state that the pH of tap water should be between 6.5 and 8.5. Still, tap water in the U.S. tends to fall below that – in the 4.3 to 5.3 range – depending on where you live.
Our pH here runs at 7.6 - 7.8. Very high in TDS as well.
I ran that code on my water sample at work and I am getting 38.02 as my reading and I know that’s way off.
When I run the code without any constraints to see what the sensor is returning RAW, I get 535.
Can you give this a try?
#!/usr/bin/env python3
import math
import sys
import time
from grove.adc import ADC
# CONSTANTS
Vref = 4.95 # volts
Vcal_mv = 646 # milli-volts (using raw value 535 * 4.95/4096 * 1000)
mv_per_ph = 59.6
ph_per_mv = 1.0 / mv_per_ph
class GrovePH:
def __init__(self, channel):
self.channel = channel
self.adc = ADC()
@property
def PH(self):
value = self.adc.read(self.channel)
if value != 0:
voltage_mv = value * Vref / 4096.0 * 1000
PHValue = 7 - ((voltage_mv - Vcal_mv) * ph_per_mv)
return PHValue
else:
return 0
def main():
if len(sys.argv) < 2:
print(‘Usage: {} adc_channel’.format(sys.argv[0]))
sys.exit(1)
sensor = GrovePH(int(sys.argv[1]))
print('Detecting PH...')
while True:
try:
print('PH Value: {:2.1f}'.format(sensor.PH))
time.sleep(1)
except KeyboardInterrupt:
print("\nExiting...")
sys.exit(0)
if __name__ == ‘__main__’:
main()
Thanks for the help!
I tried that code. This is the result:
[18:57:06] pi@openhab:~/GrovePi/Software/Python$ sudo python3 ph_sensor_2.py 4
Detecting PH…
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
PH Value: 38.1
^C
Exiting…
If I adjust the millivolts I can bring the pH in to a more appropriate value. I tried it in my other code with known sample but my values for my well water were off. I’m going to try it again with your code and see where we are.
We’re really really close though!!
I made my adjustments and it’s still off. Let me know your thoughts! I can check and verify millivolts and such if need be. Just give me a little direction as I don’t know where to start.
Thanks!!!
@cyclicalobsessive SEEED sent me over this code. They also said they were getting false readings as well and did not know why… So… We are doing something right. I couldn’t get his code to work. It kept bombing out.
Thanks again for all of your help! I’d love to know why it’s sending false readings…
import time,sys,math
from grove.adc import ADC
__all__ = ["GrovePhSensor"]
class GrovePhSensor(object):
def __init__(self, channel):
self.channel = channel
self.adc = ADC()
@property
def value(self):
return self.adc.read(self.channel)
def main():
#Connect the Grove PH Sensor to analog port A0
# SIG,NC,VCC,GND
sensor = GrovePhSensor(0)
# Reference voltage of ADC is 4.95v
Vref = 4.95
while True:
try:
# Read sensor value
# sensor_value = grove.analogRead(sensor)
# Calculate PH
# 7 means the neutral PH value,372 means the Reference value of ADC measured under neutral pH
# 59.16=Conversion method to convert the output voltage value to PH value.
ph = 7 - 1000 * (GrovePhSensor.value-372) * Vref / 59.16 / 1023
print("sensor_value =", GrovePhSensor.value, " ph =", ph)
except IOError:
print ("Error")
if __name__ == '__main__':
main()
One thing we could try adding is a variable to collect the voltage reading it is making. Than collect that voltage with a nuetral solution. Use that voltage in plce of 372 in the code. Than test that?
I really wish a GrovePi person would chime in - the chip on the GrovePi Zero is atmel328p which seems to have only a 10 bit A2D so the divisor should be 1023 not 4096. So that makes Vcal_mv more like 2588 (using raw value 535 * 4.95 / 1023 * 1000) which is close to the 2500 I was guessing.
So change:
Vcal_mv = 2588 # milli-volts (using raw value 535 * 4.95/1023 * 1000) note 10-bit A2D
and
voltage_mv = value * Vref / 1023.0 * 1000
and lets see what happens?
I agree! I’ll give this a go and see.
What would I adjust in the code to calibrate it? The sensor is reading 5.9 in ph 7 solution.
I got it!
Changed the vCal_mv to 2666 based on current voltage reading in 7.0 solution. Bingo hit 7.0
add a print for the reading so we know what the reading is in the ph7 solution - I’m guessing it will be about 604 which would make the Vcal_mv = 2922 I think.
Now let me try it in water and see if it looks off.
By the way, some of the sample code examples collect a number of readings and average the readings before plugging into the PH formula. I don’t know what the variance is, but taking the average of 10 readings will reduce the variance by the square root of the number of readings or to about 1/3 of the variance.
If one reading to the next varies a bunch like 1ph , taking 10 readings might reduce the variance to 0.3 ph.
That appears to have worked. I owe you a beer!
The only thing that would be handy would be to take 20 readings and pull an average of them. But I can probalby figure that one out. I’m not a python genius I just fumble my way through.
I saw that as well. Ha! I appreciate all of your help. It would have taken me much longer. Thank you!!