Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Voederbak voor huisdieren met 3D-geprinte onderdelen

Componenten en benodigdheden

Arduino Nano R3
× 1
DS 1307 real-time klokmodule
Je kunt elk merk RTC gebruiken, ik weet zeker dat er goedkopere opties zijn
× 1
LM-317 Spanningsregelaarmodule
× 1
Continu draaiende servo
× 1
Graandispenser
× 1
8 mm magneten
× 6
Hallsensor (unipolair)
Zorg ervoor dat de sensor die u krijgt UNIPOLAR is, zodat u de omgekeerde polariteit van de magneet niet nodig hebt reset de sensoruitgang
× 1
Adafruit RGB-achtergrondverlichting LCD - 16x2
× 1
I2C LCD-rugzak
Als je wilt, kun je het LCD-scherm kopen met de rugzak er al aan
× 1
5 mm LED:rood
× 1
5 mm LED:groen
× 1
Drukknop, tijdelijk
× 5
Vrouwelijke DC power jack-adapter
× 1
9-12 volt muurwrat
× 1
Weerstand 10k ohm
Voor de halsensor. Verbinding maken tussen Vcc- en signaalpinnen
× 1
Weerstand 330 ohm
Voor LED's. Je kunt een hogere weerstand gebruiken als je ze niet zo helder wilt hebben
× 2

Benodigde gereedschappen en machines

3D-printer (algemeen)
Boormachine / stuurprogramma, draadloos
Cirkelzaag

Over dit project

Het verhaal achter de voerbak

Ik speel al een tijdje met microcontrollers en wilde proberen om af te wijken van tutorials. Vóór Covid-19 had ik niet echt een vast schema en maakte ik behoorlijk lange uren. Het voedingsschema van mijn hond begon er echt onder te lijden en leidde tot wat zichtbaar ongemak. Mijn gebied is ook gevoelig voor overstromingen tijdens het orkaanseizoen. Helaas waren er een paar gevallen waarin ik niet thuis kon komen om mijn oude meisje te voeden. Ik moest een oplossing vinden, zodat mijn hond geen honger zou lijden als ik niet thuis zou kunnen komen. In plaats van er een te kopen voor $ 30- $ 40, waarom zou je er geen bouwen voor $ 100 +? Grapje.

De voeder!

Mijn hondenvoerbak gebruikt een Arduino-microcontroller. Er waren een paar belangrijke functies die ik nodig had die de meeste andere versies van hondenvoeders niet hadden. Namelijk een oplossing voor het herstellen van voeding bij stroomuitval en het aanpakken van het probleem dat voedsel vast komt te zitten in het uitgiftemechanisme. Mijn omgeving heeft ook last van willekeurige stroomuitval. De stroomonderbrekingen duren meestal nooit erg lang, dus ik zag geen noodzaak voor stroomredundantie. Ik wilde ook iets dat gemakkelijk uit elkaar te halen en schoon te maken was. Wees voorzichtig bij het wassen van de 3D-geprinte onderdelen, u kunt warm water gebruiken, GEEN heet water, tenzij u van plan bent te printen met ABS of PET-G.

De volledige lijst met functies is als volgt:

  • Twee voedingen per dag
  • Nauwkeurige tijdwaarneming met realtime klok
  • Handmatige tijdverandering van realtime klok
  • Handmatige invoeroptie
  • LED-indicatie van hall-sensor en realtime klokstoring
  • Overzicht van voertijden, huidige tijd en voltooide voerbeurten op het hoofdscherm
  • Eenvoudig te navigeren menu
  • Voeding stroomuitval hervat (wordt gevoed wanneer de stroom weer wordt ingeschakeld)
  • Voedingstijden en aanvullingen veilig opgeslagen in EEPROM
  • Servo "schudt" in het geval dat voedsel vast komt te zitten tijdens het uitdelen

Demo

Binnenkort demovideo!

