Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

Pengumpan Hewan Peliharaan dengan Bagian Cetakan 3D

Komponen dan persediaan

Arduino Nano R3
× 1
DS 1307 modul jam waktu nyata
Anda dapat menggunakan merek RTC apa pun, saya yakin ada opsi yang lebih murah di luar sana
× 1
Modul pengatur tegangan LM-317
× 1
Servo rotasi terus menerus
× 1
Dispenser Sereal
× 1
magnet 8mm
× 6
Sensor hall (unipolar)
Pastikan sensor yang Anda dapatkan adalah UNIPOLAR sehingga Anda tidak memerlukan polaritas terbalik magnet untuk setel ulang keluaran sensor
× 1
Adafruit RGB Backlight LCD - 16x2
× 1
Ransel LCD I2C
Jika mau, Anda dapat membeli layar LCD dengan ransel yang sudah terpasang
× 1
LED 5 mm:Merah
× 1
LED 5 mm:Hijau
× 1
Sakelar Tombol Tekan, Sesaat
× 5
Adaptor colokan listrik DC wanita
× 1
Kutil dinding 9-12 Volt
× 1
Resistor 10k ohm
Untuk sensor aula. Hubungkan antara Vcc dan pin Sinyal
× 1
Resistor 330 ohm
Untuk LED. Anda dapat menggunakan resistensi yang lebih tinggi jika Anda tidak menginginkannya begitu terang
× 2

Alat dan mesin yang diperlukan

Printer 3D (generik)
Bor / Driver, Tanpa Kabel
Gergaji Bulat

Tentang proyek ini

Kisah di balik pengumpan hewan peliharaan

Saya telah bermain-main dengan mikrokontroler untuk sementara waktu dan ingin mencoba keluar dari tutorial. Sebelum Covid-19, saya tidak memiliki jadwal yang pasti dan jam kerja yang cukup panjang. Jadwal makan anjing saya benar-benar mulai menderita dan menyebabkan ketidaknyamanan yang terlihat. Daerah saya juga rawan banjir saat musim badai. Sayangnya, ada beberapa kasus di mana saya tidak bisa kembali ke rumah untuk memberi makan gadis tua saya. Saya perlu menemukan solusi sehingga, jika saya tidak dapat pulang, anjing saya tidak akan kelaparan. Alih-alih membeli satu seharga $30-$40, mengapa tidak membuatnya seharga $100+? Hanya bercanda.

Pengumpan!

Pengumpan anjing saya menggunakan mikrokontroler Arduino. Ada beberapa fitur utama yang saya butuhkan yang tidak dimiliki oleh kebanyakan versi pengumpan anjing lainnya. Yaitu, solusi untuk pemberian makan pemulihan pemadaman listrik dan mengatasi masalah makanan yang terjebak dalam mekanisme pengeluaran. Daerah saya juga mengalami pemadaman listrik secara acak. Pemadaman biasanya tidak berlangsung lama, jadi saya tidak melihat perlunya redundansi daya. Saya juga menginginkan sesuatu yang mudah dibongkar dan dibersihkan. Hati-hati saat mencuci bagian yang dicetak 3D, Anda dapat menggunakan air hangat, BUKAN air panas kecuali jika Anda berencana untuk mencetak dengan ABS atau PET-G.

Daftar fitur lengkapnya adalah sebagai berikut:

  • Dua kali menyusui per hari
  • Ketepatan waktu yang akurat dengan jam waktu nyata
  • Perubahan waktu manual dari jam waktu nyata
  • Opsi makan manual
  • Indikasi LED dari sensor hall dan kegagalan jam real-time
  • Ringkasan waktu pengumpanan, waktu saat ini, dan penyelesaian pengumpanan di layar utama
  • Menu navigasi yang mudah
  • Resume pengumpanan listrik padam (akan mengalir saat listrik hidup kembali)
  • Waktu dan penyelesaian pengumpanan disimpan dengan aman di EEPROM
  • Servo "bergejolak" jika ada makanan yang tersangkut saat dibagikan

Demo

Video Demo segera hadir!

