Close

Testing the moisture sensor

A project log for BorosFlor

Low Cost, versatile Smart soil moisture control

boroslabborosLab 05/14/2019 at 07:110 Comments

After testing the sensor just a brief summary.

The sensor used is a cheap one purchased in china. Has no brand and is labeled as v 1.2. After a brief inspection the sensor seems to be similar to DFRobot's. A capacitive sensor based on a 555 oscilator to measure the capacitance of the pcb tracks on the sensor area:

Output is measured and confirmed that output is pulled down with a 1M resistor decoupled with a 1uF cap. 

0. Sensor range: Range is confirmed with documentation. Dry (air dry): 2.8V / Water (humidity saturation) with tap water: 1,44V.  This leave a sensitive range of 1.4V. this range is big enough for a 10-bit ADC. 

1. Startup time: When the sensor is powered from a bench power supply at 3.3V the output response require some time to output stable voltage for measurement.

When sensor is submerged in water the response is the following (blue->VCC , yellow-> sensor output):

On dry air the sensor response is similar but it require more more time as the output voltage is higher:

    This measurements provide a estimation for the response time of the sensor: 150ms

2. Current drawn: At 3.3V with the sensor floating output the current used by the sensor when power is in line with the specs: 5.3mA.



3&4: Testing output stability and measure response:
   To test sensor output I carried out simple experiment with a small pot & compost. I logged the sensor output using a Wemos D1 and small sketch to send over TCP every 2 minutes the reading of the sensor. On the server side I used my local node-RED al the readings.

   10 samples of the sensor are measured, the value transmitted is the average of the measure and also the standard deviation of the 10 samples are computed.

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <math.h>


const char *ssid="xxxxx";
const char *pwd="xxxxx";

// Report every
//#define  REPORT   10*1000
#define  REPORT   2*60*1000





void connectWiFi() {
  
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
     would try to act as both a client and an access-point and could cause
     network-issues with your other WiFi-devices on your WiFi-network. */
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pwd);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  digitalWrite(2,1); // Led on initialization
}

uint32_t order;

void setup() {

 pinMode(2,OUTPUT);
 digitalWrite(2,0); // Led on initialization
  
 Serial.begin(115200);

  // We start by connecting to a WiFi network
  connectWiFi();

  order=0;

}

ADC_MODE(ADC_TOUT)

void measure(uint16_t *m,float *std) {
  const int n=10;
  uint16_t v[n];
  int i,u=0;
  double std_dev=0.0;
  // compute avg
  for(i=0;i<n;i++) {
    v[i]=analogRead(A0);
    u+=v[i];
    delay(1);
  }
  u=u / n; // average
  // compute std dev
  for(i=0;i<n;i++) {
    std_dev += (v[i]-u) * (v[i]-u);
  }
  std_dev = sqrt(std_dev/n); // std_dev

  *m=u;
  *std=std_dev;
  Serial.printf("T:%lu, mean:%d, std dev:%f\n",millis(),u,*std);
}


uint32_t last_report=0;

void loop() {
  uint16_t m;
  float std_dev;

  if(WiFi.status() != WL_CONNECTED) connectWiFi();
  if((millis()-last_report) > REPORT) {
      digitalWrite(2,0); // Led on initialization
      measure(&m,&std_dev);
      WiFiClient client;
      if(client.connect(IPAddress(192,168,4,1),8266)) {
        Serial.print("Sending...");
        client.printf("%d,%d,%f",order,m,std_dev);
        order++;
        client.flush();
        delay(500);
        client.stop();
        Serial.println("sent!");
      }
    last_report= millis();
    digitalWrite(2,1); // Led on initialization
  }
  

}

 


1st I dry the compost in the sun to simulate a dry soil.

2nd  I insert the sensor in this dry soil for a while and check the consistency of data.

3rd I water the soil and let the soil dry to check the evolution of the reading until the soil is dry again.

The data is analyzed with simple R commands:

# Load data
no_cover=read.csv("doc/moisture_data_nocover.csv")

# Convert ADC Reading to volts
V <- data$value * ( 3.3 /1024)

png("doc/moisture_nocover.png")
plot(V,col="blue",type="l")
title("Moisture analog value")
dev.off()
png("doc/moisture_stdev_nocover.png")
plot(V,data$stddev,col="red")
title(paste("Mositure stddev mean:",mean(data$stddev)))

dev.off()

 Results are the following:

Notes:

  1. Sensor in Dry Air: Stable near 2.8V.
  2. Sensor in Dry Soil: After insertion the sensor reacts fast to a 2.5 - 2.4: to dry soil.
  3. Soil watered and let dry. Response to watering is fast: The value respond slow to drying with a linear trend.
  4.  While drying the sensor show a no linear response near 1.7V jumped to 2.0V and then stabilized around 2.1V. Then the drying continue in more or linear but with a milder slope.

The sensor shows stable readings maximum stddev is 4 units (of 10-bit resolution). Typical Std dev is low to 1 unit. This deviation is probably due to ESP2866 ADC reported by various user as volatile especially when WIFI is connected.

Conclusion

  1. Sensor performance is sufficient for the project:
    1. Stable output with little variation on output.
    2. The sensor response fast to watering events.
    3. The sensor do not show a pure linear behavior but is suitable for a linear approximation with upper and bottom limits and 3 or 5 linear ranges.
  2. Sensor consumes  5mA and has a slow response time aground 150ms to have stable reading. Power need to be gated for low power applications with big ADC window.


Next Steps on the sensor:

Repeat the test using a protected sensor. (TODO)
 

Discussions