Wat heb je nog meer nodig?

  • 4x M3-0,5 x 16 mm schroeven (encoderwiel)
  • 4x M3-0,5 x 10 mm schroeven (servobeugel)
  • 12x M3 zeskantmoeren
  • 4x M3 borgmoeren
  • 16x 1-1/2 inch (38 mm) multifunctionele houtschroeven
  • Houtlijm
  • 6x 0,315 x 0,118 inch (8 x 3 mm) magneten
  • 1-1 / 2 x 1-1/2 inch (3,8 x 3,8 cm) hout voor poten en servobevestiging
  • 1/2 x 6 in (1,27 x 15,24 cm) hout voor rug en basis

De 3D-geprinte onderdelen

Ik heb onlangs een 3D-printer gekocht en dacht:wat is een betere manier om het te leren en te gebruiken dan aangepaste onderdelen voor mijn voerbak voor huisdieren af ​​te drukken. Alles geprint is PLA+ en is geprint met een Ender 3 Pro met Cura als slicer. De STL's van alle onderdelen zijn te vinden op de Github projectpagina. Link hieronder. Lees het README-bestand voor afdrukinstructies en slicer-instellingen.

De behuizing

De behuizing is ontworpen met gemak en eenvoud in het achterhoofd. Geen schroeven of moeren nodig. Klap de componenten eenvoudig in en uit. Elke inzet heeft 4 lipjes die de componenten op hun plaats houden.

Hoewel ik aanvankelijk de sleuf op het LCD-scherm verknoeide, ging ik terug en repareerde het model in Fusion 360. Ik was gewoon te lui om terug te gaan en het opnieuw af te drukken. Ik gebruikte wat extra M3 0,5 x 6 mm schroeven die ik had liggen om het vast te zetten. Er zijn vier afstandhouders op elke hoek van de LCD-sleuf met gaten erin, zodat u het scherm indien nodig kunt vastzetten. Helaas heb ik nooit foto's gemaakt van het deksel van de behuizing voordat ik alles erin had gezet.

De encoderwielbevestiging

Het wiel-encoderwiel heeft twee doelen:

  • Voorziet de Arduino van positiefeedback van de servo
  • Bevestigt de rubberen peddel aan de servo

Eén voerportie is gelijk aan 1/6e (60 graden) draai van het wiel. Gebruik een voerweegschaal om de hoeveelheid voer die uw huisdier per voeding krijgt af te meten en pas vervolgens het portienummer aan totdat u een bereik krijgt dat aan die hoeveelheid voldoet. Ik geloof dat één voeding voor mij ongeveer 173 gram voedsel was. Een portiegrootte van 17 gaf me een bereik van 170-177 gram per voeding. Het hangt allemaal af van de grootte van je brokken. Zorg ervoor dat de hoorn tussen de 8 M3 zeskantmoeren zit.

De servobeugel en hall-sensorbevestiging

Deze aangepaste servobeugel houdt ook de hall-sensor vast en monteert de servo op een stuk hout van 1-1 / 2 x 1-1 / 2 inch (3,8 x 3,8 cm). De lengte van het hout hangt af van waar de servo zit (daarover later meer). Er is genoeg ruimte voor fouten met de houder, dus maak je geen zorgen om de perfecte lengte te krijgen.

De trechter, de voedseltrechter en de glijrail

Dit vormt het voedselbezorgsysteem. Het voedsel komt uit de dispenser door de trechter en op de trechter en in de voerbak. Helaas heb ik geen foto's van de chuterail gemaakt voordat ik deze monteerde.

Het Kader

*Disclaimer* Ik heb geen foto's gemaakt van elke stap van het montageproces. Sommige van deze foto's hebben stappen overgeslagen, maar ik zal je nog steeds stap voor stap meenemen voor de montage van het frame.

Zorg ervoor dat u alle schroeven die u gebruikt opnieuw boort. U wilt het hout splijten!

Dit is de graandispenser die ik van Amazon heb gekocht. Er zijn er die meerdere dispensers hebben als je meerdere huisdieren hebt en meerdere feeders nodig hebt, ik had er maar één nodig. Het merk is Honey Can Do, maar ik weet zeker dat elk merk zal werken.

