PetFeeder \\ How can I shorten the time?

Hi;
When I run the code, the servo motor stays on for 10 seconds.
How can I shorten the time?

Sample: https://wokwi.com/projects/359949636069453825

// RTC ALARM
//******************************************************************************
#include <RTClib.h>
RTC_DS1307 rtc; // no (SDA, SCL) arguments

// AM feeding time
int amFeedHour   = 15;
int amFeedMinute = 16;

// PM feeding time
int pmFeedHour   = 16;
int pmFeedMinute = 20;

// indicator if AM or PM feeding time
bool ampm = 0;

// char weekDays[][10] = { // removed LCD clutter
//   "SUN",
//   "MON",
//   "TUE",
//   "WED",
//   "THU",
//   "FRI",
//   "SAT"
// };

//******************************************************************************
// LCD
//******************************************************************************
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 4, 5, 6, 7); // 12 RS, 11 E, 4 D4, 5 D5, 6 D6, 7 D7

char line1[] = "@username"; // this will be centered on the LCD
char line2[] = "Pet Feeder!"; // this will be centered on the LCD

//******************************************************************************
// SERVO
//******************************************************************************
#include <Servo.h>
Servo myServo; // create instance of Servo class to control the servo

int servoPin = 3;
int position  = 0; // starting position of the servo (adjustable)
int direction = 1; // servo direction of travel
int speed = 5; // speed of servo arm. larger value is faster movement

void setup() {
  //******************************************************************************
  // GENERAL SETUP
  //******************************************************************************
  Serial.begin(115200); // Serial monitor for debugging

  //******************************************************************************
  // LCD SETUP
  //******************************************************************************
  lcd.begin(16, 2); // start the LCD
  welcome(); // the welcome screen

  //******************************************************************************
  // SERVO SETUP
  //******************************************************************************
  myServo.attach(servoPin); // attach servo to pwm pin

  //******************************************************************************
  // RTC SETUP
  //******************************************************************************
  if (! rtc.begin()) { // start rtc
    Serial.println("Couldn't find RTC"); // failed to start
    Serial.flush(); // wait for previous Serial.print(); to finish
    while (1); // stops sketch here.
  }
  // this will set RTC Date/Time from PC at compile time. COMMENT-OUT after setting
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  // this will set RTC with bespoke Date/Time
  // rtc.adjust(DateTime(2023, 3, 14, 12, 30, 0));  // March 14, 2023 at 12:30am
}

void loop() {
  DateTime now = rtc.now(); // set "now" to the RTC time

  if ((now.hour() >= pmFeedHour) && (now.hour() < amFeedHour)) { // compare hour to now/RTC for "next"
    ampm = 0; // before mid-day
    displayNextFeed(ampm, amFeedHour, amFeedMinute); // display next feed time
  } else {
    ampm = 1; // after mid-day
    displayNextFeed(ampm, pmFeedHour, pmFeedMinute); // display next feed time
  }

  //******************************************************************************
  // AM FEED THE CAT
  //******************************************************************************
  if ((now.hour() == amFeedHour && now.minute() == amFeedMinute) && now.second() < 10) {
    feedServo(); // feed now
  }

  //******************************************************************************
  // PM FEED THE CAT
  //******************************************************************************
  if ((now.hour() == pmFeedHour && now.minute() == pmFeedMinute) && now.second() < 10) {
    feedServo(); // feed now
  }

  //******************************************************************************
  // displayDate()
  //******************************************************************************
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  if (now.month() < 10) lcd.print("0");
  lcd.print(now.month(), DEC);
  lcd.print('/');
  if (now.day() < 10) lcd.print("0");
  lcd.print(now.day(), DEC);

  //******************************************************************************
  // displayDayOfWeek() // too much data for 16x02 LCD
  //******************************************************************************
  // lcd.print(" ");
  // lcd.setCursor(0, 1);
  // lcd.print(weekDays[now.dayOfTheWeek()]);
  // lcd.print(" ");

  //******************************************************************************
  // displayTime()
  //******************************************************************************
  lcd.setCursor(0, 1);
  if (now.hour() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.minute(), DEC);
  lcd.print('.');
  if (now.second() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.second(), DEC);
}

