Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Haustierfütterung mit 3D-gedruckten Teilen

Komponenten und Verbrauchsmaterialien

Arduino Nano R3
× 1
DS 1307 Echtzeituhrmodul
Sie können jede RTC-Marke verwenden, ich bin sicher, es gibt billigere Optionen
× 1
LM-317 Spannungsreglermodul
× 1
Kontinuierliche Rotationsservo
× 1
Müslispender
× 1
8-mm-Magnete
× 6
Hallsensor (unipolar)
Stellen Sie sicher, dass der Sensor, den Sie erhalten, EINPOLAR ist, damit Sie die umgekehrte Polarität des Magneten nicht benötigen Reset des Sensorausgangs
× 1
Adafruit RGB-Hintergrundbeleuchtung LCD - 16x2
× 1
I2C-LCD-Rucksack
Wenn Sie möchten, können Sie den LCD-Bildschirm mit bereits angebrachtem Rucksack kaufen
× 1
5 mm LED:Rot
× 1
5 mm LED:Grün
× 1
Druckschalter, kurzzeitig
× 5
DC-Netzstecker-Adapter weiblich
× 1
9-12 Volt Wandwarze
× 1
Widerstand 10k Ohm
Für den Hallsensor. Verbindung zwischen Vcc- und Signal-Pins
× 1
Widerstand 330 Ohm
Für LEDs. Sie können einen höheren Widerstand verwenden, wenn Sie sie nicht so hell haben möchten
× 2

Notwendige Werkzeuge und Maschinen

3D-Drucker (generisch)
Bohrschrauber / Akkuschrauber
Kreissäge

Über dieses Projekt

Die Geschichte hinter dem Futterautomat

Ich spiele schon seit einiger Zeit mit Mikrocontrollern herum und wollte versuchen, von Tutorials abzuzweigen. Vor Covid-19 hatte ich keinen wirklich festen Zeitplan und arbeitete ziemlich lange. Der Fütterungsplan meines Hundes begann wirklich zu leiden und führte zu sichtbaren Beschwerden. Mein Gebiet ist auch während der Hurrikansaison anfällig für Überschwemmungen. Leider gab es ein paar Fälle, in denen ich es nicht nach Hause schaffte, mein altes Mädchen zu ernähren. Ich musste eine Lösung finden, damit mein Hund nicht hungern würde, wenn ich es nicht nach Hause schaffen würde. Anstatt einen für 30 bis 40 US-Dollar zu kaufen, warum nicht einen für über 100 US-Dollar bauen? Ich mache nur Spaß.

Der Feeder!

Mein Hundefutterautomat verwendet einen Arduino-Mikrocontroller. Es gab ein paar wichtige Funktionen, die ich brauchte, die die meisten anderen Versionen von Hundefutterautomaten nicht hatten. Nämlich eine Lösung für die Stromversorgung nach einem Stromausfall und die Lösung des Problems, dass Lebensmittel im Ausgabemechanismus stecken bleiben. Meine Gegend leidet auch unter zufälligen Stromausfällen. Die Ausfälle dauern normalerweise nie sehr lange, daher sah ich keine Notwendigkeit für eine Stromredundanz. Ich wollte auch etwas, das sich leicht auseinandernehmen und reinigen lässt. Seien Sie beim Waschen der 3D-gedruckten Teile vorsichtig. Sie können warmes Wasser verwenden, NICHT heißes Wasser, es sei denn, Sie planen, mit ABS oder PET-G zu drucken.

Die vollständige Liste der Funktionen lautet wie folgt:

  • Zwei Fütterungen pro Tag
  • Genaue Zeitmessung mit Echtzeituhr
  • Manuelle Zeitumstellung der Echtzeituhr
  • Manuelle Fütterungsoption
  • LED-Anzeige von Hallsensor und Echtzeituhrausfall
  • Übersicht über Fütterungszeiten, aktuelle Uhrzeit und Fütterungsabschlüsse auf dem Hauptbildschirm
  • Leicht zu navigierendes Menü
  • Einspeisung bei Stromausfall wieder aufgenommen (wird einspeisen, wenn der Strom wieder eingeschaltet wird)
  • Fütterungszeiten und Vervollständigungen sicher im EEPROM gespeichert
  • Servo "wackeln" falls Lebensmittel während der Ausgabe stecken bleiben

Demo

Demo-Video kommt bald!

Was brauchst du noch?

  • 4x M3-0,5 x 16 mm Schrauben (Geberrad)
  • 4x M3-0,5 x 10 mm Schrauben (Servohalterung)
  • 12x M3 Sechskantmuttern
  • 4x M3-Kontermuttern
  • 16x 1-1/2 Zoll (38 mm) Mehrzweck-Holzschrauben
  • Holzleim
  • 6 x 0,315 x 0,118 Zoll (8 x 3 mm) Magnete
  • 1-1/2 x 1-1/2 Zoll (3,8 x 3,8 cm) Holz für Beine und Servohalterung
  • 1/2 x 6 Zoll (1,27 x 15,24 cm) Holz für Rücken und Sockel

Die 3D-gedruckten Teile

Ich habe mir vor kurzem einen 3D-Drucker zugelegt und dachte, wie könnte ich ihn besser lernen und einsetzen, als benutzerdefinierte Teile für meinen Futterautomaten auszudrucken. Alles gedruckte ist PLA+ und wurde mit einem Ender 3 Pro mit Cura als Slicer gedruckt. Die STLs für alle Teile finden Sie auf der Github-Projektseite. Link unten. Lesen Sie die README-Datei für Druckanweisungen und Slicer-Einstellungen.

Das Gehäuse

Das Gehäuse ist auf Komfort und Einfachheit ausgelegt. Keine Schrauben oder Muttern erforderlich. Stecken Sie die Komponenten einfach ein und aus. Jeder Einsatz hat 4 Laschen, die die Komponenten an Ort und Stelle halten.

