Skip to content
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

Battery Drop Correction to normalize to reading at 3.0V #3

Open
RicardoHipp opened this issue Jun 6, 2020 · 8 comments
Open

Battery Drop Correction to normalize to reading at 3.0V #3

RicardoHipp opened this issue Jun 6, 2020 · 8 comments

Comments

@RicardoHipp
Copy link

Hello

Can you explain this?

// Battery Drop Correction to normalize to reading at 3.0V
moisture = vccReading3VSetting.get() * moist_raw / batteryCharge;

Example:
vccReading3VSetting.get() = 958
moist_raw = 750
batteryCharge = 60

8.981 = 958 * 750 / 80

Result 8981.25

it should be less than 1000 or not?

Can you explain it to me?

Sorry for my bad english.

@MoJo2600
Copy link
Owner

MoJo2600 commented Jun 7, 2020

No worries! English is not my first language either. I'll try to help as good as I can. The battery charge parameter is not the battery charge in percent (like 60 or 80). Instead it is the raw measurement from the ADC. So it should be something like 958 * 750 / 800.

To let you know: I'm currently working on a V2 release of my code. It includes a calibration wizard to tune in every sensor if needed. But it is still work in progess, but if you like you can check out the branch feature/setup-view. I will release the code in a few days. I'm still not 100% satisfied with the functionality.

@RicardoHipp
Copy link
Author

Glaube du kannst auch Deutsch oder?

Ich habe für mich jetzt diese Lösung gefunden (ist Arduino Code, denke aber der ist trotzdem verständlich)

Ich berechne Quasi die Obere und untere Grenze für den Sensor in Abhängigkeit von der Batteriespannung.

Die Formeln kann man natürlich noch kürzen, aber zur Verständlichkeit habe ich es mal so gelassen

//(default 3.2 resistor 100k/220k)
const double BATTERY_CAL = 3.2;

// Moisture dry reading @3.0V
const int DEFAULT_MOIST_DRY_READING_AT_3V = 790;
// Moisture wet reading @3.0V
const int DEFAULT_MOIST_WET_READING_AT_3V = 585;
// Moisture dry reading @2.5V
const int DEFAULT_MOIST_DRY_READING_AT_2_5V = 655;
// Moisture wet reading @2.5V
const int DEFAULT_MOIST_WET_READING_AT_2_5V = 501;

// die Berechnung passt bei meinem SAensor sehr genau aber die 3,2 kann man natürlich anpassen
double vcc_reading_3V = 1024 * 3 / BATTERY_CAL ; //Raw Wert bei 3V berechnet
double vcc_reading_2_5V = 1024 * 2.5 / BATTERY_CAL ; //Raw Wert bei 2.5V berechnet

void getMoisture() {
// Connect Battery to the Pin via on PCB switch
digitalWrite(PIN_SWITCH, HIGH);
delay(200);
moisture = 0;
moisture_raw = readSoilSensor();

double Mwet = 0;
double Bwet = 0;
double Fwet = 0;

double Mdry = 0;
double Bdry = 0;
double Fdry = 0;

Mwet = (DEFAULT_MOIST_WET_READING_AT_3V - DEFAULT_MOIST_WET_READING_AT_2_5V) / (vcc_reading_3V - vcc_reading_2_5V);
//Serial.print("Mwet in getMoisture funktion: ");
//Serial.println(Mwet);
Bwet = DEFAULT_MOIST_WET_READING_AT_2_5V - Mwet * vcc_reading_2_5V;
//Serial.print("Bwet in getMoisture funktion: ");
//Serial.println(Bwet);
Fwet = Mwet * battery_raw + Bwet;
//Serial.print("Fwet in getMoisture funktion: ");
Serial.println(Fwet);

Mdry = (DEFAULT_MOIST_DRY_READING_AT_3V - DEFAULT_MOIST_DRY_READING_AT_2_5V) / (vcc_reading_3V - vcc_reading_2_5V);
//Serial.print("Mdry in getMoisture funktion: ");
//Serial.println(Mdry);
Bdry = DEFAULT_MOIST_DRY_READING_AT_2_5V - Mdry * vcc_reading_2_5V;
//Serial.print("Bdry in getMoisture funktion: ");
//Serial.println(Bdry);
Fdry = Mdry * battery_raw + Bdry;
//Serial.print("Fdry in getMoisture funktion: ");
//Serial.println(Fdry);

moisture = map(moisture_raw, Fdry, Fwet, 0, 100); // Convert to 0 - 100%, 0=Dry, 100=Wet
//Serial.print("moisture in getMoisture nach map funktion: ");
//Serial.println(moisture);

//DEFAULT_MOIST_WET_READING_AT_3V

@MoJo2600
Copy link
Owner

MoJo2600 commented Jun 9, 2020

Ja, deutsch geht auch :)

