Introduction: EAL - Arduino Controlled Coral Feeder

This instructable is a description of an Arduino controlled feeding dispenser intended for use on saltwater aquariums.

Jacob Padkær

Step 1: Explanatory Video of the Coral Feeder

Step 2: Operating the Coral Feeder

The coral feeder is very easy to operate.

Toggle the menu by pressing "Menu":

  1. Forcefeed: Feed whenever you like by pressing "Feed".
  2. Set FPD: Set the amount of feedings per day (2, 4, 6, 8, 12 or 24 times). Press "Up"/"Down" to change.
  3. Set Clock: Set the clock. "Up"=Hours, "Down" = Minutes. When first plugged in the coral feeder will be in the Set Clock Menu.
  4. Back to default screen.

The default screen shows the current time, and the time for next feeding. If no buttons are pressed for 2 minutes, the Coral Feeder will leave the menu and show the default screen.

If it is necessary to turn off the automated feedings simply press "Feed" while in the default screen, the screen will then show that feeding is off. The automated feeding times will continue to cycle in the background even if the feeding is off.

The default screen will also tell if no FPD is set.

About FPD: The Coral feeder calculates the time in between feedings from the FPD. So if FPD is 8 the Coral Feeder will feed every 3 hours, even during nighttime. In nature corals feed mainly at night.

About the food: I use a mix of two different sizes of Reef Pearls (a powder food for saltwater aquariums). I mix approximately 75% 500-1000 μm and 25% 5-200 μm Reef Pearls. Making the mix too heavy on very small particles raises the risk of the silo getting clogged up (even with the shaker motor).

At FPD = 8 the Coral feeder will hold food for approximately 2 months before the silo needs refilling.

Step 3: Parts List

Tools:

Soldering iron 3D printer Drilling machine Various tools; glue, knife, screwdrivers, drills, pliers, cutters, file, sandpaper etc. Feeder module:

3D printed parts. Servo motor. Small electrical vibrator motor (these can be found in various toys). 4-wire terminal block. Cable Gland. 3 Capacitors for soldering onto the motor to prevent electrical interference/noise (see fritzing drawings). 4 screws with nuts - preferably plastic to prevent corrosion. Electrical tape and double adhesive tape. Jumper wires

Control Box:

Front plate 3D print Arduino Mega (Arduino UNO will suffice regarding numbers of I/O, I used an Arduino Mega because I had two lying around) Small breadboard 16x2 LCD-display Electric cabinet (150x80x50) 4 Momentary pushbuttons (for 10mm hole) Relay for switching the motor 10k Ohm potentiometer 220 Ohm resistor Cable ties Self-adhesive cable tie anchors for fastening components inside the cabinet. Various jumper wires Cable (minimum 4 lead: 1 - Servo power, 2 - Servo signal, 3 - Shaker motor Signal, 4 - Common Gnd.) 2 Capacitors (see fritzing drawings) Power supply 6VDC Min. 1Amp Plug for covering USB-programming port

Step 4: The 3D Prints

The above pictures shows the coral feeder parts for 3D printing.

The first picture is the 5 parts for the coral feeder itself, and on the second picture you will find the front plate for the control box, and a small frame for gluing onto the LCD-display. The frame will make the LCD-display lay flush with the front cover once in the box.

Attached you will find the different parts as STL files.

Step 5: Building the Coral Feeder

On the pictures i have written small notes explaining/giving hints to what i did while building the Coral Feeder.

As the Coral feeder is a fairly complex build, i cannot list everything i did. So if you are going to build your own i suggest using your ingenuity and common sense.

The parts will differ depending on where you're from. I'm from Denmark and only bought a few things, the rest i had lying around, as I besides the ongoing education, am an electrician.

If you're serious about building one for yourself, please feel free to ask any questions in the comments below, and i will do my best answering.

Step 6: The Circuit

The above picture shows the electrical circuit.

Step 7: The Code

Below you will find the code for the Coral Feeder.

Three libraries is necessary for the code to work and must be downloaded to the Arduino IDE software.

  1. LiquidCrystal for the LCD
  2. TimerOne for the timer interrupt making the clock work
  3. Servo for the servomotor.
//Prototyping
void Clock();
void Feed();


//Include library codes:
#include <liquidcrystal.h> //liquidcrystal.h <br>#include <timerone.h>	   //timerone.h
#include <servo.h>	   //servo.h<br>


//Variables declaration
int S = 1;                           //Seconds
int M;                               //Minutes
int H;                               //Hours
int TBF = 0;                         //Time Between Feedings
int Menu_number = 3;                 //Switch case variable
int pos_in = 76;                     //Servo position when retracted
int pos_out = 118;                   //Servo position when out
int H_feed = 0;                      //Feeding time
unsigned int FPD = 0;                //Feedings Per Day
bool Feeding_allowed = HIGH;         //Is feeding allowed y/n?
const bool Click = 1;                //The one second click in the clock
long IdleCounter = 0;                //Variable for automatic going back to main screen
long IdleStatic = 120000;            //The time before the arduino leaves the menu and goes back to main screen


