This Update contains the wiring diagram and code for the temperature compensated feeder. This code is enough for you to make a unit to test if it works for you. I am pulling my time of day from another MCU running in the greenhouse, I advice wiring in a gps unit if you are making this a standalone unit.I will be doing a tutorial on this and how we use the time for regulating feeding timings in the near future. This is just a basics of how we compensate for temperature changes.
So why Compensate for Temperature
Most Species of Fish are cold blooded animals and as such the water temperature that they live in has a big effect on how they behave. In short cold water makes the fish slow and less hungry. As engineers what does this mean to us, well it means we have an input to a system that needs to vary with temperature if we want to use open-loop control. Luckily almost every aspect of a fish can be represented mathematically or at least closely approximated.
Below is a table representing the amount to feed fish [Tilapia] as a function of temperature to maximise food productivity[1]:
DFR: Daily Feed Rate, represent as percent of fish mass in the system.
As you can see the Water Temperature has quite a large effect on the amount of food Fish will Eat. I prefer Closed-Loop Feedback Systems, see the previous blog [Blog 5] to see how we can implement this to systems with floating food, but for systems with sinking food I am yet to think of a way to measure the food present in the system [Not to say one of you wont have a solution they feel like sharing?]
Other things that will effect how much to feed fish:
So far we have only considered the effects of temperature on Feed amount, the coming Blogs will address the other Factors in great detail, but for now here are some outlines:
Feed Spacing/Timings
The optimum time between feeding of fish depends on the size of the stomach of the fish, when they are young they require feeding regularly, decreasing as they grow larger.
Feed Chemistry
The percent of protein you fed fish is related to the age of the fish and the water temperatures.
A Note On DO:
Dissolved Oxygen measurements are expensive, measuring probes need constant calibration and as such we will be assuming the pond has adequate oxygenation for growing fish. Spreading the feed serving over the day will spread the demand for DO over the day also. So in short, feeding multiple times a day decrease the peak demands for dissolved oxygen of the system. [this is a good thing]
The Wiring diagram:
You might notice that there are no external pull up/down resistors in this circuit, I dislike soldering resistors so every thing is implemented not to need them.
The button is connected to Pin A4, that is set up as an input with the internal pull up set to on, when the button is pressed it will pull A4 to LOW.
The Temperature sensor usually has an external pull up, but we are using a modified one-wire library that does this using the internal pull ups for the data pin.
The Code
I am sure a lot of you on Element14 will have the coding side nailed down, The code below is offered as a proof of concept, is it refined, pretty or making good use of the resources available, No. But it does work and will do for a proof of concept code, Later on we will be including extra hardware and refining the code then:
>Touch screen for GUI and imputing system detail
>Gps module to pull time from [used later for feed spacings]
Remember we are not using the default one-wire library, add a pull up to the temperature probe or install the custom library [see www.michaelratcliffe.com/projects]
Arduino Uno Proof of Concept Code |
---|
/*
//************************** Libraries Needed To Compile The Script [See Read me In Download] ***************//
#include <OneWire.h> // We Need This Libaray To Read The Temperature Sensor, SEE READ ME In Downloaded Zip If You Dont Know how To install This #include <DallasTemperature.h>
//************** User Defined Variables *******************************// /*
long feedSpacing =60; //the time between feeds in mnuits const int FeedsPerDay =24; //Change this only is you change the feeding interval or total number of feeds a day
long MinWeight =5; //Minimum Weight [Kg] Of Fish You Want The Potentiometer To Represent long MaxWeight =20;//Maximum Wight [Kg] Of Fish You Want The Potentiometer To Represent const int FeedRate=8.3; // g/s How Much Feed in Grams Your Feeder Dispnces In A Second [You need to Work This out]
int PercentTenC =3; //percent of Body weight to feed fish daily at 10*C int PercenTwentSixC=12;//Percent of Body weight to feed fish daily at 26*C
int MaxFeedPercent=16; int MinFeedPercent=1; //InCase The Sensor Breaks, We Will StillFeed Them a Minimum Amount
// The Ones Below Should Be ok as they are, unless your Relay uses pull Low Triggers const int OFF=1; const int ON=0;
//****************** End Of User Variables ***************************//
//************ ONLY Cange These Values Below If You Have Wired To different Pins *****///
const int Potentiometer = A5; // Analog input pin that the potentiometer is attached to const int ButtonPin =A4; //Button Connected to Pin A4 const int Motor = A3; // Pin That Relay Triger wire is connected to
const int TempProbeNegative=8; //Temp Probe Negative connected to pin 8 const int TempProbePossitive =9; //Temp Probe power connected to pin 9 #define ONE_WIRE_BUS 10 // Data wire For Temp Probe is plugged into pin 10 on the Arduino //************* End Of Pin Selection ********************************//
int ResistorValue = 0; // value read from the pot int outputValue = 0; // value output to the PWM (analog out) int Button =1; float FeedLength =0; float Temperature=10; long FishWeight = 1; long feedSpacingMillis =0; long FeedPercent =1;
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) OneWire oneWire(ONE_WIRE_BUS); // Pass our oneWire reference to Dallas Temperature. DallasTemperature sensors(&oneWire);
//******************************* Setus up Things, This Loop Runs Once at Startup ***************************// void setup() {
Serial.begin(9600);
pinMode(Motor, OUTPUT); digitalWrite(Motor,OFF);
pinMode(Potentiometer, INPUT); pinMode(ButtonPin, INPUT_PULLUP);
pinMode(TempProbeNegative , OUTPUT ); digitalWrite(TempProbeNegative , LOW ); pinMode(TempProbePossitive , OUTPUT ); digitalWrite(TempProbePossitive , LOW );
delay(100);// gives sensor time to settle sensors.begin(); feedSpacing=feedSpacing*60000; //Converts from minutes to milli seconds
//************************************* Runs a Tester If You Hold the Feed Button When You Turns Power Switch On*************// GetReadings(); if(Button==0){
digitalWrite(Motor,ON); delay(FeedLength*1000); digitalWrite(Motor,OFF); delay(5000);
};
};
//*******************************Main Loop [This Once Loops indefinatly ***************************************//
void loop() {
GetReadings();
//*************** Checks if it is Time to Start The Feeder and delays to stop entering the loop twice *************************************************//
if( (millis()%feedSpacing<=1000 &&millis()>=1010)) { // delay(1000); //stoprs multiple eneies into the loop digitalWrite(Motor,ON); delay(FeedLength*1000); digitalWrite(Motor,OFF); };
//************** Allows the Button To operate the feeder Only While Pressed ****************************// if (Button==0){ digitalWrite(Motor,ON); //Turns the Motor on
} else { digitalWrite(Motor,OFF); };
//**************************** Makes The code Hang Here While The Sensors Settle ********************//
delay(200); PrintResults(); };
//************************ Reads The Sensors and Calcalates the Feed Length ***********************************// void GetReadings() { Button=digitalRead(ButtonPin); //Reads The Button To Check If It Is Pressed ResistorValue = analogRead(Potentiometer); //Checks what possition the potentiometer is at sensors.requestTemperatures(); // Send the command to get temperatures Temperature=sensors.getTempCByIndex(0); Temperature=Temperature*100; //easiest way to get
//************ Turns Those Readings Into Something Useful [Optimum Feed Length ******************************//
FishWeight = map(ResistorValue,0,1023, MinWeight*1000, MaxWeight*1000); //Turns The Potentiometer Reading Into Something Usefull); FeedPercent=map(Temperature,1000,2600,PercentTenC*100,PercenTwentSixC*100);
if (FeedPercent >= (MaxFeedPercent*100)){ FeedPercent= (MaxFeedPercent*100); }
if (FeedPercent<= (MinFeedPercent*100)){ FeedPercent=(MinFeedPercent*100); };
FeedLength =((FeedPercent*FishWeight)/(FeedRate*FeedsPerDay)); FeedLength = FeedLength/10000;
};
//*************************** Prints The Variables To The Computer ************************************// void PrintResults(){
Serial.print(" Water Temperature: "); Serial.print(Temperature/100 ); Serial.println("*C");
Serial.print(" User Has Selected: "); Serial.print(FishWeight/1000); Serial.println(" Kg of Fish");
Serial.print(" Feed: "); Serial.print(FeedLength*FeedRate); //Serial.print(FeedLength); Serial.print(" Grams of food Every: "); Serial.print(feedSpacing/60000); Serial.println(" minute"); }; |
The map feature will only output whole numbers and that is the reason we multiply the variables before the map and divide after [It could be better].
So I set this up for Tilapia, if you are using other fish you will need to read up about how much of their body weight to feed them at 10*C and 26*C and change the variables in the code to suit:
User Defined Species Specific |
---|
int PercentTenC =3; //percent of Body weight to feed fish daily at 10*C int PercenTwentSixC=12;//Percent of Body weight to feed fish daily at 26*C |
This Controller is still in its infancy, In the coming weeks we will be implementing control over the feeding intervals, expanding the species of fish it can feed and adding a screen to output the data.
Keep watching,
Mike
Reference
[1] [I will be adding the reference once I remember where I saved it]
Top Comments