Ich habe hier drei solcher Sensoren und das Problem, das ich habe ist, dass die Sensoren sehr unterschiedlich sind. 100% genau sind die ja sowieso nicht. Wenn man wissen will ob der Boden zu trocken oder zu nass ist, schaut Deine Berechnung gut aus. Ich würde gerne im Garten an drei Stellen messen ob meine Bewässerung funktioniert. Da habe ich aber festgestellt, dass die Sensoren mit den theoretischen Werten untereinander immense Abweichungen haben. Es wäre gut, wenn die zumindest im Bereich von, sagen wir +-5% ähnliche Werte anzeigen.

Deswegen habe ich mir überlegt, dass es gut wäre, wenn man jeden Sensor auf eine einfache Weise vorher kalibrieren könnte. In dem Branch mache ich es so, dass zuerst der Batteriewert für eine volle Batterie gemessen wird. Der liegt miestens bei etwas über 1000. Dann wird einmal gemessen wenn der Sensor trocken ist und einmal wenn der Sensor in Wasser eingetaucht ist. Damit habe ich dann die Sensor spezifischen Werte. Das passt dann bei 2 von 3 Sensoren ganz gut. Aber ich glaube, dass der eine einfach schon ne Macke hat. Der liefert auch die falsche Temperatur.

Für die Standardwerte würde ich aber die nehmen die Du da errechnet hast. Dann kann man den Sensor unkalibriert in Betrieb nehmen und hat schon mal eine gute Basis.

Wenn es Dich interessiert, ich hab hier alle Messungen an einem Sensor mal in einer Tabelle aufbereitet gehabt um zu sehen ob alle Berechnungen richtig sind: Google Spreadsheet

@RicardoHipp
Copy link
Author

Mein zweiter Sensor ist noch unterwegs um vergleiche zu machen.

Zum Kalibrieren habe ich es für mich jetzt so gelöst (bzw. bin dabei).

Wenn man im Moment des Einlegen der Batterie den Taster auf der Platine drückt geht der Sensor in einen Dauer Mess und Sende Modus.
Da sieht man dann im live die Veränderungen und kann via MQTT die Kalibierungswerte senden.
Dadurch sieht man dann auch sofort welche Auswirkungen es hat.

Um dann wieder in den Normalmodus zu kommen, einfach Batterie raus und wieder rein. Man könnte da ja auch nen nen Timer setzen, das er z.B: nach ner halben Stunde wieder in den normal Modus geht.

Ich habe es nicht hinbekommen einen MQTT Wert zu an den ESP zu senden während dieser im Deep Slepp ist und dieser dann empfangen wird wenn der Sensor wieder aufwacht. Ich habe aber auch gar keine Ahnung von MQTT und über Google habe ich da leider nix gefunden.

Diese Werte hier müssen auch bei mir kalibriert werden
// Moisture dry reading @3.0V
const int DEFAULT_MOIST_DRY_READING_AT_3V = 790;
// Moisture wet reading @3.0V
const int DEFAULT_MOIST_WET_READING_AT_3V = 585;
// Moisture dry reading @2.5V
const int DEFAULT_MOIST_DRY_READING_AT_2_5V = 655;
// Moisture wet reading @2.5V
const int DEFAULT_MOIST_WET_READING_AT_2_5V = 501;

Das sind ja die Grenzen für 2,5V nass und trocken und für 3V nass und trocken.
Bei z.B. 2,7Volt verschiebt sich ja diese Grenze. die Untere aber anderes als die obere.

Dies kann man mit dieser Formel berechnen.

f = m * (Vbat) * b

Das muss man einmal für die untere (nass) und für die obere (trocken ) machen.

Hier für Nass:
Mwet = (DEFAULT_MOIST_WET_READING_AT_3V - DEFAULT_MOIST_WET_READING_AT_2_5V) / (vcc_reading_3V - vcc_reading_2_5V);

Bwet = DEFAULT_MOIST_WET_READING_AT_2_5V - Mwet * vcc_reading_2_5V;

Fwet = Mwet * battery_raw + Bwet;

Hier für trocken.
Mdry = (DEFAULT_MOIST_DRY_READING_AT_3V - DEFAULT_MOIST_DRY_READING_AT_2_5V) / (vcc_reading_3V - vcc_reading_2_5V);

Bdry = DEFAULT_MOIST_DRY_READING_AT_2_5V - Mdry * vcc_reading_2_5V;

Fdry = Mdry * battery_raw + Bdry;

Dann kann man einfach mit der map Funktion die Grenzen setzen
moisture = map(moisture_raw, Fdry, Fwet, 0, 100); // Convert to 0 - 100%, 0=Dry, 100=Wet

Aber wie du schon sagst, das ist bei jedem Sensor anderes und muss kalibriert werden.

Ich denke aber das du niemals drei Sensoren an unterschiedlichen Stellen im Garten wirklich sinnvoll (Abweichung <5%) vergleichen kannst. Vielleicht mit viel Glück.
Dafür sind zu viele andere Faktoren gegeben, welche die Messung beeinflussen.