Obwohl ich anfangs den LCD-Bildschirmschlitz durcheinander gebracht habe, ging ich zurück und reparierte das Modell in Fusion 360. Ich war einfach zu faul, um zurückzugehen und es erneut zu drucken. Ich benutzte einige zusätzliche M3 0,5 x 6 mm Schrauben, die ich herumgelegt hatte, um es zu befestigen. An jeder Ecke des LCD-Steckplatzes befinden sich vier Abstandshalter mit Löchern, damit Sie den Bildschirm bei Bedarf befestigen können. Leider habe ich den Gehäusedeckel nie fotografiert, bevor ich alles eingesteckt habe.

Der Encoderradaufsatz

Das Rad-Encoder-Rad dient zwei Zwecken:

  • Versorgt den Arduino mit Positionsrückmeldung vom Servo
  • Befestigt das Gummipaddel am Servo

Eine Zufuhrportion entspricht 1/6 (60 Grad) Drehung des Rades. Verwenden Sie eine Futterwaage, um die Futtermenge abzumessen, die Ihr Haustier pro Fütterung erhält, und passen Sie dann die Portionszahl an, bis Sie einen Bereich erhalten, der dieser Menge entspricht. Ich glaube, eine Fütterung für mich war ungefähr 173 Gramm Futter. Eine Portionsgröße von 17 gab mir eine Bandbreite von 170-177 Gramm pro Fütterung. Es hängt alles von der Größe Ihres Krokettens ab. Stellen Sie sicher, dass das Horn zwischen den 8 M3-Sechskantmuttern sitzt.

Die Servohalterung und die Hallsensorhalterung

Diese benutzerdefinierte Servohalterung hält auch den Hallsensor und montiert das Servo auf einem Stück 3,8 x 3,8 cm (1-1/2 x 1-1/2 Zoll) Holz. Die Länge des Holzes hängt davon ab, wo das Servo sitzt (dazu später mehr). Es gibt viel Raum für Fehler bei der Halterung, also machen Sie sich keine Sorgen um die perfekte Länge.

Trichter, Futterrutsche und Rutschenschiene

Dies bildet das Essenslieferungssystem. Das Futter kommt aus dem Spender durch den Trichter und auf die Rutsche und in den Futternapf. Leider habe ich die Schurrenschiene vor der Montage nicht fotografiert.

Der Rahmen

*Haftungsausschluss* Ich habe nicht jeden Schritt des Montageprozesses fotografiert. Bei einigen dieser Bilder werden Schritte übersprungen, aber ich werde Sie dennoch Schritt für Schritt für die Rahmenmontage führen.

Achten Sie darauf, Löcher für jede Schraube, die Sie verwenden, vorzubohren.Sie möchten das Holz spalten!

Dies ist der Müslispender, den ich bei Amazon gekauft habe. Es gibt einige, die mehrere Spender haben, wenn Sie mehrere Haustiere haben und mehrere Futterautomaten benötigen, ich brauchte nur einen. Die Marke ist Honey Can Do, aber ich bin mir sicher, dass jede Marke funktioniert.

Das erste, womit ich angefangen habe, war das Entfernen des Knopfes von der Stange, die mit dem Schaufelrad des Spenders verbunden war. Ich benutzte eine Handsäge, um den Knopf zu entfernen. Sie können ein Elektrowerkzeug verwenden, wenn Sie eines haben. Schneiden Sie die Stange nicht weiter nach unten, wo das Silberteil endet. Schneiden Sie direkt an der Basis des Knopfes.

Nachdem Sie den Knopf abgesägt haben, entfernen Sie das restliche Material, indem Sie die 3 Stützen schneiden, die im letzten Bild oben zu sehen sind. Dies hat eine ganze Weile gedauert. Ich kann mir vorstellen, dass es schneller geht, wenn Sie das richtige Elektrowerkzeug haben. Sobald Sie diese drei Stützen entfernen, sollte sich das verbleibende Stück auf der Stange selbst mit etwas Ellenbogenfett lösen. Sie müssen den Teil der Stange, der dem Knopf am nächsten ist, abschleifen, damit er gut in das Encoderrad passt.

Als nächstes beginnen wir mit dem Bau der Basis des Rahmens. Ich nahm das 1/2 x 6 Zoll (1,27 x 15,24 cm) Holz und schnitt es in zwei 8 Zoll (20,32 cm) große Stücke. Dies bildet die Basis und die Rückseite des Feederrahmens. Tragen Sie etwas Holzleim auf und verbinden Sie sie mit 2 der Mehrzwecknägel in L-Form. Sie müssen ein paar rechtwinklige Stützen hinzufügen, um die Verbindung zwischen Rückwand und Bodenplatte zu verstärken. Verwenden Sie 4 Mehrzweckschrauben und etwas Holzleim, um sie sowohl an der Rück- als auch an der Bodenplatte zu befestigen. Ich habe kein Bild von diesem Schritt, aber Sie können sie weiter unten in Bildern sehen.

Von hier aus müssen Sie den Spenderständer auf eine Höhe von ca. 4,5 Zoll (11,43 cm) zuschneiden. Es muss nicht perfekt sein. Versuchen Sie, so nah wie möglich daran zu kommen. Der Trichter lässt etwas Spielraum. Sobald Sie den Ständer zurechtgeschnitten haben, legen Sie ihn gegen die Rückseite und stellen Sie sicher, dass er flach auf der Basis sitzt. Sobald Sie es in Position gebracht haben, markieren Sie mit einem Bleistift oder Kugelschreiber die Mitte des Ausgabeendes des Behälters. Anschließend müssen Sie ein Loch von 5,08 cm (2 Zoll) ganz durch die Bodenplatte bohren. Es ist wichtig, dass Sie mit diesem zweimal messen und einmal schneiden. Das wird das Loch sein, das im Bild oben zu sehen ist.

