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":
- Forcefeed: Feed whenever you like by pressing "Feed".
- Set FPD: Set the amount of feedings per day (2, 4, 6, 8, 12 or 24 times). Press "Up"/"Down" to change.
- Set Clock: Set the clock. "Up"=Hours, "Down" = Minutes. When first plugged in the coral feeder will be in the Set Clock Menu.
- 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.
Attachments
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.
- LiquidCrystal for the LCD
- TimerOne for the timer interrupt making the clock work
- 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>
Attachments
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.