Het eerste waar ik mee begon, was het verwijderen van de knop van de stang die verbonden was met het schoepenwiel op de dispenser. Ik gebruikte een handzaag om de knop te verwijderen. U kunt elektrisch gereedschap gebruiken als u er een heeft. Snijd de staaf niet verder naar beneden waar het zilveren deel eindigt. Snijd recht aan de basis van de knop.

Nadat u de knop hebt afgezaagd, verwijdert u het resterende materiaal door de 3 steunen te snijden die u op de laatste afbeelding hierboven ziet. Dit duurde vrij lang. Ik kan me voorstellen dat het sneller gaat als je het juiste elektrische gereedschap hebt. Zodra je die drie steunen hebt verwijderd, moet het resterende stuk dat op de stang zelf is achtergebleven, er met een beetje elleboogvet af komen. U zult het deel van de staaf dat zich het dichtst bij de knop bevindt, moeten schuren, zodat het mooi in het encoderwiel past.

Vervolgens beginnen we met het bouwen van de basis van het frame. Ik nam het hout van 1/2 x 6 inch (1,27 x 15,24 cm) en sneed ze in twee stukken van 20,32 cm van 8 inch. Dit vormt de basis en de achterkant van het frame van de feeder. Breng wat houtlijm aan en gebruik 2 van de multifunctionele spijkers om ze in een L-vorm te verbinden. U moet een paar haakse steunen toevoegen om de verbinding tussen het achterpaneel en het onderpaneel te versterken. Gebruik 4 multifunctionele schroeven en wat houtlijm om ze aan zowel de achter- als onderpanelen te bevestigen. Ik heb geen foto van deze stap, maar je kunt ze verderop in foto's zien.

Vanaf hier moet u de dispenserstandaard afsnijden tot een hoogte van ongeveer 11,43 cm. Het hoeft niet perfect te zijn. Probeer het zo dichtbij mogelijk te krijgen. De trechter zorgt voor wat speelruimte. Zodra u de standaard op maat hebt gezaagd, plaatst u deze tegen de achterkant en zorgt u ervoor dat deze plat op de basis staat. Zodra u het op zijn plaats hebt, gebruikt u een potlood of pen om het midden te markeren waar het uitgifte-uiteinde van de container zal zijn. U moet dan een gat van 5,08 cm (2 inch) door het basispaneel boren. Het is van cruciaal belang dat u met deze twee keer meet en één keer snijdt. Dat zal het gat zijn dat op de bovenstaande afbeelding te zien is.

Nadat u het gat in het basispaneel heeft geboord, zijn we klaar om de dispenserstandaard aan het achterpaneel te bevestigen. Wat u wilt doen, is de standaard tegen het achterpaneel plaatsen (getoond in de eerste afbeelding hieronder). Er zijn twee vakjes onder de ring van de dispenserstandaard. Dit is waar u de gaten wilt hebben (zie onderstaande afbeelding). Gebruik een potlood of pen om de hoogte van de twee gaten op het achterpaneel te markeren. Je wilt ze zo dicht mogelijk bij het midden van de dispenserstandaard. Er zijn twee schroeven die de bovenste ring van de standaard verbinden met het onderste deel dat u afsnijdt. Pas op dat u deze niet raakt tijdens het boren. Nogmaals, denk eraan om twee keer te meten en één keer te boren. Of twee keer, in dit geval.

Nu we de gaten hebben geboord, kunnen we de standaard aan het achterpaneel bevestigen met behulp van de 5/16 inch zeskantbouten, 5/16 inch zeskantmoeren en 5/16 inch ringen. U wilt doorgaan en de bouten doordrukken en ervoor zorgen dat u ringen aan het zeskantige uiteinde van de bouten plaatst voordat u ze doordringt. Nadat ze aan de andere kant naar buiten zijn gekomen, plaatst u de andere set ringen aan de kant met schroefdraad en begint u vervolgens de zeskantmoeren met de hand vast te draaien. Dit wordt een beetje lastig. Nadat u de moeren met de hand hebt aangedraaid, moet u een dopsleutel gebruiken om de moer vast te houden en ze verder vast te draaien. Slechts ongeveer 1/4 slag of zo. Pas op dat u niet te strak aandraait.