Nachdem Sie das Loch in die Bodenplatte gebohrt haben, können wir den Spenderständer an der Rückplatte befestigen. Was Sie tun möchten, ist, den Ständer gegen die Rückwand zu stellen (im ersten Bild unten gezeigt). Unter dem Ring des Spenderständers befinden sich zwei Ablagefächer. Hier sollen die Löcher sein (siehe Bild unten). Verwenden Sie einen Bleistift oder Kugelschreiber, um die Höhe der beiden Löcher auf der Rückseite zu markieren. Sie möchten sie so nah wie möglich an der Mitte des Spenderständers. Es gibt zwei Schrauben, die den oberen Ring des Ständers mit dem unteren Teil verbinden, den Sie abschneiden. Achten Sie darauf, diese beim Bohren nicht zu treffen. Denken Sie auch hier daran, zweimal zu messen und einmal zu bohren. Oder zweimal, in diesem Fall.

Nachdem wir die Löcher gebohrt haben, können wir den Ständer mit den 5/16-Zoll-Sechskantschrauben, 5/16-Zoll-Sechskantmuttern und 5/16-Zoll-Unterlegscheiben an der Rückwand befestigen. Sie möchten die Schrauben durchschieben und sicherstellen, dass Sie Unterlegscheiben am Sechskantende der Schrauben anbringen, bevor Sie sie durchschieben. Nachdem sie auf der anderen Seite herausgekommen sind, legen Sie den anderen Satz Unterlegscheiben auf die Gewindeseite und beginnen Sie dann, die Sechskantmuttern handfest anzuziehen. Das wird ein bisschen knifflig. Nachdem Sie die Muttern von Hand angezogen haben, müssen Sie eine Buchse verwenden, um die Mutter zu halten und sie weiter festzuziehen. Nur etwa 1/4 Umdrehung oder so. Achten Sie darauf, nicht zu fest anzuziehen.

Nachdem der Ständer sicher befestigt ist, können wir nun das 1/2 x 1/2 Zoll Holzstück hinzufügen, auf dem das Servo sitzen wird. Die Länge hängt davon ab, wo Ihr Servo sitzt. Fahren Sie fort und montieren Sie den Zuführmechanismus, indem Sie das Servo am Horn des Encoderrads und das Encoderrad am Gummipaddel im Kunststoffbehälter befestigen. Stellen Sie den Behälter in den oberen Ring und messen Sie, wo das Servo von der Basisplatte sitzt. Machen Sie sich keine Sorgen, dass es perfekt ist. Die Servohalterung lässt ziemlich viel Spielraum. Verwenden Sie Holzleim und eine einzelne Mehrzweckschraube, um den Holzständer zu befestigen.

Der nächste Schritt besteht darin, die Beine an der Grundplatte des Feeders zu befestigen. Die Länge der Beine hängt davon ab, wie hoch der Futternapf Ihres Haustieres ist. Mein Hund hat seinen Futternapf auf einem erhöhten Ständer; Daher musste ich meinen Feeder ziemlich hoch sitzen. Verwenden Sie 4 der Mehrzweckschrauben und etwas Holzleim, um sie zu befestigen. Ich empfehle, einen Querträger zwischen den beiden Vorder- und zwei Hinterbeinen und einen weiteren Querträger zwischen den Querträgern zu platzieren, wie unten gezeigt, um die Stabilität zu erhöhen. Verwenden Sie insgesamt 6 Mehrzweckschrauben und etwas Holzleim, um die Teile an den Beinen zu befestigen.

Die nächsten Schritte sind:

  • Führen Sie den Trichter in das Loch ein, das wir in die Bodenplatte gebohrt haben
  • Befestige das Servo an der Servohalterung
  • Befestige die Halterung am Holzständer

Befestigen Sie das Servo mit den 4 M3 x 10 mm Schrauben und 4 der M3 Sechskantmuttern an der Halterung. Sobald das Servo gesichert ist, können wir die Halterung am hölzernen Servoständer befestigen. Verwenden Sie zwei der Mehrzweckschrauben, um die Halterung leicht am Holzständer zu befestigen. Nicht zu fest anziehen, sonst beschädigen Sie die Halterung. Stellen Sie sicher, dass Sie die Schritte in dieser Reihenfolge ausführen. Der Trichter wird das Servo ein wenig anheben und es passt ziemlich eng an das Ende des Kunststoffbehälters, so dass es unmöglich ist, ihn aufzusetzen, wenn der Kunststoffbehälter bereits im oberen Ringständer sitzt.

Die letzten Schritte bestehen darin, die Einschubhalterung der Rutsche und die Rutsche selbst zu befestigen. Sie möchten die Halterung etwas hinter dem Loch in der Bodenplatte positionieren. Sie möchten es so weit wie möglich nach vorne bringen, damit der Schieber den Rahmen des Einzugs freigibt. Verwenden Sie zwei der Mehrzweckschrauben, um die Halterung an der Unterseite der Grundplatte des Rahmens zu befestigen. Am besten machst du dies mit der Folie in der Halterung, da die Halterung etwas biegsam ist und Sie einen ziemlich sicheren Sitz zwischen der Folie und der Halterung wünschen.

Die Elektronik

Leider habe ich nie Bilder vom Lötprozess gemacht. Dabei ist nicht viel dran. Löten Sie einfach jede Komponente an die entsprechenden Pins und Sie sollten gut sein. Wenn Sie stattdessen Stiftleisten verwenden möchten, können Sie dies auch so tun. Unter und über dem Arduino-Steckplatz ist genügend Freiraum für die Stifte und Anschlüsse. Ich empfehle auf jeden Fall, alles zusammenzulöten, bevor Sie alle Komponenten in ihre jeweiligen Steckplätze einsetzen.

