element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Vertical Farming
  • Challenges & Projects
  • Design Challenges
  • Vertical Farming
  • More
  • Cancel
Vertical Farming
Blog Automated Green House Blog:11.1 - Self Optimising Automated Nutrient Doser - EC Optimisation
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: m.ratcliffe
  • Date Created: 9 Oct 2015 11:25 AM Date Created
  • Views 3686 views
  • Likes 4 likes
  • Comments 25 comments
  • adapted_greenhouse
Related
Recommended

Automated Green House Blog:11.1 - Self Optimising Automated Nutrient Doser - EC Optimisation

m.ratcliffe
m.ratcliffe
9 Oct 2015

In the last Blog [11] we covered how to make a self learning Hydropinics nutrient doser, it worked out the system variables to keep the growing fluid at the specified EC. This works very well, but we might be able to go one step further.

 

This Blog will cover the theory and implementation of optimising the EC set-point for the grow system. That is instead of the user specifying the EC setpoint we will let the controller optimise the set point for itself.

 

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

Basic theory:

 

A plant will only take the nutrients it requires from the growing fluid. The concentration of the growing fluid is dependant on:

>Temperature

>Sunlight intensity

>Plant strain

>CO2 abundance

 

A lot of variables here, so not well suited to model based optimisation. Instead we will be using feedback to optimise the situation.

In theory a perfect Ec would be one where a plant takes the same ratio of water to nutrients, meaning the volume of growing liquid will decrease but the EC of it will remain the same. We can add a control loop to achieve this quite easily.

 

 

Info

The code will work flawlessly to achieve what we have told it to, but is what we told it to do correct?

The theory has good standing but I would like to run some tests before recommending this technique, this work will take place in mid 2016 [end of growing season outside in the uk at the moment  and this needs a decent test]

 

 

The Code

Header 1

 

 

/*

  ElCheapo Arduino EC-PPM measurments and Nutrient Doser and EC tuning Script

 

 

  ###### Experimental Theory, not yet tested!!!!  Use at your own risk, if in doubt use the previose version with a static EC setpoint

 

  This scrip uses a common USA two prong plug and a 1Kohm Resistor to measure the EC/PPM of a Aquaponics/Hydroponics Sytem.

  Then It Increases the Nutrient content until the set point is reached

  It will Learn the system variables, plug in some rough estimates and the controller will work the rest out for itlself

  The EC will also change to adjust for the perfect EC

 

 

  28/8/2015  Michael Ratcliffe  Mike@MichaelRatcliffe.com

 

 

          This program is free software: you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation, either version 3 of the License, or

    (at your option) any later version.

 

 

    This program is distributed in the hope that it will be useful,

    but WITHOUT ANY WARRANTY; without even the implied warranty of

    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

    GNU General Public License for more details.

 

 

    You should have received a copy of the GNU General Public License

    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 

    Parts:

    -Arduino - Uno/Mega

    -Standard American two prong plug

    -1 kohm resistor

    -DS18B20 Waterproof Temperature Sensor

    -FluidPump [Smaller is better];

 

    Limitations:

    -Cell Constant [K] and ECSetpoint must be less than 5.0 or it will Mess with the way we save values in EEPROM

    -A reset will change your set point and kell constant slightly, but not to a great extent

    -EEPROM seems to survive a reflash, so changing values in the code will not change them in the flashed software. you will need to do it via the LCD

 

    See www.MichaelRatcliffe.com/Projects for a Pinout and user guide or consult the Zip you got this code from

 

*/

 

 

//************************** Libraries Needed To Compile The Script [See Read me In Download] ***************//

// Both below Library are custom ones [ SEE READ ME In Downloaded Zip If You Dont Know how To install] Use them or add a pull up resistor to the temp probe

 

 

#include <OneWire.h>

#include <DallasTemperature.h>

#include <LiquidCrystal.h> //Standard LCD Lbrary

#include <EEPROM.h> //Standard EEPROM Library

 

 

//************************* User Defined Variables ******************************************************//

// Rememebr to ad .0 after any float definition or it will return to an initiger, ie 1.0 not 1

 

 

 

 

 

 

//********************** System Information *************************************//

 

 

float TankSize =10; //SystemVolume  in Liters

float PumpRate=0.; //Flow rate of dosing pump in L per min

long DosingInterval =60; //How often you want to dose the tank in minutes, hour intervals will be fine for most systems

long MixingTime =30; //The time for mixing of nutrients in minutes [I have a lot of water flow so 60 seonds is fine for me, if in doubt increase it to half a hour]

 

 

 

 

int Pump =14; //Pin Controlling relay for nutrient Pump

int OFF =0;

int ON=1;

 

 

//****************************** System EC Value *******************************//

//Changes for what plants you are growing, sun intensity and temperature

 

 

//###If you are using urine in a system and have not yet got a established Bacteria bed set this to ECSetpoint=0.7 for a week to let the bacteria become established##

 

 

float ECSetpoint =1.0; // How Strong you want the water system to be nutrient wise to begin with

float MinECSetpoint =0.5;

float MaxECSetpoint =2.5;

 

 

 

 

//******************** Nut Tank EC *********************************************//

//the code will optimise this number after every dosing, so we are selecting the highest end and allowing the arduino to work the rest out its self

