0

I am experimenting with Aquaponics and since I am a software developer I found it "smart" to use arduino/raspberry in order to control the water flow and not simply use a water pump with mechanical means.

The advantage is that I am able to expand easier the system. The disadvantage is that I haven't yet met the reliability that I would lie to have. I am a software engineer with basic knowledge in the hardware field. That is why I thought of starting with Raspberry.

Initially I made a setup with a single raspberry PI a few float sensors like this: https://www.hellasdigital.gr/electronics/sensors/humidity-sensor/tank-pool-water-level-liquid-sensor-float-switch/

and relay like this one: https://wiki.52pi.com/index.php/DockerPi_4_Channel_Relay_SKU:_EP-0099

I saw that sometimes the system was hanging with the relays open! This had the side effect to loose water. This is the most precious in aquaponics!

Thus I thought of creating a cluster. Thus I made a cluster of three Raspberrys. The two had the relays and only one PI had the sensors. In order to open the water pump both PIs should have given the green light. This worked better and when one of the PIs hanged then we lost no water.

But again I am thinking that it was not acceptable that the system was hanging so often (at least several times per week). Thus I thought maybe if I use an Arduino for this purpose then this would be better.

Thus this is what I did. I created a simple program (no cluster and a single Arduino). Unfortunately this had even worst results!!!

For the Arduino I used normal 5 Volt relays like this one: https://www.nettop.gr/index.php/hlektronika/relay/8-channel-5v-relay-module-with-light-coupling-5v.html and the same float sensors.

I do not believe that is software related the issue but it must be hardware. The problem is that my knowledge in the hardware field is limited! What should I do in order to prevent this? Do you think that is related with the water pumps and the relays ?

The same erroneous behavior happens at both the Raspberry and Arduino, I mean that the relay stays open and the water overflows. For Raspberry I can tell that the system stop to respond, I am sure about it. But for Arduino I cannot say for sure if the whole system was frozen or if input only for the float did not work.

I paste a link to the quick and dirty Arduino code as well for your reference. The temperature were the systems were operating could be quite hot (30 ~ 48 degrees Celsius) for several hours.

Here is the code for the Arduino:

#define POT_1_FLOAT_SENSOR  2 
#define POT_1_RELAY_1       11     

#define PIPE_1_FLOAT_SENSOR  5 
#define PIPE_1_RELAY_1       9     

#define PIPE_2_FLOAT_SENSOR       3     
#define PIPE_2_RELAY_2      10     

#define PIPE_3_RELAY_3       12    
#define PIPE_3_FLOAT_SENSOR       4     

// pot 1
const unsigned long POT_1_MAX_WATERING_PERIOD = 120000;
const unsigned long POT_1_DRAIN_PERIOD = 70000;

unsigned long pot1StartMillis = 0;
unsigned long pot1DelayStartMillis = 0;

// Pipe 2
const unsigned long PIPE_2_MAX_WATERING_PERIOD = 300000;
const unsigned long PIPE_2_DRAIN_PERIOD = 300000;

unsigned long pipe2DelayStartMillis = 0;
unsigned long pipe2StartMillis = 0;

// Pipe 3
const unsigned long PIPE_3_MAX_WATERING_PERIOD = 760000;
const unsigned long PIPE_3_DRAIN_PERIOD = 300000;
unsigned long pipe3DelayStartMillis = 0;
unsigned long pipe3StartMillis = 0;

// Pipe 1
const unsigned long PIPE_1_MAX_WATERING_PERIOD = 180000;
const unsigned long PIPE_1_DRAIN_PERIOD = 300000;
unsigned long pipe1DelayStartMillis = 0;
unsigned long pipe1StartMillis = 0;



bool pot1RedFlag = false;
bool pot1SetStartTime = false;

bool pipe1RedFlag = false;
bool pipe1SetStartTime = false;

bool pipe2RedFlag = false;
bool pipe2SetStartTime = false;

bool pipe3RedFlag = false;
bool pipe3SetStartTime = false;