Ich habe meinen Arduino über den ungeregelten externen Stromanschluss (Pin 30) mit Strom versorgt. Dies erfordert eine Eingangsspannung zwischen 7-20 Volt, da diese Spannung über den Onboard-Regler des Arduino zugeführt wird. Wenn Sie es über USB mit Strom versorgen möchten, müssen Sie nur sicherstellen, dass Sie es mit 5 Volt versorgen, NICHT mit 7-20 Volt.

Achten Sie darauf, den 10k Ohm-Widerstand zwischen den Vcc- und Signal-Pins am Hall-Sensor zu löten. Andernfalls erhalten Sie keine Anzeige. Vergessen Sie auch nicht, alle Komponenten mit einer gemeinsamen Masse zu verbinden. Ich habe den Fehler gemacht, einen der Gründe zu übersehen, und mein System würde eine Weile funktionieren, aber der Hallsensor würde irgendwann ausfallen. Das war ein wirklich guter Tag für meinen Hund.

Am Ende habe ich benutzerdefinierte Anschlüsse für den Hallsensor und die Servoverbindungen hergestellt. Ich lötete die Drähte an Stiftleisten. Diese hängen aus dem Boden des Gehäuses. Für den Hall-Sensor habe ich einen benutzerdefinierten weiblichen Adapter hergestellt, indem ich ein paar Dupont-Anschlussdrähte, die ich herumliegen hatte, abgeschnitten, abisoliert und lötet.

Für die Vcc- und Masseschiene habe ich den Stromschienenabschnitt von einem zusätzlichen Perma-Proto-Steckbrett abgeschnitten, das ich herumgelegt hatte. Alles ähnliche, was Sie in der Nähe haben, wird funktionieren. Überprüfen Sie einfach Ihre Verbindungen, bevor Sie die Schiene in ihren Steckplatz einsetzen. Das ist das Schwierigste, wenn es drin ist. Das habe ich auch auf die harte Tour gelernt.

Das ist es! Ich hoffe ihr habt genauso viel Spaß beim Bauen wie ich. Es sieht auf den ersten Blick herausfordernd aus, aber je mehr man sich darauf einlässt, desto einfacher wird es. Lassen Sie es mich wissen, wenn Sie Fragen zu irgendetwas haben. Viel Spaß beim Basteln!

Code

  • Feeder-Code