//You are using a nutrient that states the NPK and not a overpriced one that used the words "Boost" "flower" "Super" but hides the important NPK ratios?

//If not Save yourself a fortune and switch to a cheap one that is honest about its NPK

 

 

//We need to put in a estimated start point for the controller to start with

//For an estimate take the EC Estimate= (N*20) + (P*8.8) +(K*16)

 

 

float ECFluidEstimate =100.0; //if you dont know the value stick with 1000, it will sort itself out

 

 

 

 

//***********************************EC Meter **********************************//

 

 

 

 

//##################################################################################

//-----------  Do not Replace R1 with a resistor lower than 300 ohms    ------------

//##################################################################################

 

 

 

 

int R1= 1000; //The resitor we placed in voltage divider

int Ra=25; //Resistance of Arduino Digital Pins

//float Rp=0; //Resistance of figure 8 connector

int ECPin= A8;

int ECGround=A9;

int ECPower =A12;

 

 

//************ Temp Probe Related *********************************************//

#define ONE_WIRE_BUS 26          // Data wire For Temp Probe is plugged into pin 10 on the Arduino

const int TempProbePossitive =22;  //Temp Probe power connected to pin 9

const int TempProbeNegative=24;    //Temp Probe Negative connected to pin 8

 

 

//************************* User Defined Variables ********************************************************//

 

 

float CalibrationEC=1.380; //EC value of Calibration solution is s/cm

 

 

//*********** Converting to ppm [Learn to use EC it is much better**************//

// Hana      [USA]        PPMconverion:  0.5

// Eutech    [EU]          PPMconversion:  0.64

//Tranchen  [Australia]  PPMconversion:  0.7

// Why didnt anyone standardise this?

 

 

float PPMconversion=0.5;

 

 

//********************** Cell Constant For Ec Measurements *********************//

//Mine was around 2.9 , with plugs being a standard size they should all be the same

//I Recommend Calibrating your probe but if that is not an option at this time the following cell constants [K] will give a good estimated readout:

//EU plug: K= 1.76

//US Plug K= 2.88

float K=2.88;

 

 

//*************Compensating for temperature ************************************//

//The value below will change depending on what chemical solution we are measuring

//0.019 is generaly considered the standard for plant nutrients [google "Temperature compensation EC" for more info

float TemperatureCoef = 0.02; //this changes depending on what chemical we are measuring

 

 

//***************************** END Of Recomended User Inputs *****************************************************************//

//********************************************************//

 

 

// select the pins used on the LCD panel

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

 

 

// define some values used by the panel and buttons

int lcd_key    = 0;

int adc_key_in  = 0;

int button =0;

#define btnRIGHT  1

#define btnUP    2

#define btnDOWN  3

#define btnLEFT  4

#define btnSELECT 5

#define btnNONE  6

 

 

int Screen =1;

 

 

OneWire oneWire(ONE_WIRE_BUS);// Setup a oneWire instance to communicate with any OneWire devices

DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.

 

 

float Temperature=10;

float EC=0;

float EC25 =0;

int ppm =0;

 

 

float raw= 0;

float Vin= 5;

float Vdrop= 0;

float Rc= 0;

 

 

 

 

 

 

float PumpTime=0; //Variable for pumping duration

long MixingInterval=0; //variable for when to check new EC

float PostDocingEC=0;

float PreDosingEC =0;

long StartDosingMillis =0;

int NutesAdded=0;

 

 

long time=0;

 

 

//********************** Some Variables For Loging Min/Max Values ********************************//

float MinEC=100;

float MaxEC=0;

float MinT=100;

float MaxT=0;

 

 

//************************** Just Some basic Definitions used for the Up Time LOgger ************//

long Day=0;

int Hour =0;

int Minute=0;

int Second=0;

int HighMillis=0;

int Rollover=0;

 

//**************************Some Stuff For Calibration ******************************************//

float TemperatureFinish=0;

float TemperatureStart=0;

int i=0;

float buffer=0;

float Kt=0;

 

 

//***********************Some Stuff for Self Learning and Errors********************************//

float LastGoodEstimate= 0;

float PumECRateStart=0;

float PumECRate=0;

int error=6; // 6 means no error

long Doses=0;

long LastRun=0;

int ECHold=0;

 

 

 

 

//*********************** EPROM Stuff [So SetPoint and Cal Survive a reboot] ******************//

int value;

int addresSetpoint=10;

int addresCalibration=0;

 

 

 

 

 

 

//*********************************Setup - runs Once and sets pins etc ******************************************************//

void setup()