//******************************************************************************
// Welcome screen LCD and Serial Monitor
//******************************************************************************
void welcome() {
  lcd.setCursor(8 - (sizeof(line1) / 2 - 1), 0); // center line1 of the title
  lcd.print(line1);
  lcd.setCursor(8 - (sizeof(line2) / 2 - 1), 1); // center line 2 of the title
  lcd.print(line2);
  delay(1000);
  lcd.clear();
  lcd.setCursor(11, 0);
  lcd.print("Next:");

  Serial.println("Edit feeding times in the RTC ALARM section");
}

//******************************************************************************
// FEED THE CAT
//******************************************************************************
void feedServo() {
  myServo.write(0);  // set positions of servo arm
  position += direction * speed; // calculate new position
  delay(1000); // delay between movements. smaller value is faster movement
  myServo.write(90); // set position of servo arm
}

//******************************************************************************
// NEXT FEEDING TIME
//******************************************************************************
void displayNextFeed(int ampm, int nextHour, int nextMinute) { // display next feeding time
  lcd.setCursor(9, 1);
  lcd.print(nextHour);
  lcd.print(":");
  if (nextMinute < 10)
    lcd.print("0");
  lcd.print(nextMinute);

  lcd.setCursor(14, 1);
  if (ampm) // the "1" or "0" from above for AM or PM
    lcd.print("PM"); // next feed
  else
    lcd.print("AM"); // next feed
}

void displayTime() {
  // move the display-time code from void-loop() to here
}

void displayDate() {
  // move the display-date code from void-loop() to here
}

You could read the code and figure it out.

Here's where the cat is fed for ten seconds.

 //******************************************************************************
  // PM FEED THE CAT
  //******************************************************************************
  if ((now.hour() == pmFeedHour && now.minute() == pmFeedMinute) && now.second() < 10) {
    feedServo(); // feed now
  }

See if you can understand that, and use your best common sense to increase or decrease the number of seconds the feeding servo is active.

a7

Careful @alto777 : I am not sure this is OP asking. I suspect it's OP's cat, trying to get extra free food. We all know how devious cats can be...

5 Likes

I made a feeder with a food auger and a timed motor run. I would hear the auger and food coming out, but my cat would already be at the feeding point, having just jumped from doing nothing to run into the kitchen and wait.

Never did figure out what he was hearing what I could not.

Long ago I had commercial timed feeding bowls, one time was 3 PM. It seemed to work very well. Open tray, empty when I got home.

Once I had to return to get something I forget to take to work and my cat was munching away, at 8:30 AM, on his 3 PM food.

I wish I had video, the look on his face Busted!

Countermeasures were added, efficacy unknown. Today I'd leave a camera to see.

a7

2 Likes

Hi;
When I changed 10 seconds to 3 seconds, it still didn't work.
It works as 5 seconds.
I try here. “ PetFeeder - Wokwi ESP32, STM32, Arduino Simulator

The code in the simulator is no longer the code you posted.

I wonder if

delay(1000); // delay between movements. smaller value is faster movement

that changed to 5000 may have something to do with it.

For know, forget about what exactly that delay accomplishes and make it small compared to the passage of seconds, like 100.

a7

Your cat used the feeder to set his built in RTC. I swear, they have one. Our cats know our family work and school schedules.

4 Likes

I would remove this from setup and only call it right before you call the feed function. Then detach it as soon as the feed function is finished

It will save wear and tear on the servo as well as power.

How did he do that? Did he change the clock on the feeder ahead by 6.5 hours? Very, very sneaky!

1 Like

There were two theories.

One that he could twist the timer dial, it would have been within his skill set.

The other was the weakness of the little tab that held the door down until feeding time, and a gap where he could have applied pressure and popped it open.

We made some modifications to reduce the chance of either; we did leave food in one of the two instances of the feeder with time set such that we would be back home, that one seemed never to have been prematurely opened.

Clever enough not to open the one that would prove he was still getting food early? Yeah, prolly.

a7

//******************************************************************************
// RTC ALARM
//******************************************************************************
#include <RTClib.h>
RTC_DS1307 rtc; // no (SDA, SCL) arguments

// AM feeding time
int amFeedHour   = 10;
int amFeedMinute = 00;

// PM feeding time
int pmFeedHour   = 16;
int pmFeedMinute = 20;

// indicator if AM or PM feeding time
bool ampm = 0;