void setup() 
{
  Serial.begin(9600);
  // initialize the pushbutton pin as an input:
  pinMode(POT_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(POT_1_RELAY_1, OUTPUT);
  digitalWrite(POT_1_RELAY_1, LOW);

  pinMode(PIPE_1_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_1_RELAY_1, OUTPUT);
  digitalWrite(PIPE_1_RELAY_1, LOW);

  pinMode(PIPE_2_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_2_RELAY_2, OUTPUT);
  digitalWrite(PIPE_2_RELAY_2, LOW);

  pinMode(PIPE_3_FLOAT_SENSOR, INPUT_PULLUP);
  pinMode(PIPE_3_RELAY_3, OUTPUT);
  digitalWrite(PIPE_3_RELAY_3, LOW);
  
  pot1StartMillis = millis();
  pipe1StartMillis = millis();
  pipe2StartMillis = millis();
  pipe3StartMillis = millis();
}

void loop() 
{
  checkAbstractWateringTimer(pot1SetStartTime, pot1RedFlag, pot1DelayStartMillis, 
                                POT_1_DRAIN_PERIOD, POT_1_MAX_WATERING_PERIOD,
                                pot1StartMillis, POT_1_FLOAT_SENSOR, POT_1_RELAY_1);

  checkAbstractWateringTimer(pipe1SetStartTime, pipe1RedFlag, pipe1DelayStartMillis, 
                                PIPE_1_DRAIN_PERIOD, PIPE_1_MAX_WATERING_PERIOD,
                                pipe1StartMillis, PIPE_1_FLOAT_SENSOR, PIPE_1_RELAY_1);

  checkAbstractWateringTimer(pipe2SetStartTime, pipe2RedFlag, pipe2DelayStartMillis, 
                                PIPE_2_DRAIN_PERIOD, PIPE_2_MAX_WATERING_PERIOD,
                                pipe2StartMillis, PIPE_2_FLOAT_SENSOR, PIPE_2_RELAY_2);

   checkAbstractWateringTimer(pipe3SetStartTime, pipe3RedFlag, pipe3DelayStartMillis, 
                                PIPE_3_DRAIN_PERIOD, PIPE_3_MAX_WATERING_PERIOD,
                                pipe3StartMillis, PIPE_3_FLOAT_SENSOR, PIPE_3_RELAY_3);

  delay(200);
}

void checkAbstractWateringTimer(bool &abstractSetStartTime, bool &abstractRedFlag, unsigned long &abstractDelayStartMillis, 
                                unsigned long abstractDrainPeriod, unsigned long abstractMaxWateringPeriod,
                                unsigned long &abstractStartMillis, int abstractFloatSensor, int abstractRelay) {
  if (!abstractSetStartTime || (abstractSetStartTime && millis() - abstractDelayStartMillis >= abstractDrainPeriod)) {
    
    if(digitalRead(abstractFloatSensor) == LOW && !abstractRedFlag) // Need one more condition in order to emulate the delay...
    {    
      digitalWrite(abstractRelay, LOW);
      Serial.println("Pot 1 pump is open");
  
      // Set it only once at the beginning
      if (pot1SetStartTime) {
        abstractStartMillis = millis();
        abstractSetStartTime = false;
      }
      
      Serial.print("duration ");
      Serial.println(millis() - abstractStartMillis);
  
      if (millis() - abstractStartMillis >= abstractMaxWateringPeriod)  //test whether the MAX watering period has elapsed
      {
        // Close pump and do not oopen it again. Red Flag...      
        Serial.println("Pot 1 pump is closed and the red flag is ON");
        digitalWrite(abstractRelay, HIGH);
        abstractRedFlag = true;
      }
    } 
    else 
    {
      Serial.println("Pot 1 Pump is closed");
      digitalWrite(abstractRelay, HIGH);
      abstractSetStartTime = true;
      abstractDelayStartMillis = millis();
    }    
  }  
}

Please any ideas, suggestions or tests that I could do are more than welcome in order to create a reliable system.

-- UPDATE -- Both when I was using Raspberry and Arduino I haven't included any resistors between the float sensor pins and the ground. Are there any chances that this is related with the instabilities that I experienced?

Maybe I should add a resistor (10K) between the float sensor pin and the ground?

Thank you

22
  • 2
    Re “for Arduino I cannot say for sure if the whole system was frozen”: make the built-in LED blink in loop(). If it stops blinking, it's frozen. May 28, 2021 at 20:44
  • 1
    Maybe I should add a resistor (10K) between the float sensor pin and the ground? -- No, you have (roughly) 30k internal pullup resistors. Adding a 10k pulldown resistor would just confuse everything. However adding 10k pullups to 5V would help with noise rejection.
    – Majenko
    May 28, 2021 at 21:33
  • 1
    if relays sap your psu into dropping in voltage, it can affect your sensors.
    – Abel
    May 28, 2021 at 21:58
  • 1
    How long are the cable runs? Is there any electrically noisy equipment near the cable runs? Consider using some form of galvanic isolation to interface the float sensors to the MCU. The relays require 50 to 60 mA drive current but the Arduino pins can only supply 40 mA.
    – tim
    May 29, 2021 at 8:36
  • 1
    Glad we could help. Texas Instruments has a great series of videos on the subject of galvanic isolation which discusses inductive, capacitive and optical isolation techniques. Something else to consider is debouncing the float sensor signal either in hardware with a low-pass RC filter or with a software debouncer. For stronger pull-ups you could try 1K resistors, though this will use more current.
    – tim
    May 29, 2021 at 23:18

2 Answers 2

1

As requested, I've collated my comments into an answer.

How long are the cable runs? Is there any electrically noisy equipment near the cable runs? Consider using some form of galvanic isolation to interface the float sensors to the MCU. Texas Instruments has a great series of videos on the subject of galvanic isolation which discusses inductive, capacitive and optical isolation techniques. Isolate the signals in both directions – both the inputs and the outputs.

For stronger pull-ups you could try 1K resistors, though this will use more current.

Something else to consider is debouncing the float sensor signals either in hardware with a low-pass RC filter or with a software debouncer (which I've put on GitHub).

The relays require 50 to 60 mA drive current but the Arduino pins can only supply 40 mA, so the external power supply is a good idea.

Redundancy, i.e. having multiple sensors for the same measurement, will guard against the loss of a single sensor causing chaos in a critical system, e.g. loss of precious water in a hot climate. You could have 3 float sensors for each water level at different locations, then use a voting system of >= 2 to take action. The system should also flag when sensors disagree so that someone can investigate the issue. And also route the cables via 3 different paths. This physical separation will guard against a single localised event (e.g. a wayward tractor or lightning strike) damaging all the sensors at the same time.

Also consider the fail-safe mode. For example, this could be to switch off all water valves when sensors disagree and then send an alert to someone and/or sound an alarm.

As your aquaponic farm is outside, consider lightning strike protection such as using TVS diodes on all inputs and outputs.

You could add feedback sensors to the relays to verify whether they have actually responded to the commands from the Arduino to switch on or off, i.e. compare commanded value with FB sensor value. These sensors could be pullup/pulldown resistors.

These additional relay FB sensors and the float sensors could be incorporated into the fail-safe logic. Some examples include:

  1. If a relay is on when it's supposed to be off, flag the discrepancy.
  2. If it takes 5 minutes to fill a tank and the inlet relay has been on for >5 minutes, it might be overflowing or dodgy sensors.
  3. If the float sensors say a tank is empty, but the inlet relay has been on for >5 mins, something is wrong, e.g. leaking tank or dodgy sensors.
  4. If it takes 10 mins to drain a tank but the float sensors say it's still full after 11 mins, something is wrong, e.g. blocked drain or dodgy sensors.
  5. Are inlet and outlet relays on at the same time? Is this a valid condition?

There are many permutations. Happy coding...

0

thank you for your valuable input. I can say that now the system is stabilized. The source of my issues was a faulty sensor but I have taken into account all advices. For example I separated the signal cables from the power cables that this was one more source of issues, I have introduced the pull up resistors, I have used separate power source for the relay module.

Generally for me ALL the comments from this thread were super important.

Thank you!

3
  • 1
    Something else to consider is redundancy, i.e. having multiple sensors for the same measurement. This will guard against the loss of a single sensor causing chaos in a critical system, e.g. loss of precious water in a hot climate. You could have 3 float sensors at each location, then use a voting system of >= 2 to take action. The system should also flag when sensors disagree so that someone can investigate the issue.
    – tim
    Jun 15, 2021 at 11:15
  • 1
    I've assumed up till now that this is an indoor aquaponic farm. If it's outdoors, you should also consider hardening to lightning strikes, e.g. using TVS diodes on all inputs and outputs. And a slight correction to my previous comment: the 3 sensors per measurement should be at different locations, but at at the same water level. And also route the cables via 3 different paths. This physical separation will guard against a single localised event (e.g. a wayward tractor or lightning strike) damaging all the sensors at the same time.
    – tim
    Jun 15, 2021 at 14:40
  • Yes indeed it is outdoor on my house's roof. I will have a look at the diodes that you are talking about. Thank you again for the great hardware ideas that you give me. I appreciate them. Jun 15, 2021 at 14:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.