1 / 8
LabLab Pet feeder for small to HUGE pets! — zdjęcie 1
1 / 8

LabLab Pet feeder for small to HUGE pets!

Zamów wydruk tego modelu

Obliczymy ostateczną cenę na podstawie wybranego pliku. Sprawdzisz ją i zaakceptujesz przed płatnością.

Zapisane na tym urządzeniu.

Modular automatic pet feeding station compatible with small and big pets.

Ocena
5 / 5
Polubienia
20
Pobrania
71
Wydruki
1
Wyświetlenia
774
Oceny
1

Aktualizacja u źródła:

Informacje o modelu

Źródło
Printables
Kategoria
Pets
Licencja
Creative Commons — Attribution — Noncommercial

Description 

I designed a modular pet feeder that can handle any kibble size — perfect for dogs of all breeds and appetites! 🐕

I needed to make sure my fluffy friend is always fed on time, even when school or work got in the way. And since commercial feeders didn’t fit my and my Labrador's needs, I built my own. At first, it started as a student project, and I evolved it into a growing passion project. My goal? Share it with the community so more dog owners can create their perfect feeding solution.

This automated feeder keeps a consistent feeding schedule, ensures correct portion control, and the feeding height and storage volume are easily customizable to your needs. It combines 3D-printed parts, a precision motorized dispensing system, and a load cell scale for accurate meal measurements.

This is already Version 9, focused on making the design reliable, easy to clean, and modular. 
I'd love to keep developing this project further and hope the community will join me on this journey!

🔗 https://lablab.framer.website/
🔗 https://github.com/Bifanas/Pet-feeder

Functions:

  • Food dispenser — the screw mechanism with a 12V DC motor and a gear reduction that helps pushing the larger grains of food without getting stuck 
  • Scale — the load cells measure with precision how much food was dispensed
  • OLED display — for showing the recent meal history 
  • Modularity  — flexible design helps you to adapt the feeder for proper eating height and enough storage volume

Hardware and Software Used 