// char weekDays[][10] = { // removed LCD clutter
//   "SUN",
//   "MON",
//   "TUE",
//   "WED",
//   "THU",
//   "FRI",
//   "SAT"
// };

//******************************************************************************
// LCD
//******************************************************************************
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 4, 5, 6, 7); // 12 RS, 11 E, 4 D4, 5 D5, 6 D6, 7 D7

char line1[] = "@username"; // this will be centered on the LCD
char line2[] = "Pet Feeder!"; // this will be centered on the LCD

//******************************************************************************
// SERVO
//******************************************************************************
#include <Servo.h>
Servo myServo; // create instance of Servo class to control the servo

int servoPin = 3;
int position  = 0; // starting position of the servo (adjustable)
int direction = 1; // servo direction of travel
int speed = 5; // speed of servo arm. larger value is faster movement

void setup() {
  //******************************************************************************
  // GENERAL SETUP
  //******************************************************************************
  Serial.begin(115200); // Serial monitor for debugging

  //******************************************************************************
  // LCD SETUP
  //******************************************************************************
  lcd.begin(16, 2); // start the LCD
  welcome(); // the welcome screen

  //******************************************************************************
  // SERVO SETUP
  //******************************************************************************
  myServo.attach(servoPin); // attach servo to pwm pin

  //******************************************************************************
  // RTC SETUP
  //******************************************************************************
  if (! rtc.begin()) { // start rtc
    Serial.println("Couldn't find RTC"); // failed to start
    Serial.flush(); // wait for previous Serial.print(); to finish
    while (1); // stops sketch here.
  }
  // this will set RTC Date/Time from PC at compile time. COMMENT-OUT after setting
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  // this will set RTC with bespoke Date/Time
  // rtc.adjust(DateTime(2023, 3, 14, 12, 30, 0));  // March 14, 2023 at 12:30am
}

void loop() {
  DateTime now = rtc.now(); // set "now" to the RTC time

  if ((now.hour() >= pmFeedHour) && (now.hour() < amFeedHour)) { // compare hour to now/RTC for "next"
    ampm = 0; // before mid-day
    displayNextFeed(ampm, amFeedHour, amFeedMinute); // display next feed time
  } else {
    ampm = 1; // after mid-day
    displayNextFeed(ampm, pmFeedHour, pmFeedMinute); // display next feed time
  }

  //******************************************************************************
  // AM FEED THE CAT
  //******************************************************************************
  if ((now.hour() == amFeedHour && now.minute() == amFeedMinute) && now.second() < 3) {
    feedServo(); // feed now
  }

  //******************************************************************************
  // PM FEED THE CAT
  //******************************************************************************
  if ((now.hour() == pmFeedHour && now.minute() == pmFeedMinute) && now.second() < 3) {
    feedServo(); // feed now
  }

  //******************************************************************************
  // displayDate()
  //******************************************************************************
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  if (now.month() < 10) lcd.print("0");
  lcd.print(now.month(), DEC);
  lcd.print('/');
  if (now.day() < 10) lcd.print("0");
  lcd.print(now.day(), DEC);

  //******************************************************************************
  // displayDayOfWeek() // too much data for 16x02 LCD
  //******************************************************************************
  // lcd.print(" ");
  // lcd.setCursor(0, 1);
  // lcd.print(weekDays[now.dayOfTheWeek()]);
  // lcd.print(" ");

  //******************************************************************************
  // displayTime()
  //******************************************************************************
  lcd.setCursor(0, 1);
  if (now.hour() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.minute(), DEC);
  lcd.print('.');
  if (now.second() < 10) lcd.print("0"); // pad single digit with "0"
  lcd.print(now.second(), DEC);
}

//******************************************************************************
// Welcome screen LCD and Serial Monitor
//******************************************************************************
void welcome() {
  lcd.setCursor(8 - (sizeof(line1) / 2 - 1), 0); // center line1 of the title
  lcd.print(line1);
  lcd.setCursor(8 - (sizeof(line2) / 2 - 1), 1); // center line 2 of the title
  lcd.print(line2);
  delay(1000);
  lcd.clear();
  lcd.setCursor(11, 0);
  lcd.print("Next:");

  Serial.println("Edit feeding times in the RTC ALARM section");
}

