Auto-Feeder (For the Cats..)

Project Images

    I started off the project with the idea in mind that I was going to do some minor modifications to my automatic fish feeder. I quickly had problems with that setup because the cat food pieces were much larger than the fish food pellets. The auger blades weren't large enough to push the cat food through very well, and since I was just using a sweeping servo I thought that I might be able to push more food through if I re-geared the servo to continuously rotate. So I dremeled away at one of the servo gears but of course once I tested it I realized that the auger bit wasn't going to cut it.

    So I tried using one of my salvaged steppers from an old laser jet printer. It had a little metal gear already attached and I didn't have much luck removing it with the blow torch so I just hoped that epoxy would hold the auger onto the motor, which it did more or less. I tried just epoxying the entire thing together with an emptied out spaghetti jar but it was just another pretty embarrassing attempt at making a feeding mechanism. If I had more tools or more space for machining and tools then I would have tried making something else but I finally just gave in and paid $22 for a cereal dispenser (probably saved me several hours of frustration).

 

    I attached a stepper motor that I had bought from Adafruit  with a circular hub unto the cereal dispensers handle. It took a few tries to level it, and I was really afraid of seizing the motor if the axle and handle were unaligned; but it seems to be holding well. I only attached the dispenser with a zip tie and a hose claim. I tried leaving some slack just to avoid any binding of the motor shaft since the shaft and dispenser handle aren't perfectly aligned.

    I wanted the unit to be activated from my bed so I could trigger the feed unit from my bed. This was so that on Saturday/Sunday at 6am I could just lazily trip the sensor with my laser pointer instead of getting up. I thought about using an RF sensor, but ultimately decided that a green laser pointer is much cooler and it also double as another device for distracting annoying cats when they're in your face. So I wired up a couple light intensity sensors to an Arduino and compared analog values of different types of light to determine what would be tripped by the green laser vs. the sunlight (For the record, I didn't do a good job of that test..)

 

    I also added a button to press for feeding and create a simple function to read serial signals so that I could write another program to feed the cats on a timer, or to feed them when I was away from home. 




/*

 -----------------Ryan's Autofeeder Pinout

  -Orange -> 5v

  -Orange -> A1/A0

  -Yellow -> A0/A1

  -Blue   -> Pin3 - blueLED

  -Purple -> pin12 - servoPin

  -Brown  -> GND

  -White -> pin8 - CW+

  

  -Gray   -> pin53 - button

   

  -Brown - > GND - CLK-

  -Blue -> pin9 - CLK+   -Brown -> GND - CW-    

  -Red   -> A-

  *****Motor Driver*****   -Black -> B-   -Green -> B+   -Blue  -> A+ */

//--------------------- Ryan's Autofeeder Code (Arduino/ATmega) 

#include <Servo.h>

/// Declare pins 

int blueLED = 3;        // LED used for indicating that the feeding process has started

int photoResis1 = 0;    // Should be the bottom photoresistor

int photoResis2 = 1;    // Should be the flexible photo resistor, analog read needs analog pins..

int pinButton = 53;     // Pin for the button (button pressed = GND/LOW)

int step1 = 8;          // Forward

int step2 = 9;          // Reverse

//**Would be cool to see if we could "twitch" the motor by switching forward/reverse quickly to drop less food

int incomingByte = 0;               // For serial read

bool displayLightIntensity = false; // Set to true if you want to see the analog values for the light sensors

bool triggerActivated = false;      // Bool to display if trigger is caught by sensor

/// Quickly change these configuration variables

int runMode = 1;    

    // Mode0: Serial/Light Sensing/Button activates feeder - normal run mode

    // Mode1: Serial activates feeder

    // Mode2: Serial/Button activates feeder

int numberOfMicroseconds = 100; // Number of microseconds to turn the motor **used in dispenseFood()

int lightTriggerValue = 900;   // Need it to be high enough to avoid the ambient light from the sun but triggerable from a green laser diode  

/// Statements for serial output

char activatedByLight[] = "Light Intensity Exceeded: ";

char activatedBySerial[] = "Serial Message Received: ";

char activatedByButton[] = "Button Pressed. . .";

char activeMessage[] = "";  // Set active message in functions 

/// Declare functions

int senseLight(int photoResisPin, bool displaySensor);

void dispenseFood(int pinLED, int num_microseconds);

void buttonPressed(Servo feeder_servo, int ledPin, int stepperFWD);

void dispenseFoodCOM();

bool checkSerial(bool triggerActivated);

bool programRunMode(int runMode, int photoDiodePin1, int photoDiodePin2, int lightTriggerValue, int pinLED,

int pinButton, bool triggerActivated, bool displayLightIntensity);

void lightLED_ON(int pinLED);   // Self explanatory - lights LED

void lightLED_OFF(int pinLED);  // Self explanatory - turns off LED

void inspectSensorData();       // Testing values ..about ~600 for LED bulb, +900 for green laser diode

/// Arduino setup 

void setup() 

{  

  Serial.begin(9600);

  pinMode( blueLED, OUTPUT );

  pinMode(photoResis1, INPUT);

  pinMode(photoResis2, INPUT); 

  pinMode(step2,OUTPUT);

  pinMode(step1,OUTPUT);   digitalWrite(step1,LOW); 

  Serial.println("Connected to Microcontroller");

  digitalWrite(step2,LOW); }   

/// Main Arduino loop

void loop()  

  // Reset trigger before starting loop or else kitties get fat

  triggerActivated = false;

    // Wired it so it always gets voltage on when Arudino plugged in, so this turns it off

    digitalWrite(blueLED,LOW); 

        //inspectSensorData();

    triggerActivated = programRunMode(runMode, photoResis1, photoResis2, lightTriggerValue, blueLED, pinButton,

                triggerActivated, displayLightIntensity);         

    if (triggerActivated == true){dispenseFood(blueLED, numberOfMicroseconds, step2);}

    // If trigger has been activated then dispense food     delay(100); 

/// Main driver function for the autofeeder

}  bool programRunMode(int runMode, int photoDiodePin1, int photoDiodePin2, int lightTriggerValue, int pinLED, int pinButton, 

    if (runMode == 0){  // Normal run mode, all sensors, button, and serial command

                      bool triggerActivated, bool displayLightIntensity) { 

        if (triggerActivated == false){triggerActivated = checkSerial(triggerActivated);}

        // Need to check for both serial and button activation. If not responsive enough add functions below light sensor loop 

        else {triggerActivated = checkButton(pinButton, triggerActivated);}

        if (triggerActivated == false) {triggerActivated = checkSensors(photoDiodePin1, photoDiodePin2, lightTriggerValue, triggerActivated);}     }     if (runMode == 1){  // Serial | only activates feeder 

        if (triggerActivated == false) {triggerActivated = checkButton(pinButton, triggerActivated);}

        if (triggerActivated == false){triggerActivated = checkSerial(triggerActivated);}     }     if (runMode == 2){  // Serial | Button activates feeder         if (triggerActivated == false){triggerActivated = checkSerial(triggerActivated);}     }     return triggerActivated; }  /// Function to check serial to see if trigger is activated 

bool checkSerial(bool triggerActivated){

    if (Serial.available() > 0){

    incomingByte = Serial.read();

        if (incomingByte == 'f')

        { 

            Serial.println(activatedBySerial + 'f'); // Indicate why trigger was tripped

            triggerActivated = true;         }   } 

/// Function to check light sensors to see if trigger is activated

    return triggerActivated; }  bool checkSensors(int photoDiodePin1, int photoDiodePin2, int lightTriggerValue, bool triggerActivated){ 

        // For each photoresistor read the analog value to determine if light value should be tripped       

    // If trigger has not already been activated     if (triggerActivated == false){ 

        int sensorLightValue2 = senseLight(photoDiodePin2, displayLightIntensity);          

        int sensorLightValue1 = senseLight(photoDiodePin1, displayLightIntensity);         // Check if sensor analog value exceeds the trigger limit set at the top 

            Serial.println(activatedByLight + sensorLightValue1); // Indicate why trigger was tripped

        if (sensorLightValue1 > lightTriggerValue ){             triggerActivated = true;             

        if (sensorLightValue2 > lightTriggerValue ){

        } 

            Serial.println(activatedByLight + sensorLightValue2); // Indicate why trigger was tripped

            triggerActivated = true;                     }     }    

/// Function to display light intensity from sensors

    return triggerActivated; }  void inspectSensorData(){ 

  int light_intensity1 = analogRead(photoResis1);

  int light_intensity2 = analogRead(photoResis2); 

  Serial.println(light_intensity1);

  Serial.println(light_intensity2);

}  /// Function to check button is activated 

bool checkButton(int buttonPin, bool triggerActivated){

    int buttonState = digitalRead(buttonPin);

    if (buttonState == LOW)     // If the button pin is GND then the button is pressed

    { 

        Serial.println(activatedByButton); // Indicate why trigger was tripped

        triggerActivated = true;     }    

/// Light LED

    return triggerActivated; }  void lightLED_ON(int pinLED){ 

    digitalWrite(pinLED, HIGH);

} /// Turn off LED 

void lightLED_OFF(int pinLED){

    digitalWrite(pinLED, LOW);

}  /// Function that given an int value for led pin returns analog value for photoresistor 

int senseLight(int photoResisPin, bool displaySensor)

  int light_intensity = analogRead(photoResisPin);

  light_intensity = light_intensity / 2;  // Divide by 2 for a 10k resistor

  if (displaySensor == true){ 

      Serial.println(light_intensity);

  } 

  return light_intensity;

}  /// Function for dispensing food 

void dispenseFood(int pinLED, int num_microseconds, int stepperFWD)

  Serial.println("Feeding Little Shits..");  

  // Turn LED on 

  lightLED_ON(pinLED);

  for (int i = 0; i < 100; i++)   { 

  delayMicroseconds(num_microseconds);

  digitalWrite(step2, HIGH);   digitalWrite(step2, LOW); 

  lightLED_OFF(pinLED);

  delayMicroseconds(num_microseconds);   }     // Turn LED off }  /// Function to dispense food if signal received from COM 

void dispenseFoodCOM(){

  Serial.println("Feeding Little Shits..");  

  digitalWrite(blueLED,HIGH);  // Turn LED on

  for (int i = 0; i < 1000; i++)   { 

  delayMicroseconds(100);

  digitalWrite(step2, HIGH);   digitalWrite(step2, LOW); 

  digitalWrite(blueLED,LOW);

  delayMicroseconds(100);   }     // Turn LED off }