{

  Serial.begin(9600);

  pinMode(TempProbeNegative , OUTPUT ); //seting ground pin as output for tmp probe

  digitalWrite(TempProbeNegative , LOW );//Seting it to ground so it can sink current

  pinMode(TempProbePossitive , OUTPUT );//ditto but for positive

  digitalWrite(TempProbePossitive , HIGH );

  pinMode(ECPin,INPUT);

  pinMode(ECPower,OUTPUT);//Setting pin for sourcing current

  pinMode(ECGround,OUTPUT);//setting pin for sinking current

 

  pinMode(Pump,OUTPUT);//setting pin for sinking current

  digitalWrite(Pump,OFF); //makes sure we are starting from a stop

  digitalWrite(ECGround,LOW);//We can leave the ground connected permanantly

 

 

  delay(100);// gives sensor time to settle

  sensors.begin();

 

  //****************Converting to milli seconds********************//

  DosingInterval =DosingInterval*60000; //Coveerting to milliseconds

  MixingTime =MixingTime*60000;      // Converting to milliseconds

  MixingInterval=DosingInterval+MixingTime;

  PumpRate=PumpRate/60.0; //converting to L.Second-1

 

  //***************Converting to MCU related units ****************//

  PumECRate=ECFluidEstimate*(PumpRate/TankSize);    //  EC.Second-1

  PumECRate=PumECRate*2.0;//Just incase people overestimated some values

  LastGoodEstimate=PumECRate;

  PumECRateStart=PumECRate;

 

  //************** Restart Protection Stuff ********************//

  //Setpoint

  value = EEPROM.read(addresSetpoint);

  if (value <=254) ECSetpoint=value*0.02;

  //Calibration

  value = EEPROM.read(addresCalibration);

  if (value <=254) K=value*0.02;

 

 

 

 

 

R1=(R1+Ra); //Taking into acount Digital Pin Resitance

 

 

lcd.begin(16, 2);              // start the library

lcd.setCursor(0,0);

delay(1000);

lcd.print("Nutrient Doser");

lcd.setCursor(0,1);

delay(1000);

lcd.print("Mike Ratcliffe");

lcd.setCursor(0,1);

delay(1000);

lcd.setCursor(0,1);

lcd.print("Free Software  ");

delay(1000);

lcd.setCursor(0,1);

lcd.print("Mike Ratcliffe");

delay(1000);

lcd.setCursor(0,1);

lcd.print("Free Software  ");

delay(1000);

lcd.setCursor(0,0);

lcd.print("To Calibrate      ");

  lcd.setCursor(0,1);

lcd.print("Hold Select      ");

delay(3000);

  lcd.setCursor(0,0);

lcd.print("To Navigate        ");

  lcd.setCursor(0,1);

lcd.print("Use Up-Down    ");

delay(3000);

 

 

GetEC(); //gets first reading for LCD and then resets max/min

MinEC=100.0;

MaxEC=0.0;

MinT=100.0;

MaxT=0.0;

 

 

 

 

 

 

};

//******************************************* End of Setup **********************************************************************//

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

//************************************* Main Loop - Runs Forever ***************************************************************//

//Moved Heavy Work To subroutines so you can call them from main loop without cluttering the main loop

//Dont Measure the EC more than once every five second "GetEC()" or you will get bad readings and wear your probe out

 

 

void loop()

{

//*********Takes care of millis rolover**************//

if(millis()<=5000){

  NutesAdded=0;

  digitalWrite(Pump,OFF);

    delay(5000);

};

 

 

//*********Check if it is time to dose the system, we wont dose it if the probe is broken or if we are colse to the setppoint ********//

if( (button==1 || millis()%DosingInterval<=1000) && (error>=4 && EC25<=(ECSetpoint-0.1) && NutesAdded==0) ){

ECTuning();

NutrientAddition();

NutesAdded=1;

Doses++;

};

//********This fine tunes for the perticular system **************//

if((millis()>=(PumpTime+MixingTime+StartDosingMillis)) && NutesAdded==1){

EstimateEC();                                        // Goes to the script to estimate the nutrient source EC

NutesAdded=0;

};

 

 

 

 

 

 

//********** Runs the Function to estimate the EC of the hydroponics system **********//

if (millis()%5000<=1000 && ECHold==0){

GetEC();

ECHold=1;

};

if (millis()%5000>=1000){

ECHold=0;

};

 

 

//**************** Turns the pump off at the end of the pumping time********************//

if (millis()>=StartDosingMillis+PumpTime){  //Still need to take care of millis rollover!?

digitalWrite(Pump,OFF);

 

 

};

 

 

read_LCD_buttons();

Calibration();

ChangeECSetpoint();

Error();

PrintReadings();  // Cals Print routine [below main loop]

 

 

//************* Stopinf Funky Readings From unmixed solution**********//

if(NutesAdded==0) LogEC();

 

 

delay(50);

 

 

}

//************************************** End Of Main Loop **********************************************************************//

 

 

 

 

 

 

 

 

 

 

 

 

//*******************************Turns on Pump To Dose System *********************************//

 

 

                  void NutrientAddition(){

              

                  PreDosingEC =EC25; //Makes note of the initial EC

                  PumpTime=1000*((ECSetpoint-PreDosingEC)/PumECRate);

                  StartDosingMillis=millis();

                  digitalWrite(Pump,ON);

              

                  };

 

 

 

 

//******************************** System Automatd Learning ************************************//

                //This Function optimises the dosing volume for the main tank volume and Strength of Nutrient tank

            

            

                void EstimateEC(){

              

                PostDocingEC=EC25;  //Makes Note of the EC at the end of the addition

            

                //*********Rapidly change EC Estimation on startup************//                        

                if(PostDocingEC>=(PreDosingEC+0.05)){

            

                PumECRate =(1000.0*((PostDocingEC-PreDosingEC)/PumpTime));

                LastGoodEstimate=PumECRate;

                }

                          

                else  PumECRate=PumECRate/2.0;                          

                };

 

 

 

 

 

 