Apa lagi yang Anda butuhkan?

  • Sekrup 4x M3-0,5 x 16 mm (roda encoder)
  • Sekrup 4x M3-0,5 x 10 mm (braket servo)
  • 12x mur hex M3
  • 4x mur pengunci M3
  • Sekrup kayu serbaguna 16x 1-1/2 inci (38 mm)
  • lem kayu
  • Magnet 6x 0,315 x 0,118 inci (8 x 3 mm)
  • Kayu 1-1/2 x 1-1/2 inci (3,8 x 3,8 cm) untuk kaki dan dudukan servo
  • Kayu 1/2 x 6 inci (1,27 x 15,24 cm) untuk punggung dan alas

Bagian yang dicetak 3D

Saya baru-baru ini memperoleh printer 3D dan berpikir, cara apa yang lebih baik untuk mempelajari dan menggunakannya selain mencetak suku cadang khusus untuk pengumpan hewan peliharaan saya. Semua yang dicetak adalah PLA+ dan dicetak menggunakan Ender 3 Pro menggunakan Cura sebagai alat pengiris. STL untuk semua bagian dapat ditemukan di halaman proyek Github. Tautan di bawah. Baca file README untuk instruksi pencetakan dan pengaturan pemotong.

Perumahan

Perumahan dirancang dengan kenyamanan dan kesederhanaan dalam pikiran. Tidak ada sekrup atau mur yang dibutuhkan. Cukup masukkan dan keluarkan komponen. Setiap sisipan memiliki 4 tab yang menahan komponen di tempatnya.

Meskipun awalnya saya mengacaukan slot layar LCD, saya kembali dan memperbaiki model di Fusion 360. Saya terlalu malas untuk kembali dan mencetak ulang. Saya menggunakan beberapa sekrup ekstra M3 0,5 x 6mm yang saya miliki untuk mengamankannya. Terdapat empat spacer di setiap sudut slot LCD dengan lubang di dalamnya sehingga Anda dapat mengamankan layar jika diperlukan. Sayangnya, saya tidak pernah memotret penutup enklosur sebelum memasukkan semuanya.

Lampiran roda encoder

Roda encoder roda memiliki dua tujuan:

  • Memberikan umpan balik posisi dari servo kepada Arduino
  • Pasang dayung karet ke servo

Satu porsi makan sama dengan 1/6 (60 derajat) putaran roda. Gunakan timbangan makanan untuk mengukur jumlah makanan yang diterima hewan peliharaan Anda per pemberian makan dan kemudian sesuaikan jumlah porsinya hingga Anda mendapatkan kisaran yang memenuhi jumlah tersebut. Saya percaya satu kali makan untuk saya adalah sekitar 173 gram makanan. Ukuran porsi 17 memberi saya kisaran 170-177 gram per makan. Itu semua tergantung pada ukuran kibble Anda. Pastikan klakson berada di antara 8 mur heksagonal M3.

Braket servo dan dudukan sensor hall

Braket servo khusus ini juga menahan sensor hall dan memasang servo ke sepotong kayu berukuran 1-1/2 x 1-1/2 inci (3,8 x 3,8 cm). Panjang kayu akan tergantung di mana servo duduk (lebih lanjut nanti). Ada banyak ruang untuk kesalahan dengan mount jadi jangan terlalu khawatir untuk mendapatkan panjang yang sempurna.

Corong, saluran makanan, dan rel saluran

Ini membentuk sistem pengiriman makanan. Makanan turun dari dispenser melalui corong dan ke saluran dan ke dalam mangkuk makanan. Sayangnya, saya tidak memotret rel parasut sebelum memasangnya.

Bingkai

*Penafian* Saya tidak memotret setiap langkah proses perakitan. Beberapa dari gambar ini akan melewatkan langkah-langkahnya, tetapi saya masih akan membawa Anda langkah demi langkah untuk perakitan bingkai.

Pastikan lubang bor untuk semua sekrup yang Anda gunakan. Anda harus membelah kayu!

Ini adalah dispenser sereal yang saya beli dari Amazon. Ada beberapa yang memiliki banyak dispenser jika Anda memiliki banyak hewan peliharaan dan membutuhkan banyak tempat makan, saya hanya membutuhkan satu. Mereknya adalah Honey Can Do, tapi saya yakin merek apa pun bisa digunakan.

