# TUGAS PROYEK SMART PET FEEDER WITH PID CONTROL ## Nama Kelompok - Rafli Limandijaya (1103210243) - Barawan Sopiatno (1103213022) - Dimas Rizqie Pratikta (1103210016) - Shavira Nur Annisa (1103213239) - A. Muh, Eza Hidayathullah (1103213081) ## Daftar Isi > [TOC] > **[CLO 4]** Memiliki kemampuan untuk menganalisis sistem kendali loop tertutup pada kondisi transien dan steady state untuk melihat performansinya. > **[CLO 5]** Memiliki kemampuan merancang sistem kendali motor DC. <!-- > **Capaian CLO 4:** > 1.Mahasiswa mampu menjelaskan konsep kendali umpan balik. > 2.Mahasiswa mampu merancang sistem kendali PID. > 3.Mahasiswa mampu mengevaluasi dan optimasi sistem kendali PID. > **Capaian CLO 5:** > 1.Mahasiswa mampu mendapatkan fungsi transfer sistem dari mekanisme transfer daya. > 2.Mampu menjelaskan cara kerja dan karakteristik motor listrik, khususnya motor DC. > 3.Mampu menganalisis hubungan antara torsi dan kecepatan motor. > 4.Mahasiswa mampu mendemonstrasikan sistem mekanisme transfer daya sederhana menggunakan gear dan motor DC. > --> ## Pendahuluan Laporan ini dibuat untuk menyelesaikan tugas akhir pada mata kuliah Sistem Kendali dan Mekanika. Pada tugas ini, kami membuat projek smart ped feeder menggunakan sistem kontrol PID untuk kontrol posisi dari motor DC. Kontrol posisi motor dc dilakukan dengan cara mengatur nilai dari PID untuk mencapai set point. Sistem ini dapat digunakan untuk mempelajari dan memahami dasar-dasar kontrol PID. ## Rancangan Sistem Kendali Loop Tertutup PID PID merupakan jenis kontrol umpan balik yang banyak digunakan dalam otomatisasi dan sistem kontrol. PID digunakan untuk mengendalikan sistem dinamis dengan mengukur perbedaan antara nilai yang diinginkan dan nilai yang sebenarnya. Dalam sistem pet feeder kami, nilai P menentukan seberapa cepat motor DC mencapai set point. Namun, nilai P saja hanya mempengaruhi kecepatan sistem mencapai set point tanpa memperhatikan atau mengoreksi error. Jika nilai P terlalu tinggi, motor akan bergerak cepat tetapi menyebabkan overshoot. Nilai I membantu sistem menangani error dengan mengakumulasi respon terhadap error tersebut. Namun, jika nilai I terlalu tinggi, sistem akan mengakumulasi respon secara berlebihan, menyebabkan osilasi. Di sinilah nilai D berfungsi sebagai "rem" untuk mengendalikan osilasi. Nilai D memperhitungkan perubahan error dari setiap putaran motor yang dibaca oleh encoder. Namun, jika nilai D terlalu besar, motor DC akan berhenti-berhenti saat berputar karena dianggap terus-menerus direm. Penelitian ini dimulai dengan menyusun model smart pet feeder. Cara kerja sistem ini adalah sebagai berikut: 1. Ketika sistem menerima perintah untuk memulai tugas, sistem akan mulai mengerjakan tugas tersebut. 2. Pertama-tama, sistem membunyikan buzzer untuk memanggil hewan peliharaan. 3. Jika sensor jarak mendeteksi adanya hewan peliharaan pada jarak yang diinginkan, motor DC akan memutar botol yang berisi makanan hewan tersebut agar makanan jatuh ke load cell. 4. Jika beban makanan yang diukur oleh load cell sudah mencukupi, motor DC akan kembali berputar ke posisi awal (posisi 0). Smart pet feeder kami menggunakan botol sebagai komponen utama yang digerakkan oleh motor DC. Di bawah ini adalah gambar dari rancangan sistem PID pada motor DC-nya. ![image](https://hackmd.io/_uploads/rJ7vI1EI0.png) Tentukan sensor dan aktuator dan hubungan-hubungannya ## Mekanik Motor DC Pada proyek smart pet feeder ini, sistem menggunakan motor DC dengan encoder yang diatur oleh motor driver L298N untuk menggerakkan botol berisi makanan hewan. Fungsi transfer dalam sistem ini bertujuan untuk mengontrol kecepatan dan posisi motor DC berdasarkan sinyal kontrol yang diberikan. Sinyal PWM yang dikirim oleh driver motor L298N mengontrol kecepatan dan arah putaran motor DC. Encoder pada motor DC memberikan umpan balik mengenai posisi dan kecepatan motor, yang digunakan oleh kontrol PID untuk menyesuaikan sinyal PWM secara real-time. Mekanisme daya dalam sistem ini melibatkan beberapa komponen utama: 1. Motor Driver L298N: Mengontrol arus yang mengalir ke motor DC berdasarkan sinyal PWM dari mikrokontroler. 2. Motor DC dengan Encoder: Mengonversi energi listrik menjadi energi mekanik untuk menggerakkan botol yang berisi makanan. Encoder memberikan umpan balik posisi dan kecepatan motor ke sistem kontrol. 3. Botol Sebagai Komponen yang Digerakkan: Botol berisi makanan hewan yang digerakkan oleh motor DC untuk mengeluarkan makanan ke load cell. Jika botol makanan semakin penuh maka motor dc akan mengeluarkan torsi yang lebih besar untuk menggerakannya. ## Analisis Transient Respon ``` #include <ESP32Firebase.h> #include <WiFi.h> #include "time.h" #include <ESP32Servo.h> #include <EEPROM.h> #include <HX711_ADC.h> // Firebase Configuration #define API_KEY "AIzaSyC0gTd2C245vsfdCVhmDlWFw3QL6XpbBR0" #define DATABASE_URL "https://tesiot-ef201-default-rtdb.asia-southeast1.firebasedatabase.app/" #define FIREBASE_AUTH "mn4aY2EtkxgfnQhut144ABkfnEMNZ1GVYoTk29hX" // Motor DC Configuration #define motorDirPin 23 #define motorPWMPin 22 #define enablePin 19 // Encoder Configuration #define encoderA 18 #define encoderB 17 bool dCW = 0; // PID Control Parameters float kp = 18 ; float ki = 1.5; float kd = 0.04; float prevError = 0; float integral = 0; float dt = 0.01; unsigned long previousMillis = 0; const long interval = 10; int error = -100; int control = 0; int velocity = 0; int encoderPos = 0; // Load Cell Configuration const int HX711_dout = 25; const int HX711_sck = 26; HX711_ADC LoadCell(HX711_dout, HX711_sck); const int calVal_eepromAdress = 0; unsigned long t = 0; // WiFi Configuration const char* ssid = "WIFIID"; const char* password = "WIFIPASS"; // NTP Server Configuration const char* ntpServer1 = "pool.ntp.org"; const char* ntpServer2 = "time.nist.gov"; const long gmtOffset_sec = 21600; const int daylightOffset_sec = 3600; int user_input_hour = 22; // Timestamp Variables unsigned long lastTimestamp = 0; int lastHourProcessed = -1; int lastDay = -1; // Ultrasonic Sensor Configuration const int ultrasonicEchoPin = 32; const int ultrasonicTriggerPin = 27; const int maxDistance = 90; // Buzzer Configuration const int buzzerPin = 21; // Servo Configuration const int servoPin = 33; Servo myservo; // Firebase Firebase firebase(DATABASE_URL); void setup() { Serial.begin(115200); delay(100); delay(100); setupWiFi(); delay(100); setupFirebase(); delay(100); setupLoadCell(); delay(100); setupEncoder(); delay(100); setupUltrasonic(); delay(100); setupBuzzer(); delay(100); setupServo(); delay(100); tareWeight(); delay(100); } void loop() { if (millis() - lastTimestamp >= 1000) { checkTime(); checkSerialInput(); fetchUserInputHour(); lastTimestamp = millis(); } } void setupWiFi() { Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" CONNECTED"); configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2); } void setupFirebase() { firebase.setString("Example/setString", "It's Working"); fetchUserInputHour(); } void setupLoadCell() { LoadCell.begin(); float calibrationValue = 696.0; EEPROM.begin(512); EEPROM.get(calVal_eepromAdress, calibrationValue); unsigned long stabilizingtime = 2000; boolean _tare = true; LoadCell.start(stabilizingtime, _tare); if (LoadCell.getTareTimeoutFlag()) { Serial.println("Timeout, check MCU>HX711 wiring and pin designations"); while (1); } else { LoadCell.setCalFactor(calibrationValue); Serial.println("Startup is complete"); } } void setupEncoder() { pinMode(encoderA, INPUT_PULLUP); pinMode(encoderB, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(encoderA), doEncoderA, RISING); pinMode(motorDirPin, OUTPUT); pinMode(enablePin, OUTPUT); encoderPos = 0; // Initialize encoder position to 0 } void setupUltrasonic() { pinMode(ultrasonicTriggerPin, OUTPUT); pinMode(ultrasonicEchoPin, INPUT); } void setupBuzzer() { pinMode(buzzerPin, OUTPUT); digitalWrite(buzzerPin, LOW); } void setupServo() { myservo.attach(servoPin); myservo.write(0); } void fetchUserInputHour() { int hourValue = firebase.getInt("SetHour"); if (hourValue != -1) { user_input_hour = hourValue; Serial.print("Updated user_input_hour from Firebase: "); Serial.println(user_input_hour); } else { Serial.println("Failed to get SetHour from Firebase or SetHour is invalid"); } } void checkTime() { struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } Serial.print("Current time: "); Serial.println(&timeinfo, "%H:%M:%S"); if (timeinfo.tm_mday != lastDay) { lastDay = timeinfo.tm_mday; lastHourProcessed = -1; Serial.println("New day detected, reset lastHourProcessed."); } if (timeinfo.tm_hour == user_input_hour && timeinfo.tm_hour != lastHourProcessed) { Serial.println("Desired time reached!"); lastHourProcessed = timeinfo.tm_hour; activateBuzzer(); } } void activateBuzzer() { Serial.println("void activate buzzer"); delay(100); tareWeight(); buzzerOn(); unsigned long startTime = millis(); int distance; while (true) { distance = getDistance(); if (distance <= maxDistance && distance != 0) { buzzerOff(); Serial.println("Ultrasonic sensor detected, turning off buzzer."); break; } } checkWeight(); } int getDistance() { unsigned long duration; int distance; digitalWrite(ultrasonicTriggerPin, LOW); delayMicroseconds(2); digitalWrite(ultrasonicTriggerPin, HIGH); delayMicroseconds(10); digitalWrite(ultrasonicTriggerPin, LOW); duration = pulseIn(ultrasonicEchoPin, HIGH); distance = duration * 0.034 / 2; Serial.println(distance); return distance; } void buzzerOn() { digitalWrite(buzzerPin, HIGH); } void buzzerOff() { digitalWrite(buzzerPin, LOW); } void tareWeight() { delay(100); int t=0; float weight = 0.0; while (true) { if (LoadCell.update()) { float berat = LoadCell.getData(); Serial.print("Load_cell output val: "); Serial.println(berat); weight = berat; t=t+1; } delay(2); if (weight <=1 || t>=40) { break; } } } void checkWeight() { int portionValue = firebase.getInt("Portions"); digitalWrite(enablePin, HIGH); controlMotor(180); delay(100); float weight = 0.0; while (true) { if (LoadCell.update()) { float berat = LoadCell.getData(); Serial.print("Load_cell output val: "); Serial.println(berat); weight = berat; } delay(2); if (weight >= 20.0) { break; } } controlMotor(0); Serial.println("Servo gerak"); firebase.setString("Example/setString", "Task working"); firebase.setString("ManualInput", "false"); } void controlMotor(int targetPos) { unsigned long startTime = millis(); while (millis() - startTime < 100) { // Kosong, hanya untuk menunggu } digitalWrite(enablePin, HIGH); error = -100; int i=0; int countWithinRange = 0; // Counter untuk melacak berapa kali error berada dalam batas yang diinginkan const int threshold = 5; // Jumlah kali error harus berada dalam batas sebelum berhenti Serial.print("time 1"); Serial.println(startTime); while ((error <= -5 || error >= 5 )|| countWithinRange < threshold) { unsigned long time = millis(); if (time - previousMillis >= interval) { Serial.println(encoderPos); previousMillis = time; error = targetPos - encoderPos; integral = integral + (error * dt); float derivative = (error - prevError) / dt; control = (kp * error) + (ki * integral) + (kd * derivative); velocity = min(max(control, -255), 255); if (velocity >= 0) { digitalWrite(motorDirPin, dCW); analogWrite(motorPWMPin, velocity); } else { digitalWrite(motorDirPin, !dCW); analogWrite(motorPWMPin, 255 + velocity); } i++; prevError = error; // Update counter if (abs(error) <= 5) { countWithinRange++; } else { countWithinRange = 0; // Reset counter jika error di luar batas } } } Serial.print("time 2"); unsigned long stopTime = millis(); Serial.println(stopTime); analogWrite(motorPWMPin, 0); digitalWrite(enablePin, LOW); delay(10); Serial.print("Error: "); Serial.println(error); } void doEncoderA() { digitalRead(encoderB) ? encoderPos-- : encoderPos++; } void checkSerialInput() { String manualInputStr = firebase.getString("ManualInput"); bool manualInput = (manualInputStr == "true"); if (manualInput) { Serial.println("Manual input dari Firebase"); activateBuzzer(); } if (Serial.available() > 0) { String input = Serial.readStringUntil('\n'); input.trim(); if (input.equals("start")) { Serial.println("Manual task input dari Serial Monitor"); activateBuzzer(); } } } ``` <!-- ![image](https://hackmd.io/_uploads/ByiVMrsv6.png) --> Gambar plot <!-- Panduan Analisis (CLO4) 1 Plot respon transient Kondisi nilai KP, KI, dan KD yang seperti apa yang membuat sistem paling cepat stabil 2 Plot respon transient Kondisi nilai KP, KI, dan KD yang seperti apa yang membuat sistem memiliki error paling besar 3 Bandingkan set point dengan output hitung berapa besar steady state error (SSE) 4 Mana yang paling rentan menyebabkan sistem berosilasi? 5 (Catatan: dikatakan berosilasi jika berulang kali bolak-balik melewati set point untuk mencapai set point yang diinginkan sampai berada di titik stabil. 6 Bagaimana respons transien sistem tersebut dari masing-masing kategori kecepatan yang diberikan? Hitung dengan menggunakan stopwatch dan berikan penjelasan dari masing-masing waktu berikut ini: 1.Delay time (Td) 2.Rise time (Tr) 3.Peak time (Tp) 4.Settling time (Ts) --> ![image](https://hackmd.io/_uploads/By29HWNLA.png) **Plot respon transien tanpa PID** Diatas adalah gambar dari respon sistem tanpa PID(kP=1,kI=0,kD=0). Setpoint yang diinginkan adalah 180. Saat tidak ada nilai PID, dapat dilihat dari grafik diatas, bahwa sistem akan lama mencapai daerah set point. Selain itu erornya juga sangat besar yaitu sekitar 50 atau sekitar 28%. Plot respon transien ini memiliki nilai eror terbesar dalam percobaan kami. Pengukuran ulang setelah dilakukan tuning PID <!-- ![image](https://hackmd.io/_uploads/BJQtMBsDp.png) --> ![image](https://hackmd.io/_uploads/S1YTQZVLR.png) **Plot respon transien dengan nilai PID terbaik** Gambar di atas adalah plot respon transient yang membuat sistem paling cepat stabil dengan nilai PID sebagai berikut : 1. KP = 18 2. KI = 1.5 3. KD = 0.04 Respon sistem diatas memiliki eror dengan rata-rata nilai 4. Kami anggap sistem sudah stabil karena 4/180 adalah sekitar 2% dan angka tersebut bisa dibilang stabil. Sistem akan rentan berosilasi jika nilai KI terlalu besar. Hal tersebut terjadi karena perkiraan eror terlalu besar dan sistem terlalu cepat untuk merespon eror sehingga akan sering lebih dan kurang dari setpoint. Sistem kami menyetabilkan posisi motor dc dengan sangat cepat. Kami coba melihat waktunya dengan cara print millis sebelum dan sesudah motor dc stabil. Didapati jedanya hanya sekitar 0.7 detik. Oleh karena itu kami tidak mampu untuk melihat delay time, rise time, peak time, dan settling time. Sebagai gantinya kami akan menjelaskan arti dari istilah-istilah diatas. 1. Delay time adalah waktu yang dibutuhkan sistem untuk mencapai 50% dari setpoint 2. Rise time adalah waktu yang dibutuhkan sistem untuk mencapai set point pertama kali 3. Peak time adalah waktu yang dibutuhkan sistem untuk mencapai nilai tertinggi. 4. Settling time adalah waktu yang dibutuhkan sistem untuk mencapai kestabilan(biasanya 2% atau 5%). ## Analisis Mekanika <!-- Panduan Analisis Mekanika (CLO 5) --> ### Analisis Kecepatan Motor terhadap Beban <!-- Nyalakan motor listrik tanpa beban. 1.Hubungkan beban dengan motor (sesuai kasus project). Apakah motor masih dapat berputar? 2.Tambahkan lagi beban secara bertahap hingga motor berhenti berputar. Lakukan analisis hubungan antara torsi dan kecepatan dari setiap beban yang ditambah hingga motor berhenti berputar. 3.Jika beban terus ditambahkan dan menyebabkan motor berhenti berputar, apakah beban tersebut tetap dapat diputar dengan menggunakan gear? Jelaskan! 4.Bagaimana mengatur komposisi gear agar beban tersebut dapat berputar? Mengapa beban menjadi dapat berputar setelah ditambahkan rangkaian gear? Jelaskan hal-hal apa saja yang terjadi saat beban motor meningkat, khususnya dilihat dari: 1.kecepatan, 2.CEMF, 3.arus (current), 4.torsi. --> Kami melakukan percobaan untuk analisis kecepatan motor terhadap beban. Pertama-tama saat motor tidak diberi beban, motor berputar dengan sangat cepat sesuai dengan tegangan yang diberikan. Saat tidak ada beban, motor berputar pada kecepatan maksimal. Setelah itu kami meletakkan beban yang berupa botol di dc motor. Kami mencoba dengan 2 kondisi, yaitu dengan tegangan 5V dan 12V. Pada saat botol diisi setengah dengan tegangan 5V motor berhenti berputar. Pada saat botol diisi penuh dengan tegangan 12V motor berhenti berputar. Saat beban ditambahkan, torsi yang diperlukan untuk menggerakkan beban meningkat. Motor akan mengalami penurunan kecepatan karena harus menghasilkan torsi yang lebih besar. Hubungan antara torsi dan kecepatan motor adalah berbanding terbalik dimana semakin besar torsi yang diperlukan, semakin lambat kecepatan motor. Jika beban maksimal diberikan gear, maka motor akan dapat memutarnya. Hal ini dikarenakan gear memperingan kerja motor, seperti yang ada di materi pertemuan 14 tentang gear. Gear yang ada di motor DC (biasanya yang berukuran lebih kecil) melihat inersia yang lebih rendah daripada inersia yang sebenarnya dimiliki oleh beban. Pengaturan komposisi gear biasanya dilakukan dengan menaruh gear yang kecil di motor driver, dan gear yang lebih besar di bebannya. Hal ini terjadi karena misalkan gear driver dan gear driven memiliki ratio 1 : 5, maka torsi yang diberikan pada output gear akan lima kali lebih besar dari torsi yang dihasilkan oleh motor. Hal ini meningkatkan fluks magnetik dalam motor, yang pada gilirannya meningkatkan CEMF. CEMF yang lebih tinggi akan menurunkan tegangan yang diberikan oleh sumber daya untuk menjaga arus motor tetap stabil. Selain itu saat motor harus menghasilkan torsi yang lebih besar untuk mengatasi beban tambahan, arus yang mengalir melalui gulungan motor juga akan meningkat. Hukum Ohm menyatakan bahwa arus (I) adalah hasil dari tegangan (V) dibagi resistansi (R), dan dengan peningkatan torsi, resistansi efektif motor juga bisa meningkat. ## Hasil dan Saran Link Video : https://www.youtube.com/watch?v=UqHqrdbgwk4 **Hasil** Hasil dari proyek smart pet feeder dengan kontrol PID memberikan kami wawasan berharga tentang pengimplementasian PID, Motor DC, dan sistem closed loop. Kami menemukan bahwa: Penggunaan PID: Implementasi kontrol PID memungkinkan pengendalian posisi motor DC dengan presisi tinggi, yang memastikan jumlah makanan yang diberikan sesuai dengan yang diharapkan. Motor DC: Motor DC yang dilengkapi dengan encoder memungkinkan kami untuk memantau dan mengontrol putaran dengan akurat, mendukung efektivitas sistem dalam mendistribusikan makanan. Sistem Closed Loop: Sistem closed loop memberikan umpan balik real-time, yang membantu dalam menyesuaikan keluaran motor sesuai kebutuhan, meningkatkan stabilitas dan responsivitas sistem. Secara keseluruhan, penggunaan PID, Motor DC, dan sistem closed loop sangat berguna di dunia robotika dan sistem tertanam untuk mengoptimalkan kinerja sebuah sistem. **Saran** Masih ada beberapa kekurangan dari proyek kami, diantaranya adalah kurangnya pendesaianan dari produk sehingga proyek kami masih belum bisa digunakan untuk implementasi di dunia nyata, melainkan masih merupakan prototipe dari sebuah sistem. ## Referensi https://www.hackster.io/qlu_1/a-smart-automatic-pet-feeder-based-on-onem2m-1c1a73 https://www.youtube.com/watch?v=cNW5oSgtswM&t=412s https://www.youtube.com/watch?v=OCXsHwNEYiU https://www.wevolver.com/article/pid-loops-a-comprehensive-guide-to-understanding-and-implementationv=JFTJ2SS4xyA&ab_channel=Electronoobs ## Rubrik Penilaian | Penilaian Indikator Ketercapaian CLO | Bobot | | -------- | -------- | | Mahasiswa mampu mengevaluasi dan optimasi sistem kendali PID (soal CLO 4). | 50 % | |Mahasiswa mampu mendemonstrasikan sistem mekanisme transfer daya sederhana menggunakan gear dan motor DC (soal CLO 5)|50%| ### Kriteria Nilai | 65-80 | 50-65 | 80-100 | 40-50 | 0-40 | | ----- | ----- | ------ | ----- | ---- | | CLO 4 | | | | | Mampu menjelaskan konsep kendali umpan balik, merancang sistem kendali PID, hingga mengevaluasi dan optimasi sistem kendali PID.| Mampu menjelaskan konsep kendali umpan balik, merancang, dan mengevaluasi sistem kendali PID.|Mampu menjelaskan konsep kendali umpan balik dan merancang sistem kendali PID.|Mampu menjelaskan konsep kendali umpan balik dan PID, tetapi kesulitan dalam merancang dan mengevaluasi sistem kendali PID.| Kesulitan dalam menjelaskan konsep kendali umpan balik dan PID.| | CLO 5 | | | | Mampu mendapatkan fungsi transfer sistem dari mekanisme transfer daya, menganalisis hubungan antara torsi dan kecepatan motor, menjelaskan cara kerja dan karakteristik motor listrik, serta mendemonstrasikan sistem mekanisme transfer daya sederhana menggunakan gear dan motor DC.| Mampu mendapatkan fungsi transfer sistem dari mekanisme transfer daya, menganalisis hubungan antara torsi dan kecepatan motor, menjelaskan cara kerja dan karakteristik motor listrik, tetapi kesulitan dalam mendemonstrasikan sistem mekanisme transfer daya sederhana menggunakan gear dan motor DC. |Mampu mendapatkan fungsi transfer sistem dari mekanisme transfer daya, menganalisis hubungan antara torsi dan kecepatan motor, tetapi kesulitan dalam menjelaskan cara kerja dan karakteristik motor listrik. | Mampu mendapatkan fungsi transfer sistem dari mekanisme transfer daya dan menganalisis hubungan antara torsi dan kecepatan motor. |Tidak dapat menentukan satu langkah pun untuk menjelaskan mengenai mekanisme transfer daya.|