0

Moisture sensor issues..
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Moisture sensor issues..

by jim_lee on Sun Sep 08, 2019 11:50 pm

I designed this..

Image

With a nifty display.

Image

And built these..

Image

I've potted the sensor guts in epoxy..

Image

I even built a nifty touchscreen handheld for setting paramiters out in the field.

Image

About 2 weeks ago it rained. Since then the large pots have sat at 100% pretty much ever since. Until last night when it rained again and now some are showing that things are getting dryer?

The tray of seedlings suddenly (after or during the rain) drained its jar of water.

As far as i can tell, these sensors are more sensitive to the pressure of the soil around them than the moisture content. As it rains the soil loosens up and the readings go down. I think this has been a problem with my seed trays. As soon as they need watering they ocasonally flood them selves as the soil loosens up.

Does anyone have experience with these sensors? I'm in need for some ideas here. I need this to be more reliable. How are people making these things work?

Thanks!

-jim lee

jim_lee
 
Posts: 549
Joined: Thu May 24, 2012 8:24 pm

Re: Moisture sensor issues..

by adafruit_support_bill on Mon Sep 09, 2019 8:37 am

Nice looking probe and pump units! Can you post the code that you are using?

Probe response will be somewhat dependent on the soil composition. Temperature and/or concentration of fertilizers can also affect readings. But in general, the dielectric constant of water is much higher than the air or the particles that make up the soil. So the readings should largely follow the percentage of water content in the soil.

As it rains the soil loosens up and the readings go down.

Loosens up in what way? Is it expanding in volume?

adafruit_support_bill
 
Posts: 74618
Joined: Sat Feb 07, 2009 10:11 am

Re: Moisture sensor issues..

by jim_lee on Mon Sep 09, 2019 2:19 pm

Thanks! It was a lot of interesting work developing the packaging. The pumps run at so much lower volume & pressure than your typical watering system, I had to develop an entire line of low pressure sprinkler stuff that I could 3D print to work with them. Then I found out, the hard way, that 3D printed stuff is not waterproof at all! I'd designed these nifty bottles with threaded lids that ended up being completely useless. After the first rain they were full of water. This is what led me to the canning jar idea. Once I'd decided to cover them in canning jars, I realized I could incorporate the little OLEDs into the design. Those OLEDs have been great for seeing what's going on in their little brains.

And posting code.. Well, as always, there's a lot.

Here's the .ino file I'm using for the watering unints.

Code: Select all | TOGGLE FULL SIZE
#include <Adafruit_seesaw.h>

#include <blinker.h>
#include <colorObj.h>
#include <idlers.h>
#include <lists.h>
#include <mapper.h>
#include <mechButton.h>
#include <multiMap.h>
#include <PulseOut.h>
#include <resizeBuff.h>
#include <runningAvg.h>
#include <timeObj.h>
#include <quickCom.h>
#include <lilParser.h>


#include "parameters.h"
#include "pumpObj.h"
#include "textComObj.h"
#include "handheld.h"
#include "globals.h"
#include "UI.h"

Adafruit_seesaw ss;                               // The moisture sensor.

timeObj*      waterTime = NULL;                   // Time length to water when plant shows dry. (ms)
timeObj*      soakTime = NULL;                    // Time to wait after watering before going back to watching mosture level.
mapper*       mudMapper = NULL;                   // Mapper from raw capacitive reading to percent.

runningAvg    cSmoother(DEF_CSMOOTHER);           // Running avarage for the raw capacitive readings.
runningAvg    tSmoother(DEF_TSMOOTHER);           // Running avarage for the raw tempature readings.
timeObj       readTime(DEF_READ_TIME);            // Time between moisture readings.


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

// I Think this is how they tell if the unit is online or not. Maybe I
// can use this as a periodic check to see if its running or not?

/*
uint8_t c = this->read8(SEESAW_STATUS_BASE, SEESAW_STATUS_HW_ID);
  if (c != SEESAW_HW_ID_CODE) {
    return false;
  }
  return true;
*/

// ********************************************************************
// ********************************************************************
// ********************************************************************
// Flipping the screen.

// Normal
//0xA8 = 64;
//0xA0 A[4] = 0;
//0xA2 = 0;
//0xA1 = 0;

// Inverse?
//0xA8 = 64;
//0xA0 A[4] = 1;
//0xA2 = 0;
//0xA1 = 0;



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



