My Automatic Cat Feeder

Here is my first try to use atmega328 in a cat feeder device.
My feeder is supposed to work without AC power and without maintenance long time.
Previously I designed a device without avr controller, just using digital alarm clock and very simple electrical circuit. In that project met several problems.

  1. Functionality - That alarm clock has only 2 alarms to set and I needed more to set more feeding times;
  2. Power supply - I used batteries (AC power wasn't an option) that may drain suddenly and cause feeder to stop;
  3. Stability - some times clock may reset accidentally loosing alarm sets.

I think new project with Arduino board solved these problems.

I designed electrical circuit with charger via solar panel and rechargeable battery, also I used atmega power down mode to save battery power.
Here is my scheme attached.
And here is the code Google Code Archive - Long-term storage for Google Code Project Hosting.
I used simple KeyPad and LCD1602.
Device can be programmed to feed up to 15 times per day.
Now it's designed to feed with the same interval but I upgrade this version to able to program any time feeding.
Solar panel also used as day time detector to rerun the schedule (Arduino timer isn't good to be used as permanent timer).

for KeyPad I use only 1 pin, that drove me to write complicated module for KeyPad, preventing bouncing and electrical noise.

Here is whole project archived - http://petfeeder.googlecode.com/files/CatFeeder_07-111225a.zip

cat's are happy :slight_smile:

Some details of the project.
1) Mechanical part
The main engine is simple brushed geared motor from DX

The feeder consists of food tank and food issuing device that is like Archimedes Screw made of simple comb

I used comb to prevent the device from sticking due to food pieces.

2) Solar Panel
The whole device works autonomously, without any external AC/DC power supply. For powering I use a 1.5 watt/12 volt solar panel.
There are many of them at ebay for about 10$. I mounted a panel outdoor at safe place to prevent it from bad weather conditions and same time let to get more solar light. The panel gives enough power even in very cloudy weather. Keep in mind that window glass isn't 100% transparent.

3) Rechargeable Battery
The device should work all the time, even in bad weather or dark time, therefore I need some battery to supply it at that time when there is no sufficient solar power. I used very simple 6Volt VRLA battery with capacity 4AH. Even if we suppose that this battery really gives out only 1AH, it will be enough to power the device few days without solar energy (device average consumption is 1.5-2ma).
The battery is charging via solar panel. Atmega controls charging process via electrical scheme.
Charging algorithm is very simple, goal is floating voltage for VRLA battery that is mentioned in datasheet. If voltage from solar panel is greater then battery voltage and battery voltage is less then floating voltage, then the MOSFET opens and charging starts.
Here is a part of code

    SetCharge(false);
    
    VExt=kVExt*analogRead(VExtPin);
    VBat=kVBat*analogRead(VBatPin);
    
    if((VExt>VBat) && (VBat<LevBat))
        SetCharge(true);

The first SetCharge(false) guarantees that solar panel voltage doesn't drops due to load. Coefficients kVExt and KVBat normalize analog reading to real voltage and should be tuned according drop resistors of the scheme.
The solar panel also used as daytime detector. I reset the time counter on sun rise. To detect sun rise I use averaged voltage of solar panel

    SAn=AvgKS*SAn+AvgKA*VExt;    
    IsDay = IsDay ? SAn >= LevNigth : SAn > LevDay;

Code seems little complicated but easy to understand, first line works like voltage integrator, SAn accumulates and averages voltage with some delay, delay time depends on AvgKS and AvgKA coefficients (AvgKA + AvgKS = 1), as closer AvgKS is to 1 as longer delay we get.
But what for do we need this delay? - To prevent any accidental light detection at night time (for example car headlamps).
Second line is hysteresis trigger - without it the code begins twilight bouncing. If voltage on panel is about day and night threshold, code can switch between day and night mode many times during such light conditions. So we have 2 threshold voltages, one for detecting day after night and another for detecting night after day (LevDay and LevNigt).

solar_panel.jpg

4) KeyPad
I used simple 16 4x4 Matrix Keyboard Keypad. you can buy it online or locally for few dollars.
This keypad has 8 connectors (4x4 matrix rows and columns).
I decided to connect it Arduino via only one wire. Usually most people connects each row/column out to controller digital pin, therefore uses 8 digital in-s.
But why 8 pin when there is one pin enough?!
You just need few resistors.
Resistors should be selected to guarantee voltages spread as mach as possible.
here is a table with resistors and according voltage readings (after ADC converted it to int, we suppose VCC is converted to 1024 as in Arduino)

R (in kOhm) 0 22 47 68
0 0 185 327 414
82 461 522 577 614
180 658 685 711 730
280 755 769 784 795

This numbers are more presentable in chart. Goal is to avoid chart lines crossing.
Even though the readings from ADC may cross due to electrical noises in circuit.
To avoid this I use software filter

char KeyPad::ReadKey(int KeyReads, int KeyReadDelay) 
{
   char ret=NoKeyChar;
   int ai;
   int aiMin=1024, aiMax=0;
   float aiAvr=0;
   for (int i=0;i<KeyReads;i++)
   {
      ai=analogRead(KeyPadPin);
      if (ai<aiMin)
        aiMin=ai;
      if (ai>aiMax)
        aiMax=ai;
      aiAvr+=ai;
      delay(KeyReadDelay);
   }
   aiAvr/=(float)mKeyReads;
   float dev;
   if (aiAvr==0)
     dev=0;
   else
     dev=(aiMax-aiMin)/aiAvr;
   if (dev<KeyReadPrec)
   {
     ai=aiAvr;
     for (int i=0;i<mKeyCount;i++)
     {
       if(ai>=mKeyIntsL[i] and ai<=mKeyIntsH[i])
       {
           ret=mKeys[i];
           break;
       }
     }
   }
  return(ret);  
  
}

The function ReadKey has 2 parameters KeyReads and KeyReadDelay.
Code reads KeyPin several times (KeyReads) with some delay (KeyReadDelay) to get average reading that prevents analog noise.
But noise isn't the only problem for KeyPad, there is transitional state during pressing or releasing key, when resistance of connector is changing from 0 to disconnected and if this function runs this moment, it may get wrong reading. To prevent this, I use max and min values of readings and compare them to average value, than I calculate difference (let call it deviation). If the deviation is too big, then KeyPad isn't in stable state and reading should be discarded. here we check it

     dev=(aiMax-aiMin)/aiAvr;
   if (dev<KeyReadPrec)

KeyReadPrec is acceptable deviation to guarantee stable readings.

You can note in electrical scheme that there is used another digital pin of Atmega. That is due to Atmega powerdown mode. KeyPad used also wake up interrupt.
Here is intterupt attaching code from main fail of the project.

attachInterrupt(0, wakeUpNow, LOW);

In KeyPad library there are many other functions that will discussed lately.

KeyPadonOnePin.png

KeyVoltagesChart.png

This is great! I know it's been posted for a long time but just thought I'd show my appreciation :slight_smile: I'm considering making an own feeder and using a simple comb for the feed mechanism is a great idea i hadn't thought of.