//******************************************************************************
// FEED THE CAT
//******************************************************************************
void feedServo() {
  myServo.write(0);  // set positions of servo arm
  position += direction * speed; // calculate new position
  delay(500); // delay between movements. smaller value is faster movement
  myServo.write(90); // set position of servo arm
}

//******************************************************************************
// NEXT FEEDING TIME
//******************************************************************************
void displayNextFeed(int ampm, int nextHour, int nextMinute) { // display next feeding time
  lcd.setCursor(9, 1);
  lcd.print(nextHour);
  lcd.print(":");
  if (nextMinute < 10)
    lcd.print("0");
  lcd.print(nextMinute);

  lcd.setCursor(14, 1);
  if (ampm) // the "1" or "0" from above for AM or PM
    lcd.print("PM"); // next feed
  else
    lcd.print("AM"); // next feed
}

void displayTime() {
  // move the display-time code from void-loop() to here
}

void displayDate() {
  // move the display-date code from void-loop() to here
}

key edits:

void feedServo() {
  myServo.write(0);  // set positions of servo arm
  position += direction * speed; // calculate new position
  delay(500); // delay between movements. smaller value is faster movement
  myServo.write(90); // set position of servo arm
}

changed delay to 500

if ((now.hour() == amFeedHour && now.minute() == amFeedMinute) && now.second() < 3) {
    feedServo(); // feed now
  }

changed to 3 seconds

But I'm writing up something I personally like a little better

Rough version of the changes I would make:

#include <Wire.h>
#include <RTClib.h>
#include <Servo.h>
#include <LiquidCrystal.h>

// Create RTC, Servo, and LCD instances
RTC_DS1307 rtc;
Servo feederServo;
LiquidCrystal lcd(12, 11, 4, 5, 6, 7); // Pins for the LCD

// Feeding times
const int feedHour1 = 10;  // First feeding at 10:00 AM
const int feedMinute1 = 0;
const int feedSecond1 = 0;  // Ensure feeding occurs at exactly 00 seconds
const int feedHour2 = 16;  // Second feeding at 4:20 PM
const int feedMinute2 = 20;
const int feedSecond2 = 0;  // Ensure feeding occurs at exactly 00 seconds

// Servo positions and feed duration
const int servoOpenPos = 90;
const int servoClosePos = 0;
const unsigned long feedDuration = 3000;  // Duration in milliseconds (3 seconds)

// Non-blocking control variables
unsigned long lastFeedTime = 0;
const unsigned long feedCooldown = 60000;  // 1 minute cooldown between feeds
unsigned long servoOpenTime = 0;
bool isFeeding = false;  // Flag to track if feeding is in progress

char line1[] = "@username"; // Centered on the LCD
char line2[] = "Pet Feeder!"; // Centered on the LCD

void setup() {
  // Start serial communication for debugging
  Serial.begin(9600);

  // Initialize LCD and show welcome message
  lcd.begin(16, 2);
  welcome();

  // Attach servo to pin 3
  feederServo.attach(3);
  feederServo.write(servoClosePos);  // Ensure the servo is closed initially

  // Start RTC
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  } else {
    Serial.println("RTC found");
    DateTime now = rtc.now();
    displayDateTime(now);  // Display the current time
  }
}

void loop() {
  DateTime now = rtc.now();

  // Check for feeding times at exactly hh:mm:00
  if ((now.hour() == feedHour1 && now.minute() == feedMinute1 && now.second() == feedSecond1) ||
      (now.hour() == feedHour2 && now.minute() == feedMinute2 && now.second() == feedSecond2)) {
    if (!isFeeding && millis() - lastFeedTime >= feedCooldown) {
      startFeeding();  // Start the feeding process
    }
  }

  // If feeding is in progress, check if the feeding duration has passed
  if (isFeeding && millis() - servoOpenTime >= feedDuration) {
    finishFeeding();  // Finish the feeding process by closing the servo
  }

  // Display the current time and next feeding time
  displayDateTime(now);
  displayNextFeedTime(now);

  delay(1000);  // Update every second
}

void startFeeding() {
  Serial.println("Feeding cat...");
  feederServo.write(servoOpenPos);  // Open the servo to dispense food
  isFeeding = true;                 // Set feeding flag to true
  servoOpenTime = millis();         // Record the time when feeding started
  lastFeedTime = millis();          // Update the last feed time
}