//************ This Loop Is called From Main Loop************************//

void GetEC(){

 

 

//*********Reading Temperature Of Solution *******************//

 

 

 

 

sensors.requestTemperatures();// Send the command to get temperatures

Temperature=sensors.getTempCByIndex(0); //Stores Value in Variable

raw= analogRead(ECPin);

 

 

//************Estimates Resistance of Liquid ****************//

digitalWrite(ECPower,HIGH);

//raw= analogRead(ECPin);

raw= analogRead(ECPin);// This is not a mistake, First reading will be low beause if charged a capacitor

digitalWrite(ECPower,LOW);

 

 

 

 

//***************** Converts to EC **************************//

Vdrop= (Vin*raw)/1024.0;

Rc=(Vdrop*R1)/(Vin-Vdrop);

Rc=Rc-Ra;

EC = 1000/(Rc*K);

LogEC();

//*************Compensating For Temperaure********************//

EC25  =  EC/ (1.0+ TemperatureCoef*(Temperature-25.0));

ppm=(EC25)*(PPMconversion*1000);

 

 

;}

 

 

 

 

 

 

 

 

//***********This Loop Is called From  Else Where- Prints to serial usefull info **************//

                void PrintReadings(){

            

                Serial.print("EC: ");

                Serial.print(EC25);

                Serial.print(" Simens  ");

                Serial.print(ppm);

                Serial.print(" ppm  ");

                Serial.print(Temperature);

                Serial.print(" *C  ");

                Serial.print("PumpRate EC/s: ");

                Serial.println( PumECRate);

            

        

                                  

                                  

                                      //** First Screen Shows Temp and EC **//

                                      if(Screen==1){

                                      lcd.setCursor(0,0);

                                      lcd.print("Arduino EC-PPM  ");

                                      lcd.setCursor(0,1);

                                      lcd.print("EC:              ");

                                      lcd.setCursor(3,1);

                                      lcd.print(EC25);

                                      lcd.setCursor(9,1);

                                      lcd.print(Temperature);

                                      lcd.print("'C");

                                      }

                                      //** Second Screen Shows PPM **//

                                      else if(Screen==2){

                                      lcd.setCursor(0,0);

                                      lcd.print("Arduino EC-PPM  ");

                                      lcd.setCursor(0,1);

                                      lcd.print("PPM:        ");

                                      lcd.setCursor(4,1);

                                      lcd.print(ppm);

                                      lcd.setCursor(9,1);

                                      lcd.print(Temperature);

                                      lcd.print("'C");

                                      }

                                  

                                      //**Third Screen Shows Min and Max **//

                                      else if(Screen==3){

                                      lcd.setCursor(0,0);

                                      lcd.print("Min:              ");

                                      lcd.setCursor(4,0);

                                      lcd.print(MinEC);

                                      lcd.setCursor(9,0);

                                      lcd.print(MinT);

                                      lcd.print("'C");

                                      lcd.setCursor(0,1);

                                      lcd.print("Max:              ");

                                      lcd.setCursor(4,1);

                                      lcd.print(MaxEC);

                                      lcd.setCursor(9,1);

                                      lcd.print(MaxT);

                                      lcd.print("'C");

                                      }

                                  

                                  

                                      else if(Screen==4){

                                

                                      lcd.setCursor(0,0);

                                      lcd.print("Uptime Counter:              ");

                                  

                                      lcd.setCursor(0,1);

                                      lcd.print("                                    ");//Clearing LCD

                                      lcd.setCursor(0,1);

                                      lcd.print(Day);

                                      lcd.setCursor(3,1);

                                      lcd.print("Day");

                                      lcd.setCursor(8,1);

                                      lcd.print(Hour);

                                      lcd.setCursor(10,1);

                                      lcd.print(":");

                                      lcd.setCursor(11,1);

                                      lcd.print(Minute);

                                      lcd.setCursor(13,1);

                                      lcd.print(":");

                                      lcd.setCursor(14,1);

                                      lcd.print(Second);

                                  

                                  

                                      }

                    

                                  

                                      else if(Screen==5){

                                    

                                      lcd.setCursor(0,0);

                                      lcd.print("Factors          ");

                                      lcd.setCursor(8,0);

                                      lcd.print("PPMC:");

                                      lcd.setCursor(13,0);

                                      lcd.print(PPMconversion);

                                  

                                      lcd.setCursor(0,1);

                                      lcd.print("K:              ");

                                      lcd.setCursor(2,1);

                                      lcd.print(K);

                                      lcd.setCursor(9,1);

                                      lcd.print("a:");

                                      lcd.setCursor(11,1);

                                      lcd.print(TemperatureCoef);

                                      }

                                      else if(Screen==6){

                                    

                                      lcd.setCursor(0,0);

                                      lcd.print("EC.Sec-1:                  ");

                                      lcd.setCursor(10,0);

                                      lcd.print(PumECRate,5);

                                  

                                      lcd.setCursor(0,1);

                                      lcd.print("Doses:                          ");

                                      lcd.setCursor(10,1);

                                      lcd.print(Doses);

                                      }

                                      else if(Screen==7){

                                    

                                      lcd.setCursor(0,0);

                                      lcd.print("EC Setpoint:        ");

                                      lcd.setCursor(12,0);

                                      lcd.print(ECSetpoint,3);

                                  

                                      lcd.setCursor(0,1);

                                      lcd.print("Hold Select Change                        ");

                                  

                                      }

            

          

              if((millis()%6000)<=3000){

            

                //************************* Printing any errors we have ***********//

                if  (error==1) {lcd.setCursor(0,0);

                                      lcd.print("Error:          ");

                                      lcd.setCursor(8,0);

                                      lcd.print(error);

                                      lcd.setCursor(0,1);

                                      lcd.print("Probe Problem              "); }

                                  

                else if (error==2) {lcd.setCursor(0,0);

                                      lcd.print("Error:          ");

                                      lcd.setCursor(8,0);

                                      lcd.print(error);

                                      lcd.setCursor(0,1);

                                      lcd.print("Large Overshoot              "); }

                                  

                else if (error==3) {lcd.setCursor(0,0);

                                      lcd.print("Error:          ");

                                      lcd.setCursor(8,0);

                                      lcd.print(error);

                                      lcd.setCursor(0,1);

                                      lcd.print("Temp Problem              "); }

                                  

                else if (error==4) {lcd.setCursor(0,0);

                                      lcd.print("Error:          ");

                                      lcd.setCursor(8,0);

                                      lcd.print(error);

                                      lcd.setCursor(0,1);

                                      lcd.print("Pump Problem              "); }

                                  

                else if (error==5  ) {lcd.setCursor(0,0);

                                      lcd.print("Error:          ");

                                      lcd.setCursor(8,0);

                                      lcd.print(error);

                                      lcd.setCursor(0,1);

                                      lcd.print("System Learning              "); }

                else;

              

              

              

              };

                              

                

                /*

                //********** Usued for Debugging ************

                Serial.print("Vdrop: ");

                Serial.println(Vdrop);

                Serial.print("Rc: ");

                Serial.println(Rc);

                Serial.print(EC);

                Serial.println("Siemens");

                //********** end of Debugging Prints *********

                */

};

 

 

 

 