Hal pertama yang saya mulai adalah melepas kenop dari batang yang terhubung ke roda dayung di dispenser. Saya menggunakan gergaji tangan untuk melepas kenop. Anda dapat menggunakan alat listrik jika kebetulan memilikinya. Jangan memotong batang lebih jauh ke bawah di mana bagian perak berakhir. Potong tepat di dasar kenop.

Setelah Anda melihat kenop, keluarkan bahan yang tersisa dengan memotong 3 penyangga yang terlihat pada gambar terakhir di atas. Ini memakan waktu cukup lama. Saya membayangkan akan lebih cepat jika Anda memiliki alat listrik yang tepat. Setelah Anda melepaskan ketiga penyangga itu, sisa bagian yang tersisa di batang itu sendiri akan terlepas dengan sedikit minyak siku. Anda harus mengampelas bagian batang yang paling dekat dengan kenop sehingga pas dengan roda encoder.

Selanjutnya, kita mulai membangun dasar bingkai. Saya mengambil kayu berukuran 1/2 x 6 inci (1,27 x 15,24 cm) dan memotongnya menjadi dua bagian berukuran 8 inci (20,32 cm). Ini akan membentuk dasar dan bagian belakang bingkai pengumpan. Oleskan sedikit lem kayu dan gunakan 2 paku serbaguna untuk menyatukannya dalam bentuk L. Anda perlu menambahkan beberapa penyangga sudut kanan untuk memperkuat sambungan panel belakang dan panel bawah. Gunakan 4 sekrup serbaguna dan beberapa lem kayu untuk mengencangkannya ke panel belakang dan bawah. Saya tidak memiliki gambar langkah ini, tetapi Anda dapat melihatnya di gambar di bawah.

Dari sini Anda harus memotong dudukan dispenser hingga ketinggian sekitar 4,5 inci (11,43 cm). Tidak harus sempurna. Cobalah untuk mendapatkannya sedekat mungkin. Corong memungkinkan untuk beberapa ruang gerak. Setelah dudukan dipotong sesuai ukuran, letakkan di belakang dan pastikan dudukan rata di alasnya. Setelah Anda meletakkannya di posisinya, gunakan pensil atau pulpen untuk menandai bagian tengah di mana ujung wadah akan ditempatkan. Anda kemudian perlu mengebor lubang sepanjang 2 inci (5,08 cm) melalui panel dasar. Sangat penting bahwa Anda mengukur dua kali dan memotong sekali dengan yang satu ini. Itu akan menjadi lubang yang terlihat pada gambar di atas.

Setelah Anda mengebor lubang di panel dasar, kami siap memasang dudukan dispenser ke panel belakang. Yang ingin Anda lakukan adalah memasang dudukan pada panel belakang (ditunjukkan pada gambar pertama di bawah). Ada dua area cubby di bawah ring stand dispenser. Di sinilah Anda ingin membuat lubang (lihat gambar di bawah). Gunakan pensil atau pena untuk menandai ketinggian di mana kedua lubang seharusnya berada di panel belakang. Anda ingin mereka sedekat mungkin dengan bagian tengah dudukan dispenser. Ada dua sekrup yang menghubungkan cincin atas dudukan ke bagian bawah yang Anda potong. Berhati-hatilah agar tidak mengenainya saat mengebor. Sekali lagi, ingatlah untuk mengukur dua kali dan mengebor sekali. Atau dua kali, dalam hal ini.

Sekarang kita memiliki lubang yang dibor, kita dapat memasang dudukan ke panel belakang menggunakan baut segi enam 5/16 inci, mur segi enam 5/16 inci, dan ring 5/16 inci. Anda ingin melanjutkan dan mendorong baut dengan memastikan Anda menempatkan ring di ujung hex baut sebelum mendorongnya. Setelah keluar dari sisi yang lain, tempatkan set washer lainnya di sisi yang berulir dan kemudian mulai kencangkan mur hex dengan tangan. Ini akan menjadi sedikit rumit. Setelah Anda mengencangkan mur dengan tangan, Anda harus menggunakan soket untuk menahan mur dan mengencangkannya lebih jauh. Hanya sekitar 1/4 putaran atau lebih. Hati-hati jangan sampai terlalu kencang.