void finishFeeding() {
  feederServo.write(servoClosePos); // Close the servo
  isFeeding = false;                // Reset the feeding flag
}

// Welcome screen on the LCD
void welcome() {
  lcd.setCursor(8 - (sizeof(line1) / 2 - 1), 0); // Center the first line
  lcd.print(line1);
  lcd.setCursor(8 - (sizeof(line2) / 2 - 1), 1); // Center the second line
  lcd.print(line2);
  delay(2000);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Next Feed:");
}

// Display the current time on the LCD
void displayDateTime(DateTime now) {
  lcd.setCursor(0, 0);
  lcd.print(now.year(), DEC);
  lcd.print('/');
  if (now.month() < 10) lcd.print("0");
  lcd.print(now.month(), DEC);
  lcd.print('/');
  if (now.day() < 10) lcd.print("0");
  lcd.print(now.day(), DEC);

  lcd.setCursor(0, 1);
  if (now.hour() < 10) lcd.print("0");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  if (now.minute() < 10) lcd.print("0");
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  if (now.second() < 10) lcd.print("0");
  lcd.print(now.second(), DEC);
}

// Display the next feeding time on the LCD
void displayNextFeedTime(DateTime now) {
  int nextFeedHour, nextFeedMinute;
  if (now.hour() < feedHour1 || (now.hour() == feedHour1 && now.minute() < feedMinute1)) {
    nextFeedHour = feedHour1;
    nextFeedMinute = feedMinute1;
    lcd.setCursor(11, 1);
    lcd.print("AM");
  } else {
    nextFeedHour = feedHour2;
    nextFeedMinute = feedMinute2;
    lcd.setCursor(11, 1);
    lcd.print("PM");
  }
  lcd.setCursor(9, 1);
  lcd.print(nextFeedHour);
  lcd.print(":");
  if (nextFeedMinute < 10) lcd.print("0");
  lcd.print(nextFeedMinute);
}

Missing some Serial debugging I would put in to confirm timing/accuracy/function

The original request for the sketch was for slow movement to not startle the animal, give the device time to deliver the food and for the animal to be clear of the mechanical device when it stows. I probably dropped the ball on the 5000ms thing. That becomes 7.5 minutes.

1 Like

Friends. Can you edit here for me to understand better.

“ Friends. Can you edit here for me to understand better.”

I don’t think that’s going to work. You need to put the leg work in . Do some debugging ( add print statements etc ) to find the issue .
Meanwhile ….
Cats always seem to defeat your efforts .
I have a cat flap with switches so I can detect the direction ‘in ‘ or ‘out’.
Often found the cat in when she is registered as out .
Spent ages trying to fix the code , then noticed sometimes she opened the flap
Looked outside , then backed up and stayed in !

1 Like

What do you not understand? The RTC keeps time while the program waits for two "feed" times. When a feed time arrives, a servo actuates ("dispenses food"), then "delay()" for five seconds, then closes.

Some commented-out lines in the program are for setting the clock to system time or setting the clock to your preferred time.

This function is called continuously when it's feeding period:

void feedServo() {
  myServo.write(0);  // set positions of servo arm
  position += direction * speed; // calculate new position
  delay(500); // delay between movements. smaller value is faster movement
  myServo.write(90); // set position of servo arm
}

so the net effect is

  myServo.write(0);
  delay(500);
  myServo.write(90);
  myServo.write(0);
  delay(500);
  myServo.write(90);
  myServo.write(0);
  delay(500);
  myServo.write(90);
  myServo.write(0);
  delay(500);
  myServo.write(90);

Placing an additional delay after the 90 degree moves makes the stirring action much nicer. Back, pause, forth, pause and so on:

void feedServo() {
  myServo.write(0);  // forth
  delay(100);
  myServo.write(90);  // and back
  delay(100);
}

The other lines in the original don't seem to be used, I removed them.

a7

Never let your cat know you're working on a cat project. She was watching you, I'll bet. "Oh, hey @hammy, nice to see you, wanna hear my purr motor?" or "did you forget to serve me breakfast?" are common ploys. DON'T TRUST THAT CAT.

That cat, that sneaky CAT! That cat...was watching you code and she laughed a little inside for your pitiful human efforts to outsmart her.

Don't you know what the 'C' in "C++" stands for?

3 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.