//Inputs/Outputs
const int Feed_on_off = 33;
const int Menu = 32;
const int Up = 31;
const int Down = 30;
const int Shaker = 10;


//Create servo motor "Feeder"
Servo Feeder;


//Initialize the LCD library with the numbers of the interface pins
LiquidCrystal lcd(28, 26, 5, 4, 3, 2);




void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);


  // Initialize timer1, and set a ~1 second period, corrected for program read time
  // and attach the timer service routine to seperate void (Clock)
  Timer1.initialize(994000);
  Timer1.attachInterrupt(Clock);




  //Buttons declaration
  pinMode(Feed_on_off, INPUT_PULLUP);
  pinMode(Menu, INPUT_PULLUP);
  pinMode(Up, INPUT_PULLUP);
  pinMode(Down, INPUT_PULLUP);


  //Shaker motor declaration
  pinMode(Shaker, OUTPUT);


  //Servomotor declaration & initialization
  Feeder.attach(24);
  Feeder.write(pos_in);


}




void loop()
{
  //Back to default at 2 min idle
  if (digitalRead(Menu) == LOW || digitalRead(Up) == LOW || digitalRead(Down) == LOW && Menu_number != 0 )
  {
    IdleStatic = millis() + 120000;
  }
  IdleCounter = millis();
  if (IdleStatic < IdleCounter && IdleCounter < IdleStatic + 50)
  {
    Menu_number = 0;
    lcd.clear();
  }


  //Enter Menu
  if (digitalRead(Menu) == LOW)
  {
    delay(200);
    Menu_number = Menu_number + 1;
    lcd.clear();
  }


  //Reset Menu_number
  if (Menu_number == 4)
  {
    Menu_number = 0;
  }


  //Menu switch case
  switch (Menu_number)
  {
    case 1: //Forcefeed
      {
        //LCD info
        lcd.setCursor(0, 0);
        lcd.print("Menu: Forcefeed");
        lcd.setCursor(0, 1);
        lcd.print("Press Feed");


        //Forcefeed
        if (digitalRead(Feed_on_off) == LOW)
        {
          Feed();
        }


      }
      break;






    case 2: //Feedings per day (FPD)
      {
        //LCD info
        lcd.setCursor(0, 0);
        lcd.print("Menu: Set FPD");
        lcd.setCursor(0, 1);
        lcd.print("Daily Feeds");


        if (FPD < 10)
        {
          lcd.setCursor(15, 1);
          lcd.print(FPD);
          lcd.setCursor(14, 1);
          lcd.print(" ");


        }
        if (FPD > 9)
        {
          lcd.setCursor(14, 1);
          lcd.print(FPD);


        }


        //Adjust FPD up
        if (digitalRead(Up) == LOW)
        {
          delay(200);
          FPD = FPD + 2;
          if (FPD == 10)
          {
            FPD = 12;
          }
          if (FPD == 14)
          {
            FPD = 24;
          }
          TBF = 24 / FPD;
          H_feed = H + TBF;


          if (H_feed >= 24)
          {
            H_feed = H_feed - 24;
          }
        }


        //Adjust FPD down
        if (digitalRead(Down) == LOW)
        {
          delay(200);
          FPD = FPD - 2;
          if (FPD == 22)
          {
            FPD = 12;
          }
          if (FPD == 10)
          {
            FPD = 8;
          }
          TBF = 24 / FPD;
          H_feed = H + TBF;


          if (H_feed >= 24)
          {
            H_feed = H_feed - 24;
          }
        }


        //Prevent FPD > 24
        if (FPD > 24)
        {
          FPD = 0;
        }


      }


      break;


    case 3: //Set clock
      {
        //LCD info
        lcd.setCursor(0, 0);
        lcd.print("Menu: Set clock");


        //LCD CLOCK
        if (H < 10)
        {


          lcd.setCursor(6, 1);
          lcd.print("0");
          lcd.setCursor(7, 1);
          lcd.print(H);
        }
        else
        {
          lcd.setCursor(6, 1);
          lcd.print(H);
        }
        if (M < 10)
        {
          lcd.setCursor(8, 1);
          lcd.print(":");
          lcd.print("0");
          lcd.setCursor(10, 1);
          lcd.print(M);
        }
        else
        {
          lcd.setCursor(8, 1);
          lcd.print(":");
          lcd.print(M);
        }


        //Set clock
        //Hours
        if (digitalRead(Up) == LOW)
        {
          delay(200);
          H = H + 1;
        }
        //Minutes
        if (digitalRead(Down) == LOW)
        {
          delay(200);
          M = M + 1;


        }
        if (H > 23)
        {
          H = 0;
        }
        if (M > 59)
        {
          M = 0;
        }


      }
      break;


    default:


      //LCD CLOCK
      lcd.setCursor(0, 0);
      lcd.print("    ");
      lcd.setCursor(12, 0);
      lcd.print("     ");


      if (H < 10)
      {


        lcd.setCursor(4, 0);
        lcd.print("0");
        lcd.setCursor(5, 0);
        lcd.print(H);
      }
      else
      {
        lcd.setCursor(4, 0);
        lcd.print(H);
      }
      if (M < 10)
      {
        lcd.setCursor(6, 0);
        lcd.print(":");
        lcd.print("0");
        lcd.setCursor(8, 0);
        lcd.print(M);
      }
      else
      {
        lcd.setCursor(6, 0);
        lcd.print(":");
        lcd.print(M);
      }
      if (S < 10)
      {
        lcd.setCursor(9, 0);
        lcd.print(":");
        lcd.print("0");
        lcd.setCursor(11, 0);
        lcd.print(S);
      }
      else
      {
        lcd.setCursor(9, 0);
        lcd.print(":");
        lcd.print(S);
      }


      //Feeding on/off toggle
      if (digitalRead(Feed_on_off) == LOW)
      {
        delay(200);
        Feeding_allowed = !Feeding_allowed;
        lcd.clear();
      }


      //LCD info
      if (Feeding_allowed == LOW)
      {


        lcd.setCursor(2, 1);
        lcd.print("Feeding  Off");


      }
      else if (FPD == 0)
      {
        lcd.setCursor(1, 1);
        lcd.print("Please set FPD");


      }
      else
      {
        lcd.setCursor(0, 1);
        lcd.print("Feeding at");
        if (H_feed < 10)
        {


          lcd.setCursor(11, 1);
          lcd.print("0");
          lcd.setCursor(12, 1);
          lcd.print(H_feed);
        }
        else
        {
          lcd.setCursor(11, 1);
          lcd.print(H_feed);
        }
        lcd.setCursor(13, 1);
        lcd.print(":");
        lcd.print("00");


      }


      //Feeding conditionals
      //First feeding cycle after FPD change is reset at H == 10 to bind the cycle to aquarium light schedule


      //Normal feeding
      if (H_feed == H && M == 0 && S == 0 && Feeding_allowed == HIGH && FPD > 0
          || H == 10 && M == 0 && S == 0 && Feeding_allowed == HIGH && FPD > 0)
      {
        Feed();
        H_feed = H + TBF;
      }


      //Next feed adjustment at feeding off
      else if (H_feed == H && M == 0 && S == 0 && Feeding_allowed == LOW && FPD > 0
               || H == 10 && M == 0 && S == 0 && Feeding_allowed == LOW && FPD > 0)
      {
        H_feed = H + TBF;
      }


      else
      {
        digitalWrite(Shaker, LOW);
        Feeder.write(pos_in);
      }


      if (H_feed >= 24)
      {
        H_feed = H_feed - 24;
      }




      break;
  }


}