Nu de standaard veilig is vastgezet, kunnen we nu het stuk hout van 1/2 x 1/2 inch toevoegen waar de servo op gaat zitten. De lengte hiervan hangt af van waar je servo zal zitten. Ga je gang en monteer het invoermechanisme door de servo aan de hoorn op het encoderwiel en het encoderwiel aan de rubberen peddel in de plastic container te bevestigen. Plaats de container in de bovenste ring en meet waar de servo vanaf het basispaneel zit. Maak je geen zorgen dat het perfect is. De servobeugel zorgt voor nogal wat bewegingsruimte. Gebruik houtlijm en een enkele universele schroef om de houten standaard vast te zetten.

De volgende stap is het bevestigen van de poten aan het basispaneel van de feeder. De lengte van de poten hangt af van hoe hoog de voerbak van uw huisdier is. Mijn hond heeft haar voerbak op een verhoogde standaard; daarom had ik mijn feeder nodig om vrij hoog te zitten. Gebruik 4 van de multifunctionele schroeven en wat houtlijm om ze op hun plaats te bevestigen. Ik raad aan om een ​​dwarsbalk tussen de twee voor- en twee achterpoten te plaatsen en een andere dwarsbalk tussen de dwarsbalken, zoals hieronder weergegeven voor extra stabiliteit. Gebruik in totaal 6 multifunctionele schroeven en wat houtlijm om de stukken aan de poten te bevestigen.

De volgende stappen zijn:

  • steek de trechter in het gat dat we in het basispaneel hebben geboord
  • bevestig de servo aan de servobeugel
  • bevestig de beugel aan de houten standaard

Bevestig de servo aan de beugel met behulp van de 4 M3 x 10 mm schroeven en 4 van de M3 zeskantmoeren. Zodra de servo is vastgezet, kunnen we de beugel op de houten servostandaard bevestigen. Gebruik twee van de multifunctionele schroeven om de beugel lichtjes op de houten standaard te bevestigen. Draai niet te vast, anders beschadigt u de beugel. Zorg ervoor dat u de stappen in die volgorde uitvoert. De trechter zal de servo een beetje omhoog brengen en hij past mooi strak tegen het uiteinde van de plastic container, dus het is onmogelijk om aan te trekken als de plastic container al in de bovenste ringstandaard zit.

De laatste stappen zijn om de inschuifbeugel van de glijbaan en de glijbaan zelf te bevestigen. U wilt de beugel iets achter het gat in het basispaneel plaatsen. Je wilt het zo ver naar voren als je kunt krijgen, zodat de dia het frame van de feeder vrijmaakt. Gebruik twee van de multifunctionele schroeven om de beugel aan de onderkant van het basispaneel van het frame te bevestigen. Het is het beste om dit te doen met de schuif in de beugel, omdat de beugel wat flex heeft en je een behoorlijk stevige pasvorm tussen de slede en de beugel wilt.

De elektronica

Helaas heb ik nooit foto's gemaakt van het soldeerproces. Veel is er echter niet aan de hand. Soldeer gewoon elk onderdeel aan de bijbehorende pinnen en je zou goed moeten zijn om te gaan. Als u in plaats daarvan pin-headers wilt gebruiken, kunt u dat ook op die manier doen. Er is voldoende ruimte onder en boven het Arduino-slot om de pinnen en connectoren mogelijk te maken. Ik raad zeker aan om alles aan elkaar te solderen voordat je alle componenten in hun respectievelijke slots plaatst.

Ik heb mijn Arduino van stroom voorzien via de niet-gereguleerde externe voedingspin (pin 30). Hiervoor is een ingangsspanning tussen de 7-20 volt nodig omdat deze spanning via de Arduino's onboard regelaar wordt gevoerd. Als je hem via USB wilt voeden, moet je er alleen voor zorgen dat je hem voedt met 5 Volt, NIET de 7-20 Volt.

