Arduino uno timer not working properly

Looking at the inside of the SG90 Servo (Fig-1), the modification seems to be not straightforward.
servocircuit
Figure-1:

Now, I have clearly understood what you want to achive. I am following post #14 @westfw to modify SG90 for continuous rotation and write codes to achive your goals.

1 Like

I haven't actually done it. I believe that there's also a physical stop on one of the gears that you have to cut off, so I suspect the process is "straightforward", but perhaps not "easy."

Probably the keyword you want for finding an actual servo to buy is "continuous rotation", rather than "360 degree." (I don't know if there's one for any simulator; it's probably not needed.)

1 Like

Adafruit covers it on one part of its six-step process:

So this means the servo i have, is actually modified version of 180 deg? So i still need to code it as a 180deg servo?

Side note, what does this have to do with the interval not triggering correctly? Im interested to know more..

You need a system where the Motor makes a continuos rotation for certain amount of time. This can be achived by using a DC Motor (Fig-1). Modifying a SG90 into a continuous rotating motor is not that much easy. I have dropped the idea of modifying my SG90 as I have plenty of DC motors. However, disassembling, modifying, and re-assembly of SG90 would be a good skill-acquiring exercise for those who have not done before such kind of works.
DCMotor
Figure-1:

Nothing. If it works properly in real life when hooked to the computer but not when hooked up to other power it sounds like a power problem.

What Arduino are you using? Pics?


Im using Arduino uno..

How do i troubleshoot the power problem? I already have 4x AA batteries to power up the servo.

I have recorded over 16 hrs of video with on screen timer, now uploading to YouTube. The purpose was to find out the exact time the servo rotates, but didn't have the time to review it yet.

Will update this post with link once upload finishes.

Thanks for the pictures. You are using an Uno clone.

The first step is a good schematic and inventory of parts.

This discusses powering a servo:

https://docs.arduino.cc/learn/electronics/servo-motors/

How healthy are your 4xAAs? Are your connections all reliable? Do you have equipment to check the power supplyig the board and supplying the servo?

1 Like

I ran the code from the wokwi, which still uses the "life too short" intervals.

The code functions perfectly. I added to the information it prints. FWIW I do not see why printing should make any difference in this case.


                         state = 0
27 Dispensing 8am
28  stop and -> 1
                         state = 1
33  done waiting, -> 2
                         state = 2
33 Dispensing 1pm
34  stop and -> 3
                         state = 3
39  done waiting, -> 4
                         state = 4
39 Dispensing 6pm
40  stop and -> 5
                         state = 5
54  done waiting, -> 0
                         state = 0
54 Dispensing 8am
55  stop and -> 1
                         state = 1
60  done waiting, -> 2
                         state = 2
60 Dispensing 1pm
61  stop and -> 3
                         state = 3
66  done waiting, -> 4
                         state = 4
66 Dispensing 6pm
67  stop and -> 5
                         state = 5
81  done waiting, -> 0
                         state = 0
81 Dispensing 8am

It shows the correct motion through the states and the times. The left hand column is seconds since the beginning of time (millis() / 1000). We see one second feeding stirs and 5 or 14 (or +/- 1) seconds between feedings. Servo twitches as required to stir for one second and stop.

Here's the code which should be logically identical, just a bit more informative with a few tricks to reduce printing and/or make it more meaningful:

// This pet feeder timing dispense food at 0 hours (startup), next is 5 hours,
// then 5 hours then 14 hours, total 24 hours. Suggestion to turn on the machine
// at 8am, next feed is 1pm, and 5pm after that, then wait. Next feeding is 8am next
// morning.

// Trial time is 0 second start up, 5 second feed 1, 5 seconds feed 2 and
// wait for 14 seconds

#include <Servo.h>

Servo feederServo;
const int servoPin = 9;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
const unsigned long servoRunTime = 1000; // 1 second rotation
const unsigned long fiveSeconds = 5000; // 5 second rotation
const unsigned long fourteenSeconds = 14000; // 14 second rotation

const unsigned long fiveHours = 18000000; // 5 hours in milliseconds
const unsigned long nineHours = 32400000; // 9 hours in milliseconds

int state = 0; // To track the sequence of operations

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

	feederServo.attach(servoPin);
	feederServo.write(90);     // Start at neutral position

	previousMillis = millis(); // Initialize previousMillis at startup
}

bool once;