void Feed() //Feeding
{
  digitalWrite(Shaker, HIGH);
  delay(40);
  digitalWrite(Shaker, LOW);
  delay(200);
  digitalWrite(Shaker, HIGH);
  delay(40);
  digitalWrite(Shaker, LOW);
  delay(200);
  digitalWrite(Shaker, HIGH);
  Feeder.write(pos_out);
  delay(40);
  digitalWrite(Shaker, LOW);
  delay(200);
  Feeder.write(pos_in);
  delay(250);
  lcd.begin(16, 2);


}




void Clock()  //System clock
{


  //Clock
  S = S + Click;


  if (S > 59)
  {
    S = 0;
  }


  if (S == 0)
  {
    M = M + 1;
  }


  if (M > 59)
  {
    M = 0;
  }


  if (M == 0 && S == 0)
  {
    H = H + 1;
  }


  if (H > 23)
  {
    H = 0;
  }
}




















</servo.h></timerone.h></liquidcrystal.h>

Step 8: I/O - List (Arduino)

Buttons:

  • Feed on/off: Digital Pin 33
  • Menu: Digital Pin 32
  • Up: Digital Pin 31
  • Down: Digital Pin 30

Shaker motor (relay signal) : Digital Pin 10

Servo signal : Digital Pin 24

LCD-Display:

  • LCD RS: Digital Pin 28
  • LCD Enable: Digital Pin 26

  • LCD D4: Digital Pin 5
  • LCD D5: Digital Pin 4
  • LCD D6: Digital Pin 3
  • LCD D7: Digital Pin 2

For other wiring please consult the electrical schematic.