Components and supplies
10 jumper wires 150mm male
Arduino® UNO R4 WiFi
Arduino Plug and Make Kit
continuous servo x 2 springrc sm-s4303r
Threaded Inserts or Glue
Tools and machines
3D printer
Apps and platforms
Arduino Cloud
Project description
Code
Pet Feeder
cpp
Create a 3D printed pet feeder to schedule food di
1/* 2This code shows a pet feeder using a continuous servo motor to dispense food notifying the pet through a short melody and a light. 3 4Modulino Buzzer: 5- Plays a melody before the food is dispensed. 6 7Modulino Pixels: 8- Turns on a light when food is dispensed or Modulino Distance is triggered. 9 10Modulino Distance: 11- Show the time since last dispense when someone approaches. 12 13Initial author: Hannes Siebeneicher (h.siebeneicher@arduino.cc) 14*/ 15 16#include "ArduinoGraphics.h" 17#include <Servo.h> 18#include <Modulino.h> 19#include "thingProperties.h" 20#include <Arduino_LED_Matrix.h> 21#include <Arduino_CloudConnectionFeedback.h> 22 23// Object instances 24Servo myServo; 25ModulinoBuzzer buzzer; 26ModulinoDistance distance; 27ModulinoPixels leds; 28ArduinoLEDMatrix matrix; 29 30// Modulino Pixels settings 31ModulinoColor COLOR_OFF(0, 0, 0); 32ModulinoColor newColor(255, 0, 255); 33int brightness = 0; 34 35// Buzzer melody 36int melody[] = { 262, 196, 196, 220, 196, 0 }; 37 38// Time Variables 39unsigned long lastFeedingTime = 0; // Store the time of the last feeding 40unsigned long currentTime = 0; // Store the current time 41unsigned long timePassed = 0; // Store the elapsed time since the last feeding 42 43// Add a debounce time for the distance sensor 44unsigned long lastTriggerTime = 0; // Tracks the last time the distance sensor was triggered 45const unsigned long debounceDelay = 3000; // Debounce delay in milliseconds 46int stableCount = 0; // Count of consecutive stable readings 47const int stableThreshold = 3; // Number of stable readings needed to trigger an event 48const int activationDistance = 100; // Trigger distance threshold 49 50// Servo Varibales 51const int servoPin = 9; 52const int SLOW = 1; 53const int AVERAGE = 2; 54const int FAST = 3; 55 56const int SLOW_SPEED = 103; // Servo speed for slow 57const int AVERAGE_SPEED = 115; // Servo speed for average 58const int FAST_SPEED = 180; // Servo speed for fast 59 60const float SLOW_FACTOR = 1.5; // Slow takes 1.5x longer than average 61const float AVERAGE_FACTOR = 1.0; // Average is the baseline 62const float FAST_FACTOR = 0.5; // Fast takes half the time as average 63 64// Adjust this value to calibrate the dispensing time for a full portion (100% of food). 65// The default value is 10000ms, which equals 10 seconds. 66const unsigned long BASE_TIME_FOR_100_PERCENT = 10000; 67 68// Initialize everything 69void setup() { 70 Serial.begin(9600); 71 delay(1500); 72 initProperties(); 73 74 Modulino.begin(); 75 buzzer.begin(); 76 leds.begin(); 77 distance.begin(); 78 matrix.begin(); 79 80 ArduinoCloud.begin(ArduinoIoTPreferredConnection); 81 waitForArduinoCloudConnection(matrix); 82 setDebugMessageLevel(2); 83 ArduinoCloud.printDebugInfo(); 84 85 // Default to 50% food and average speed 86 amountPercent = 50; 87 speedSetting = AVERAGE; 88} 89 90/** 91 * A short melody played when the food is dispensed 92*/ 93void playMelody() { 94 for (int i = 0; i < 8; i++) { 95 int note = melody[i]; 96 97 buzzer.tone(note, 250); 98 delay(250); 99 } 100} 101 102/** 103* Apply settings to Modulino Pixels 104*/ 105void setPixel(int pixel, ModulinoColor color) { 106 leds.set(pixel, color, 25); 107 leds.show(); 108} 109 110/** 111 * Play a short animation when distance sensor is triggered 112*/ 113void playAnimation() { 114 for (int i = 0; i < 8; i++) { 115 if (i == 0 || i == 1) { 116 setPixel(i, RED); 117 } else if (i == 2 || i == 3) { 118 setPixel(i, BLUE); 119 } else if (i == 4 || i == 5) { 120 setPixel(i, GREEN); 121 } else if (i == 6 || i == 7) { 122 setPixel(i, VIOLET); 123 } else if (i == 7 || i == 8) { 124 setPixel(i, WHITE); 125 } 126 127 delay(25); 128 } 129 130 for (int i = 0; i < 8; i++) { 131 setPixel(i, COLOR_OFF); 132 delay(25); 133 } 134} 135 136/** 137 * Turn light on / off 138*/ 139void toggleLight(bool light) { 140 if (light) { 141 brightness = 25; 142 } else if (!light) { 143 brightness = 0; 144 } else { 145 brightness = 0; 146 } 147 148 for (int i = 0; i < 8; i++) { 149 leds.set(i, newColor, brightness); 150 } 151 152 leds.show(); 153} 154 155/** 156 * Dispenses food by activating the servo, plays a melody and turns on the light 157*/ 158void dispenseFood(int amountPercent, int speedSetting) { 159 int servoSpeed; 160 float speedFactor; 161 162 // Store the time when food is dispensed 163 lastFeedingTime = millis(); 164 165 // Active cloud switch 166 feeding = true; 167 168 // Notify Pet through sound and light 169 playMelody(); 170 toggleLight(true); 171 172 // Determine servo speed and time based on user input 173 if (speedSetting == SLOW) { 174 servoSpeed = SLOW_SPEED; 175 speedFactor = SLOW_FACTOR; 176 } else if (speedSetting == AVERAGE) { 177 servoSpeed = AVERAGE_SPEED; 178 speedFactor = AVERAGE_FACTOR; 179 } else if (speedSetting == FAST) { 180 servoSpeed = FAST_SPEED; 181 speedFactor = FAST_FACTOR; 182 } else { 183 // Default to average if an invalid speed is provided 184 servoSpeed = AVERAGE_SPEED; 185 speedFactor = AVERAGE_FACTOR; 186 } 187 188 // Calculate duration based on amount and speed factor (100% food at average speed) 189 unsigned long calculatedDuration = BASE_TIME_FOR_100_PERCENT * (amountPercent / 100.0); 190 unsigned long adjustedDuration = calculatedDuration * speedFactor; 191 192 // Operate the servo 193 myServo.attach(servoPin); 194 myServo.write(servoSpeed); 195 196 // Non-blocking timing 197 unsigned long startTime = millis(); 198 while (millis() - startTime < adjustedDuration) { 199 ArduinoCloud.update(); // Keep cloud connected 200 } 201 202 // Stop servo 203 myServo.write(0); 204 myServo.detach(); 205 206 // Reset feeding and turn light off 207 feeding = false; 208 toggleLight(false); 209 210 // Clear the matrix after dispensing food 211 matrix.clear(); 212} 213 214/** 215 * Show the time since last feeding on the LED Matrix 216*/ 217void displayTimeOnMatrix(unsigned long minutes) { 218 matrix.beginDraw(); 219 matrix.stroke(0xFFFFFFFF); 220 221 char timeStr[10]; 222 snprintf(timeStr, sizeof(timeStr), "%lu", minutes); 223 224 matrix.textFont(Font_4x6); 225 matrix.beginText(1, 2, 0xFFFFFF); 226 matrix.println(timeStr); 227 matrix.endText(); 228 matrix.endDraw(); 229} 230 231void loop() { 232 ArduinoCloud.update(); 233 234 // Calculate the elapsed time since the last feeding 235 currentTime = millis(); 236 timePassed = (currentTime - lastFeedingTime) / 1000; // Elapsed time in seconds 237 238 // Convert passed time to minutes 239 unsigned long minutesPassed = timePassed / 60; 240 241 // Distance sensor logic 242 if (distance.available()) { 243 int measure = distance.get(); 244 245 // Check if the distance is within the activation threshold 246 if (measure < activationDistance) { 247 stableCount++; 248 } else { 249 stableCount = 0; // Reset count if measurement is out of range 250 } 251 252 // Trigger event only if stable readings exceed threshold 253 if (stableCount >= stableThreshold) { 254 unsigned long now = millis(); 255 256 // Ensure debounce time has passed 257 if (now - lastTriggerTime > debounceDelay) { 258 lastTriggerTime = now; // Update last trigger time 259 stableCount = 0; // Reset stable count 260 261 Serial.println("TRIGGER"); 262 Serial.print("Distance: "); 263 Serial.println(measure); 264 265 // Display passed time on the LED matrix 266 displayTimeOnMatrix(minutesPassed); 267 delay(3000); 268 matrix.clear(); 269 } 270 } 271 } 272 273 // Start dispensing food based on scheduler 274 if (feedingSchedule.isActive()) { 275 digitalWrite(LED_BUILTIN, HIGH); 276 dispenseFood(amountPercent, speedSetting); 277 } 278 279 // Short delay for stability 280 delay(20); 281} 282 283 284void onAmountPercentChange() { 285 if (amountPercent < 0) { 286 amountPercent = 0; 287 } else if (amountPercent > 100) { 288 amountPercent = 100; 289 } 290} 291 292void onSpeedSettingChange() { 293 if (speedSetting < 1 || speedSetting > 3) { 294 speedSetting = AVERAGE; // Default to average if invalid 295 } 296} 297 298void onFeedingChange() { 299 if (feeding) { 300 dispenseFood(amountPercent, speedSetting); 301 } 302} 303 304void onPixelsColorChange() { 305 // Read the color from the cloud and store it as RGB 306 uint8_t r, g, b; 307 308 // Get colors from dashboard widget 309 pixelsColor.getValue().getRGB(r, g, b); 310 311 // Convert the color in the format required by the ModulinoPixels object 312 newColor = ModulinoColor(r, g, b); 313 314 // Set Modulino Pixels to new color 315 for (int i = 0; i < 8; i++) { 316 leds.set(i, newColor, brightness); 317 } 318} 319 320void onFeedingScheduleChange() {}
Downloadable files
Pet Feeder 3D Models
This .zip contains all 3D model files
pet_feeder.zip
Comments
Only logged in users can leave comments