Feeder-CodeC/C++
// Endgültige Version für den Tierfutterautomat/* Features:- Leicht zu navigierendes Menü - Übersicht über Fütterungszeiten, aktuelle Uhrzeit, Fütterungsende und Fütterungsportion auf dem Hauptbildschirm - Kontrollierbare Portionen mit Hallsensor für Feedback - Genau Zeitmessung mit DS1307-Chip - Kann die eingestellte Zeit im DS1307-Chip manuell ändern - Zwei Fütterungen pro Tag - Manuelle Fütterungsoption - Fütterungsneustart bei Stromausfall - LED-Anzeige von Hallsensor und Echtzeituhr - Fütterungszeiten und -fertigstellungen werden sicher im EEPROM gespeichert - Servo "wackeln" bei festsitzendem Essen*/#include #include #include #include #include # include #include // Erstellt ein Servo-Objekt zur Steuerung Ihres servoServo myservo;// Zuweisung aller meiner Eingangs- und E/A-Pins#define ENTER_BUTTON_PIN 11#define UP_BUTTON_PIN 10#define DOWN_BUTTON_PIN 9#define BACK_BUTTON_PIN 8#define POWER_LED_PIN 5#define MANUAL_BUTTON_PIN A1#define hallPin 2#define HALL_LE D_PIN 7#define SERVO_PIN 6// Definieren aller Buttons, funktioniert mit der JC_Button BibliothekButton enterBtn (ENTER_BUTTON_PIN);Button hochBtn (UP_BUTTON_PIN);Button runterBtn (DOWN_BUTTON_PIN);Button zurückBtn (BACK_BUTTON_PIN);Button_MANUALFeedB/ .t); LCD I2C und RTCLiquidCrystal_I2C lcd(0x27, 16, 2);RTC_DS1307 rtc;//Variablen, die im gesamten Code verwendet werdenunsigned long hallSensorTime;unsigned long rotationTime =400;unsigned long led_preMillis =0;const long interval_delay =1000;unsigned long delay_interval =2000; int ledState =LOW;boolean manualFeed =false;boolean hall_sensor_fail =false;unsigned long blink_preMillis =0;unsigned long blink_currentMillis =0;unsigned long blink_interval =500;unsigned long delay_currentMillis =0;unsigned lange blink_preMillis_state =false;boolean; int count;boolesche Fütterung1_complete =false;boolesche Fütterung2_complete =false;boolesche Fütterung1_trigger =false;boolesche Fütterung2_trigger =false;boolesche Fütterung servoOn =tru e; // Hall-Sensor-Interruptvolatile Boolean hallSensorActivated =false;volatile int isr_count =1;void hallActiveISR() { hallSensorActivated =true; digitalWrite (HALL_LED_PIN, HIGH); isr_count =isr_count + 1;}/* Ich verwende hier Aufzählungen, um besser zu verfolgen, welche Schaltfläche gedrückt wird, anstatt nur jede Schaltfläche auf einen ganzzahligen Wert setzen zu lassen.*/enum { btnENTER, btnUP, btnDOWN, btnBACK,}; /* Zustände des Zustandsautomaten. Das gleiche hier mit dem Enum-Typ. Es macht es einfacher zu verfolgen, in welchem ​​Menü Sie sich befinden oder gehen möchten, anstatt jedem Menü einen Ganzzahlwert zu geben*/enum STATES { MAIN, MENU_EDIT_FEED1, MENU_EDIT_FEED2, MENU_EDIT_TIME, MENU_EDIT_PORTION, EDIT_FEED1_HOUR, EDIT_FEED1_MIN, EDIT_FEED2 , EDIT_MIN, EDIT_PORTION};// Hält den Zustand des Zustands machineSTATES state;//Benutzereingabevariablenint Hour;int Minute;int portion;int feed_time1_hour;int feed_time1_min;int feed_time2_hour;int feed_time2_min;int userInput;// Sonderzeichen Checkmarkbyte check_Char[8] ={ B00000, B00000, B00001, B00011, B10110, B11100, B11000, B00000};//======================Das Setup===========================void setup () { Wire.begin (); Serial.begin (9600); lcd.init(); LCD-Rücklicht(); lcd.createChar(0, check_Char); if (!rtc.begin()) {Serial.println("Konnte RTC nicht finden!"); } // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); //Die Schaltflächen enterBtn.begin(); upBtn.begin(); downBtn.begin(); backBtn.begin(); manualFeedBtn.begin(); //Einrichten des Anfangszustands der Zustandsmaschine state =MAIN; // Ein- und Ausgänge einrichten pinMode (POWER_LED_PIN, OUTPUT); pinMode (HALL_LED_PIN, AUSGANG); pinMode (hallPin, EINGANG); /* Anfügen eines Interrupts an den Pin, der mit dem Hallsensor verbunden ist. Der von mir verwendete Hallsensor ist auf HIGH eingestellt und geht auf LOW, wenn er auf einen Magneten trifft. Deshalb ist es auf FALLING gesetzt */ attachInterrupt (digitalPinToInterrupt(hallPin), hallActiveISR, FALLING); // Standardzustand der LEDs digitalWrite (POWER_LED_PIN, HIGH); digitalWrite (HALL_LED_PIN, LOW); /* Diese Funktionen holen beim Start die gespeicherte Fütterungszeit, die abgeschlossene Fütterung und die Portionsgröße aus dem EEPROM. Ich habe das gemacht, weil ich hier, wo ich wohne, zufällige Stromausfälle bekomme. */ get_feed_time1(); get_feed_time2(); get_completed_feedings(); get_portion();}//======================Die Schleife===========================void loop () { change_states (); check_buttons(); check_feedtime (); check_rtc(); manual_feed_check ();}//===============Die Funktionen =======================/* Verwendet die JC_Button-Bibliothek, um ständig zu überprüfen, ob eine Schaltfläche gedrückt wurde. Abhängig davon, welche Taste gedrückt wird, wird die Variable userInput für die Funktion menu_transitions*/void check_buttons () { enterBtn.read(); upBtn.read(); downBtn.read(); backBtn.read(); manualFeedBtn.read(); if (enterBtn.wasPressed()) { Serial.println ("Sie haben die Eingabetaste gedrückt!"); userInput =btnENTER; menu_transitions (Benutzereingabe); } if (upBtn.wasPressed()) {Serial.println ("Sie haben nach oben gedrückt!"); userInput =btnUP; menu_transitions (Benutzereingabe); } if (downBtn.wasPressed()) {Serial.println ("Sie haben nach unten gedrückt!"); userInput =btnDOWN; menu_transitions (Benutzereingabe); } if (backBtn.wasPressed()) {Serial.println ("Sie haben zurückgedrückt!"); userInput =btnBACK; menu_transitions (Benutzereingabe); } if (manualFeedBtn.wasPressed()) {Serial.println ("Sie füttern manuell!"); manuelleFeed =true; }}//====================================================/* Diese Funktion bestimmt, was angezeigt wird, je nachdem in welchem ​​Menü oder "Zustand" Sie sich befinden. Jedes Menü hat eine Funktion, die das jeweilige Menü anzeigt*/void change_states() { switch (state) { Fall MAIN:display_current_time(); display_feeding_times(); display_portion(); brechen; Fall MENU_EDIT_FEED1:display_set_feed_time1_menu(); brechen; Fall MENU_EDIT_FEED2:display_set_feed_time2_menu(); brechen; Fall MENU_EDIT_TIME:display_set_time_menu(); brechen; Fall MENU_EDIT_PORTION:display_set_portion_menu (); brechen; Fall EDIT_FEED1_HOUR:set_feed_time1(); brechen; Fall EDIT_FEED1_MIN:set_feed_time1(); brechen; Fall EDIT_FEED2_HOUR:set_feed_time2(); brechen; Fall EDIT_FEED2_MIN:set_feed_time2(); brechen; Fall EDIT_HOUR:set_the_time(); brechen; Fall EDIT_MIN:set_the_time(); brechen; Fall EDIT_PORTION:set_the_portion(); brechen; }}//====================================================/* Dies ist der Übergangsteil der Zustandsmaschine. So können Sie von einem Menü zum anderen wechseln und Werte ändern*/void menu_transitions(int input) { switch (state) { case MAIN:if (input ==btnENTER) { lcd.clear(); Zustand =MENU_EDIT_FEED1; } if (input ==btnBACK) { hall_sensor_fail =false; } brechen; //------------------------------------------------ ---- Fall MENU_EDIT_FEED1:if (input ==btnBACK) { lcd.clear(); Zustand =HAUPT; aufrechtzuerhalten. Sonst if (Eingabe ==btnENTER) {lcd.clear(); Zustand =EDIT_FEED1_HOUR; aufrechtzuerhalten. Sonst if (Eingabe ==btnDOWN) {lcd.clear(); Zustand =MENU_EDIT_FEED2; } brechen; //------------------------------------------------ ---- Fall EDIT_FEED1_HOUR:// Benötigen Sie dies, um zu verhindern, dass das Servo beim Einstellen der Zeit ausgeht servoOn =false; if (Eingabe ==btnUP) { feed_time1_hour++; if (feed_time1_hour> 23) { feed_time1_hour =0; } } else if (input ==btnDOWN) {feed_time1_hour--; if (feed_time1_hour <0) { feed_time1_hour =23; } } else if (input ==btnBACK) { lcd.clear(); servoOn =true; state =MENU_EDIT_FEED1; } else if (input ==btnENTER) { state =EDIT_FEED1_MIN; } brechen; //---------------------------------------------------- case EDIT_FEED1_MIN:if (input ==btnUP) { feed_time1_min++; if (feed_time1_min> 59) { feed_time1_min =0; } } else if (input ==btnDOWN) { feed_time1_min--; if (feed_time1_min <0) { feed_time1_min =59; } } else if (input ==btnBACK) { state =EDIT_FEED1_HOUR; } else if (input ==btnENTER) { lcd.clear(); lcd.setCursor(0, 0); lcd.print( "*Settings Saved*"); Verzögerung (1000); lcd.clear(); servoOn =true; write_feeding_time1 (); state =MAIN; } brechen; //---------------------------------------------------- case MENU_EDIT_FEED2:if (input ==btnUP) { lcd.clear(); state =MENU_EDIT_FEED1; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_FEED2_HOUR; } else if (input ==btnDOWN) { lcd.clear(); state =MENU_EDIT_TIME; } brechen; //---------------------------------------------------- case EDIT_FEED2_HOUR:servoOn =false; if (input ==btnUP) { feed_time2_hour++; if (feed_time2_hour> 23) { feed_time2_hour =0; } } else if (input ==btnDOWN) { feed_time2_hour--; if (feed_time2_hour <0) { feed_time2_hour =23; } } else if (input ==btnBACK) { lcd.clear(); servoOn =true; state =MENU_EDIT_FEED2; } else if (input ==btnENTER) { state =EDIT_FEED2_MIN; } brechen; //---------------------------------------------------- case EDIT_FEED2_MIN:if (input ==btnUP) { feed_time2_min++; if (feed_time2_min> 59) { feed_time2_min =0; } } else if (input ==btnDOWN) { feed_time2_min--; if (feed_time2_min <0) { feed_time2_min =59; } } else if (input ==btnBACK) { state =EDIT_FEED2_HOUR; } else if (input ==btnENTER) { lcd.clear(); lcd.setCursor(0, 0); lcd.print( "*Settings Saved*"); Verzögerung (1000); lcd.clear(); servoOn =true; write_feeding_time2 (); state =MAIN; } brechen; //---------------------------------------------------- case MENU_EDIT_TIME:if (input ==btnUP) { lcd.clear(); state =MENU_EDIT_FEED2; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_HOUR; } else if (input ==btnDOWN) { lcd.clear(); state =MENU_EDIT_PORTION; } brechen; //---------------------------------------------------- case EDIT_HOUR:if (input ==btnUP) { Hour++; if (Hour> 23) { Hour =0; } } else if (input ==btnDOWN) { Hour--; if (Hour <0) { Hour =23; } } else if (input ==btnBACK) { lcd.clear(); state =MENU_EDIT_TIME; } else if (input ==btnENTER) { state =EDIT_MIN; } brechen; //---------------------------------------------------- case EDIT_MIN:if (input ==btnUP) { Minute++; if (Minute> 59) { Minute =0; } } else if (input ==btnDOWN) { Minute--; if (Minute <0) { Minute =59; } } else if (input ==btnBACK) { state =EDIT_HOUR; } else if (input ==btnENTER) { lcd.clear(); lcd.setCursor(0, 0); lcd.print( "*Settings Saved*"); Verzögerung (1000); lcd.clear(); rtc.adjust(DateTime(0, 0, 0, Hour, Minute, 0)); state =MAIN; } brechen; //---------------------------------------------------- case MENU_EDIT_PORTION:if (input ==btnUP) { lcd.clear(); state =MENU_EDIT_TIME; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_PORTION; } brechen; //---------------------------------------------------- case EDIT_PORTION:if (input ==btnUP) { portion++; if (portion> 20) { portion =1; } } else if (input ==btnDOWN) { portion--; if (portion <1) { portion =20; } } else if (input ==btnBACK) { lcd.clear(); state =MENU_EDIT_PORTION; } else if (input ==btnENTER) { lcd.clear(); lcd.setCursor(0, 0); lcd.print( "*Settings Saved*"); Verzögerung (1000); lcd.clear(); write_portion(); state =MAIN; } brechen; }}//=====================================================// This function checks the feed time against the current timevoid check_feedtime (){ DateTime now =rtc.now(); if (now.second() ==0) { if ((now.hour() ==feed_time1_hour) &&(now.minute() ==feed_time1_min)) { feeding1_trigger =true; if (servoOn) { if (feeding1_complete ==false) { lcd.clear(); lcd.setCursor(3, 0); lcd.print ("Dispensing"); lcd.setCursor(1, 1); lcd.print("First Feeding"); startFeeding(); } } } else if ((now.hour() ==feed_time2_hour) &&(now.minute () ==feed_time2_min)) { feeding2_trigger =true; if (servoOn) { if ( feeding2_complete ==false) { lcd.clear(); lcd.setCursor(3, 0); lcd.print ("Dispensing"); lcd.setCursor(0, 1); lcd.print("Second Feeding"); startFeeding(); } } } } // Midnight Reset if ( (now.hour() ==0) &&(now.minute() ==0)) { feeding1_complete =false; feeding2_complete =false; EEPROM.write(4, feeding1_complete); EEPROM.write(5, feeding2_complete); } /*If power outtage happens during a feed time, this checks to see if the feed time has passed and if the feeding occurred. If not, it feeds. */ if ( (now.hour()>=feed_time1_hour) &&(now.minute()> feed_time1_min)) { if ((feeding1_complete ==0) &&(feeding1_trigger ==0)) { lcd.clear(); lcd.setCursor(5, 0); lcd.print ("Uh-Oh!"); lcd.setCursor(2, 1); lcd.print("Power Outage"); startFeeding(); } } if ( (now.hour()>=feed_time2_hour) &&(now.minute()> feed_time2_min)) { if ((feeding2_complete ==0) &&(feeding2_trigger ==0)) { lcd.clear(); lcd.setCursor(5, 0); lcd.print ("Uh-Oh!"); lcd.setCursor(2, 1); lcd.print("Power Outage"); startFeeding(); } }}//=====================================================// Displays the set portion menu optionvoid display_set_portion_menu () { lcd.setCursor(2, 0); lcd.print("Menu Options"); lcd.setCursor(0, 1); lcd.print("Set the Portion");}//=====================================================// Displays the menu where you change the current timevoid set_the_time (){ lcd.setCursor(2, 0); lcd.print("Set the Time"); switch (state) { //---------------------------------------------------- case EDIT_HOUR:if (blink_state ==0) { lcd.setCursor(5, 1); add_leading_zero(Hour); } else { lcd.setCursor(5, 1); lcd.print(" "); } lcd.print(":"); add_leading_zero(Minute); brechen; //---------------------------------------------------- case EDIT_MIN:lcd.setCursor(5, 1); add_leading_zero(Hour); lcd.print(":"); if (blink_state ==0) { lcd.setCursor(8, 1); add_leading_zero(Minute); } else { lcd.setCursor(8, 1); lcd.print(" "); } brechen; } blinkFunction();}//=====================================================// Displays the menu where you change the feeding portionvoid set_the_portion (){ lcd.setCursor (0, 0); lcd.print("Set the Portion"); switch (state) { case EDIT_PORTION:if (blink_state ==0) { lcd.setCursor(7, 1); add_leading_zero(portion); } else { lcd.setCursor(7, 1); lcd.print(" "); } } blinkFunction();}//=====================================================//Displays the menu option for setting the timevoid display_set_time_menu () { lcd.setCursor(2, 0); lcd.print("Menu Options"); lcd.setCursor(2, 1); lcd.print("Set the Time");}//=====================================================// Displays the menu where you change the second feeding timevoid set_feed_time2 (){ lcd.setCursor(0, 0); lcd.print("Set Feed Time 2"); switch (state) { //---------------------------------------------------- case EDIT_FEED2_HOUR:if (blink_state ==0) { lcd.setCursor(5, 1); add_leading_zero(feed_time2_hour); } else { lcd.setCursor(5, 1); lcd.print(" "); } lcd.print(":"); add_leading_zero(feed_time2_min); brechen; //---------------------------------------------------- case EDIT_FEED2_MIN:lcd.setCursor(5, 1); add_leading_zero(feed_time2_hour); lcd.print(":"); if (blink_state ==0) { lcd.setCursor(8, 1); add_leading_zero(feed_time2_min); } else { lcd.setCursor(8, 1); lcd.print(" "); } brechen; } blinkFunction();}//=====================================================// Displays the menu where you change the first feeding timevoid set_feed_time1 (){ lcd.setCursor(0, 0); lcd.print("Set Feed Time 1"); switch (state) { //---------------------------------------------------- case EDIT_FEED1_HOUR:if (blink_state ==0) { lcd.setCursor(5, 1); add_leading_zero(feed_time1_hour); } else { lcd.setCursor(5, 1); lcd.print(" "); } lcd.print(":"); add_leading_zero(feed_time1_min); brechen; //---------------------------------------------------- case EDIT_FEED1_MIN:lcd.setCursor(5, 1); add_leading_zero(feed_time1_hour); lcd.print(":"); if (blink_state ==0) { lcd.setCursor(8, 1); add_leading_zero(feed_time1_min); } else { lcd.setCursor(8, 1); lcd.print(" "); } brechen; } blinkFunction();}//=====================================================// Adds a leading zero to single digit numbersvoid add_leading_zero (int num) { if (num <10) { lcd.print("0"); } lcd.print(num);}//=====================================================/* Displays the feeding time on the main menu as well as the check mark for visual comfirmation of a completed feeding*/void display_feeding_times () { //Displaying first feed time lcd.setCursor(0, 0); lcd.print ("F1:"); add_leading_zero(feed_time1_hour); lcd.print(":"); add_leading_zero(feed_time1_min); lcd.print(" "); if (feeding1_complete ==true) { lcd.write(0); } else { lcd.print(" "); } //Displaying second feed time lcd.setCursor(0, 1); lcd.print("F2:"); add_leading_zero(feed_time2_hour); lcd.print(":"); add_leading_zero(feed_time2_min); lcd.print(" "); if (feeding2_complete ==true) { lcd.write(0); } else { lcd.print(" "); }}//=====================================================// Displays the current time in the main menuvoid display_current_time () { DateTime now =rtc.now(); lcd.setCursor(11, 0); add_leading_zero(now.hour()); lcd.print(":"); add_leading_zero(now.minute());}//=====================================================// Displays the menu option for setting the first feed timevoid display_set_feed_time1_menu () { lcd.setCursor(2, 0); lcd.print("Menu Options"); lcd.setCursor(0, 1); lcd.print("Set Feed Time 1");}//=====================================================// Displays the meny option for setting the second feed timevoid display_set_feed_time2_menu () { lcd.setCursor(2, 0); lcd.print("Menu Options"); lcd.setCursor(0, 1); lcd.print("Set Feed Time 2");}//=====================================================// Displays the feeding portion in the main menuvoid display_portion (){ lcd.setCursor (12, 1); lcd.print("P:"); add_leading_zero(portion);}//=====================================================// Starts the feeding process.void startFeeding(){ // attach the servo to the pin myservo.attach(SERVO_PIN); count =1; hallSensorTime =millis(); // loop so that the servo runs until desired portion is reached while (count <=portion) { servoStart(); if (hallSensorActivated ==true) { // digitalWrite(LED_PIN,HIGH); count =count + 1; //resetting for next interrupt hallSensorTime =millis(); hallSensorActivated =false; digitalWrite(HALL_LED_PIN, LOW); } /* Moved the servo clockwise a bit to dislodge food stuck in the dispensing mechanism */ if (millis() - hallSensorTime> rotationTime) { hall_sensor_fail =true; Serial.println("I'm in Jiggle"); jiggle(); } } // Keeps track of which feeding just happened and writes it to EEPROM if ((feeding1_complete ==false) &&(feeding2_complete ==false)) { feeding1_complete =true; EEPROM.write(4, feeding1_complete); } else if ((feeding1_complete ==true) &&(feeding2_complete ==false)) { feeding2_complete =true; EEPROM.write(5, feeding2_complete); } servoStop(); digitalWrite(HALL_LED_PIN, LOW); /* Detaches the servo from the pin so that it is no longer recieving a signal. You may have to add a delay before this so the sensor stops when a magnet is over the hall sensor. There was significant momentum left in my system that I did not need it */ myservo.detach(); lcd.clear(); delay_currentMillis =millis(); while (millis() - delay_currentMillis <=delay_interval) { lcd.setCursor(2, 0); lcd.print ("Feeding Done"); } lcd.clear();}//=====================================================void servoStart(){ myservo.write(180);}//=====================================================void servoStop(){ // this value will vary, you have to find it through trial and error myservo.write(94);}//=====================================================// "jiggles" the servo in case food gets stuckvoid jiggle(){ myservo.write(80); Verzögerung (30); myservo.write(93); Verzögerung (30); myservo.write(180);}//=====================================================// Writes the hour and minute valies set for 1st feeding to the EEPROMvoid write_feeding_time1 (){ EEPROM.write(0, feed_time1_hour); EEPROM.write(1, feed_time1_min);}//=====================================================// Writes the hour and minute values set for 2nd feeding to the EEPROMvoid write_feeding_time2 () { EEPROM.write(2, feed_time2_hour); EEPROM.write(3, feed_time2_min);}//=====================================================// Writes portion value set to the EEPROMvoid write_portion (){ EEPROM.write(6, portion);}//=====================================================// Reads the hour and minute values from 1st feed time from EEPROMvoid get_feed_time1 (){ feed_time1_hour =EEPROM.read(0); if (feed_time1_hour> 23) feed_time1_hour =0; feed_time1_min =EEPROM.read(1); if (feed_time1_min> 59) feed_time1_min =0;}//=====================================================// Reads the hour and minute values from 2nd feed time from EEPROMvoid get_feed_time2 (){ feed_time2_hour =EEPROM.read(2); if (feed_time2_hour> 23) feed_time2_hour =0; feed_time2_min =EEPROM.read(3); if (feed_time2_min> 59) feed_time2_min =0;}//=====================================================// Reads portion set value from EEPROMvoid get_portion (){ portion =EEPROM.read(6);}//=====================================================// Reads boolean value of whether or not feedings have occured from EEPROMvoid get_completed_feedings(){ feeding1_complete =EEPROM.read(4); feeding2_complete =EEPROM.read(5);}//=====================================================/* Checks to see if the hall sensor has failed to read a magnet and blinks the red LED*/void check_hall_sensor () { if (hall_sensor_fail ==true) { if (blink_state ==0) { digitalWrite(HALL_LED_PIN, HIGH); } else { digitalWrite(HALL_LED_PIN, LOW); } blinkFunction(); } else { digitalWrite(HALL_LED_PIN, LOW); hall_sensor_fail =false; }}//=====================================================// Checks if you push the manual feed buttonvoid manual_feed_check () { if (manualFeed ==true) { lcd.clear(); lcd.setCursor(0, 0); lcd.print(" Manual Feeding"); startFeeding(); manualFeed =false; }}//=====================================================// checks to see if RTC is runningvoid check_rtc () { if (!rtc.isrunning()) { led_blink(); }}//=====================================================/* Blinks the red led when RTC has failed. Note:the led will be blinking at a different rate than when the hall sensor fails*/void led_blink(){ unsigned long led_currentMillis =millis(); if (led_currentMillis - led_previousMillis>=interval_delay) { led_previousMillis =led_currentMillis; if (ledState ==LOW) { ledState =HIGH; } else { ledState =LOW; } digitalWrite(HALL_LED_PIN, ledState); }}//=====================================================// Creates the blinking effect when changing valuesvoid blinkFunction(){ blink_currentMillis =millis(); if (blink_currentMillis - blink_previousMillis> blink_interval) { blink_previousMillis =blink_currentMillis; blink_state =!blink_state; }}//=====================================================
Link to Code on my Github
https://github.com/russo08/Pet-feeder/blob/main/feeder_final.ino

Kundenspezifische Teile und Gehäuse

Fusion 360 and STL files on my Github
Here are all the fusion 360 files in case you want to customize them for different component sizes. I have also provided the STL files. The only model not on there is the tube for the hall sensor. That should be pretty easy to model and print.https://github.com/russo08/Pet-feeder.git

Schaltpläne

This is the circuit schematic. You can change it up if you need to. If you do, just remember to make the same adjustments in the code.

Herstellungsprozess

  1. Endbearbeitung von 3D-gedruckten Teilen mit… Buntstiften?
  2. Linienverfolgungssensor mit RPi
  3. Umgebungssensor-API mit einem RPi
  4. Portenta- und Thermoelement-Sensor (mit MAX6675)
  5. Bessere Qualitätskontrolle mit 3D-gedruckten Teilen
  6. Schnallen Sie sich an mit funktionalen 3D-gedruckten Teilen!
  7. Neue Vorstellung des Go-Karts mit 3D-gedruckten Teilen
  8. Webinar:Starke 3D-Druckteile mit Eiger drucken
  9. 3D gedruckte Extremdrohnen
  10. Das Rennen ins Ziel mit 3D-gedruckten Formel-SAE-Fahrzeugteilen