void read_LCD_buttons(){

  adc_key_in = analogRead(0);      // read the value from the sensor

// my buttons when read are centered at these valies: 0, 144, 329, 504, 741

// we add approx 50 to those values and check to see if we are close

if (adc_key_in > 1000)  button =0;

 

 

else if (adc_key_in < 50)  button =1;

else if (adc_key_in < 250)  button =2;

else  if (adc_key_in < 450)  button =3;

else if (adc_key_in < 650)  button =4;

else if (adc_key_in < 850)  button =5;

 

 

if(button==2){

Screen++;

 

 

}

else if (button==3){

Screen--;

};

 

 

if (Screen>=7) Screen=7;

if(Screen<=1) Screen=1;

};

 

 

//******************************* LOGS Min/MAX Values and Uptime Counter*******************************//

                          void LogEC(){

                        

                        

                            //**********So We dont Get First Few Readings**********//

                                                            

                                                                if( Doses==5){

                                                                  MinEC=100.0;

                                                                  MaxEC=0.0;

                                                                  MinT=100.0;

                                                                  MaxT=0.0;

                                                                };

                                                            

                      

                            if(EC25>=MaxEC)  MaxEC=EC25;

                            if(EC25<=MinEC)  MinEC=EC25;

                        

                            if(Temperature>=MaxT) MaxT=Temperature;

                            if(Temperature<=MinT) MinT=Temperature;

                      

                          //** Making Note of an expected rollover *****//

                          if(millis()>=3000000000){

                          HighMillis=1;

                      

                          }

                          //** Making note of actual rollover **//

                          if(millis()<=100000&&HighMillis==1){

                          Rollover++;

                          HighMillis=0;

                          }

                      

                          long secsUp = millis()/1000;

                      

                          Second = secsUp%60;

                      

                          Minute = (secsUp/60)%60;

                      

                          Hour = (secsUp/(60*60))%24;

                      

                          Day = (Rollover*50)+(secsUp/(60*60*24));  //First portion takes care of a rollover [around 50 days]

                                              

                                              

                          };

 

 

//******************************* Checks if Select button is held down and enters Calibration routine if it is ************************************//

