ec probe calibration
This commit is contained in:
parent
798ef496e1
commit
f0678485be
112
include/ec.h
112
include/ec.h
|
@ -2,11 +2,13 @@
|
|||
#define _EC_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
/*
|
||||
mqttValueTiming timing_ec_adc;
|
||||
mqttValueTiming timing_ec_calibadc;
|
||||
mqttValueTiming timing_ec_adcadjusted;
|
||||
mqttValueTiming timing_ec_ec;
|
||||
mqttValueTiming timing_ec_sc;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +19,7 @@ bool ec_flag_measurement_available=false;
|
|||
|
||||
|
||||
#define EC_PIN_RELAY_PROBE 27
|
||||
#define EC_PIN_RELAY_PROBESELECT 26
|
||||
|
||||
|
||||
//#define EC_PIN_ADC 4
|
||||
|
@ -26,7 +29,8 @@ bool ec_flag_measurement_available=false;
|
|||
#define EC_RESOLUTION 8
|
||||
#define EC_FREQUENCY 5000
|
||||
|
||||
#define EC_CALIB_ARRAY_SIZE 128
|
||||
//#define EC_CALIB_ARRAY_SIZE 128
|
||||
#define EC_CALIB_ARRAY_SIZE 32 //temporarily changed
|
||||
uint16_t ec_calib_array[EC_CALIB_ARRAY_SIZE];
|
||||
uint16_t ec_calib_array_pos=0;
|
||||
#define EC_CALIB_READ_INTERVAL 250 //interval of reading adc value inside a measurement
|
||||
|
@ -48,13 +52,22 @@ unsigned long ec_last_change_relay=0; //millis of last relay change
|
|||
|
||||
enum ECState{IDLE,MEASURE};
|
||||
|
||||
uint8_t probeselect=0;
|
||||
const uint8_t num_probes=2;
|
||||
|
||||
ECState ecstate=IDLE;
|
||||
|
||||
float ec_adc;
|
||||
float ec_adc_adjusted; //adjusted for reference resistor
|
||||
float ec_calib_adc;
|
||||
float ec; //ec value after adjustment for reference (at current temperature)
|
||||
float ec25; //ec value but temperature adjusted for 25 degC
|
||||
|
||||
float ec_adc_A;
|
||||
float ec_adc_adjusted_A; //adjusted for reference resistor
|
||||
float ec_A; //ec value after adjustment for reference (at current temperature)
|
||||
float ec25_A; //ec value but temperature adjusted for 25 degC
|
||||
|
||||
float ec_adc_B;
|
||||
float ec_adc_adjusted_B; //adjusted for reference resistor
|
||||
float ec_B; //ec value after adjustment for reference (at current temperature)
|
||||
float ec25_B; //ec value but temperature adjusted for 25 degC
|
||||
|
||||
float ec_tempadjust_alpa=0.02;
|
||||
float ec_reference_adc=6016.88; //adc reference value for the calibration resistor measurement.
|
||||
|
@ -66,21 +79,27 @@ float ec_reference_adc=6016.88; //adc reference value for the calibration resist
|
|||
//float ec_calibration_polynom[]={1033.928052655456,-3.8909104921922895,0.005627541436014758,-4.103988840997024e-06,1.7231981870816133e-09,-4.433707707721975e-13,7.203892111369395e-17,-7.406549810844244e-21,4.667420606439905e-25,-1.6439457516812463e-29,2.477292190335455e-34}; //20220505
|
||||
//float ec_calibration_polynom[]={-323.68589929771457,0.5836096440900665,-0.000279737392438965,5.98673062873e-08,-5.4460235093798435e-12,1.8535134644431135e-16}; //20230509
|
||||
//float ec_calibration_polynom[]={212.6826331524675,-0.6043878865263305,0.000571551634082491,-1.827897106718841e-07,2.682337041246909e-11,-1.8368511021965982e-15,4.8269168538877025e-20}; //20230509 manuell
|
||||
float ec_calibration_polynom[]={-202.42892340068445,0.3775267988688599,-0.0001603031198536654,3.398964768344757e-08,-3.0277753798278316e-12,1.0137804308289433e-16}; //20230620, graphite electrodes
|
||||
float ec_calibration_linearize_below_adc=4000; //use linear approximation below this adc value. 0=disable
|
||||
float ec_calibration_linear_lowADC=746; //x0
|
||||
float ec_calibration_linear_lowEC=0; //y0
|
||||
float ec_calibration_polynom_A[]={18.953002079376887,-0.057529180570340156,7.44612274805891e-05,-8.847448650204697e-09,5.388914121653647e-13}; //20240423, graphite electrodes
|
||||
float ec_calibration_linearize_below_adc_A=2000; //use linear approximation below this adc value. 0=disable
|
||||
float ec_calibration_linear_lowADC_A=728; //x0
|
||||
float ec_calibration_linear_lowEC_A=0; //y0
|
||||
|
||||
|
||||
float ec_calibration_polynom_B[]={40.838922264426685,-0.08846039894456156,7.671298605466989e-05,-9.161423581523883e-09,5.529701600660142e-13}; //20240423, graphite electrodes
|
||||
float ec_calibration_linearize_below_adc_B=2000; //use linear approximation below this adc value. 0=disable
|
||||
float ec_calibration_linear_lowADC_B=728; //x0
|
||||
float ec_calibration_linear_lowEC_B=0; //y0
|
||||
|
||||
bool ec_measurementReady();
|
||||
void ec_startMeasurement();
|
||||
void ec_setRange(uint8_t range);
|
||||
void ec_connectProbe(bool);
|
||||
void ec_connectProbe(bool, uint8_t);
|
||||
void ec_releaseRelay();
|
||||
float ec_getECfromADC(float adc);
|
||||
float ec_getECfromADC(float adc, float ec_calibration_polynom[], size_t len_ec_calibration_polynom, float ec_calibration_linearize_below_adc, float ec_calibration_linear_lowADC, float ec_calibration_linear_lowEC);
|
||||
float ec_calculateEC25(float pEC,float pTemp);
|
||||
|
||||
void ec_setup() {
|
||||
|
||||
/*
|
||||
timing_ec_adc.minchange=0.0;
|
||||
timing_ec_adc.maxchange=250;
|
||||
timing_ec_adc.mintime=10*000;
|
||||
|
@ -105,13 +124,14 @@ void ec_setup() {
|
|||
timing_ec_sc.maxchange=50;
|
||||
timing_ec_sc.mintime=10*000;
|
||||
timing_ec_sc.maxtime=60*60*1000;
|
||||
|
||||
*/
|
||||
|
||||
ledcSetup(EC_PWM_CH, EC_FREQUENCY, EC_RESOLUTION);
|
||||
ledcAttachPin(EC_PIN_FREQ, EC_PWM_CH);
|
||||
ledcWrite(EC_PWM_CH, 127); //50% duty cycle
|
||||
|
||||
pinMode(EC_PIN_RELAY_PROBE,OUTPUT); //LOW=Calibration/idle, HIGH=Probe connected
|
||||
pinMode(EC_PIN_RELAY_PROBESELECT,OUTPUT); //LOW=Probe A, HIGH=Probe B
|
||||
ec_releaseRelay();
|
||||
|
||||
}
|
||||
|
@ -125,10 +145,12 @@ void ec_loop(unsigned long loopmillis) {
|
|||
case IDLE:
|
||||
|
||||
if (loopmillis>last_measurement_ec+EC_MEASUREMENT_INTERVAL || force_ec_measurement) { //start measurement if idle
|
||||
//Serial.println("DEBUG: Start measurement");
|
||||
last_measurement_ec=loopmillis;
|
||||
force_ec_measurement=false;
|
||||
ec_startMeasurement();
|
||||
ec_connectProbe(true);
|
||||
ec_connectProbe(true,0); //Probe A
|
||||
|
||||
|
||||
ecstate=MEASURE;
|
||||
}
|
||||
|
@ -136,23 +158,58 @@ void ec_loop(unsigned long loopmillis) {
|
|||
|
||||
case MEASURE:
|
||||
if (ec_measurementReady()) {
|
||||
//Serial.println("DEBUG: Measurement Ready");
|
||||
float ec_adc;
|
||||
float ec_adc_adjusted;
|
||||
float ec;
|
||||
float ec25;
|
||||
|
||||
ec_releaseRelay();
|
||||
ec_adc=getMean(ec_array,EC_ARRAY_SIZE);
|
||||
if (isValueArrayOK(ec_calib_array,EC_CALIB_ARRAY_SIZE,EC_ADC_UNAVAILABLE)){
|
||||
ec_calib_adc=getMean(ec_calib_array,EC_CALIB_ARRAY_SIZE);
|
||||
ec_adc_adjusted=mapf(ec_adc,0,ec_calib_adc,0,ec_reference_adc);
|
||||
ec=ec_getECfromADC(ec_adc_adjusted);
|
||||
if (probeselect==0) {
|
||||
ec=ec_getECfromADC(ec_adc_adjusted, ec_calibration_polynom_A, sizeof(ec_calibration_polynom_A), ec_calibration_linearize_below_adc_A, ec_calibration_linear_lowADC_A, ec_calibration_linear_lowEC_A);
|
||||
}else if (probeselect==1) {
|
||||
ec=ec_getECfromADC(ec_adc_adjusted, ec_calibration_polynom_B, sizeof(ec_calibration_polynom_B), ec_calibration_linearize_below_adc_B, ec_calibration_linear_lowADC_B, ec_calibration_linear_lowEC_B);
|
||||
}
|
||||
ec25=ec_calculateEC25(ec,tempC_reservoir);
|
||||
//Serial.println("DEBUG: EC OK");
|
||||
}else{
|
||||
ec_calib_adc=EC_ADC_UNAVAILABLE;
|
||||
ec_adc_adjusted=EC_ADC_UNAVAILABLE;
|
||||
ec=EC_UNAVAILABLE;
|
||||
ec25=EC_UNAVAILABLE;
|
||||
//Serial.println("DEBUG: EC unavailable");
|
||||
}
|
||||
|
||||
ec_flag_measurement_available=true;
|
||||
if (probeselect==0) {
|
||||
//Serial.println("DEBUG: Assigning to A");
|
||||
ec_adc_A=ec_adc;
|
||||
ec_adc_adjusted_A=ec_adc_adjusted;
|
||||
ec_A=ec;
|
||||
ec25_A=ec25;
|
||||
|
||||
last_measurement_ec=loopmillis;
|
||||
force_ec_measurement=false;
|
||||
ec_startMeasurement();
|
||||
probeselect=1; //Select Probe B
|
||||
ec_connectProbe(true,probeselect); //Probe B
|
||||
ecstate=MEASURE;
|
||||
|
||||
}else if(probeselect==1) {
|
||||
//Serial.println("DEBUG: Assigning to B");
|
||||
ec_adc_B=ec_adc;
|
||||
ec_adc_adjusted_B=ec_adc_adjusted;
|
||||
ec_B=ec;
|
||||
ec25_B=ec25;
|
||||
|
||||
probeselect=0; //Reset to Probe A
|
||||
ec_flag_measurement_available=true;
|
||||
ecstate=IDLE;
|
||||
}
|
||||
|
||||
ecstate=IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -209,21 +266,36 @@ bool ec_measurementReady(){
|
|||
}
|
||||
|
||||
|
||||
void ec_connectProbe(bool relay) {
|
||||
void ec_connectProbe(bool relay, uint8_t probeselect) {
|
||||
bool val=digitalRead(EC_PIN_RELAY_PROBE);
|
||||
bool valsel=digitalRead(EC_PIN_RELAY_PROBESELECT);
|
||||
if (val!=relay) { //write only if different
|
||||
digitalWrite(EC_PIN_RELAY_PROBE,relay);
|
||||
//Serial.print("DEBUG: Set Relay to "); Serial.println(relay);
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
if (valsel!=probeselect) { //write only if different
|
||||
if (probeselect==0) {
|
||||
digitalWrite(EC_PIN_RELAY_PROBESELECT,false);
|
||||
//Serial.println("DEBUG: Selected Probe A");
|
||||
}else if (probeselect==1) {
|
||||
digitalWrite(EC_PIN_RELAY_PROBESELECT,true);
|
||||
//Serial.println("DEBUG: Selected Probe B");
|
||||
}
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
}
|
||||
|
||||
void ec_releaseRelay() {
|
||||
digitalWrite(EC_PIN_RELAY_PROBE,LOW);
|
||||
digitalWrite(EC_PIN_RELAY_PROBESELECT,LOW);
|
||||
//Serial.println("DEBUG: Released Relays");
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
|
||||
float ec_getECfromADC(float adc) {
|
||||
uint8_t polynom_order=sizeof(ec_calibration_polynom) / sizeof(ec_calibration_polynom[0]);
|
||||
float ec_getECfromADC(float adc, float ec_calibration_polynom[], size_t len_ec_calibration_polynom, float ec_calibration_linearize_below_adc, float ec_calibration_linear_lowADC, float ec_calibration_linear_lowEC) {
|
||||
//uint8_t polynom_order=sizeof(ec_calibration_polynom) / sizeof(ec_calibration_polynom[0]);
|
||||
uint8_t polynom_order=len_ec_calibration_polynom / sizeof(ec_calibration_polynom[0]);
|
||||
double _ec=0;
|
||||
if (adc>=ec_calibration_linearize_below_adc) { //adc is in range where polynomial approximation fits well
|
||||
for (uint8_t i=0;i<polynom_order;i++) {
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
#ifndef _EC_H_
|
||||
#define _EC_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define EC_PIN_RELAY_PROBE 27
|
||||
#define EC_PIN_RELAY_CALIBRATION 26
|
||||
#define EC_PIN_RELAY_RANGE 25
|
||||
|
||||
|
||||
#define EC_PIN_ADC 4
|
||||
#define EC_PIN_FREQ 5
|
||||
#define EC_PWM_CH 0
|
||||
#define EC_RESOLUTION 8
|
||||
#define EC_FREQUENCY 5000
|
||||
|
||||
#define EC_ARRAY_SIZE 128
|
||||
uint16_t ec_array_rangeLow[EC_ARRAY_SIZE];
|
||||
uint16_t ec_array_rangeHigh[EC_ARRAY_SIZE];
|
||||
uint16_t ec_array_pos=EC_ARRAY_SIZE*2;
|
||||
#define EC_MEASUREMENT_INTERVAL 10000 //complete filtered measurement every x ms
|
||||
//One filtered measurement takes EC_READ_INTERVAL*EC_ARRAY_SIZE*2
|
||||
#define EC_READ_INTERVAL 5 //interval of reading adc value inside a measurement
|
||||
|
||||
|
||||
|
||||
float ec_calib_rangeLow_Rlow=0; //adc value for low value resistor on low resistor value range
|
||||
float ec_calib_rangeLow_Rhigh=0; //adc value for high value resistor on low resistor value range
|
||||
float ec_calib_rangeHigh_Rlow=0; //adc value for low value resistor on high resistor value range
|
||||
float ec_calib_rangeHigh_Rhigh=0; //adc value for high value resistor on high resistor value range
|
||||
const float ec_calibresistor_low=990; //value of low value calibration resistor. Low is Relay NO
|
||||
const float ec_calibresistor_high=9943; //value of high value calibration resistor. HIGH is Relay NC
|
||||
|
||||
unsigned long ec_last_calibration=0; //millis of last calibration
|
||||
#define EC_CALIBRATION_VALID_TIME 120000 //time in ms a calibration is valid for
|
||||
#define EC_RELAY_SWITCH_SETTLETIME 500 //time until voltage of ec circuit has settled
|
||||
|
||||
unsigned long ec_last_change_relay=0; //millis of last relay change
|
||||
|
||||
enum ECState{IDLE,CALIBRATELOW,CALIBRATEHIGH,MEASURE};
|
||||
|
||||
ECState ecstate=CALIBRATELOW;
|
||||
|
||||
|
||||
bool ec_measurementReady();
|
||||
void ec_startMeasurement();
|
||||
void ec_setRange(bool);
|
||||
void ec_connectProbe(bool);
|
||||
void ec_setCalibration(bool calib);
|
||||
void ec_releaseRelay();
|
||||
void ec_startCalibration();
|
||||
void ec_checkIfSettleTimeOK();
|
||||
float ec_getResistance(float adc,float caliblow,float resistorlow,float calibhigh,float resistorhigh);
|
||||
|
||||
void ec_setup() {
|
||||
pinMode(EC_PIN_ADC,INPUT);
|
||||
|
||||
ledcSetup(EC_PWM_CH, EC_FREQUENCY, EC_RESOLUTION);
|
||||
ledcAttachPin(EC_PIN_FREQ, EC_PWM_CH);
|
||||
ledcWrite(EC_PWM_CH, 127); //50% duty cycle
|
||||
|
||||
pinMode(EC_PIN_RELAY_PROBE,OUTPUT); //LOW=Calibration/idle, HIGH=Probe connected
|
||||
pinMode(EC_PIN_RELAY_CALIBRATION,OUTPUT); //LOW=NC Calibration Resistor, HIGH=NO Calib. Res.
|
||||
pinMode(EC_PIN_RELAY_RANGE,OUTPUT); //LOW=NC Range Resistor, HIGH=NO Range Resistor
|
||||
ec_releaseRelay();
|
||||
|
||||
|
||||
ec_startCalibration();
|
||||
}
|
||||
|
||||
void ec_loop(unsigned long loopmillis) {
|
||||
static unsigned long last_measurement_ec=0;
|
||||
static unsigned long last_read_ec=0;
|
||||
|
||||
switch (ecstate) {
|
||||
case IDLE:
|
||||
|
||||
if (loopmillis>ec_last_calibration+EC_CALIBRATION_VALID_TIME) { //calibration needed
|
||||
ec_last_calibration=loopmillis;
|
||||
ecstate=CALIBRATELOW;
|
||||
|
||||
ec_startCalibration();
|
||||
}
|
||||
|
||||
|
||||
if (loopmillis>last_measurement_ec+EC_MEASUREMENT_INTERVAL && ecstate==IDLE) { //start measurement if idle
|
||||
last_measurement_ec=loopmillis;
|
||||
ec_startMeasurement();
|
||||
ec_connectProbe(true);
|
||||
ecstate=MEASURE;
|
||||
Serial.println("EC Take Measurement");
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CALIBRATELOW:
|
||||
if (ec_measurementReady()) {
|
||||
//Serial.println("EC CALIBRATELOW measurement ready");
|
||||
//save measurement
|
||||
ec_calib_rangeLow_Rlow=getMean(ec_array_rangeLow,EC_ARRAY_SIZE);
|
||||
ec_calib_rangeHigh_Rlow=getMean(ec_array_rangeHigh,EC_ARRAY_SIZE);
|
||||
|
||||
//ec_checkIfSettleTimeOK();
|
||||
|
||||
//Switch to High calibration
|
||||
ecstate=CALIBRATEHIGH;
|
||||
|
||||
ec_setCalibration(HIGH);
|
||||
ec_setRange(LOW);
|
||||
ec_startMeasurement();
|
||||
//Serial.println("EC Start calibration high");
|
||||
}
|
||||
break;
|
||||
|
||||
case CALIBRATEHIGH:
|
||||
if (ec_measurementReady()) {
|
||||
//Serial.println("EC CALIBRATEHIGH measurement ready");
|
||||
//save measurement
|
||||
ec_calib_rangeLow_Rhigh=getMean(ec_array_rangeLow,EC_ARRAY_SIZE);
|
||||
ec_calib_rangeHigh_Rhigh=getMean(ec_array_rangeHigh,EC_ARRAY_SIZE);
|
||||
|
||||
//ec_checkIfSettleTimeOK();
|
||||
|
||||
//Serial.println("EC Release Relay");
|
||||
ec_releaseRelay();
|
||||
|
||||
ecstate=IDLE;
|
||||
|
||||
/*
|
||||
Serial.println("EC Calibration done");
|
||||
Serial.print("ec_calib_rangeLow_Rlow="); Serial.println(ec_calib_rangeLow_Rlow);
|
||||
Serial.print("ec_calib_rangeHigh_Rlow="); Serial.println(ec_calib_rangeHigh_Rlow);
|
||||
Serial.print("ec_calib_rangeLow_Rhigh="); Serial.println(ec_calib_rangeLow_Rhigh);
|
||||
Serial.print("ec_calib_rangeHigh_Rhigh="); Serial.println(ec_calib_rangeHigh_Rhigh);
|
||||
*/
|
||||
Serial.println("EC Calibration Result: ");
|
||||
Serial.print(ec_calib_rangeLow_Rlow);
|
||||
Serial.print(", "); Serial.print(ec_calib_rangeHigh_Rlow);
|
||||
Serial.print(", "); Serial.print(ec_calib_rangeLow_Rhigh);
|
||||
Serial.print(", "); Serial.println(ec_calib_rangeHigh_Rhigh);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case MEASURE:
|
||||
if (ec_measurementReady()) {
|
||||
ec_releaseRelay();
|
||||
float adc_rangelow=getMean(ec_array_rangeLow,EC_ARRAY_SIZE);
|
||||
float adc_rangehigh=getMean(ec_array_rangeHigh,EC_ARRAY_SIZE);
|
||||
|
||||
Serial.println();
|
||||
float resistance_rangelow=ec_getResistance(adc_rangelow,ec_calib_rangeLow_Rlow,ec_calibresistor_low,ec_calib_rangeLow_Rhigh,ec_calibresistor_high);
|
||||
Serial.print("Range Low: ADC="); Serial.print(adc_rangelow); Serial.print(", resistance="); Serial.println(resistance_rangelow);
|
||||
Serial.println();
|
||||
float resistance_rangehigh=ec_getResistance(adc_rangehigh,ec_calib_rangeHigh_Rlow,ec_calibresistor_low,ec_calib_rangeHigh_Rhigh,ec_calibresistor_high);
|
||||
Serial.print("Range High: ADC="); Serial.print(adc_rangehigh); Serial.print(", resistance="); Serial.println(resistance_rangehigh);
|
||||
ecstate=IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (loopmillis>last_read_ec+EC_READ_INTERVAL && ec_array_pos/2<EC_ARRAY_SIZE) { //take reading into array if measurement running
|
||||
last_read_ec=loopmillis;
|
||||
|
||||
//flag_print= ec_array_pos==EC_ARRAY_SIZE;
|
||||
//ec_array_pos%=EC_ARRAY_SIZE;
|
||||
|
||||
if (ec_array_pos<EC_ARRAY_SIZE){ //low range
|
||||
ec_setRange(LOW);
|
||||
}else{ //high range
|
||||
ec_setRange(HIGH);
|
||||
}
|
||||
|
||||
if (loopmillis>ec_last_change_relay+EC_RELAY_SWITCH_SETTLETIME) { //values have settled
|
||||
uint16_t value=analogRead(EC_PIN_ADC);
|
||||
if (ec_array_pos<EC_ARRAY_SIZE){ //low range
|
||||
ec_array_rangeLow[ec_array_pos%EC_ARRAY_SIZE]=value;
|
||||
|
||||
}else{ //high range
|
||||
ec_array_rangeHigh[ec_array_pos%EC_ARRAY_SIZE]=value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (ec_array_pos==0) {
|
||||
Serial.println(""); Serial.print("Lowrange:");
|
||||
}
|
||||
if (ec_array_pos==EC_ARRAY_SIZE) {
|
||||
Serial.println(""); Serial.print("Highrange:");
|
||||
}
|
||||
Serial.print(value); Serial.print(" ");
|
||||
if (ec_array_pos==EC_ARRAY_SIZE*2-1) {
|
||||
Serial.println("");
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
ec_array_pos++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ec_startCalibration() {
|
||||
//Switch to Low calibration
|
||||
ec_setCalibration(LOW);
|
||||
ec_setRange(LOW);
|
||||
ec_startMeasurement();
|
||||
Serial.println("EC Started Calibration");
|
||||
}
|
||||
|
||||
void ec_startMeasurement() {
|
||||
ec_array_pos=0;
|
||||
}
|
||||
|
||||
bool ec_measurementReady(){
|
||||
if (ec_array_pos>=EC_ARRAY_SIZE*2) { //reached end of both arrays
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ec_setRange(bool range) {
|
||||
//range low means low resistor value -> NO -> relay High
|
||||
bool val=digitalRead(EC_PIN_RELAY_RANGE);
|
||||
if (val!=!range) { //write only if different
|
||||
digitalWrite(EC_PIN_RELAY_RANGE,!range);
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
}
|
||||
|
||||
void ec_connectProbe(bool relay) {
|
||||
bool val=digitalRead(EC_PIN_RELAY_PROBE);
|
||||
if (val!=relay) { //write only if different
|
||||
digitalWrite(EC_PIN_RELAY_PROBE,relay);
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
}
|
||||
|
||||
void ec_setCalibration(bool calib) {
|
||||
//calib low means low resistor value -> NO -> relay high
|
||||
ec_connectProbe(false);
|
||||
bool val=digitalRead(EC_PIN_RELAY_CALIBRATION);
|
||||
if (val!=!calib) { //write only if different
|
||||
digitalWrite(EC_PIN_RELAY_CALIBRATION,!calib);
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
}
|
||||
|
||||
void ec_releaseRelay() {
|
||||
digitalWrite(EC_PIN_RELAY_PROBE,LOW);
|
||||
digitalWrite(EC_PIN_RELAY_CALIBRATION,LOW);
|
||||
digitalWrite(EC_PIN_RELAY_RANGE,LOW);
|
||||
ec_last_change_relay=millis();
|
||||
}
|
||||
|
||||
void ec_checkIfSettleTimeOK() {
|
||||
/*
|
||||
Serial.print("ec_array_rangeLow[0]="); Serial.println(ec_array_rangeLow[0]);
|
||||
Serial.print("rangeLow min="); Serial.println(getMin(ec_array_rangeLow,EC_ARRAY_SIZE));
|
||||
Serial.print("rangeLow max="); Serial.println(getMax(ec_array_rangeLow,EC_ARRAY_SIZE));
|
||||
*/
|
||||
if (ec_array_rangeLow[0]<=getMin(ec_array_rangeLow,EC_ARRAY_SIZE) || ec_array_rangeLow[0]>=getMax(ec_array_rangeLow,EC_ARRAY_SIZE)){
|
||||
//is first value the highest or lowest?
|
||||
Serial.println("Warning: EC_RELAY_SWITCH_SETTLETIME might be too low! (ec_calib_rangeLow_Rlow)");
|
||||
}
|
||||
|
||||
/*
|
||||
Serial.print("ec_array_rangeHigh[0]="); Serial.println(ec_array_rangeHigh[0]);
|
||||
Serial.print("rangeHigh min="); Serial.println(getMin(ec_array_rangeHigh,EC_ARRAY_SIZE));
|
||||
Serial.print("rangeHigh max="); Serial.println(getMax(ec_array_rangeHigh,EC_ARRAY_SIZE));
|
||||
*/
|
||||
if (ec_array_rangeHigh[0]<=getMin(ec_array_rangeHigh,EC_ARRAY_SIZE) || ec_array_rangeHigh[0]>=getMax(ec_array_rangeHigh,EC_ARRAY_SIZE)){
|
||||
//is first value the highest or lowest?
|
||||
Serial.println("Warning: EC_RELAY_SWITCH_SETTLETIME might be too low! (ec_array_rangeHigh)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float ec_getResistance(float adc,float caliblow,float resistorlow,float calibhigh,float resistorhigh)
|
||||
{
|
||||
//adc = adc reading to calculate resistance for
|
||||
//caliblow = adc value from calibration. Low resistance
|
||||
//resistorlow = actual resistor value. Low resistance
|
||||
//calibhjgh = adc value from calibration. High resistance
|
||||
//resistorhigh = actual resistor value. High resistance
|
||||
|
||||
//y=mx+a;
|
||||
//resistorlow=m*caliblow+a;
|
||||
//resistorhigh=m*calibhigh+a;
|
||||
|
||||
//linear interpolation interpolate
|
||||
double m=(resistorhigh-resistorlow)/(calibhigh-caliblow);
|
||||
float a=resistorlow-m*caliblow;
|
||||
|
||||
Serial.print("m="); Serial.println(m);
|
||||
Serial.print("a="); Serial.println(a);
|
||||
|
||||
return m*adc+a;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -140,6 +140,7 @@ void temperature_loop(unsigned long loopmillis) {
|
|||
}
|
||||
}
|
||||
|
||||
/* temporarily disabled
|
||||
tempC_air = sensors.getTempC(thermometerAir);
|
||||
if (tempC_air == DEVICE_DISCONNECTED_C)
|
||||
{
|
||||
|
@ -152,6 +153,7 @@ void temperature_loop(unsigned long loopmillis) {
|
|||
tempCmean_air=DEVICE_DISCONNECTED_C;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
tempC_case = sensors.getTempC(thermometerCase);
|
||||
if (tempC_case == DEVICE_DISCONNECTED_C)
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef _WATERLEVEL_H_
|
||||
#define _WATERLEVEL_H_
|
||||
|
||||
|
||||
#include <HCSR04.h>
|
||||
#define HCSR04_PIN_ECHO 17
|
||||
#define HCSR04_PIN_TRIGGER 16
|
||||
#define HCSR04_TIMEOUT 5000 //default is 100000 (uS)
|
||||
#define READINTERVAL_HCSR04 200
|
||||
|
||||
#define WATERLEVELMEAN_SIZE 32
|
||||
#define WATERLEVELMEAN_FILTER_CUTOFF 8 //max value is around WATERLEVELMEAN_SIZE/2
|
||||
float waterlevelMean_array[WATERLEVELMEAN_SIZE];
|
||||
uint16_t waterlevelMean_array_pos=0;
|
||||
#define WATERLEVEL_UNAVAILABLE -1
|
||||
float waterlevel=WATERLEVEL_UNAVAILABLE; //distance from floor to water surface [mm]
|
||||
float watervolume=WATERLEVEL_UNAVAILABLE; //calculated Volume in Reservoir
|
||||
|
||||
uint16_t waterlevel_failcounter=0;
|
||||
#define WATERLEVEL_MAXFAILS 15 //maximum counter value
|
||||
#define WATERLEVEL_FAILTHRESHOLD 10 //if failcounter is greater or equal this value waterlevel will not be valid
|
||||
|
||||
//Calibration
|
||||
float waterlevel_calib_offset_measured=0; //Sollwert
|
||||
float waterlevel_calib_offset_sensor=178.67; //Istwert
|
||||
|
||||
float waterlevel_calib_reservoirArea=27*36.5; //area in cm^2
|
||||
|
||||
|
||||
float waterlevel_heightToVolume(float distance);
|
||||
|
||||
|
||||
void waterlevel_setup() {
|
||||
|
||||
//HCSR04.begin(HCSR04_PIN_TRIGGER, HCSR04_PIN_ECHO);
|
||||
HCSR04.begin(HCSR04_PIN_TRIGGER, HCSR04_PIN_ECHO,HCSR04_TIMEOUT, HCSR04.eUltraSonicUnlock_t::unlockSkip);
|
||||
for (uint16_t i=0;i<WATERLEVELMEAN_SIZE;i++) {
|
||||
waterlevelMean_array[i]=-1; //-1 is also timeout value
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void waterlevel_loop(unsigned long loopmillis) {
|
||||
|
||||
static unsigned long last_read_hcsr04;
|
||||
if (loopmillis>=last_read_hcsr04+READINTERVAL_HCSR04) {
|
||||
last_read_hcsr04=loopmillis;
|
||||
float temperature=20.0;
|
||||
if (tempCmean_air!=DEVICE_DISCONNECTED_C) { //sensor ok
|
||||
temperature=tempCmean_air;
|
||||
}
|
||||
|
||||
double* distances = HCSR04.measureDistanceMm(temperature);
|
||||
double distance=distances[0];
|
||||
//Serial.print("Distance reading:"); Serial.println(distance);
|
||||
|
||||
if (distance!=WATERLEVEL_UNAVAILABLE) { //successful
|
||||
waterlevelMean_array[waterlevelMean_array_pos]=distance;
|
||||
waterlevelMean_array_pos++;
|
||||
waterlevelMean_array_pos%=WATERLEVELMEAN_SIZE;
|
||||
if (waterlevel_failcounter>0) { //reduce failcounter if sucessfull
|
||||
waterlevel_failcounter--;
|
||||
}
|
||||
}else{
|
||||
if (waterlevel_failcounter<WATERLEVEL_MAXFAILS) {
|
||||
waterlevel_failcounter++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (isValueArrayOKf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVEL_UNAVAILABLE)){
|
||||
//float _distance=getFilteredf(waterlevelMean_array,WATERLEVELMEAN_SIZE,WATERLEVELMEAN_FILTER_CUTOFF);
|
||||
float _distance=getMaxf(waterlevelMean_array,WATERLEVELMEAN_SIZE);
|
||||
|
||||
//Invert distance and offset
|
||||
waterlevel=distance-(waterlevel_calib_offset_sensor+waterlevel_calib_offset_measured);
|
||||
watervolume=waterlevel_heightToVolume(_distance);
|
||||
|
||||
//float _meanWaterlevel=getMeanf(waterlevelMean,WATERLEVELMEAN_SIZE);
|
||||
//Serial.print("\t Dist="); Serial.print(_filteredWaterlevel); Serial.print("mm"); Serial.print("(+- "); Serial.print((getMaxf(waterlevelMean,WATERLEVELMEAN_SIZE)-getMinf(waterlevelMean,WATERLEVELMEAN_SIZE))/2.0); Serial.print(")"); Serial.print(" [mean="); Serial.print(_meanWaterlevel); Serial.print("]");
|
||||
}
|
||||
|
||||
if (waterlevel_failcounter>=WATERLEVEL_FAILTHRESHOLD) { //too many failed readings
|
||||
waterlevel=WATERLEVEL_UNAVAILABLE;
|
||||
watervolume=WATERLEVEL_UNAVAILABLE;
|
||||
/*if (debug) {
|
||||
Serial.print("Waterlevel Failcounter="); Serial.println(waterlevel_failcounter);
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
float waterlevel_heightToVolume(float distance){
|
||||
return waterlevel_calib_reservoirArea/100 * distance/100; //area[cm^2] in dm^2 * height in dm = dm^3= L
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
const char ssid[] = "";
|
||||
const char pass[] = "";
|
||||
const char ssid[] = "fischnetziot";
|
||||
const char pass[] = "LiMkJ1sVcEAU68MPEgJ";
|
||||
const char mqtt_host[] = "10.0.0.1";
|
||||
|
||||
const char client_id[] = "hydroponic";
|
|
@ -1,3 +1,5 @@
|
|||
#Use venv
|
||||
|
||||
import numpy as np
|
||||
|
||||
from scipy.optimize import curve_fit
|
||||
|
@ -8,32 +10,36 @@ import matplotlib.pyplot as plt
|
|||
from pandas import *
|
||||
|
||||
# reading CSV file
|
||||
data = read_csv("20230620_NaCl_raw.csv")
|
||||
data = read_csv("20240423_EC_Calibration.csv")
|
||||
|
||||
# converting column data to list
|
||||
#solutionAdded = data['solutionAdded'].tolist() #in ml
|
||||
solutionAdded = data['solutionAdded'].tolist() #in ml
|
||||
tempReservoir = data['tempReservoir'].tolist() #in C
|
||||
adc = data['ECadcAdjusted'].tolist() #adc reading
|
||||
adc = data['ECadcAdjusted_B'].tolist() #adc reading
|
||||
|
||||
solutionConcentration=5924.8 #mg/L NaCl
|
||||
startWaterAmount=0.3 #L
|
||||
#solutionConcentration=5924.8 #mg/L NaCl
|
||||
solutionConcentration=5690 #mg/L NaCl
|
||||
startWaterAmount=300 #mL (same unit as solutionAded)
|
||||
|
||||
ppmToECfactor=1/0.46
|
||||
|
||||
#concentration = [x*solutionConcentration/(startWaterAmount+x) for x in solutionAdded]
|
||||
#ECcalculated = [x*ppmToECfactor for x in concentration] #uS/cm
|
||||
concentration = [x*solutionConcentration/(startWaterAmount+x) for x in solutionAdded]
|
||||
ECcalculated = [x*ppmToECfactor for x in concentration] #uS/cm
|
||||
|
||||
ECmeasured = data['ecMeasured'].tolist() #in C
|
||||
#ECmeasured = data['ecMeasured'].tolist() #in C
|
||||
|
||||
#print(concentration)
|
||||
#print(ECcalculated)
|
||||
print("Concentration")
|
||||
print(concentration)
|
||||
print("")
|
||||
print("ECcalculated")
|
||||
print(ECcalculated)
|
||||
|
||||
|
||||
|
||||
x = adc
|
||||
|
||||
#y = ECcalculated
|
||||
y = ECmeasured
|
||||
y = ECcalculated
|
||||
#y = ECmeasured
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
numpy==1.22
|
||||
scipy
|
||||
matplotlib
|
||||
pandas
|
100
src/main.cpp
100
src/main.cpp
|
@ -4,9 +4,13 @@
|
|||
|
||||
#include "wifi_functions.h"
|
||||
|
||||
bool debug=true; //print Serial information
|
||||
bool mqtt=true;
|
||||
bool eccalibrationoutput=false; //serial output for ec calibration
|
||||
bool debug=false; //print Serial information
|
||||
bool mqtt=false;
|
||||
bool eccalibrationoutput=true; //serial output for ec calibration
|
||||
/* Write to file with:
|
||||
sudo stty -F /dev/ttyUSB0 115200
|
||||
cat /dev/ttyUSB0 | tee received.txt
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -75,8 +79,8 @@ void setup() {
|
|||
Serial.println("Setup EC");
|
||||
ec_setup();
|
||||
|
||||
Serial.println("Setup Waterlevel");
|
||||
waterlevel_setup();
|
||||
//Serial.println("Setup Waterlevel");
|
||||
//waterlevel_setup(); //temporarily disabled
|
||||
|
||||
Serial.println("Setup Temperature");
|
||||
temperature_setup();
|
||||
|
@ -116,7 +120,7 @@ void loop() {
|
|||
|
||||
temperature_loop(loopmillis);
|
||||
|
||||
waterlevel_loop(loopmillis);
|
||||
//waterlevel_loop(loopmillis);
|
||||
|
||||
flow_loop(loopmillis);
|
||||
|
||||
|
@ -132,11 +136,23 @@ void loop() {
|
|||
delay(100);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (eccalibrationoutput && !digitalRead(PIN_BUTTON) && !getReading) {
|
||||
getReading=true;
|
||||
force_ec_measurement=true;
|
||||
ec_flag_measurement_available=false;
|
||||
digitalWrite(PIN_LED,HIGH);
|
||||
if (!isValueArrayOK(ec_calib_array,EC_CALIB_ARRAY_SIZE,EC_ADC_UNAVAILABLE)) {
|
||||
for (uint8_t blink=0;blink<5;blink++) {
|
||||
digitalWrite(PIN_LED,HIGH);
|
||||
delay(100);
|
||||
digitalWrite(PIN_LED,LOW);
|
||||
delay(100);
|
||||
}
|
||||
}else{
|
||||
getReading=true;
|
||||
force_ec_measurement=true;
|
||||
ec_flag_measurement_available=false;
|
||||
digitalWrite(PIN_LED,HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -148,8 +164,10 @@ void loop() {
|
|||
Serial.print(loopmillis); Serial.print(",");
|
||||
Serial.print(tempCmean_reservoir); Serial.print(",");
|
||||
Serial.print(ec_calib_adc); Serial.print(",");
|
||||
Serial.print(ec_adc); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted);
|
||||
Serial.print(ec_adc_A); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted_A); Serial.print(",");
|
||||
Serial.print(ec_adc_B); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted_B);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
@ -164,7 +182,7 @@ void loop() {
|
|||
if (sm_mean1==SM_DISCONNECTED || sm_mean2==SM_DISCONNECTED) {
|
||||
valueError=true;
|
||||
}
|
||||
if (ec==EC_UNAVAILABLE){
|
||||
if (ec_A==EC_UNAVAILABLE || ec_B==EC_UNAVAILABLE){
|
||||
valueError=true;
|
||||
}
|
||||
|
||||
|
@ -213,14 +231,25 @@ void loop() {
|
|||
Serial.print("Flow = "); Serial.print(flow);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("EC ec_calib_adc,ec_adc,ec_adc_adjusted = ");
|
||||
Serial.print("EC ec_calib_adc,ec_adc_A,ec_adc_adjusted_A = ");
|
||||
Serial.print(ec_calib_adc); Serial.print(",");
|
||||
Serial.print(ec_adc); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted);
|
||||
Serial.print(ec_adc_A); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted_A);
|
||||
Serial.println();
|
||||
Serial.print("EC ec,ec25 = ");
|
||||
Serial.print(ec); Serial.print(",");
|
||||
Serial.print(ec25);
|
||||
Serial.print("EC ec_A,ec25_A = ");
|
||||
Serial.print(ec_A); Serial.print(",");
|
||||
Serial.print(ec25_A);
|
||||
Serial.println();
|
||||
|
||||
|
||||
Serial.print("EC ec_calib_adc,ec_adc_B,ec_adc_adjusted_B = ");
|
||||
Serial.print(ec_calib_adc); Serial.print(",");
|
||||
Serial.print(ec_adc_B); Serial.print(",");
|
||||
Serial.print(ec_adc_adjusted_B);
|
||||
Serial.println();
|
||||
Serial.print("EC ec_B,ec25_B = ");
|
||||
Serial.print(ec_B); Serial.print(",");
|
||||
Serial.print(ec25_B);
|
||||
Serial.println();
|
||||
|
||||
Serial.print("Waterlevel,Volume = ");
|
||||
|
@ -273,18 +302,35 @@ void loop() {
|
|||
|
||||
if (ec_flag_measurement_available){
|
||||
ec_flag_measurement_available=false;
|
||||
if (ec_adc!=0) {
|
||||
publishValue("ec/adc",ec_adc,0);
|
||||
}
|
||||
|
||||
if (ec_calib_adc!=0) {
|
||||
publishValue("ec/eccalibadc",ec_calib_adc,0);
|
||||
}
|
||||
if (ec_adc_adjusted!=0) {
|
||||
publishValue("ec/adcadjusted",ec_adc_adjusted,0);
|
||||
|
||||
//Probe A
|
||||
if (ec_adc_A!=0) {
|
||||
publishValue("ecA/adc",ec_adc_A,0);
|
||||
}
|
||||
if (ec!=EC_UNAVAILABLE){
|
||||
publishValue("ec/ec",ec,0);
|
||||
publishValue("ec/sc",ec25,0);
|
||||
|
||||
if (ec_adc_adjusted_A!=0) {
|
||||
publishValue("ecA/adcadjusted",ec_adc_adjusted_A,0);
|
||||
}
|
||||
if (ec_A!=EC_UNAVAILABLE){
|
||||
publishValue("ecA/ec",ec_A,0);
|
||||
publishValue("ecA/sc",ec25_A,0);
|
||||
}
|
||||
|
||||
//Probe B
|
||||
if (ec_adc_B!=0) {
|
||||
publishValue("ecB/adc",ec_adc_B,0);
|
||||
}
|
||||
|
||||
if (ec_adc_adjusted_B!=0) {
|
||||
publishValue("ecB/adcadjusted",ec_adc_adjusted_B,0);
|
||||
}
|
||||
if (ec_B!=EC_UNAVAILABLE){
|
||||
publishValue("ecB/ec",ec_B,0);
|
||||
publishValue("ecB/sc",ec25_B,0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue