Auto-Feeder (For the Cats..)
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 }