void Calibration(){

 

 

 

 

if(Screen!=5) return;

if(button!=5) return;

else delay(1000);

read_LCD_buttons();

if(button!=5) return;

 

 

 

 

 

while(1){

read_LCD_buttons();

lcd.setCursor(0,0);

lcd.print("Set Calibration EC  ");

lcd.setCursor(0,1);

lcd.print("EC:                ");

lcd.setCursor(3,1);

lcd.print(CalibrationEC);

 

 

if (button==2) CalibrationEC=CalibrationEC+0.01 ;

if(button==3)  CalibrationEC=CalibrationEC-0.01;

if(button==1) break;

delay(100);

      };

 

 

lcd.setCursor(0,0);

lcd.print("Calibrating        ");

lcd.setCursor(0,1);

lcd.print("EC:                ");

lcd.setCursor(3,1);

lcd.print(CalibrationEC);

 

 

i=1;

buffer=0;

sensors.requestTemperatures();// Send the command to get temperatures

TemperatureStart=sensors.getTempCByIndex(0); //Stores Value in Variable

 

 

//************Estimates Resistance of Liquid ****************//

            while(i<=10){

        

            

            digitalWrite(ECPower,HIGH);

            raw= analogRead(ECPin);

      

            digitalWrite(ECPower,LOW);

            buffer=buffer+raw;

            i++;

            delay(5000);

            };

        

        

raw=(buffer/10.0);

sensors.requestTemperatures();// Send the command to get temperatures

TemperatureFinish=sensors.getTempCByIndex(0); //Stores Value in Variable

 

 

//*************Compensating For Temperaure********************//

EC =CalibrationEC*(1+(TemperatureCoef*(TemperatureFinish-25.0))) ;

 

//***************** Calculates R relating to Calibration fluid **************************//

Vdrop= (((Vin)*(raw))/1024.0);

Rc=(Vdrop*R1)/(Vin-Vdrop);

Rc=Rc-Ra; //Taking into account pin resistance

Kt= 1000/(Rc*EC);

 

 

 

 

 

 

 

 

                    if (TemperatureStart==TemperatureFinish ){

                      Serial.println("  Results are Trustworthy");

                      Serial.print("Calibration Fluid EC: ");

                      Serial.print(CalibrationEC);

                      Serial.print(" S  ");  //add units here

                      Serial.print("Cell Constant K");

                      Serial.print(K);

                  

                  

                      lcd.setCursor(0,0);

                      lcd.print("GoodResults        ");

                  

                  

                      lcd.setCursor(0,1);

                      lcd.print("EC:                    ");

                      lcd.setCursor(3,1);

                      lcd.print(CalibrationEC);

                      lcd.setCursor(9,1);

                      lcd.print("K:");

                      lcd.setCursor(11,1);

                      lcd.print(Kt);

                  

                              while (1) { // wee need to keep this function running until user opts out with return function

                          

                              read_LCD_buttons();

                              if(button==4) return; //exits the loop without saving becauser user asked so

                              if (button==5){

                            

                            

                              K=Kt; //saving the new cell constant

                          

                          

                          //******8*Saving the new value to EEprom**********//

                            value=K/0.02;

                            EEPROM.write(addresCalibration, value);

 

 

 

 

                          

                              lcd.setCursor(0,0);

                              lcd.print("Saved Calibration        ");

                                                        

                              lcd.setCursor(0,1);

                              lcd.print("K:                        ");

                              lcd.setCursor(3,1);

                              lcd.print(Kt);

                              delay(2000);

                              return;

                              }

                          

                              if(millis()%4000>=2000){

                              lcd.setCursor(0,0);

                              lcd.print("GoodResults        ");

                          

                          

                              lcd.setCursor(0,1);

                              lcd.print("EC:                  ");

                              lcd.setCursor(2,1);

                              lcd.print(CalibrationEC);

                              lcd.setCursor(9,1);

                              lcd.print("K:");

                              lcd.setCursor(11,1);

                              lcd.print(Kt);

                          

                              }

                              else{

                          

                              lcd.setCursor(0,0);

                              lcd.print("Select To Save      ");

                          

                              lcd.setCursor(0,1);

                              lcd.print("Down to Exit          ");

                              };

                          

                            

                              }

                  

                      }

                    

                              else{

                              Serial.println("  Error Wait For Temperature To settle");

                          

                                        while (1) {

                                        read_LCD_buttons();

                                        if(button==2) Calibration();

                                        if(button==3) return;

                                    

                                        lcd.setCursor(0,0);

                                        lcd.print("Bad Results        ");

                                        lcd.setCursor(0,1);

                                        lcd.print("Press DWN Exit          ");

                                    

                                  }

                  

                            }

 

 

};

//**************************************** End OF CALIBRATION ROUTINE ******************************//

 

 

//**************************************Start OF Function To Change EC Setpoint*********************//

 

 

void ChangeECSetpoint(){

if(Screen!=7) return;

if(button!=5) return;

 

else delay(1000);

read_LCD_buttons();

if(button!=5) return;

 

 

 

while(1){

read_LCD_buttons();

lcd.setCursor(0,0);

lcd.print("Set EC SetPoint  ");

lcd.setCursor(0,1);

lcd.print("R:exit EC:                ");

lcd.setCursor(11,1);

lcd.print(ECSetpoint);

 

 

if (button==2) ECSetpoint=ECSetpoint+0.01 ;

if(button==3)  ECSetpoint=ECSetpoint-0.01;

if(button==1) {

  value=ECSetpoint/0.02;

  EEPROM.write(addresSetpoint, value);

break;

}

delay(100);

      };

 

 

 

 

 

 

                  

                    

                        

 

 

};

 

 

//*******************************End OF Change EC Setpoint *********************************************//

 

 

 

 

 

 

 

//*********************************Function to Check for any errors**************************************//