Zorg ervoor dat u de weerstand van 10k Ohm tussen de Vcc- en signaalpinnen op de hall-sensor soldeert. Anders krijg je geen lezing. Vergeet ook niet om alle componenten op de common ground aan te sluiten. Ik maakte de fout om een ​​van de gronden te missen en mijn systeem zou een tijdje werken, maar de hall-sensor zou uiteindelijk beginnen te falen. Dat was echt een goede dag voor mijn hond.

Ik heb uiteindelijk aangepaste connectoren gemaakt voor de hall-sensor- en servo-aansluitingen. Ik heb de draden gesoldeerd aan mannelijke pin-headers. Deze hangen uit de onderkant van de behuizing. Voor de hall-sensor heb ik een aangepaste vrouwelijke adapter gemaakt door een paar Dupont-connectordraden die ik had liggen te knippen, strippen en solderen.

Voor de Vcc en grondrail sneed ik het stroomrailgedeelte af van een extra perma-proto breadboard dat ik had liggen. Iets soortgelijks dat je in de buurt hebt, zal werken. Controleer gewoon uw verbindingen voordat u de rail in de sleuf plaatst. Dit is het moeilijkste om eruit te komen als het er eenmaal in zit. Dat heb ik ook op de harde manier geleerd.

Dat is het! Ik hoop dat jullie net zoveel plezier beleven aan het bouwen van dit als ik. In het begin ziet het er uitdagend uit, maar hoe meer je erin verdiept, hoe makkelijker het wordt. Laat het me weten als je ergens vragen over hebt. Veel plezier met knutselen!

Code

  • Feedercode