Hardware: 

  • Power source 12V 2A
  • Jack socket
  • DC DC converter ( 12V to 5V)
  • OLED Display (128x64)
  • Motor Driver (L293D
  • DC motor 12V 18rpm
  • ARDUINO UNO
  • Real-time Clock ( DS3231)
  • Load cells (4x scale type)
  • Bolts : 2x(M3x30mm) 1x(M3x15mm) 4x(M3x5mm)

Software: 

The design was made in Fusion 360. The code was developed in C++, aided by Arduino IDE with auxiliary libraries.

 

Printing Instructions & components:

The dimensions of the pieces are compatible with most 3D printers. Concerning the printing settings, you know your printer the best. We got the best results using a 0.4 mm nozzle, printing in PETG filament on a lower layer height (≤0.16mm). No supports are needed.

 

 

Assembly Instructions 

The assembly is quite easy. The feeder is composed of two most important parts, the Main unit where the screw is located and the Base where the load cells are embedded and the electronics are placed.

 

Main unit: Following the video, place the motor in the dedicated space from the bottom. Add the motor attachment and bolt the screw to it. 

Base: Use the load cell adaptors to fix the 4 load cells to the Base. Then pull the wires from the load cells through the small channels to the inside of the base.

Electronics: Use the wiring diagram to connect all the electronic parts. This will be placed in the base plate. If you're using the OLED display, mount it to the display adapter and connect the wires. 

Code and calibration: Upload the code to your Arduino Uno and do few calibrations.

Set up the time for the real time clock:

 // RTC SETUP-------------------------------------------------------
 URTCLIB_WIRE.begin();

//rtc.set(0,50,21, 6, 31, 8, 2024);

//(second, minute, hour, dayOfWeek, dayOfMonth, month, year)

Remove the “//” in the beginning of rtc.set function. Change the number accordingly with the current time. Compile and load the code into the MCU. Add “//” in the beginning of the line again. Compile and load the code into the MCU. 

Calibrate your load cells and change the calibration factor to your specific ones:

// LOAD CELL DEFINES---------------------------------------------------------

#define LOADCELL_DOUT_PIN 4 #define LOADCELL_SCK_PIN 5 float calibration_factor = 23.5; //need to czech int weigth = 0;

Lastly calibrate your motor to define how much food is being dispensed in one turn of the motor. 

// Motor DEFINES ------------------------------------------------------------

float cal = 17.7; // auxiliary declaration of an initial Calibration value // calibration for motor 12V 28rpm // cal should be the amout of foog in grams dispensed by one full turn of the motor

And that's it! Congratulations, you made your pet feeder! 🎉

 

Code 

https://github.com/Bifanas/Pet-feeder/blob/main/Main.ino

Code structure:

     1.  Libraries — these libraries have to be installed to ensure the code works. They can be downloaded from the GitHub repository or found in the Arduino IDE library section.

  • HX711 (for the load cells)
  • Adafruit SSD1306 and GFX (for the OLED display)
  • uRTCLib (for the real-time clock)

     2. Definitions — define the pins and variables

     3. Functions — functions help clean the Main code and make it easy to read.

     4. Meal schedule setup  — here is where you need to define the meal size and time.

     5. Main  — it is the part of the code that loops and checks if it is time to feed, and when it's the right time, it dispenses the correct food amount. It also keeps track of the amount of food that has been dispensed. 

 

This code uses the ARDUINO UNO, but you can change the pins depending on which microcontroller you have:

//////////////////////////////////////////////////////////////////
//                             LIBRARIES                        //
//////////////////////////////////////////////////////////////////

//LOAD CELL LIB------------------------------------------------------------- #include "HX711.h" HX711 scale;

//OLED DISP LIB-------------------------------------------------------------- #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h>

// Real Time Clock LIB------------------------------------------------------- #include "Arduino.h" #include "uRTCLib.h" uRTCLib rtc(0x68); // uRTCLib rtc;

/////////////////////////////////////////////////////////////////// // DEFINES // //////////////////////////////////////////////////////////////////

// LOAD CELL DEFINES---------------------------------------------------------

#define LOADCELL_DOUT_PIN 4 #define LOADCELL_SCK_PIN 5 float calibration_factor = 23.5; //need to czech int weigth = 0;

// OLED DISP DEFINES---------------------------------------------------------

#define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for SSD1306 display connected using I2C #define OLED_RESET -1 // Reset pin #define SCREEN_ADDRESS 0x3C Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int bufferSize = 4; // Size of the circular buffer struct Measurement { char Calendar[20]; float weight; }; Measurement measurements[bufferSize]; // Array to store the measurements int currentIndex = 0; // Index to keep track of the current position in the buffer

// RTC DEFINES--------------------------------------------------------------- //char Calendar[20]; // string UTF8 end zero

// Motor DEFINES ------------------------------------------------------------

float cal = 17.7; // auxiliary declaration of an initial Calibration value // calibration for motor 12V 28rpm // cal should be the amout of foog in grams dispensed by one full turn of the motor

// Motor A connections #define enA 8 #define in1 9 #define in2 10

int16_t Hour_A; // 32767.. +32767 optimize the data type int16_t Hour_B; int16_t Minute_A; int16_t Minute_B; int16_t Meal_size_A; int16_t Meal_size_B;

////////////////////////////////////////////////////////////////// // FUNCTIONS // //////////////////////////////////////////////////////////////////

void MotorControl(float time, bool direrction) { analogWrite(enA, 255); // Set motors to maximum speed if (direrction) { digitalWrite(in1, HIGH); // 1 Forward digitalWrite(in2, LOW); } else if (!direrction) { // 0 Reverse digitalWrite(in1, LOW); digitalWrite(in2, HIGH); } delay(time); // Keep spinning (Food control) 

digitalWrite(in1, LOW); // Turn off motors digitalWrite(in2, LOW); analogWrite(enA, 0); // Disable the motors }

//------------------------------------------------------------------

void feed(float cal, int amount) { float turns = 2900 * (50/ cal);

// (2900) = 1 tunr, 50g = portion size, cal = 18g per turn

for (int i = 0; i < amount; i = i + 50) { // feeds in 50g pulses MotorControl(turns, 1); // Spins forward MotorControl(1000, 0); // Spins backwards } }

char now[20]; void addMeasurement(float newWeight, char current_calendar[]) { // Create a new measurement Measurement newMeasurement; strcpy(newMeasurement.Calendar, current_calendar); // Use strcpy to copy the content newMeasurement.weight = newWeight; // Add the new measurement to the buffer at the current index measurements[currentIndex] = newMeasurement; // Increment the current index and wrap around if necessary currentIndex = (currentIndex + 1) % bufferSize; } void Main_screan_print() { //Serial.println("Buffer:"); // Print the contents of the buffer /* for (int i = 0; i < bufferSize; i++) { Serial.print("Timestamp: "); Serial.print(measurements[i].Calendar); Serial.print(" Weight: "); Serial.println(measurements[i].weight, 2); } Serial.println(); */ display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE); display.setCursor(0, 0); display.print(rtc.hour()); display.print(":"); display.print(rtc.minute()); display.print(":"); display.print(rtc.second()); display.setTextSize(1); display.print(" "); display.print(rtc.day()); display.print("/"); display.print(rtc.month()); display.setCursor(0, 25); display.setTextSize(1);

for (int i = 0; i < bufferSize; i++) { //display.print("");

display.print(measurements[i].Calendar); display.print(" "); display.print(measurements[i].weight); display.println(" g");
} display.display(); }

void setup() { Serial.begin(9600);

// MOTOR SETUP----------------------------------------------------- // Set all the motor control pins to outputs pinMode(enA, OUTPUT); pinMode(in1, OUTPUT); pinMode(in2, OUTPUT); // Turn off motors - Initial state digitalWrite(in1, LOW); digitalWrite(in2, LOW);

// RTC SETUP------------------------------------------------------- URTCLIB_WIRE.begin(); //rtc.set(0,50,21, 6, 31, 8, 2024); //(second, minute, hour, dayOfWeek, dayOfMonth, month, year)

//LOAD CELL SETUP-------------------------------------------------- scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); scale.set_scale(calibration_factor); //Adjust to this calibration factor scale.tare(); //Reset the scale to 0 long zero_factor = scale.read_average(); //Get a baseline reading Serial.print("Zero factor: "); //This can be used to remove the need to tare the scale. Useful in permanent scale projects. Serial.println(zero_factor);

//OLED DISP SETUP--------------------------------------------------- // initialize the OLED object if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { Serial.println(F("SSD1306 allocation failed")); for (;;) ; // Don't proceed, loop forever } // Clear the buffer. display.clearDisplay();

////////////////////////////////////////////////////////////////// // MEAL SCHEDULE SETUP // //////////////////////////////////////////////////////////////////

// Change the time and size of the first meal! Hour_A = 8; Minute_A = 0; Meal_size_A = 200; // Change the time and size of the first meal! Hour_B = 17; Minute_B = 0; Meal_size_B = 200; }

////////////////////////////////////////////////////////////////// // MAIN // //////////////////////////////////////////////////////////////////

int old_weigth = 0; int new_weigth = 0; unsigned long seconds = 1000L;
unsigned long minutes = seconds * 60;

void loop() {

 //Updates the data ------------------------------------------------------

rtc.refresh(); // Check the current time. sprintf(now, "%02d/%02d %02d:%02d", rtc.day(), rtc.month(), rtc.hour(), rtc.minute()); Serial.println(now); Main_screan_print(); // Serial.println(scale.get_units(5)); // Mesures how much food is inside.

//schedule detection ------------------------------------------------------ if (Hour_A == rtc.hour() && Minute_A == rtc.minute() && 0 == rtc.second()) { old_weigth = scale.get_units(5); feed(cal, Meal_size_A); delay(5*minutes); new_weigth = scale.get_units(5); old_weigth = old_weigth - new_weigth; addMeasurement(old_weigth, now); } if (Hour_B == rtc.hour() && Minute_B == rtc.minute() && 0 == rtc.second()) {

old_weigth = scale.get_units(5);

feed(cal, Meal_size_B); delay(5*minutes); new_weigth = scale.get_units(5); old_weigth = old_weigth - new_weigth; addMeasurement(old_weigth, now); } delay(500); }

Check out one of the previous versions: 

Tagi