void Error(){

error=6; //For Some Reason the Errors are not refreshing like they shoud, this fixes it

//*********Checking if the Probe is in the Solution********//

  if(EC25<=0.05){

  Serial.println("Probe Problem: Check it is in the liquid and not shorted ");

  error=1;

 

  }

 

 

 

//***********Checking if we seriosly overshot the setpoint**//

  else if((EC25>=(ECSetpoint*1.3))&& NutesAdded==0){

  Serial.println("Dosing Problem: We overshot the setpoint, Will attempt to fix its self ");

  error=2;

 

  }

 

 

 

//******** Checking Temp Probe is In range ****************//

else if((Temperature>=50.0) || (Temperature<=0.5)){

  Serial.println("Temperature Problem: Check Wiring [Also Check Probe has pull up] ");

  error=3;

}

 

//****** Checking Dosing Pump Is working******************//

else if( (PostDocingEC<=(PreDosingEC+0.05) ) && (NutesAdded==0 && EC25<=ECSetpoint-0.2) ){

Serial.println("Dosing Problem: Check Nute Tank is full and pump is not broken ");

 

              if(Doses<=10){

              //Still Geting a good estimate for the EC

              //error=5;

          

              };

              if(Doses>=11) {

              //Proberbly a pump problem

                error=4;

              };

                                }

else error=6;

 

};

 

 

 

 

 

 

//***************** EC Optimisation ***************************//

void ECTuning(){

 

 

//stops us changing to early on [may not be needed

if(Doses<=10) return;

 

 

if(PostDocingEC>=EC25)ECSetpoint=ECSetpoint+0.1;

if(PostDocingEC<=EC25)ECSetpoint=ECSetpoint-0.1;

 

 

 

 

//Stoping the system getting a bit giddy

if (ECSetpoint>=MaxECSetpoint) ECSetpoint=MaxECSetpoint;

if(ECSetpoint<=MinECSetpoint) ECSetpoint=MinECSetpoint;

 

 

 

 

};

 

 

 

Keep watching,

Mike

  • Sign in to reply

Top Comments

  • DAB
    DAB over 7 years ago in reply to nigelburke +3
    You have confirmed what I have read about hydroponics. With the right measurement sensors you can maintain the proper growing environment for the plants and achieve impressive optimal growing rates and…
  • nigelburke
    nigelburke over 8 years ago in reply to m.ratcliffe +2
    No pictures I'm afraid m.ratcliffe , that would be somewhat akin to seeing a right-hook coming, and then actually leaning into it. I can tell you however, that the system has worked really well with the…
  • nigelburke
    nigelburke over 8 years ago +1
    Hi Mike, I am loving your work so far. Thank you for your efforts. Now. I thought I would give this a go, but using Comfrey Tea instead of urine, so I went about making a few gallons, and now have a small…