void loop() {
	currentMillis = millis();

	static int lastState = -1;   // no it does not!
	if (lastState != state) {
		Serial.print("                         state = ");
		Serial.println(state);
		lastState = state;
	}

	switch (state) {
	case 0: // Rotate the servo for 1 second at startup
		if (currentMillis - previousMillis < servoRunTime) {
			feederServo.write(60); // Rotate servo (adjust angle for your servo)
			if (!once) {
				Serial.print(millis() / 1000); Serial.print(" ");
				Serial.println("Dispensing 8am");  // Print "Dispensing" when servo rotates
				once = true;
			}
		} else {
			once = false;
			feederServo.write(90);  // Stop rotation
			previousMillis = currentMillis;
			//Serial.println("Next dispense 1pm");     // Print "Waiting" after servo rotation
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" stop and -> 1");
			state = 1; // Move to next state
		}
		break;

	case 1: // Pause for 5 hours
		if (currentMillis - previousMillis >= fiveSeconds) {
			previousMillis = currentMillis;
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" done waiting, -> 2");
			state = 2; // Move to next state
		}
		break;

	case 2: // Rotate servo for 1 second
		if (currentMillis - previousMillis < servoRunTime) {
			feederServo.write(60); // Rotate servo
			if (!once) {
				Serial.print(millis() / 1000); Serial.print(" ");
				Serial.println("Dispensing 1pm");  // Print "Dispensing" when servo rotates
				once = true;
			}
		} else {
			once = false;
			feederServo.write(90);  // Stop rotation
			previousMillis = currentMillis;
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" stop and -> 3");
			//Serial.println("Next dispense 6pm");     // Print "Waiting" after servo rotation
			state = 3; // Move to next state
		}
		break;

	case 3: // Pause for 5 hours
		if (currentMillis - previousMillis >= fiveSeconds) {
			previousMillis = currentMillis;
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" done waiting, -> 4");
			state = 4; // Move to next state
		}
		break;

	case 4: // Rotate servo for 1 second
		if (currentMillis - previousMillis < servoRunTime) {
			feederServo.write(60); // Rotate servo
			if (!once) {
				Serial.print(millis() / 1000); Serial.print(" ");
				Serial.println("Dispensing 6pm");  // Print "Dispensing" when servo rotates
				once = true;
			}
		} else {
			once = false;
			feederServo.write(90);  // Stop rotation
			previousMillis = currentMillis;
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" stop and -> 5");
			//Serial.println("Next dispense tomorrow 8am");     // Print "Waiting" after servo rotation
			state = 5; // Move to next state
		}
		break;

	case 5: // Pause for 14 hours / seconds
		if (currentMillis - previousMillis >= fourteenSeconds) {
			Serial.print(millis() / 1000); Serial.print(" ");
			Serial.println(" done waiting, -> 0");
			previousMillis = currentMillis;
			state = 0; // Restart the cycle
		}
		break;
	}
}

As a theoretical matter, the longer intervals should just work. It may be better one day to do the long timing using an RTC. This would also mean better management of power outrages.

a7

2 Likes

Is it required to append ul with 32400000?

No. The compiler knows how many digits are in the number before it is cast into the storage type.

1 Like

You are right. The first one I did broke, the second worked but not properly, then I gave up and bought a 360 instead.

1 Like

Or UL.

No, it is not. But it is one thing I checked, even though I was sure.

I am a fan of leaving out ink wherever possible. If a person knows the language, there are all kindsa places where one can leave off things others will claim are necessary…

However, it is sometimes just polite to put the unnecessary stuff in.

Some will always use { braces } even if the a block is just one simple statement. I don't:

  if (nDonuts == 0)
  {
    timeToMakeTheDonuts();
  }

Some will put ( parentheses ) in expressions to remove any doubt about their intention. I might, but probably not:

  if (((now - then) > period) && (nDonuts == 0))
  {
    timeToMakeTheDonuts();
  }

In the present case it would be polite to use UL just to keep anyone reading who does not know every corner of the language from needing to ask, or needing to do a quick experiment to confirm unsolidified knowledge.

a7

1 Like

I know that If() structure is followed by a subordinate claues(s). If there are more than one statements in the subordinate clause, they must be within pair of braces{}; else, it is not needed. However, I always put pair of braces {} for clarity.

ul/UL
Is there any case, where UL must be appended to get a correct result?

Yes.

  unsigned long millsInOneDay = 24 * 60 * 60 * 1000;

The right hand side, in an environment where int is 16 bits, is computed using 16 bit values.

Here is one place where explicitly making one of those an unsigned long will help.

But be careful.

void setup() {
  Serial.begin(115200);

  unsigned long x = 24 * 60 * 60 * 1000;
  Serial.println(x);

  unsigned long y = 24UL * 60 * 60 * 1000;
  Serial.println(y);

  unsigned long z = 24 * 60 * 60 * 1000UL;
  Serial.println(z);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Produces

23552
86400000
20864000

Only one of the three expressions is properly computed and assigned to the variable.

HTH

a7

2 Likes

Would appreciate to hear your opinion/reason for incorrect (23552,
86400000, 20864000) and correct (86400000 20864000) results. (I am not saying that 23552, 20864000 86400000 are wrong results; but, they are incorrect.) //Edit

Some of them did signed integer overflow and have undefined results.

23552 is 86400000 mod 65536. The bottom 16 bits of the correct result.

86400000 is correct.

In this last one, the computation proceeds in the 16 bit world,

20864 is (24 * 60 * 60) mod 65563

then switches to 32 bits when multiply by 1000UL, so 20864000.

a7

2 Likes

Yes. I am so old that there is nothing undefined about it at all, but I appreciate times has changed.

I've seen crap ton of code that still expects things to work, like rolling over an integer.

a7

1 Like