// Setup everything we can without a param set. Everything that is only done once.
// Then we read in the parameters and start up operation. The doReadParams() call is
// different in that it can be called randomly during the runtime of the machine.
void setup() {

  ourPump.setPump(false);                               // Off with the pump. This must be called first to lock down control of the pump.
                                                        // Otherwise, if say.. You find you have a dead sensor and the progam locks here..
                                                        // The pump will randomly activate. It pickes up stray currents on the line that
                                                        // trigger the driver hardware. Once this is called, the pump contol is locked in
                                                        // and your good to go.
                                                       
  Serial.begin(57600);                                  // Fire up serial port. (Debugging)
  Serial.println("Hello?");

  ourDisplay.begin();                                   // Fire up our "human interface". (fancy!)
  Serial.print("We have a display? ");
  Serial.println(ourDisplay.mHaveScreen);
 
  textComs.begin();                                     // Set up parser so we can talk to the computer.
  Serial.println("text coms are up.");
 
  ourHandheld.begin();                                  // Setup coms for the handheld controller.
  Serial.print("ourHandheld result (0 is good) : ");
  Serial.println(ourHandheld.readErr());
 
  //delay(1000);                                          // Just in case its not ready, go have a cigar-ette. Then we'll have a go at firing it up.
 
  if (!ss.begin(0x36)) {                                // Start up moisture sensor.
    Serial.println("ERROR! no Sensor.");                // Failed!
    ourDisplay.sensorDeath();                           // This will lock everything up and just blink. (Game over!)
  }

  ourParamObj.readParams();                             // Read our saved running params.
  updateEnv();                                          // Setup what we need to setup with params.
 
  weAre = soaking;                                      // Our state is soaking. This gives things time to settle out.
  soakTime->start();                                    // And we start up the soak timer for that time.
  readTime.start();                                     // Fire up the read timer. We're live!

  Serial.println("Sytem online!");
}


// We have a fresh load of parameters. Initialze the machine with them
void updateEnv(void) {

  if (waterTime) delete(waterTime);                                             // These three are for freeing memeory from the
  if (soakTime) delete(soakTime);                                               // Last set of parameters. We'll need to build up
  if (soakTime) delete(soakTime);                                               // a new set for doing all the math, timing n stuff.
 
  waterTime   = new timeObj(ourParamObj.getWaterTime());                        // Create an object for tracking watering time.
  soakTime    = new timeObj(ourParamObj.getSoakTime());                         // Create an object for tracking soak time.
  mudMapper   = new mapper(ourParamObj.getDry(),ourParamObj.getMud(),0,100);    // Create the mapper to calculate moiture percent.
 
  ourPump.setPWMPercent(ourParamObj.getPWMPercent());
  ourPump.setPWMPeriod(ourParamObj.getPWMPeriod());
  needReset = false;
}


// After all the nonsense in loop(). It all boils down to, do we want the pump on or not?
// Here's where we look at everything and do just that.
void doSetPump(void) {

  if (pumpCom||weAre==watering) {   // Currently two things tell us to water. pumpCom from the controller and our state.
    if (!ourPump.pumpOn()) {        // We want the pump on and its not on now?
      ourPump.setPump(true);        // Turn on the pump.
    }
  } else {                          // We want the pump off?
    ourPump.setPump(false);         // Off with the pump.
  }
  if (ourPump.pumpOn()) {
    ourPump.setSpeed();
  }
}


// Get the info from the sensor and refine it to the point we can use it.
void doReading(void) {
 
  tempC = ss.getTemp();                   // Read the temperature from the sensor.
  capread = ss.touchRead(0);              // Read the capacitive value from the sensor.
  capread = cSmoother.addData(capread);   // Pop the capacitive value into the capacitive smoother. (Running avarage)
  tempC = tSmoother.addData(tempC);       // Pop the temperature value into the tempature smoother. (Again, running avarage)
  moisture = mudMapper->Map(capread);      // Map the resulting capacitive value to a percent.
  moisture = round(moisture);             // Round it to an int.
}


// Ah loop(). This is what we do all day.
void loop() {
 
  idle();                                             // Calling idle() first is always a good idea. Just in case there are idlers that need it.
  if (needReset) {                                    // If our params have changed..
    updateEnv();                                      // Update all the things they effect.
  }
  textComs.checkTextCom();                            // Check to see if theres a guy at the computer looking to talk to us.
  ourHandheld.checkComs();                            // Now we bop off and check to see if anything has come in from a handheld controller.
 
  if (readTime.ding()) {                              // If its tiome to do a reading..
    doReading();                                      // Well, do it.
    readTime.stepTime();                              // Reset the timer for the next reading.
  }

  switch (weAre) {                                    // OK, state stuff. Depending on our current state..
    case sitting :                                    // Sitting = watching moisture wating to start watering.
      if (moisture<ourParamObj.getDryLimit()) {       // If its too dry? Time to water..
        Serial.println("Watering");                   // Tell the world what's up next. (Again, if they are listening)
        waterTime->start();                           // Start up the watering timer.
        weAre = watering;                             // Set state that we are in watering mode.
      }
     break;                                           // All done, jet!
     case watering :                                  // Watering = running the pump and watering plants.
      if (waterTime->ding()) {                        // If our time for watering has expired...           
        Serial.println("Soaking");                    // Tell the world what's up next. (And again, if they are listening)
        soakTime->start();                            // Start up the soaking timer.
        weAre = soaking;                              // Set state that we are in soaking mode.
      }
     break;                                           // That's it for now.
     case soaking :                                   // soaking = waiting for the water to soak through the soil to the sensor.
      if (soakTime->ding()) {                         // If soak time has expired..
        Serial.println("Back sitting.");              // Tell the world what's up next.
        weAre = sitting;                              // Set state that we are in sitting mode.
      }
     break;                                           // All done, lets bolt!
  }
  doSetPump();                                        // Now that commands and state have been checked, decide if the pump goes on or off.
}


