-
Notifications
You must be signed in to change notification settings - Fork 1
Update control.py #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: pH_v1
Are you sure you want to change the base?
Changes from all commits
20cca21
77985ab
b681e36
62571c3
194a2fd
930133e
7eca15f
20f13b4
9a0837e
a9b0779
0ff6716
818126c
f223974
7e4bf2e
71bf83c
f466cae
7433728
d93df0c
b1e98ea
69c5f5f
33697e1
3b34878
74893dd
b60fc14
ec362bd
b07d4ac
86ecabc
7945c3f
a9bbfc8
8f4dcd8
59a08ef
76753c3
79ad909
814be13
3d5bb2b
bf5086d
53dd5af
0bcb78d
53f1c03
381f790
af6a823
0967cda
ee49ede
35a5f50
aa983d9
20b8b7f
7156d02
d7434e1
97d31b6
08529df
ebbf598
6e67b7b
21de782
02d9df3
899bf4f
888e77b
9488f7a
25e2b8b
ca7626c
191e79e
c9286ea
f98237c
343855f
3316656
8c20930
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,132 @@ | ||
| #Python script to read analog voltage values from ADS1115 16bit ADC with PGA | ||
| #Author: Carson Berry | ||
| #Date: February 2nd, 2021 | ||
| #usage: | ||
| # python3 | ||
| # import src.adc as adc | ||
| # sensors = adc.adc_sensors() | ||
| # sensors.read_leak() | ||
| # sensors.read_pH() | ||
| # Reference provided at: https://learn.adafruit.com/adafruit-4-channel-adc-breakouts/python-circuitpython | ||
|
|
||
| #----------------------------------------------Template--------------------------------------------------# | ||
| # This is a brief template on creating *new threading modules* | ||
| # 1. Create a class, for example: class ph_control(object): | ||
| # 2. Copy all the exiting initialization functions for sensors | ||
| # 3. Add the new initialization function for the new sensor/device | ||
| # 4. Set up the threading module at the end of this file, this includes: | ||
| # 4.1. Define your class, for example: VARIABLE_NAME = NAME_OF_THE_CLASS() | ||
| # 4.2. Create the thread module, for example: NAME_OF_THREAD = Thread(target = VARIABLE_NAME.FUNCTION_NAME) | ||
| # Notice that the FUNCTION_NAME should be the function in the class (defined before), and is the one that you would like it to iterate | ||
| # 4.3. Start the thread, for example: NAME_OF_THREAD.start() | ||
| #-----------------------------------------------CODE COMPLETE---------------------------------------------# | ||
| # class ph_control(object): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't ph_control() already defined as a class? Correct me if I'm wrong, but don't we need to instantiate an object of this class similar to you do below. I'm guessing an example might look like this: Do threads only work for single functions?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the aim of define ph_control(object) should just be an example for the users indicate that they should create a class. I will edit and try to make my sample code more obvious. |
||
| # VARIABLE_NAME = NAME_OF_THE_CLASS() | ||
| # NAME_OF_THREAD = Thread(target = VARIABLE_NAME.FUNCTION_NAME) | ||
| # NAME_OF_THREAD.start() | ||
|
|
||
|
|
||
|
|
||
|
|
||
| import RPi.GPIO as GPIO | ||
| import time | ||
| import board | ||
| import threading | ||
| import busio | ||
| import adafruit_ads1x15.ads1115 as ADS | ||
| from adafruit_ads1x15.analog_in import AnalogIn | ||
| from threading import Thread | ||
| import RPi.GPIO as GPIO | ||
| import time | ||
| import src.pins | ||
|
|
||
|
|
||
|
|
||
| # Add timers for different outputs ex. ph_timer, water_level_timer, temp_timer | ||
| class ph_control(object): | ||
| def __init__(self): | ||
| self.ads=0 | ||
| self.init_i2c() | ||
|
|
||
| class adc_sensors(object): | ||
| self.pH_sensor = 0 | ||
| self.init_pH() | ||
| self.pH_intercept = 7 | ||
| self.pH_offset = 1.65 | ||
| self.pH_slope = -3.3 | ||
| self.desired_ph = 7 | ||
|
|
||
| def init_i2c(self): | ||
| #define i2c object | ||
| i2c = busio.I2C(board.SCL, board.SDA) | ||
| #create object | ||
| self.ads = ADS.ADS1115(i2c) | ||
|
|
||
| def init_ph(self): | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P2) | ||
|
|
||
|
|
||
|
|
||
| def init_pH(self): | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P2) | ||
|
|
||
| def read_pH(self): | ||
| pH_voltage = self.pH_sensor.voltage | ||
| pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope) | ||
| return pH | ||
|
|
||
| def read_ph(self): | ||
| pH_voltage = self.pH_sensor.voltage | ||
| pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope) | ||
| return pH | ||
|
|
||
| # Calibration function | ||
| # Intended to assist with the calibration of the pH_probe at regular (eg. monthly) intervals | ||
| # | ||
| # REQUIRES USER ENGAGEMENT - THEY MUST CHANGE THE pH PROBE SOLUTION WHEN PROMPTED | ||
| # total process will take about 3 minutes. | ||
| # | ||
| # inputs: self, pH of calibration solution 1 (eg 7), pH of calibration solution 2 (eg. 4) | ||
| # updates: self.pH_slope, self.pH_intercept | ||
| #use: ph_control.calibrate(self,7,4) | ||
| def calibrate(self, calibration_pH_1, calibration_pH_2): | ||
| #this function constructs a linear function of the form: | ||
| # y = m(x-offset)+b | ||
| # or | ||
| # pH = (slope)*(voltage-offset_voltage)+ pH_at_offset_voltage | ||
|
|
||
| print('Please place the pH probe in the first solution with pH ',calibration_pH_1,', and mix the solution with the probe. Wait 60 seconds.') | ||
| #should we wait for confirmation? From testing, 1 minute is not enough | ||
| for _ in range(60): | ||
| time.sleep(1) | ||
| print('.') | ||
| print('Reading now') | ||
| v1 = self.pH_sensor.voltage # read the pH meter's voltage in the known solution | ||
|
|
||
| print('Please place the pH probe in the second solution with pH ',calibration_pH_2,', and mix the solution with the probe. Wait 60 seconds.') | ||
| #should we wait for confirmation? From testing, 1 minute is not enough | ||
| for _ in range(60): | ||
| time.sleep(1) | ||
| print('.') | ||
| print('Reading now') | ||
| v2 = self.pH_sensor.voltage # read the pH meter's voltage in the known solution | ||
|
|
||
| #calculate slope of pH-voltage curve (should be negative) | ||
| self.pH_slope = (calibration_pH_1-calibration_pH_2)/(v1-v2) | ||
|
|
||
| #pH curve 'intercept' anchored around first datapoint | ||
| self.pH_intercept = calibration_pH_1 | ||
| self.pH_offset = v1 | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| def test_ph(self): | ||
| print('init start') | ||
| print('the value of x is', end=' ') # sorry these are test code that I use. Will clean this up | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P2) | ||
| pH_voltage = self.pH_sensor.voltage | ||
| pH = self.pH_intercept +(pH_voltage-self.pH_offset)*(self.pH_slope) #test self.x here | ||
| while True: | ||
| time.sleep(2) | ||
| print('loop start') | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P2) | ||
| pH = self.read_pH() | ||
| if (pH<=self.desired_pH): #test self.desired_ph here | ||
| print('pump opened') | ||
| GPIO.setup(26,GPIO.OUT) | ||
| GPIO.output (26,GPIO.HIGH) | ||
| time.sleep(2) | ||
| GPIO.output (26,GPIO.LOW) | ||
| time.sleep(2) | ||
|
|
||
| class wl_control(object): #It turns out to be a bug when there's no (object) | ||
| def __init__(self): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also remove unnecessary fields
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, all I meant by unnecessary fields was that instantiating/pointing to the pH channel on the adc in the water_level control object is unnecessary because it exists elsewhere. |
||
|
|
||
| self.ads=0 | ||
| self.init_i2c() | ||
| self.leak_sensor = 0 | ||
|
|
@@ -45,61 +142,38 @@ def init_i2c(self): | |
|
|
||
| def init_leak(self): | ||
| self.leak_sensor= AnalogIn(self.ads,ADS.P0) | ||
|
|
||
| def water_level_init(self): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The water level sensor does not use the ADC. Please review the recently merged water_level.py on the main branch for code.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! |
||
| self.level = 0 | ||
| self.setup() | ||
| self.read() # update level | ||
|
|
||
|
|
||
| def init_ph(self): | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P1) | ||
|
|
||
| def init_pH(self): | ||
| self.pH_sensor= AnalogIn(self.ads,ADS.P1) | ||
|
|
||
| def read_leak(self): | ||
| return self.leak_sensor.voltage | ||
|
|
||
| def read_pH(self): | ||
| pH_voltage = self.pH_sensor.voltage | ||
| pH = 7.7 +(pH_voltage-14.7/10)*(-3.3) #formula adjusted for use with a voltage divider to map the 5 V output to 3.3V for use with a 3.3V ADC | ||
| pH = 7.7 +(pH_voltage-1.65)*(-3.3) | ||
| return pH | ||
|
|
||
| def read_waterlevel(self): | ||
| try: | ||
| #self.level = GPIO.input(pins.WATER_LEVEL) | ||
| self.level = GPIO.input(11) | ||
| return self.level | ||
| except: | ||
| GPIO.cleanup() | ||
| return -1 | ||
|
|
||
| def pump_open(self): | ||
| print ('pump opened') | ||
| GPIO.output(9,GPIO.HIGH) #9 for the relay pin on pH pump | ||
| time.sleep(1) | ||
| GPIO.output(9,GPIO.LOW) | ||
| #Here I add the function of the timer | ||
| #This code here correspond update the data at default time | ||
| #Using threading method | ||
| def test_ph(self): | ||
|
|
||
| def read_ph(self): | ||
| pH_voltage = self.pH_sensor.voltage | ||
| pH = 7.7 +(pH_voltage-1.65)*(-3.3) | ||
| return pH | ||
|
|
||
| def test_wl(self): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So test_wl(self) is the control loop for the water level?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes exactly!
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great! If you can just add a brief description, so that future users know what this module's function is. |
||
| while True: | ||
| read_ph() | ||
| if (int(read_ph()<= 11)): | ||
| pump_open() | ||
| time.sleep(10) | ||
|
|
||
| def test_waterlevel(self): | ||
| while True: | ||
| read_leak() | ||
| if (read_waterlevel()== -1): | ||
| GPIO.output(8,HIGH) | ||
| time.sleep(1) | ||
| GPIO.output(8,GPIO.LOW) | ||
| time.sleep(20) | ||
|
|
||
|
|
||
| x = adc_sensors() | ||
| thread1 = threading.Thread(target=x.test_ph()) | ||
| thread2 = threading.Thread(target=x.test_waterlevel()) | ||
|
|
||
| thread1.start() | ||
| thread2.start() | ||
| #print('valve opened') | ||
| time.sleep(6) | ||
|
|
||
|
|
||
| #Create Class | ||
| First = wl_control() | ||
| FirstThread=Thread(target=First.test_wl) | ||
| FirstThread.start() | ||
|
|
||
| #Create Class | ||
| Second = ph_control() | ||
| SecondThread=Thread(target=Second.test_ph) | ||
| SecondThread.start() | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this Template description! Would you please be able to add all of the example code together at the end of it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure