Objectifying plant watering

Every spring I struggle with my superpower: killing perfectly healthy plants by watering them too much. Every year, around July or August, I accept the same conclusion: I should give up trying to cultivate plants and, next year, I should spare plants the misery of being nurtured by me. But then spring comes again and brings with it the scent of flowers, the sight, and odor of cooking herbs and therefore the temptation to try again. This year instead of suppressing my craving I will adopt a smarter approach. I bought a sensor to monitor the plants’ moisture which I will use to prevent me from drowning the plants. With the moisture values as a starting base, I will apply the scientific method to the subtle art of watering plants.

I bought an ESP8266 module and, after connecting it with an FC-28 Soil Moisture Sensor and a 10 kilo Ohm resistor I can measure the amount of moisture in the plant pot. For a total expense of five dollars, this is a small investment for the well-being of my plant.

Connections

One pin of the FC-28 is connected to pin A0 of the ESP8266. This pin is also connected through the resistor to the ground pin (I chose the GND pin close to the CLK pin on the side of the pin A0) of the ESP8266. The other pin of the FC-28 is connected to pin D1 of the ESP8266.

Reading moisture

I used the Arduino IDE to program the ESP8266 to read the values from the FC-28. Below is an example which reads the value from the FC-28 and prints it to the Serial Monitor:

const size_t d1 = 5;
const size_t a0 = 0;

void setup() {
  pinMode(d1, OUTPUT);
  digitalWrite(d1, LOW);
  Serial.begin(115200);
}

void loop() {
  digitalWrite(d1, HIGH);
  int moistureValue = analogRead(a0);
  digitalWrite(d1, LOW);
  Serial.print(moistureValue);
  Serial.print(' ');
  delay(1000);
}

The 1000 ms delay prevents cluttering the Serial Monitor with values by printing values each second instead of each millisecond. Furthermore, during the first measurements, I noticed that it took quite a bit before the values would get stable. For example, for the first 30-60 seconds, the moisture values increased monotonically. Therefore I included some subroutines computing the values’ mean and variance to get a better grasp of what levels reflected actual values and which one reflected the measurement noise before the device settled.

const int nObs = 12;
int values[nObs] = {0,0,0,0,0,0,0,0,0,0,0,0};

long sum(int values[], const int nObs){
  long sumVals = 0;
  for(int index = 0; index < nObs; sumVals += values[index++]);
  return sumVals;  
}

double mean(int values[], const int nObs){
  return((sum(values, nObs)* 1.0)/nObs);
}

double var(int values[], const int nObs){
  double meanVal = mean(values, nObs);
  double sumVals = 0;
  for(int index = 0; index < nObs; index++)
    sumVals += ((values[index] - meanVal) 
      * (values[index] - meanVal));
  return(sumVals/(nObs-1));
}

I expanded the loop function to print out the mean and variance of the measurements every twelve observations, and that is it.

size_t counter = 0;

void loop() {
  digitalWrite(d1, HIGH);
  int moistureValue = analogRead(a0);
  digitalWrite(d1, LOW);
  Serial.print(moistureValue);
  Serial.print(' ');
  values[counter % nObs] = moistureValue;
  if ((counter > 0) && (counter % nObs == 0))
    Serial.println(" mean is " + String(mean(values, nObs)) 
      + " " + String(var(values, nObs))); 
  counter++;
  delay(1000);
}

I noticed that after a week of measurements the values become more stable. In fact, nowadays the variance among twelve measurements is always between .5 and 3 whereas before it could be as large as 100.

Interpreting moisture values

In spite of being able to measure the moisture values, estimating whether the plant is healthy or not is a whole different issue. My intuition-based, self-experienced green-thumb classifier is very accurate but incapable of prediction. My intuition-based, self-experienced green-thumb classifier has two states: healthy and dead. Classification is rudimentary and based on dryness inspection. Its rule is: if the plant looks dried than it is dead otherwise the plant is healthy. But for this project, I needed to be able to prevent the plant from getting to much water. In fact, observing that a plant has dried is the opposite of having too much water. Moreover, observing that a plant has dried is too late for intervention. Therefore, until I do not master the ability to resuscitate plants, having an estimate of when and how much to water the plant should suffice to prevent the plant’s death.

To know when and how much water to give I had to extrapolate the level of moisture the plant should be kept in. Interpolating values to infer moisture levels was not my initial idea. My initial idea was to measure the moisture level the day of the purchase. My reasoning was that nothing could match the shop’s assistant expertise in keeping plants at the perfect moisture level. Therefore, the shop-moisture level would have been the golden standard to match to best nurture my plant. However, I could measure the plant’s moisture level only the day after I bought it. Moreover, after the first readings, I was not sure about the meaning of the values I was measuring since I did not know the measurement scale and its variation because the values spanned a very broad range. To quantify the variation among measurements I thought of making measurements from three different sites. I chose one site in which the ground looked dry, one in which the ground seemed wet and as for the last sample the ground hosting the plant. The following day I repeated the measurements to determine the change in moisture from one day to the following one. Now, with two subsequent time points at three sites, I fitted a model to predict the moisture level in the plant ground on the day in which I bought the plant. The estimated moisture level at the shop turned out to be about 800 and I have been trying to keep the plant moisture level around that value for the past week. Does it work? The plant has not drowned yet, but it is too early to tell whether this strategy works. I will definitely bring it up in a follow-up post.

Advertisements
Objectifying plant watering

A simple fork example timed with chrono

I always wanted to experiment with parallel computing and multi threading. However, when and how to use parallel computing has always been a bit difficult to conceptualize for me. Until I discovered forking. Here I will describe a simple implementation of fork using the chrono Time c++ library to time the forked processes.

Continue reading “A simple fork example timed with chrono”

A simple fork example timed with chrono