As for the rest of the main program's code, here's the github link to it : https://github.com/leftCoast/Arduino/tree/master/flora_II

The rest is in the libraries in the LC_* folders : https://github.com/leftCoast/Arduino/tree/master/libraries

What I've found is that if these things run inside (With no water being added) they seem solid as a rock. (So far). Its when they get out into the "environment" that everything falls apart. When it rains, they go insane. My theory of the moment is that you get a lot of water and the resulting mud doesn't pack as tightly as semi dry dirt. What I'm actually seeing is wild moisture swings 0-100%. This is over maybe a 15 second or so period?

I thought that water was getting past the original RTV sealant. Drying them out in a vacuum chamber for a coupe hours seemed to "fix" them. And that went along with my theory that the RTV wasn't doing it job. So the last batch, the ones outside now, are all sealed in epoxy encapsulating compound. As far as I can tell, this didn't help at all. I just had to go out and unplug the power as they were all randomly seeing dry plants and trying to water them. (Nothing's dry out there, its raining!)

Anyway, that's where things sit at the moment. Like I said, any help would be appreciated. I'm assuming I"m not the only one using these so there must be some people out there who can give me some tips.

thanks!

-jim lee

jim_lee
 
Posts: 549
Joined: Thu May 24, 2012 8:24 pm

Re: Moisture sensor issues..

by adafruit_support_bill on Mon Sep 09, 2019 3:17 pm

It would be interesting to see what the raw sensor readings are - before any of the smoothing or mapping. It looks like you are doing everything in floating point, so there shouldn't be any overflows there. But it would be good to see what the raw data looks like coming from the driver.

adafruit_support_bill
 
Posts: 74618
Joined: Sat Feb 07, 2009 10:11 am

Re: Moisture sensor issues..

by jim_lee on Mon Sep 09, 2019 3:30 pm

I agree! I'm thinking I'll do a debug version that just displays the raw value on the screen before its dropped into the running average thing.

The RTV ones would stop working altogether until they went through the vacuum chamber. My theroy, in that case, the backside of the sensor was getting wet through the 3D case and shorting out the addressing pads. I'm not seeing this with the epoxy ones (so far).

-jim lee

jim_lee
 
Posts: 549
Joined: Thu May 24, 2012 8:24 pm

Re: Moisture sensor issues..

by adafruit_support_bill on Mon Sep 09, 2019 4:05 pm

How is the epoxy done? Looks like a 3D printed shell. Do you just mount the shell to the sensor and fill with epoxy?

adafruit_support_bill
 
Posts: 74618
Joined: Sat Feb 07, 2009 10:11 am

Re: Moisture sensor issues..

by jim_lee on Tue Sep 10, 2019 2:19 am

You do it like this..

Image
First clip away the shell of the connector. So you can solder wires to it.

Image
Then the 3D printed cover slides up the shaft..

Image
In position, ready to fasten on there.

Image
A couple 2 x 6mm screws lock it into place.

Image
See? Nice little hollow to pour in your resin.

Image
Getting ready to pot a couple of them. I cook them at 120 F for three hours to get a pretty good cure. There are still issues with the resin leaking out past the shaft. I have some ideas for that though.

-jim lee

jim_lee
 
Posts: 549
Joined: Thu May 24, 2012 8:24 pm

Re: Moisture sensor issues..

by adafruit_support_bill on Tue Sep 10, 2019 5:59 am

That should give you a good seal around the electronics. The only potential weakness I see is the cable. You could have some ingress via capillary action under the heat-shrink.

One technique I've used with good results is to put a squirt of silicone on the cable before the heat-shrink. With a tightly twisted wire like that, you need to untwist it a bit to let the silicone fill the internal voids. A little squeeze-out at the ends after shrinking is an indication of a good seal.

adafruit_support_bill
 
Posts: 74618
Joined: Sat Feb 07, 2009 10:11 am

Re: Moisture sensor issues..

by jim_lee on Tue Sep 10, 2019 1:57 pm

I thought of that, but.. The heat shrink doesn't go all the way to the electronics. It ends about 1/8" before them, so there's still an epoxy seal.

Had another idea last night though. Could the capacitance of the wires between the sensor and the processor effect things? Maybe, the sensor sets up a capacitive "normal" to measure against? And that, in some way, includes the wires. When it rains, the wires get wet causing the "normal" to go up. Which would, in turn, show the plants as getting dryer. This would fit why I never see the issue on the bench testing, but outside its crazy sauce.

I have one on the bench data logging raw values. I need to polish it up a bit then get a few out "in the field" updated to log info.

-jim

jim_lee
 
Posts: 549
Joined: Thu May 24, 2012 8:24 pm

Re: Moisture sensor issues..

by adafruit_support_bill on Tue Sep 10, 2019 2:50 pm

In theory, the i2c interface is on the digital side of things and should not affect the analog sensor readings. But is probably something worth testing.

adafruit_support_bill
 
Posts: 74618
Joined: Sat Feb 07, 2009 10:11 am

Please be positive and constructive with your questions and comments.