Z.B. Temperatur des ESP, Temperatur des Boden, Beschaffenheit des Boden (Dichte, Mineralgehalt, wie fest liegt die Erde am Sensor usw.)
Ich habe mich auch mal mit einem Freund unterhalten (dieser arbeitet in der Sensortechnik und hat der mehr Ahnung als ich).

Die Kalibrierung der Batterie sollte man nicht mit einer vollen Batterie machen da der ADC maximal 3,2V messen kann und wenn dieser dann auf Anschlag wäre (1024) dann verfälscht es das Ergebnis.

Wenn du schon bei deinen Sensoren bei der Batteriespannung so unterschiedliche Werte bekommst, bist du da der Ursache mal auf den Grund gegangen? Also Spannungsteiler gemessen (die beiden Widerstände) bzw die reelle am ADC anliegende Spannung?

Auch wenn der Spannungsteiler nicht genau ist, sollte zum kalibrieren der Batterie ein Wert reichen, da sich dieser wirklich linear ändert. Der ADC hat nun mal eine fixe Auflösung von 1024 von 0 bis 1V direkt am ADC.
Mit dieser Berechnung
double vcc_reading_3V = 1024 * 3 / BATTERY_CAL
kann man dann den Wert für jede Spannung ausrechnen, für die 3 halt die gewünschte Spannung und BATTERY_CAL kann man nach Umstellen der Formel damit ja auch berechen. Aber wie gesagt ich würde keine vollen Batterie nehmen, da wäre der Sensor am Anschlag.

PS: Danke übrigens für den netten Gedankenaustausch, ich habe aus deinem Programm auch einiges mitnehmen können da ich ja kein Programmierer bin.
Bin auf dein fertiges Programm gespannt. (ich konnte nur nicht so lange warten :-) )

@MoJo2600
Copy link
Owner

MoJo2600 commented Jun 9, 2020

Ja, bei dem Messen an drei Stellen wirst Du recht haben. Vielleicht verlange ich da zuviel. Aber es wäre gut herauszufinden ob bei der Bewässerung überhaupt an allen Stellen Wasser ankommt. Ich habe derzeit alle drei Sensoren direkt nebeneinander stehen. Da sieht es relativ gut aus: Grafana

Zum MQTT: Senden im DeepSleep geht, wenn Du die MQTT Nachrichten 'retains' d.h. Du kannst beim Senden festlegen, dass der Server die Nachricht speichern soll. Normalerweise ist MQTT so ausgelegt, dass Du Nachrichten schickst und der Empfänger sie nimmt oder halt nicht. Retainte Nachrichten liegen am Server bis sie gelesen wurden. Der Ablauf wäre dann so, Du sendest so eine Nachricht (Ich nehm immer MQTT Explorer, der hat einen Haken beim senden den man setzen kann), dann wacht irgendwann der Sensor aus dem Tiefschlaf aus und liest dann den Wert, welcher gespeichert wurde. Das Homie Framework macht das z.B. mit seiner Konfiguration so. Wenn Du was ändern möchtest schickst Du die geänderte config an ein bestimmtes topic.

Zur Batterie: Mit normalen AA Batterien kriegst Du ja keine Spannung die den ADC auf 1024 bringt. Zumindest hatte ich das nicht. Der Wert lag immer so bei um die 1000. Aber Du hast recht, der eine Wert zum Kalibirieren muss reichen.

Ich gehe meinen Code nochmal durch. Vielleicht hast Du ja Lust die neue Version mit dem zweiten Sensor dann zu testen :)

@RicardoHipp
Copy link
Author

Werde deine neue Version auf jeden Fall testen.

Das mit dem Retain habe ich probiert aber irgendwie wollte es nicht so (das lag aber wohl eher an mir)
Für mich ist das mit dem Dauer Modus irgendwie besser, da man da gleich sieht was es für Auswirkungen hat.

Habe gerade mal noch meine JA-Batterie gemessen. Diese hat 1,65Volt neu was mit zwei ja 3,3V sind und damit zu viel (warum auch immer dieser Spannungsteiler so komisch ausgelegt ist, auch beim D1 mini ist der so). Ist nicht schlimm man muss es nur wissen und beim kalibrieren bedenken (evtl. Abfangen und eine Kalibrierung mit einem Wert von 1024 verhindern)

@MoJo2600
Copy link
Owner

MoJo2600 commented Jun 9, 2020

1,65V ja aber Leerlaufspannung. Wenn der sensor das 70mA zieht müsste die Spannung niedriger sein, oder? Und ja, wenn 1024 kommt ist was komisch.

@RicardoHipp
Copy link
Author

Ja fällt schon ab die Spannung , aber bleibt trotzdem über 3,2V wenn die Batterien ganz neu sind. So ca 3,25V beide zusammen. Ist wie gesagt nett wild, sollte man halt nur wissen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants