Home > Blog > UCL-Embedded-Automatic-Arduino-Pet-Feeder

UCL-Embedded-Automatic-Arduino-Pet-Feeder

Summary of UCL-Embedded-Automatic-Arduino-Pet-Feeder


This article presents a guide from UCL Odense on building an automatic pet feeder using an Arduino Mega 2560. The device utilizes an ultrasonic sensor to detect food levels, a stepper motor for dispensing, and an OLED display with a real-time clock module to show time and status. The project includes 3D printed components for the housing and bowl, controlled by custom C++ code that schedules feeding times based on user-defined morning and afternoon slots.

Parts used in the Automatic Pet Feeder:

  • Arduino Mega 2560
  • Stepper Motor 12V 28BYJ-48
  • Stepper Motor Driver ULN2003
  • Ultrasonic sensor HC-SR04
  • Clock Module DS1307
  • 0.91" IIC I2C 128x32 SSD1306 SPI OLED Display Module
  • Wires M/F and M/M
  • Breadboard
  • Battery
  • 3D Printed STL files (mounts, spacers, bowl)

Ever been in a situation where you had to leave your beloved pet at home while you’re on vacation, running errands or at work? Or perhaps your petsitter is on a tight schedule, making every minute saved invaluable in ensuring your pet’s well-being.

Well, fret not! Thanks to our recent development from the Automation Engineering department at UCL Odense, we’ve created a guide on how you can create this magnificent machine.

Using the powerful and compact hardware solutions of an Arduino Mega 2560, a Stepper Motor, Stepper Driver and an Ultrasonic Sensor making for one sturdy unit.

Step 1: Hardware Required

– 1x Arduino Mega 2560

– 1x Stepper Motor 12V 28BYJ-48

– 1x Stepper Motor Driver ULN2003

– 1x Ultrasonic sensor HC-SR04

– 1x Clock Module DS1307

– 1x 0.91″ IIC I2C 128×32 SSD1306 SPI OLED Display Module

– 20x Wires M/F & 2x Wire M/M

– 1x Breadboard

– 1x Battery

Step 2: Setup

Power = 5V

Ground = GND

OLED_MOSI = 9

OLED_CLK = 10

OLED_DC = 11

OLED_CS = 12

OLED_RESET = 13

trigPin = 2

echoPin = 3

RTC SDA = SDA 20

RTC SCL = SCL 21

motorPin1Feed = 22

motorPin2Feed = 24

motorPin3Feed = 26

motorPin4Feed = 28

Step 3: 3D Printing… 3D Printing… and Some More 3D Printing

As you might’ve noticed there’s quite the amount of STL-files attached to this Instructable, so it’s quite a necessity for our construction to have a 3D printer at hand.

Although we used all of our designs to create this machine, there are a couple of STL-files you can technically live without;

  • “mount-base-pet-feeder.stl” – Depends on how you intend to set up the cabin containing the wiring, Arduino, Stepper Motor and Step Driver
  • “left-mount-adjuster-pet-feeder.stl” –
  • “right-mount-adjuster-pet-feeder.stl” –
  • “left-spacer-mount-adjuster-pet-feeder.stl” –
  • “right-spacer-mount-adjuster-pet-feeder.stl” –
  • “Bowl-v2.stl” – We won’t hold a grudge if you don’t use our purpose-built bowl.
  • “M&M’s.stl” – This was only used for rendering and illustrating our Automatic PetFeeder in Autodesk Fusion 360. **Not to be used as food for your pet. We hold no responsibility in improper usage**

Step 4: Let’s Add Some Code

<p>//Basic Embedded Programming 2. Semester Project UCL</p><p>//TinyRTC I2C module DS1307
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}</p><p>#include 
#include 
#include 
#include 
#include 
#include 
RTC_DS1307 RTC;
//#include DS1307 rtc(SDA, SCL);</p><p>//declaring variables for the motor (driver) pins
int motorPin1Feed = 22;
int motorPin2Feed = 24;
int motorPin3Feed = 26;
int motorPin4Feed = 28;</p><p>//if(hour >= 
int petFeedMorning;
int petFeedAfternoon;</p><p>int petFedMorning;
int petFedAfternoon;</p><p>//Declare ultrasonic sensor pins
int trigPin = 2;    // Trigger
int echoPin = 3;    // Echo
long duration, cm, inches;</p><p>// Variables will change:
//Millis()
long previousMillis = 0;        // will store last time LED was updated</p><p>// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000; // interval at which to blink (milliseconds)</p><p>//Disp millis()
//int period = 1000;
unsigned long time_now = 0;</p><p>#define STEPSFeed 64
#define STEPSTop 64  //Number of steps per revolution
#define STEPSBottom 64  //Number of steps per revolution</p><p>//The pin connections need to be 4 pins connected
// to Motor Driver In1, In2, In3, In4 and then the 
// here in the sequence 1-3-2-4 for proper sequencing of 28BYJ48
Stepper small_stepperFeed(STEPSFeed, motorPin1Feed, motorPin3Feed, motorPin2Feed, motorPin4Feed);</p><p>Stepper small_stepperTop(STEPSTop, motorPin1Top, motorPin3Top, motorPin2Top, motorPin4Top);</p><p>int Steps2TakeFeed;
int Steps2TakeTop;</p><p>unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds</p><p>#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels</p><p>// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);</p><p>// 'Logo 2', 128x32px
static const unsigned char myBitmap [] PROGMEM = {
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbc, 0x3c, 0xc6, 0x1e, 0x0e, 0x07, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbc, 0x3c, 0xc6, 0x3c, 0x0f, 0x07, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xb4, 0x7c, 0xc6, 0x78, 0x1f, 0x07, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbe, 0x7c, 0xc6, 0xf0, 0x1b, 0x87, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbe, 0x7c, 0xc7, 0xe0, 0x1b, 0x87, 0xf8, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xb6, 0x7c, 0xc7, 0xe0, 0x39, 0x87, 0xf8, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xba, 0x5c, 0xc7, 0xf0, 0x31, 0xc7, 0xf8, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbb, 0xdc, 0xc7, 0x70, 0x7f, 0xc7, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbb, 0xdc, 0xc6, 0x38, 0x7f, 0xc7, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbb, 0xdc, 0xc6, 0x1c, 0x60, 0xe7, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xbb, 0x9c, 0xc6, 0x1e, 0xe0, 0xe7, 0xfc, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0xb9, 0x9c, 0xc6, 0x0e, 0xe0, 0x67, 0xfc, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xe7, 0xfc, 0xe0, 0xc7, 0x0e, 0x73, 0x83, 0x07, 0xe1, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xc7, 0xfc, 0xf0, 0xc7, 0x0e, 0x73, 0x83, 0x0f, 0xf1, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xe7, 0x00, 0xf8, 0xc7, 0x8e, 0x73, 0xc3, 0x1c, 0x39, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xe7, 0x00, 0xf8, 0xc7, 0x8e, 0x73, 0xe3, 0x38, 0x19, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xc7, 0x00, 0xfc, 0xc6, 0xce, 0x73, 0x63, 0x38, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xe7, 0xfc, 0xec, 0xc6, 0xee, 0x73, 0x73, 0x38, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xe7, 0xfc, 0xee, 0xc6, 0x6e, 0x73, 0x33, 0x38, 0xf9, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xc7, 0x00, 0xe6, 0xc6, 0x7e, 0x73, 0x1b, 0x30, 0xf9, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xc7, 0x00, 0xe3, 0xc6, 0x3e, 0x73, 0x1b, 0x38, 0x19, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x60, 0xe7, 0x00, 0xe3, 0xc6, 0x3e, 0x73, 0x0f, 0x38, 0x39, 0xff, 
  0xff, 0xbf, 0xff, 0xff, 0xfc, 0x60, 0xc7, 0xfc, 0xe1, 0xc6, 0x1e, 0x73, 0x0f, 0x1e, 0x79, 0xff, 
  0xff, 0xbf, 0xff, 0xff, 0xfc, 0x60, 0xc7, 0xfc, 0xe1, 0xc6, 0x0e, 0x73, 0x07, 0x0f, 0xf9, 0xff, 
  0xff, 0xbf, 0xff, 0xff, 0xfc, 0x60, 0xe7, 0xfe, 0xe0, 0xc6, 0x0e, 0x73, 0x07, 0x07, 0xc9, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 
  0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff
};</p><p>void setup() {</p><p>  Wire.begin();
  //Serial Port begin
  Serial.begin(9600);
  // Using this to set the initial time:
  // DS1307 seconds, minutes, hours, day, date, month, year
  // setDS1307time(30,9,19,1,1,4,19);
  // 1 = Sunday
  
  //Define inputs and outputs (Ultrasonic sensor)
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);</p><p>  startMillis = millis();  //initial start time</p><p>  // put your setup code here, to run once:
  small_stepperFeed.setSpeed(200);
  small_stepperTop.setSpeed(200);</p><p>  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }</p><p>  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(500); // Pause for 2 seconds</p><p>  // Clear the buffer
  display.clearDisplay();</p><p>}</p><p>void loop() {
  
  //Over 35 cm display length, time, day and date
  if(cm >= 45) {
    ultrasonic();
    displayTimeSerial();
    displayTimeDisplay();
    delay(750);
    displayDayDateDisplay();
    delay(750);
    checkTime();
    Serial.print("Morning: ");
    Serial.println(petFeedMorning);
    Serial.print("Afternoon: ");
    Serial.println(petFeedAfternoon);
    }
  //Between 35 cm (under) and 5 cm (over) feed pet, turn motor CW
  //else if(cm <= 20 && hour >= 7 && hour <= 13) {
  if(cm <= 45 && cm >8) {
    ultrasonic();
    stepMotorFeed();
  }
  //Under 5 cm display length, time, day and date
  else if(cm <= 8) {
    ultrasonic();
    displayTimeSerial();
    displayTimeDisplay();
    if(petFedMorning <1) {
      petFedMorning +1;
      Serial.print(petFedMorning);
    }
  }
}</p><p>void setDS1307time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS1307
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}</p><p>void readDS1307time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0); // set DS1307 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  // request seven bytes of data from DS1307 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}</p><p>void checkTime() {
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS1307
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  
  if(hour >= 6 && hour <= 11) {
    petFeedMorning = 1;
  }
  else if (hour >= 5 && hour <= 13) {
    petFeedMorning = 0;
  }
  if(hour >= 17 && hour <= 21) {
    petFeedAfternoon = 1;
  }
  else if(hour <= 16 && hour >= 18) {
    petFeedAfternoon = 0;
  }
  
}</p><p>void displayTimeSerial()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS1307
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  //Current function prints this on the serial monitor
  Serial.print(hour, DEC);
  
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }</p><p>  //Print seconds on serial monitor
  Serial.print(second, DEC);
  Serial.print(" ");
  //Print numerical day of the month on serial monitor
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  //Print month on serial monitor
  Serial.print(month, DEC);
  Serial.print("/");
  //Print year on serial monitor
  Serial.print(year, DEC);
  Serial.print(" Day of week: ");
  //Determine specific day of the week
  switch(dayOfWeek){
  case 1:
    Serial.println("Sunday");
    break;
  case 2:
    Serial.println("Monday");
    break;
  case 3:
    Serial.println("Tuesday");
    break;
  case 4:
    Serial.println("Wednesday");
    break;
  case 5:
    Serial.println("Thursday");
    break;
  case 6:
    Serial.println("Friday");
    break;
  case 7:
    Serial.println("Saturday");
    break;
  }
}</p><p>void displayTimeDisplay()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS1307
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  //Current function shows this on the OLED display
  //Display
  //TODO Millis
/*
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    display.clearDisplay();
    display.display();
    display.setCursor(0,0);
    display.setTextSize(2);             // Draw 2X-scale text
    display.setTextColor(WHITE);
    display.print(cm);
    display.println(" Millis");
    display.display();
    digitalWrite(trigPin, LOW);
    delayMicroseconds(5);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
  */
  
  //Display distance measured from Ultrasonic sensor on OLED
  display.clearDisplay();
  display.display();
  display.setCursor(0,0);
  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.print(cm);
  display.println(" cm");
  
  display.setTextSize(1);             // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.println();
  //Display hours on OLED
  display.print(hour, DEC);
  
  //Converting the byte variable to a decimal number when displayed
  display.print(":");
  if (minute<10)
  {
    display.print("0");
  }
  //Display minutes on OLED
  display.print(minute, DEC);
  display.print(":");
  if (second<10)
  {
    display.print("0");
  }
  
  //Display seconds on OLED
  display.print(second, DEC);
  display.print(" ");</p><p>  //Between 35 cm (under) and 5 cm (over) feed pet, turn motor CW
  //else if(cm <= 20 && hour >= 7 && hour <= 13) {
  if(cm <= 35 && cm >5) {
    display.setCursor(85,25);
    display.setTextSize(1);             // Draw 2X-scale text
    display.setTextColor(WHITE);
    display.print("FEEDING");
  }
  //Under 5 cm display length, time, day and date
  else if(cm <= 5) {
    display.setCursor(85,25);
    display.setTextSize(1);             // Draw 2X-scale text
    display.setTextColor(WHITE);
    display.print("DONE");
  }
  
  display.display();
  //TODO Millis
  //delay(1000);
}</p><p>void displayDayDateDisplay()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  //Retrieving data from DS1307
  readDS1307time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  //Sending it to the OLED display
  //Display
  //TODO Millis
  //Day
  display.clearDisplay();
  display.setCursor(0,0);
  display.setTextSize(1);             // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.println();</p><p>  //Determine specific day of the week
  switch(dayOfWeek){
  case 1:
    display.println("Sunday");
    //display.println();
    break;
  case 2:
    display.println("Monday");
    break;
  case 3:
    display.println("Tuesday");
    break;
  case 4:
    display.println("Wednesday");
    break;
  case 5:
    display.println("Thursday");
    break;
  case 6:
    display.println("Friday");
    break;
  case 7:
    display.println("Saturday");
    break;
  }
  //Date
  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(WHITE);
  display.print(dayOfMonth, DEC);
  display.print("/");
  display.print(month, DEC);
  display.print("/");
  display.print(year, DEC);
  display.println(" ");
  
  display.display();
  //TODO Millis
  //delay(500);
}</p><p>void ultrasonicTimeout() {
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  /*
  //Without Millis
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  */</p><p>  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    digitalWrite(trigPin, LOW);
    delayMicroseconds(5);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
 
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
 
  // Convert the time into a distance
  cm = (duration/2) / 29.1;     // Divide by 29.1 or multiply by 0.0343
  inches = (duration/2) / 74;   // Divide by 74 or multiply by 0.0135
  
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();</p><p>  //delay(200);
}</p><p>void ultrasonic() {
  // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  /*
  //Without Millis
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  */
  
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    digitalWrite(trigPin, LOW);
    delayMicroseconds(5);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
 
  // Read the signal from the sensor: a HIGH pulse whose
  // duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(echoPin, INPUT);
  duration = pulseIn(echoPin, HIGH);
 
  // Convert the time into a distance
  cm = (duration/2) / 29.1;     // Divide by 29.1 or multiply by 0.0343
  inches = (duration/2) / 74;   // Divide by 74 or multiply by 0.0135
  
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();
}</p><p>void stepMotorFeed() {
/*
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    //function to turn stepper motor 32 steps left
    small_stepperFeed.setSpeed(300);  // 200 as max speed?
    //ultrasonic();
    Steps2TakeFeed  =   -3200;  // Rotate CW
    //ultrasonic();
    small_stepperFeed.step(Steps2TakeFeed);
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
  */
  
  //function to turn stepper motor 32 steps left
  small_stepperFeed.setSpeed(300);  // 200 as max speed?
  //ultrasonic();
  Steps2TakeFeed  =   -520;  // Rotate CW
  //ultrasonic();
  small_stepperFeed.step(Steps2TakeFeed);
}</p><p>void testdrawlogo() {
  display.clearDisplay();</p><p>  display.drawBitmap(
    (display.width()  - SCREEN_WIDTH ),
    (display.height() - SCREEN_HEIGHT),
    myBitmap, SCREEN_WIDTH, SCREEN_HEIGHT, 1);
  display.display();
  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(8000);
}</p>

Source: UCL-Embedded-Automatic-Arduino-Pet-Feeder

Quick Solutions to Questions related to Automatic Pet Feeder:

  • What hardware is required to build this pet feeder?
    The project requires an Arduino Mega 2560, a 12V 28BYJ-48 Stepper Motor, a ULN2003 driver, an HC-SR04 Ultrasonic sensor, a DS1307 Clock Module, an OLED Display, wires, a breadboard, and a battery.
  • How does the system detect when to feed the pet?
    The ultrasonic sensor measures the distance to the food; if the distance is between 8 cm and 45 cm, the motor turns clockwise to dispense food.
  • Can I use the provided STL files without printing everything?
    Yes, some files like the mount bases and spacers depend on your cabin setup, and the bowl or M&M rendering file can be skipped or substituted.
  • Which pins are connected to the OLED display?
    The OLED connections are MOSI to pin 9, CLK to pin 10, DC to pin 11, CS to pin 12, and RESET to pin 13.
  • How does the code determine morning and afternoon feeding times?
    The checkTime function sets morning feeding if the hour is between 6 and 11, and afternoon feeding if the hour is between 17 and 21.
  • What happens when the food level drops below 5 cm?
    When the distance is under 5 cm, the system displays DONE on the screen and increments the morning fed counter.
  • Is the M&M STL file safe to use as a food container?
    No, the M&M STL file was only used for rendering in Autodesk Fusion 360 and should not be used for actual pet food.
  • What libraries are included in the embedded programming code?
    The code includes Wire.h, Adafruit_SSD1306.h, Adafruit_GFX.h, RTClib.h, and the Stepper library.

About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:
LinkedinTwitter
Scroll to Top