Parents
  • nigelburke
    nigelburke over 8 years ago

    Hi Mike,

    I am loving your work so far. Thank you for your efforts.

    Now. I thought I would give this a go, but using Comfrey Tea instead of urine, so I went about making a few gallons, and now have a small indoor grow setup to give it a whirl. It has been running for a few days now without any plants so it can build up some helpful bacteria and stuff.

    No problems so far, but I was wondering if you have done any more testing yet, and if you had any advice that might prevent me making any big mistakes.

    m.ratcliffe

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • m.ratcliffe
    m.ratcliffe over 8 years ago in reply to nigelburke

    Thanks Nigel,  My only advice is to add some max [might be min?] limits to the estimated EC/second for the self learning portion. That way if you get a temporary blocked pump [or similar issue] it wont go crazy and kill your system image

     

     

    Best of luck

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • m.ratcliffe
    m.ratcliffe over 8 years ago in reply to nigelburke

    Thanks Nigel for the feedback, I appreciate it. A few pictures of your setup would be great. Are you in the uk?

     

    We too have been experimenting with eggshells and bicarb for pH adjustments, great isnt it image

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • nigelburke
    nigelburke over 8 years ago in reply to m.ratcliffe

    No pictures  I'm afraid  m.ratcliffe, that would be somewhat akin to seeing a right-hook coming, and then actually leaning into it.  image

    I can tell you however, that the system has worked really well with the Comfrey/Eggshell-pottassium-bicarb mix.

    So well that I intend to try again, but with more Comfrey at a stronger rate to begin with. Next year that though, after Comfrey  harvest.

    What I would love for it to do as well would be to read the level in the nutrient tank and top-up with water accordingly.

    I can see it won't be long now before we can pretty-much 'plant-and-walk-away' until harvest time. It is all very clever stuff and I am but a grateful end-user. Thanks again.  I will, of course, let you know of any breakages/developments as and when they arrive,all the way from Wales.

    ....And yes,it is great! image

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • m.ratcliffe
    m.ratcliffe over 8 years ago in reply to nigelburke

    Hey Nigel,  If your only in wales I can send you the next generation hydroponics automation via post, for free catch being I would love some critical feedback about it image

     

    Drop me a text/call if your interested 07510530073

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • nigelburke
    nigelburke over 8 years ago in reply to m.ratcliffe

    So here we are, some time since the last update of Dec 14 last year.

     

    Same plant, being fed by the same system, but this time using Canna Aqua two-part nutes, pre-mixed with water to an EC of about 10 as a nutrient supply.

     

    All I did was to switch off the 'Dweeb' (As it has become affectionately known) and the pump while I drained and flushed the main tank, and also mixed the nutes up. I then refilled with 70 or-so litres of water, dropped the pump into the new mix, flicked the Dweeb back on and went in for tea and bed.

     

    Sure enough, by the next morning, when the temperature of the water had raised back up to 18-19degC, the EC was exactly as I had set it.

    The plant, which is what it is all about, is as green as a green thing too.

    Still can't fault this system.m.ratcliffe  As before, the adventure continues.

     

    Many thanks again.

     

    Nigel.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • nigelburke
    nigelburke over 8 years ago in reply to nigelburke

    Just a quick question m.ratcliffe, if that's ok.

     

    Suppose I set an EC of, say, 1.5 while growing a plant known to be a 'greedy feeder', and the plant is happy enough for a while but then, as you explain in the video, a plants needs can change and the EC Tuning routine you have developed is to change the EC as needed. My question is that, should the EC change by more than a certain amount (half-a-point?), is that when it warns of an overshoot?

     

    Regards

     

    Nigel

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • nigelburke
    nigelburke over 8 years ago in reply to nigelburke

    Just a quick question m.ratcliffe, if that's ok.

     

    Suppose I set an EC of, say, 1.5 while growing a plant known to be a 'greedy feeder', and the plant is happy enough for a while but then, as you explain in the video, a plants needs can change and the EC Tuning routine you have developed is to change the EC as needed. My question is that, should the EC change by more than a certain amount (half-a-point?), is that when it warns of an overshoot?

     

    Regards

     

    Nigel

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
  • nigelburke
    nigelburke over 8 years ago in reply to nigelburke

    Ok. Grow's over. Final analysis.

     

    Because of the way my plants feed, it seems it exceeded one or two ranges that were set for the more general vegetable gardening.

    For instance, it gave an overshoot warning after the EC had raised more than .5, as mentioned above, but this is has been a months-long test growing plants it was never designed to.

    I believe we can still get some useful information from it though none-the-less.

     

    We have a very poor/intermittent mains power supply here with frequent power-downs and cuts. The software coped admirably with it all, needing no attention at all when restarting after an interruption, and proving to be rock-solid in the way it stores variables in the Eprom.

     

    Plant health was dodgy at first, due to me trying a home-made Comfrey nutrient mix that was too weak.

    During the flowering stage though, I used conventional two-part nutrients and the system produced one of the healthiest plants I have seen in a goodly while.

    All the way through to the very end the plant was in excellent health and as green as I have seen one.

     

    Overall, I can't recommend this software/system enough, to be fair. I have one or two tiny tweaks to make to suit, nothing much, and there are more than one persons asking me to help copy the system for them too. What better praise?

     

    Thanks again m.ratcliffe. Not just for the instructions and software, but also for helping me understand better how to grow healthy plants, and for making my life easier whilst doing it.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB over 8 years ago in reply to nigelburke

    At the very least you now have a baseline system to compare future improvements against.

     

    Any farmer will tell you that each growing season is unique.  Regardless of all the planning, preparations, and every thing else, there are just too many weather and growing variables to do accurate year to year comparisons.

     

    At harvest time, you get what you get.  Hopefully it is enough to survive.

     

    The key to survival is eliminating as many variables as possible using new technology to give yourself that extra edge.

     

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • nigelburke
    nigelburke over 8 years ago in reply to DAB

    Indeed DAB

    I am just starting afresh. This time with two-part nutrients from the beginning so the software can have its head..

    I spoke to the good people at Canna who advised me that making up a strong nutrient mix, so I would have to use only one nutrient supply pump was acceptable, providing the mix was kept agitated by reading it some British pre-election claptrap, or an airstone, which was my final choice. image

    So yes. Off again with a little more understanding of both the plants and the software, and with a lot more confidence in the system as a whole..... Although tomorrow I intend to do away with the plug-in power connector, in favour of soldering the power cable directly to the 'VIN' posts because I have bumped it once or twice, just lightly, and the poor connection made the whole thing reset. I can't afford to have the thing power down on me when the going's good...

    Whilst typing this I am simply waiting for the software to bring the EC up to a starting-point of 0.8 just to get us off and to water the seedlings with. Having already filled and tested the system for leaks, all I hade to do was make up the nutrient bucket, plop a small pump into it and turn the whole thing on....

    Gardening was never so easy DAB. I had just about resigned myself to having to stop growing because of my ever-decreasing mobility and inability to haul buckets of water around. This has pretty much eliminated that side of it and given me something to smile about again.

    Happy days.

     

    Nigel.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB over 8 years ago in reply to nigelburke

    Sounds good.

     

    Keep us updated on your progress.

     

    If you keep making it look easy, I just might have to install one myself. image

     

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • nigelburke
    nigelburke over 8 years ago in reply to DAB

    Almost there @DAB. Just a week or two away from harvest, as far as I can tell.

    Uneventful is the word really. The whole grow, from top to bottom is green. Green and shiny.

     

    It turned out, somehow or other, that one of the four plants was an unwanted male, which would have spoiled things by fertilising the female, who in turn would have in turn spent their energy producing seeds. After the male had been removed it took next to no time for the remaining three plants to fill in the void and use up all the space in the 'screen of green' as some are wont to call it, and it is still crowded. Perhaps next time, two plants will be enough to fill the 1.2msq net.

     

    I'm really looking forward to cropping-time this time around. The software has had a reasonably fair trial using commercial nutrients, so now it's all about the harvest. Fingers crossed, but if looks alone are anything to go by there's going to be plenty to go around.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube