Assistance with cycling of pump on/off

Hi All,

I would greatly appreciate some assistance. I am trying to cycle a water pump on based on two level sensors, low and high. I currently have rudimentary code written that gets someway to what I am hoping to achieve.

The sensors are in the first of three connected resevoirs. When the pump turns on water flows into the resevoir where the two sensors are located filling until it hits the low level and continues to fill until until the high level is reached. Then Pump turns off.

My problem is; the water flows into the first resevoir faster than it flows between resevoirs, therefore, when the water level finally settles out it is midway between the low sensor and the high sensor. This is undesirable in my application and I require the water level to be at the high level each time it refils.

I have played around with my code and can easily get it to fill all the way; pump starts, fills, stops, waits and repeats until full. I then have the issue that the slightest drop in the level and the pump starts again. This too is undesirable.

If anyone is willing to steer me in the right direction I would be most thankful.

// set outputs and inputs tags

const int pumpOne = 10;
const int pumpTwo = 11;
const int pumpThree = 12;
const int mainTankLowLED = 13;

const int highLVLone = 6;
const int lowLVLone = 2;
const int highLVLtwo = 7;
const int lowLVLtwo = 3;
const int highLVLthree = 8;
const int lowLVLthree = 4;
const int highLVLfour = 9;
const int lowLVLfour = 5;

int tierOneLow = 0;
int tierOneHigh = 0;

void setup() {

  Serial.begin(9600);

  // set Pin Modes
  pinMode (pumpOne, OUTPUT);
  pinMode (pumpTwo, OUTPUT);
  pinMode (pumpThree, OUTPUT);
  pinMode (mainTankLowLED, OUTPUT);

  pinMode (highLVLone, INPUT);
  pinMode (lowLVLone, INPUT);
  pinMode (highLVLtwo, INPUT);
  pinMode (lowLVLtwo, INPUT);
  pinMode (highLVLthree, INPUT);
  pinMode (lowLVLthree, INPUT);
  pinMode (highLVLfour, INPUT);
  pinMode (lowLVLfour, INPUT);

  Serial.println ("running");

}

void loop() {

  // Tier One Control

  tierOneLow = digitalRead(lowLVLone);
  tierOneHigh = digitalRead(highLVLone);

  if (tierOneLow == 0) {
    Serial.println ("Pump ONE on");
    digitalWrite (pumpOne, HIGH);
  }
  else if (tierOneHigh == 1) {
    Serial.println ("Pump ONE off");
    digitalWrite (pumpOne, LOW);
  }
  Serial.println ("levels one");
  Serial.println (tierOneLow);
  Serial.println (tierOneHigh);
 // delay (1000);

  //Tier Two Control

  bool tierTwoLow = digitalRead (lowLVLtwo);
  bool tierTwoHigh = digitalRead (highLVLtwo);

  if (tierTwoLow == 0) {
    Serial.println ("Pump TWO on");
    digitalWrite (pumpTwo, HIGH);
  }

  else if (tierTwoHigh == 1) {
    Serial.println ("Pump TWO off");
    digitalWrite (pumpTwo, LOW);

  }
  Serial.println ("levels two");
  Serial.println (tierTwoLow);
  Serial.println (tierTwoHigh);
  //delay (1000);

  // Tier Three Control

  bool tierThreeLow = digitalRead (lowLVLthree);
  bool tierThreeHigh = digitalRead (highLVLthree);

  if (tierThreeLow == 0) {
    Serial.println ("Pump THREE on");
    digitalWrite (pumpThree, HIGH);
  }

  else if (tierThreeHigh == 1) {
    Serial.println ("Pump THREE off");
    digitalWrite (pumpThree, LOW);
  }

  Serial.println ("levels three");
  Serial.println (tierThreeLow);
  Serial.println (tierThreeHigh);
  //delay (1000);
}

You talk about a pump and two sensors. The code starts with three pumps and 6 sensors... What's up with that?

So you want it to fill, stop when it hits the high sensor but continue when it drops because the rest isn't full? And does it drain at a certain point?

But how can you detect the difference between the "it dropped a bit but it's not full"-state and the "it's just a little drop but the system is full"-state?

And a tip, once you start numbering variables, arrays, always arrays ;)

For complex things like this, we typically use a “state machine”. You can look it up on wikipedia, but unfortunately the computer science guys have gotten at it and made it all much more complicated than it needs to be.

In any case. Perhaps what you want to do is once the water level gets past the low point, start switching the pump on for (say) half the time. 5 seconds on, 5 seconds off, and don’t move onto “I have finished filling” until the top sensor stays on for a full 30 seconds or whatever.

septillion

septillion: You talk about a pump and two sensors. The code starts with three pumps and 6 sensors... What's up with that?

As the code is the same for all three instances I thought it best to just narrow my question to one instance.

septillion: So you want it to fill, stop when it hits the high sensor but continue when it drops because the rest isn't full? And does it drain at a certain point?

It does not drain the water is used or evaporates. If I use this code;

  tierOneLow = digitalRead(lowLVLone);
  tierOneHigh = digitalRead(highLVLone);

  if ((tierOneLow == 0)&&(tierOneHigh == 0)||(tierOneLow == 1)&&(tierOneHigh == 0)) {
    Serial.println ("Pump ONE on");
    digitalWrite (pumpOne, HIGH);
  }
  else if (tierOneHigh == 1) {
    Serial.println ("Pump ONE off");
    digitalWrite (pumpOne, LOW);
  }

I can achieve the refil until full but obviously the level only deviates from FULL to just under full and then the pump kicks in again. So far as your question;

septillion: But how can you detect the difference between the "it dropped a bit but it's not full"-state and the "it's just a little drop but the system is full"-state?

I am not so much looking to know where the level is at - I only care about full or low - the issue is that full occurs before the entire system is TRULLY full.

So far as arrays go I will do some reading.

Thank you for your time to respond.

PaulMurrayCbr,

I did some reading on the "state-machine" although I am not sure I fully comprehend the it. The example used of the turnstile makes sense but as I require my pump to be either On or Off and have only Low or High as inputs I am unsure how it could resolve my issue..

PaulMurrayCbr: In any case. Perhaps what you want to do is once the water level gets past the low point, start switching the pump on for (say) half the time. 5 seconds on, 5 seconds off, and don't move onto "I have finished filling" until the top sensor stays on for a full 30 seconds or whatever.

This sounds like chunky PWM...? This could work, allowing time for the water to pass through the system before initiating the pump again. is there a function I can use so that I loop on one pump at a time until full before I move onto the next or any other ideas of implementation? If I allow enough time for the water to make its way through the first time that the HIGH sensor triggers should be the true HIGH and not need to be timed...

I was contemplating using a tap to physical restrict water flow but it would add another point of failure and expense to the system but your idea effectively does the same thing.

Thank you for your reply. Much appreciated

Hi, Can you post a diagram of your reservoir and sensor layout please, especially how the reservoirs are connected. A picture of a hand drawn diagram will do.

Thanks.. Tom... :)

Jradian: As the code is the same for all three instances I thought it best to just narrow my question to one instance.

Then it would also been best to edit the code to reflect that ;)

Jradian: It does not drain the water is used or evaporates.

Isn't using it a form of draining? :D Alright, evaporates maybe not but I meant, the water level will decrease over time not because of the pomp or the leveling of the reservoir.

Jradian: I am not so much looking to know where the level is at - I only care about full or low - the issue is that full occurs before the entire system is TRULLY full.

Okay, so let me rephrase it, how can YOU tell the difference between full and truly full?

On then you can learn the Arduino that difference as well.

My thought, when it's truly full it stays high for a longer amount of time?

And if it's truly full, do you want to refill it water drains/gets used/evaporates? Or if it was truly full, do you want to wait until it hits low again? (Otherwise, what is the use of the low sensor...)

It is difficult to know what will work for your setup and what assumptions we can make, but I will suggest a strategy.

Check reservoirs to determine if any are low. If there is a low reservoir start running the pumps until that reservoir and those upstream are full.

For example, if reservoir #2 is low run the pumps until reservoirs #1 and #2 are full. We know reservoir #2 was low and we drained #1 to fill #2, so we should fill them both. Any other reservoirs are ignored, we do not know if they are almost full or almost low.

I wrote some code to demonstrate how this might function. It could easily be changed to fill all reservoirs if any are low if that is more desirable. I imagine that when reservoirs are being filled pumps will have to turn on and off to prevent overflowing since the reservoirs fill at different speeds.

This may not fit your situation but hopefully will give you some ideas.

const byte NUM_PUPMPS = 3;

typedef struct  {

  int pumpPin;      // pump to fill resevoir pin
  int highSensor;   // high sensor pin
  int lowSensor;    // low sensor pin
} 
resevoir;

// pin definitions for each resevoir
resevoir resevoirs[] = {
  {
    10,6,2              }
  ,
  {
    11,7,3              }
  ,
  {
    12,8,4              }
  ,
};


// Return true if all resevoirs up to the passed index are full
//
boolean allFull(int lastIdx)
{
  boolean retVal = true;

  // for each resevoir 
  for(int i=lastIdx; i >= 0; i--)
  {
    // if not full
    if( !digitalRead(resevoirs[i].highSensor) )
    {
      retVal = false;
      break;

    } // if

    return retVal;

  } // for

}

// Return index of resevoir highest upstream that is low, or -1 if none are low
//
int lowRes()
{
  int retVal = (-1);

  // if a resevoir is low, set return value and leave
  for(int i=NUM_PUPMPS-1; i >=0; i--)
  {
    // if low
    if( digitalRead(resevoirs[i].lowSensor) )
    {
      // return index
      retVal = i;
      break;

    } // if

    return retVal;

  } // for

}

void setup()
{
  int i;

  // set pin modes
  for(i=0; i < NUM_PUPMPS; i++)
  {
    pinMode(resevoirs[i].pumpPin, OUTPUT);
    pinMode(resevoirs[i].highSensor,INPUT);
    pinMode(resevoirs[i].lowSensor,INPUT);   

  } // for

}

void loop()
{

  int downStreamRes;

  // get index of furhtest resevoir downstream that is low
  downStreamRes = lowRes();

  // if any resevoir is low
  if( downStreamRes >= 0 )
  {

    // fill resevoir found low and those upstream 
    while( !allFull(downStreamRes) )
    {
      for(int i=downStreamRes; i >= 0 ; i--)
      {
        // pump into this resevoir if not fill
        digitalWrite(resevoirs[i].pumpPin, !digitalRead(resevoirs[i].highSensor));

      } // for

    } // while

  } // if

}

TomGeorge,

there is an attachement in the original post showing the layout of the system

Blue Eyes,

Thank you for your time in replying. Attached to the original post is a (crude) hand drawing showing my setup. I only have sensors located in the first of the trays in any tier/level. to have switches in each tray would make the project prohibitively expensive this is why I am trying to find a programming solution rather than adding more hardware.

The water is drawn from a main tank rather than between trays or tiers. So, from main tank to first tray and then between trays via a connecting hose. The connection point is the bottle neck but is fixed by design. Therefire the water flows faster from the pump than it does between trays, thus, giving false feedback that ALL trays are full when in fact after a time this will settle out and the level will not be at max.

septillion: Okay, so let me rephrase it, how can YOU tell the difference between full and truly full?

Exactly.

Jradian, imagine that you are your arduino. You are locked inside a cell and your watertank is … somewhere else. You have an on/off switch for the pump. You have a couple of lights set into the wall one for your low level sensor, one for the high sensor.

You know all about the physical setup - how big the tank is, how fast the water flows when you turn the pump on. But the only feedback you get is those two lights on the wall.

Your job is to fill the water tank using your on off switch.

Can you describe in words what you do to fill the tank correctly? How long do you hold the button on for? How long do you turn it off? How do you decide that - finally - your tank is "full"?

Hi, Where in the tank are the sensors, specifically the low one. What we are looking at here is a top up system, not a filling system.

Your lower sensor should be at the 2/3 or 3/4 full mark. That way your topping up the tank and keeping a head of water in the tank.

It sounds like you see your problem as only if you are filling from empty but once full, the tanks will never empty if you use 2/3 or 3/4 full for your low sensor.

Just an idea.. Tom.. :)

septillion: And if it's truly full, do you want to refill it water drains/gets used/evaporates? Or if it was truly full, do you want to wait until it hits low again? (Otherwise, what is the use of the low sensor...)

Correct, I would want to wait until it is low again before refilling to "true" full.

would it be possible to utilise millis for the timing or would it require an RTC?

I don't see any way to determine the water level in the lower two tiers if you only have float switches in the top. I'm afraid you're gonna have to splurge for 4 more float switches. :(

Jradian: would it be possible to utilise millis for the timing or would it require an RTC?

An RTC is only needed if you want a precise time. Here, you don't. But to answer the question better (or actually at all) you have to start answering the main question I asked ;) PaulMurrayCbr even broke it up for you. As long as you can't answer the question there is NO way you'll be able to learn the Arduino how to do it ;)

PaulMurrayCbr: Exactly.

Jradian, imagine that you are your arduino. You are locked inside a cell and your watertank is … somewhere else. You have an on/off switch for the pump. You have a couple of lights set into the wall one for your low level sensor, one for the high sensor.

You know all about the physical setup - how big the tank is, how fast the water flows when you turn the pump on. But the only feedback you get is those two lights on the wall.

Your job is to fill the water tank using your on off switch.

Can you describe in words what you do to fill the tank correctly? How long do you hold the button on for? How long do you turn it off? How do you decide that - finally - your tank is "full"?

I would wait for the tank to fill to the high sensor, knowing that the water will flow through the system and equalise in x time, I would check the time. When the high sensor goes low I would check the time again, if the time between when I first checked and last checked is greater than x but less than y (a margin of say 10%) I would assume that this is due to the system equalising and start the pump again.

If the time between time checks is greater than y I would epxect the system is actually full and thus I should wait until it reaches the low level before turning the pump back on and repeating the above cycle.

Any thoughts on this process?

Okay, THAT is a good analysis :D And that's key to program a system. If you can't tell how you would do it it's impossible to learn a system. Now all you need to do is implement that :)

Only comment,

Jradian: When the high sensor goes low I would check the time again, if the time between when I first checked and last checked is greater than x but less than y (a margin of say 10%)

Now you assume it always happens in x +-some. But that may be faster some times, what should happen then? Assume full? Also, if you start pumping right after the high sensor becoming inactive it doesn't take long to trigger it again. So it will probably oscillate a few times while the system is equalizing.

So I would change that to, after the high sensor is triggered the first time you stop. But instead of starting again when it goes low you wait for a z amount of time, z should be more then x (the time to drop below high because of the other tanks) but lower then the time it takes to drop in normal use. After z you check the high sensor. If it's not triggered (water not high) you start the pump. After it reaches high, you do this check (with z time) again. Is the tank still full after z you assume the whole system is full and only restart pumping after water drops below low.

This gives you a bit more margin between the water level and the high sensor when you start pumping again because the system is still equalizing. This will result in it restarting less often and not oscillate around the high point.