FeedercodeC/C++
// Definitieve versie voor de voerbak/* Kenmerken:- Makkelijk te navigeren menu - Overzicht van voertijden, huidige tijd, voereinden en voerportie op het hoofdscherm - Regelbare porties met behulp van een halsensor voor feedback - Nauwkeurig tijdwaarneming met DS1307-chip - Kan de ingestelde tijd handmatig wijzigen in de DS1307-chip - Twee voedingen per dag - Handmatige voeroptie - Voerherstart in geval van stroomuitval - LED-indicatie van halsensor en realtime klok - Voertijden en aanvullingen veilig opslaan in EEPROM - Servo "schudt" in het geval dat voedsel vastloopt*/#include #include #include #include #include # include #include // Creëert servo-object om uw servoServo myservo te besturen;// Wijs al mijn invoer- en I/O-pinnen toe#define ENTER_BUTTON_PIN 11#define UP_BUTTON_PIN 10#define DOWN_BUTTON_PIN 9#define BACK_BUTTON_P 8#define POWER_LED_PIN 5#define MANUAL_BUTTON_PIN A1#define hallPin 2#define HALL_LE D_PIN 7#define SERVO_PIN 6// Definiëren van alle knoppen, werkt met de JC_Button-bibliotheekButton enterBtn (ENTER_BUTTON_PIN);Button upBtn (UP_BUTTON_PIN);Button downBtn (DOWN_BUTTON_PIN);Button_BUTTON_PIN);Button_BUTTON_PIN);Button_BUTTON_PIN);Button_BUTTON_PIN);Button_BUTTON_PIN); LCD I2C en RTCLiquidCrystal_I2C lcd(0x27, 16, 2);RTC_DS1307 rtc;//Variabelen gebruikt in de codeunsigned long hallSensorTime;unsigned long rotationTime =400;unsigned long led_previousMillis =0;const long interval_delay =1000;unsigned long delay_interval =2000; int ledState =LAAG;boolean manualFeed =false;boolean hall_sensor_fail =false;unsigned long blink_previousMillis =0;unsigned long blink_currentMillis =0;unsigned long blink_interval =500;unsigned long delay_currentMillis =0;unsigned long delay_previousMillis =0;boole; int count;booleaanse voeding1_complete =false;booleaanse voeding2_complete =false;booleaanse voeding1_trigger =false;booleaanse voeding2_trigger =false;booleaanse servoOn =tru e;//Hall-sensor interruptvolatile boolean hallSensorActivated =false;volatile int isr_count =1;void hallActiveISR(){ hallSensorActivated =true; digitalWrite (HALL_LED_PIN, HOOG); isr_count =isr_count + 1;}/* Ik gebruik hier opsommingen om beter bij te houden op welke knop wordt gedrukt, in plaats van elke knop op een interger-waarde te zetten.*/enum { btnENTER, btnUP, btnDOWN, btnBACK,}; /* Staten van de staatsmachine. Hetzelfde hier met het enum-type. Het maakt het gemakkelijker om bij te houden in welk menu u zich bevindt of waarnaar u wilt gaan in plaats van elk menu een gehele waarde*/enum STATES { MAIN, MENU_EDIT_FEED1, MENU_EDIT_FEED2, MENU_EDIT_TIME, MENU_EDIT_PORTION, EDIT_FEED1_HOUR, EDIT_FEED1_HOUR, EDIT_FEED1_MIN2 EDIT_FEED_FEED, , EDIT_MIN, EDIT_PORTION};// Bevat de status van de status machineSTATES status;//Gebruikersinvoervariabelenint Hour;int Minuut;int portie;int feed_time1_hour;int feed_time1_min;int feed_time2_hour;int feed_time2_min;int userInput;// Speciaal teken check markbyte check_Char [8] ={ B00000, B00000, B00001, B00011, B10110, B11100, B11000, B00000};//======================De Setup===========================ongeldige setup() { Wire.begin(); Serieel.begin(9600); lcd.init(); lcd.achtergrondverlichting(); lcd.createChar (0, check_Char); if (!rtc.begin()) { Serial.println("Kon RTC niet vinden!"); } // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // De knoppen enterBtn.begin(); upBtn.begin(); downBtn.begin(); backBtn.begin(); manualFeedBtn.begin(); //Initiële status van State instellen Machinestatus =MAIN; // In- en uitgangen pinMode instellen (POWER_LED_PIN, OUTPUT); pinMode (HALL_LED_PIN, UITGANG); pinMode(hallPin, INPUT); /* Interrupt toevoegen aan de pin die is verbonden met de hall-sensor. De hall-sensor die ik heb gebruikt, is ingesteld op HOOG en wordt LAAG wanneer hij een magneet tegenkomt. Daarom is het ingesteld op FALLING */ attachInterrupt (digitalPinToInterrupt(hallPin), hallActiveISR, FALLING); // standaardstatus van LED's digitalWrite (POWER_LED_PIN, HIGH); digitalWrite (HALL_LED_PIN, LAAG); /* Deze functies halen bij het opstarten de opgeslagen voertijd, voltooide voerbeurt en portiegrootte uit EEPROM. Ik deed dit omdat ik hier waar ik woon willekeurige stroomstoringen krijg. */ get_feed_time1(); get_feed_time2(); get_completed_feedings(); get_portion();}//======================De lus===========================void loop() { changing_states(); check_buttons(); check_feedtime (); check_rtc(); manual_feed_check ();}//===============De functies =======================/* Gebruik de JC_Button Library om continu te controleren of er op een knop is gedrukt. Afhankelijk van de knop die wordt ingedrukt, stelt het de variabele userInput in die moet worden gebruikt in de functie menu_transitions*/void check_buttons () { enterBtn.read(); upBtn.lezen(); downBtn.lezen(); backBtn.lezen(); manualFeedBtn.read(); if (enterBtn.wasPressed()) { Serial.println ("Je hebt op Enter gedrukt!"); gebruikersinvoer =btnENTER; menu_transitions (gebruikersinvoer); } if (upBtn.wasPressed()) { Serial.println ("Je hebt gedrukt!"); gebruikersinvoer =btnUP; menu_transitions (gebruikersinvoer); } if (downBtn.wasPressed()) { Serial.println ("Je hebt ingedrukt!"); gebruikersinvoer =btnDOWN; menu_transitions (gebruikersinvoer); } if (backBtn.wasPressed()) { Serial.println ("Je hebt terug gedrukt!"); gebruikersinvoer =btnBACK; menu_transitions (gebruikersinvoer); } if (manualFeedBtn.wasPressed()) { Serial.println ("U voert handmatig in!"); handmatige invoer =waar; }}//=====================================================/* Deze functie bepaalt wat er wordt weergegeven, afhankelijk van in welk menu of "status" u zich bevindt. Elk menu heeft een functie die het respectievelijke menu weergeeft*/void changing_states() { switch (state) { hoofdlettergebruik:display_current_time(); display_feeding_times(); display_portion(); pauze; geval MENU_EDIT_FEED1:display_set_feed_time1_menu(); pauze; geval MENU_EDIT_FEED2:display_set_feed_time2_menu(); pauze; geval MENU_EDIT_TIME:display_set_time_menu(); pauze; case MENU_EDIT_PORTION:display_set_portion_menu (); pauze; geval EDIT_FEED1_HOUR:set_feed_time1(); pauze; geval EDIT_FEED1_MIN:set_feed_time1(); pauze; geval EDIT_FEED2_HOUR:set_feed_time2(); pauze; geval EDIT_FEED2_MIN:set_feed_time2(); pauze; geval EDIT_HOUR:set_the_time(); pauze; geval EDIT_MIN:set_the_time(); pauze; geval EDIT_PORTION:set_the_portion(); pauze; }}//=====================================================/* Dit is het overgangsgedeelte van de staatsmachine. Hiermee kunt u van het ene menu naar het andere gaan en waarden wijzigen*/void menu_transitions(int input) { switch (state) { case MAIN:if (input ==btnENTER) { lcd.clear(); staat =MENU_EDIT_FEED1; } if (invoer ==btnBACK) { hall_sensor_fail =false; } pauze; //---------------------------------------------------- case MENU_EDIT_FEED1:if (input ==btnBACK) { lcd.clear(); state =MAIN; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_FEED1_HOUR; } else if (input ==btnDOWN) { lcd.clear(); state =MENU_EDIT_FEED2; } break; //---------------------------------------------------- case EDIT_FEED1_HOUR:// Need this to prevent servo going off while setting time servoOn =false; if (input ==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; } break; //---------------------------------------------------- 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*"); vertraging (1000); lcd.wissen(); servoOn =true; write_feeding_time1 (); state =MAIN; } break; //---------------------------------------------------- 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; } break; //---------------------------------------------------- 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; } break; //---------------------------------------------------- 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*"); vertraging (1000); lcd.wissen(); servoOn =true; write_feeding_time2 (); state =MAIN; } break; //---------------------------------------------------- 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; } break; //---------------------------------------------------- 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; } break; //---------------------------------------------------- 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*"); vertraging (1000); lcd.wissen(); rtc.adjust(DateTime(0, 0, 0, Hour, Minute, 0)); state =MAIN; } break; //---------------------------------------------------- case MENU_EDIT_PORTION:if (input ==btnUP) { lcd.clear(); state =MENU_EDIT_TIME; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_PORTION; } break; //---------------------------------------------------- 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*"); vertraging (1000); lcd.wissen(); write_portion(); state =MAIN; } break; }}//=====================================================// 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); pauze; //---------------------------------------------------- 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(" "); } break; } 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); pauze; //---------------------------------------------------- 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(" "); } break; } 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); pauze; //---------------------------------------------------- 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(" "); } break; } 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.wissen(); 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); vertraging (30); myservo.write(93); vertraging (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

Aangepaste onderdelen en behuizingen

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

Schema's

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.

Productieproces

  1. 3D-geprinte onderdelen afwerken met… kleurpotloden?
  2. Lijnvolgsensor met RPi
  3. Milieusensor-API met een RPi
  4. Portenta- en thermokoppelsensor (met MAX6675)
  5. Betere kwaliteitscontrole met 3D-geprinte onderdelen
  6. Blijf jezelf vast met functionele 3D-geprinte onderdelen!
  7. De Go Kart opnieuw vormgeven met 3D-geprinte onderdelen
  8. Webinar:sterke 3D-geprinte onderdelen printen met Eiger
  9. 3D-geprinte extreme drones
  10. De race naar de finish met 3D-geprinte Formula SAE-voertuigonderdelen
  11. Versterking van 3D-geprinte onderdelen met efficiënte glasvezelroutering:deel 1