Sekarang setelah dudukan diamankan dengan aman, sekarang kita dapat menambahkan potongan kayu berukuran 1/2 x 1/2 inci yang akan digunakan servo. Panjang ini akan tergantung di mana servo Anda akan duduk. Silakan dan merakit mekanisme makan dengan menempelkan servo ke tanduk pada roda encoder dan roda encoder ke dayung karet di dalam wadah plastik. Atur wadah ke ring atas dan ukur di mana servo duduk dari panel dasar. Jangan khawatir tentang itu menjadi sempurna. Braket servo memungkinkan sedikit ruang gerak. Gunakan lem kayu dan satu sekrup serbaguna untuk mengencangkan dudukan kayu.

Langkah selanjutnya adalah menempelkan kaki ke panel dasar pengumpan. Panjang kaki akan tergantung pada seberapa tinggi mangkuk makanan hewan peliharaan Anda. Anjing saya meletakkan mangkuk makanannya di atas dudukan yang ditinggikan; oleh karena itu, saya membutuhkan pengumpan saya untuk duduk cukup tinggi. Gunakan 4 sekrup serbaguna dan beberapa lem kayu untuk mengencangkannya pada tempatnya. Saya merekomendasikan untuk meletakkan balok silang di antara dua kaki depan dan dua kaki belakang dan balok silang lainnya di antara balok silang seperti yang ditunjukkan di bawah ini untuk menambah stabilitas. Gunakan total 6 sekrup serbaguna dan beberapa lem kayu untuk mengencangkan potongan ke kaki.

Langkah selanjutnya adalah:

  • masukkan corong ke dalam lubang yang kami bor di panel dasar
  • pasang servo ke braket servo
  • kencangkan braket ke dudukan kayu

Pasang servo ke braket menggunakan 4 sekrup M3 x 10 mm dan 4 mur hex M3. Setelah servo diamankan, kami dapat mengencangkan braket ke dudukan servo kayu. Gunakan dua sekrup serbaguna untuk mengencangkan braket dengan ringan ke dudukan kayu. Jangan terlalu kencang atau Anda akan merusak braket. Pastikan Anda melakukan langkah-langkah dalam urutan itu. Corong akan menaikkan servo sedikit dan cukup pas dengan ujung wadah plastik sehingga tidak mungkin untuk dipasang jika wadah plastik sudah berada di dudukan cincin atas.

Langkah terakhir adalah memasang braket slide-in chute dan slide itu sendiri. Anda ingin menempatkan braket sedikit di belakang lubang di panel dasar. Anda menginginkannya sejauh mungkin sehingga slide menghapus bingkai pengumpan. Gunakan dua sekrup serbaguna untuk menahan braket ke bagian bawah panel dasar bingkai. Sebaiknya lakukan ini dengan slide di braket karena braket memiliki beberapa kelenturan dan Anda akan menginginkan pas yang cukup aman antara slide dan braket.

Elektronik

Sayangnya, saya tidak pernah memotret proses penyolderan. Tidak ada banyak untuk itu. Cukup solder setiap komponen ke pin yang sesuai dan Anda harus siap melakukannya. Jika Anda ingin menggunakan header pin, Anda juga dapat melakukannya dengan cara itu. Ada jarak yang cukup di bawah dan di atas slot Arduino untuk memungkinkan pin dan konektor. Saya sangat merekomendasikan menyolder semuanya bersama-sama sebelum mengatur semua komponen di slotnya masing-masing.

Saya memberi daya pada Arduino saya melalui pin daya eksternal yang tidak diatur (pin 30). Ini membutuhkan tegangan input antara 7-20 volt karena tegangan ini diumpankan melalui regulator onboard Arduino. Jika Anda ingin menyalakannya melalui USB, Anda hanya perlu memastikan bahwa Anda mensuplainya dengan 5 Volt, BUKAN 7-20 Volt.

Pastikan untuk menyolder resistor 10k Ohm antara Vcc dan pin Sinyal pada sensor hall. Jika tidak, Anda tidak akan mendapatkan bacaan. Juga, jangan lupa untuk menghubungkan semua komponen ke kesamaan. Saya membuat kesalahan dengan melewatkan salah satu landasan dan sistem saya akan bekerja untuk sementara waktu, tetapi sensor hall pada akhirnya akan mulai gagal. Itu adalah hari yang sangat baik untuk anjing saya.

Saya akhirnya membuat konektor khusus untuk sensor hall dan koneksi servo. Saya menyolder kabel ke header pin pria. Ini menggantung keluar dari bagian bawah kandang. Untuk sensor hall, saya membuat adaptor perempuan khusus dengan memotong, mengupas, dan menyolder beberapa kabel konektor Dupont yang saya miliki.

Untuk Vcc dan ground rail, saya memotong bagian power rail dari beberapa papan tempat memotong roti perma-proto ekstra yang saya miliki. Apa pun yang serupa yang Anda miliki di sekitar akan berfungsi. Cukup periksa kembali koneksi Anda sebelum memasang rel di slotnya. Ini adalah hal tersulit untuk keluar setelah masuk. Saya juga belajar itu dengan cara yang sulit.

Itu dia! Semoga kalian bersenang-senang membangun ini seperti yang saya lakukan. Ini terlihat menantang pada awalnya, tetapi semakin Anda masuk ke dalamnya semakin mudah. Beri tahu saya jika Anda memiliki pertanyaan tentang apa pun. Selamat mengutak-atik!

Kode

  • Kode pengumpan
Kode pengumpanC/C++
// Versi final untuk pengumpan hewan peliharaan/* Fitur:- Menu yang mudah dinavigasi - Tinjauan waktu pemberian makan, waktu saat ini, penyelesaian pemberian makan, dan porsi pemberian makan di layar utama - Porsi yang dapat dikontrol menggunakan sensor hall untuk umpan balik - Akurat menjaga waktu dengan chip DS1307 - Dapat secara manual mengubah waktu yang disetel dalam chip DS1307 - Dua pemberian makan per hari - Opsi pengumpanan manual - Pengumpanan ulang jika terjadi pemadaman listrik - Indikasi LED dari sensor hall dan jam waktu nyata - Waktu dan penyelesaian pengumpanan disimpan dengan aman di EEPROM - Servo "bergoyang" jika makanan tersangkut*/#include #include #include #include #include # include #include // Membuat objek servo untuk mengontrol servoServo myservo Anda;// Menetapkan semua input dan pin I/O saya#define ENTER_BUTTON_PIN 11#define UP_BUTTON_PIN 10#define DOWN_BUTTON_PIN 9#define BACK_PIN 8#menentukan POWER_LED_PIN 5#menentukan MANUAL_BUTTON_PIN A1#menentukan hallPin 2#menentukan HALL_LE D_PIN 7#define SERVO_PIN 6// Mendefinisikan semua Tombol, bekerja dengan JC_Button libraryButton enterBtn (ENTER_BUTTON_PIN);Tombol upBtn (UP_BUTTON_PIN);Tombol turunBtn (DOWN_BUTTON_PIN);Tombol kembaliBtn/Button_PINEDBUTTON_PINEDBUTTON_PINEDBUTTON_MAN (PINEDBUTTON_PIN_BUTTON_BUTTON_BUTTn LCD I2C dan RTCLiquidCrystal_I2C lcd (0x27, 16, 2);RTC_DS1307 rtc;//Variabel yang digunakan di seluruh codeunsigned long hallSensorTime;unsigned long rotationTime =400;unsigned long led_previousMillis =0;const long interval_delay =delay_;unsigned long; int ledState =RENDAH;boolean manualFeed =false;boolean hall_sensor_fail =false;blink panjang tanpa tanda_previousMillis =0;kedipan panjang tanpa tanda_currentMillis =0;kedipan panjang tanpa tanda_interval =500;penundaan panjang tidak bertanda_currentMillis =0;keterlambatan panjang tidak bertanda_keadaan sebelumnyaMillis =0 =false; int count;pengumpanan boolean1_lengkap =false;pengumpanan boolean2_lengkap =false;pengumpanan boolean1_trigger =false;pengumpanan boolean2_trigger =false;boolean servoOn =tru e;//Hall sensor interruptvolatile boolean hallSensorActivated =false;volatile int isr_count =1;void hallActiveISR(){ hallSensorActivated =true; digitalWrite(HALL_LED_PIN, TINGGI); isr_count =isr_count + 1;}/* Saya menggunakan enum di sini untuk melacak dengan lebih baik tombol apa yang ditekan daripada hanya mengatur setiap tombol ke nilai interger.*/enum { btnENTER, btnUP, btnDOWN, btnBACK,}; /* Status Mesin Negara. Hal yang sama di sini dengan tipe enum. Itu memudahkan untuk melacak menu apa yang Anda gunakan atau ingin buka daripada memberi setiap menu nilai integer*/enum STATES { MAIN, MENU_EDIT_FEED1, MENU_EDIT_FEED2, MENU_EDIT_TIME, MENU_EDIT_PORTION, EDIT_FEED1_HOUR, EDIT_FEED1_FE_HIT_FEED_,OUR_HIT_FEED_ , EDIT_MIN, EDIT_PORTION};// Memegang status status machineSTATES;//Variabel input penggunaint Jam;int Menit;int porsi;int feed_time1_hour;int feed_time1_min;int feed_time2_hour;int feed_time2_min;int userInput;// Karakter khusus memeriksa markbyte check_Char[8] ={ B00000, B00000, B00001, B00011, B10110, B11100, B11000, B00000};//====================Pengaturan===========================void setup() { Wire.begin(); Serial.begin(9600); lcd.init(); lcd.lampu latar(); lcd.createChar(0, check_Char); if (!rtc.begin()) { Serial.println("Tidak dapat menemukan RTC!"); } // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); //Tombol enterBtn.begin(); upBtn.begin(); downBtn.begin(); backBtn.begin(); manualFeedBtn.begin(); //Menyiapkan status awal status State Machine =MAIN; //Mengatur input dan output pinMode(POWER_LED_PIN, OUTPUT); pinMode(HALL_LED_PIN, OUTPUT); pinMode (pin hall, INPUT); /* Memasang interupsi ke pin yang terhubung ke sensor hall. Sensor hall yang saya gunakan disetel ke HIGH dan menjadi LOW ketika bertemu magnet. Itu sebabnya disetel ke FALLING */ attachInterrupt (digitalPinToInterrupt(hallPin), hallActiveISR, FALLING); // status default LED digitalWrite(POWER_LED_PIN, HIGH); digitalWrite (HALL_LED_PIN, RENDAH); /* Fungsi-fungsi ini mendapatkan waktu pengumpanan yang disimpan, pengumpanan selesai, dan ukuran porsi dari EEPROM saat start-up. Saya melakukan ini karena saya mendapatkan pemadaman listrik acak di sini tempat saya tinggal. */ get_feed_time1(); get_feed_time2(); get_completed_feedings(); get_portion();}//======================The Loop============================void loop() { perubahan_status(); check_buttons(); check_feedtime(); cek_rtc(); manual_feed_check ();}//================Fungsi =======================/* Menggunakan Perpustakaan JC_Button untuk terus memeriksa apakah tombol ditekan. Bergantung pada tombol apa yang ditekan, ia menetapkan variabel UserInput untuk digunakan dalam fungsi menu_transitions*/void check_buttons () { enterBtn.read(); upBtn.read(); downBtn.read(); backBtn.read(); manualFeedBtn.read(); if (enterBtn.wasPressed()) { Serial.println ("Anda Menekan Enter!"); masukan pengguna =btnENTER; menu_transitions(masukan pengguna); } if (upBtn.wasPressed()) { Serial.println ("Anda Menekan!"); masukan pengguna =btnUP; menu_transitions(masukan pengguna); } if (downBtn.wasPressed()) { Serial.println ("Anda Menekan!"); masukan pengguna =btnDOWN; menu_transitions(masukan pengguna); } if (backBtn.wasPressed()) { Serial.println ("Anda Menekan Kembali!"); masukan pengguna =btnBACK; menu_transitions(masukan pengguna); } if (manualFeedBtn.wasPressed()) { Serial.println ("Anda Memberi Makan Secara Manual!"); manualFeed =benar; }}//=====================================================/* Fungsi ini menentukan apa yang ditampilkan, tergantung pada menu atau "status" apa Anda berada. Setiap menu memiliki fungsi yang menampilkan menu masing-masing*/void change_states() { switch (state) { kasus UTAMA:display_current_time(); display_feeding_times(); tampilan_bagian(); merusak; kasus MENU_EDIT_FEED1:display_set_feed_time1_menu(); merusak; kasus MENU_EDIT_FEED2:display_set_feed_time2_menu(); merusak; kasus MENU_EDIT_TIME:display_set_time_menu(); merusak; kasus MENU_EDIT_PORTION:display_set_portion_menu(); merusak; kasus EDIT_FEED1_HOUR:set_feed_time1(); merusak; kasus EDIT_FEED1_MIN:set_feed_time1(); merusak; kasus EDIT_FEED2_HOUR:set_feed_time2(); merusak; kasus EDIT_FEED2_MIN:set_feed_time2(); merusak; kasus EDIT_HOUR:set_the_time(); merusak; kasus EDIT_MIN:set_the_time(); merusak; kasus EDIT_PORTION:set_the_portion(); merusak; }}//=====================================================/* Ini adalah bagian transisi dari mesin negara. Inilah yang memungkinkan Anda untuk berpindah dari satu menu ke menu lainnya dan mengubah nilai*/void menu_transitions(int input) { switch (state) { case MAIN:if (input ==btnENTER) { lcd.clear(); status =MENU_EDIT_FEED1; } if (input ==btnBACK) { hall_sensor_fail =false; } merusak; //------------------------------------------------ ---- case MENU_EDIT_FEED1:if (input ==btnBACK) { lcd.clear(); negara =UTAMA; } else if (masukan ==btnENTER) { lcd.clear(); status =EDIT_FEED1_HOUR; } else if (masukan ==btnDOWN) { lcd.clear(); status =MENU_EDIT_FEED2; } merusak; //------------------------------------------------ ---- case EDIT_FEED1_HOUR:// Perlu ini untuk mencegah servo mati saat mengatur waktu servoOn =false; if (masukan ==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 (masukan ==btnBACK) { lcd.clear(); servoOn =benar; status =MENU_EDIT_FEED1; } else if (input ==btnENTER) { state =EDIT_FEED1_MIN; } merusak; //---------------------------------------------------- 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*"); penundaan (1000); lcd.clear(); servoOn =true; write_feeding_time1 (); state =MAIN; } merusak; //---------------------------------------------------- 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; } merusak; //---------------------------------------------------- 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; } merusak; //---------------------------------------------------- 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*"); penundaan (1000); lcd.clear(); servoOn =true; write_feeding_time2 (); state =MAIN; } merusak; //---------------------------------------------------- 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; } merusak; //---------------------------------------------------- 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; } merusak; //---------------------------------------------------- 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*"); penundaan (1000); lcd.clear(); rtc.adjust(DateTime(0, 0, 0, Hour, Minute, 0)); state =MAIN; } merusak; //---------------------------------------------------- case MENU_EDIT_PORTION:if (input ==btnUP) { lcd.clear(); state =MENU_EDIT_TIME; } else if (input ==btnENTER) { lcd.clear(); state =EDIT_PORTION; } merusak; //---------------------------------------------------- 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*"); penundaan (1000); lcd.clear(); write_portion(); state =MAIN; } merusak; }}//=====================================================// 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); merusak; //---------------------------------------------------- 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(" "); } merusak; } 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); merusak; //---------------------------------------------------- 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(" "); } merusak; } 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); merusak; //---------------------------------------------------- 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(" "); } merusak; } 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); penundaan (30); myservo.write(93); penundaan (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 =TINGGI; } else { ledState =RENDAH; } 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

Suku cadang dan penutup khusus

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

Skema

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.

Proses manufaktur

  1. Menyelesaikan bagian cetakan 3D dengan… krayon?
  2. Sensor pelacakan garis dengan RPi
  3. API sensor lingkungan dengan RPi
  4. Portenta dan Sensor Termokopel (dengan MAX6675)
  5. Kontrol Kualitas Lebih Baik Dengan Bagian Cetakan 3D
  6. Kencangkan diri Anda dengan komponen cetak 3D yang fungsional!
  7. Membayangkan kembali Go Kart dengan Bagian Cetakan 3D
  8. Webinar:Mencetak Bagian Cetakan 3D yang Kuat dengan Eiger
  9. Drone Ekstrim Cetak 3D
  10. Perlombaan Hingga Selesai dengan Suku Cadang Kendaraan Formula SAE Cetak 3D