stacking delay for servo motor raise up time

Hello, i am new to arduino coding. i have a project that when a sensor senses an object a servo motor will raise up to 90 degrees for 15 seconds, so far i am successful on adding the 90 degrees and the 15 second raise up time, but i need that time to stack for an additional 15 seconds everytime it senses an object without having the servo motor return to 0 degrees.

#include <Servo.h>
int servoPin = 3;

int message = 0;
Servo Servo1;
void setup() {
Serial.begin(9600);
Servo1.attach(servoPin);
}

void loop() {
if (Serial.available() > 0 ) {
message = Serial.read();
if (message == ‘O’) {
Servo1.write(0);
delay(1000);
Servo1.write(90);
delay(15000);
Servo1.write(0);
}
}
}

Use timestamp instead of delay(). timestamp will be reset each time you each time it senses an object without having the servo motor return to 0 degrees. You can refer to BlinkWithoutDelay example to see how to implement timestamp

The functions delay() and delayMicroseconds() block the Arduino until they complete. Have a look at how millis() is used to manage timing without blocking in Several Things at a Time.

And see Using millis() for timing. A beginners guide if you need more explanation.

...R

Apart from what IoT_hobbyist and Robin2 say, you need in this kind of thing to manage the start conditions, for safety and practical reasons.

As it stands, the servo attaches at 90 degrees because you're not telling it to do otherwise. Then the first 'O' tells it to move down for a second before going up for 15 then down to finish.

But after that, it's already down for the next cycle, since each cycle ends with it down.

What's special about the first cycle that it goes down from 90? You could perhaps (not knowing the actual application) do a Servo1.move(0) before the Servo1.attach() so it always starts at 0.

Then each cycle needn't explicitly start with a Servo1.write(0) since it's already there, and it just needs to wait a second before heading upwards. (Presumably there's a reason for that second before going up? Perhaps it's for safety to get people to stand clear?)

I'd go for a state machine* approach like this, with a variable called say state:

  • Start with state = 0, say "idle" for human readability, with servo attached at 0 (ie down, unless there was a compelling reason to have started it at 90?), and continuously reading serial for a 'O'. You would have a variable called say stayUpFor, initialised 0 in idle.
  • If it gets a 'O' make state =1 (say "standClear" for humans) and start a millis() based timer for the first second where it waits lowered (assuming that's actually a need, perhaps safety). Add 15000 to stayUpFor, which is then 15000 since this is the first time we got a 'O'. Continuously read Serial, and if you get a 'O', add 15000 to stayUpFor, assuming commands could be arriving in this state? When the 1 second timer expires, set state = 2 ("raised" say, for humans)
  • On arrival in state=2, raise the servo and start a new millis() based timer. Continuously read Serial, and if you get a 'O', add 15000 to stayUpFor . Check the elapsed time in this state against stayUpFor (which would be increasing by new arrivals of 'O' if any), and when it expires, lower the servo and set state=0.
  • (Arrival back at state=0 sets stayUpFor back to 0, so the next 'O' is a first 'O' for a new cycle)
  • Rinse and repeat

(*Don't be put off by the phrase "state machine" and its state variable.... it's really just a variable that keeps track of where we are in the process, and if state=x do stuff and set state to y or z or wherever it's supposed to go next, if it's z do otherStuff. (Although it's common to use switch...case instead of an "if" spaghetti.)

This may provide some ideas

enum states
{
  INITIAL_WAIT,
  TIMING_IN_PROGRESS
};
byte currentState = INITIAL_WAIT;

unsigned long startTime;
unsigned long currentTime;
unsigned long waitTime = 5000;
byte currentInputState = HIGH;
byte previousInputState = HIGH;
const byte inputPin = A3;

void setup()
{
  Serial.begin(115200);
  pinMode(inputPin, INPUT_PULLUP);
  Serial.println(F("Waiting for initial input"));
}

void loop()
{
  currentTime = millis();
  switch (currentState)
  {
    case INITIAL_WAIT:
      if (readInput())
      {
        startTime = currentTime;
        currentState = TIMING_IN_PROGRESS;
        Serial.println(F("Starting timing"));
      }
      break;
    case TIMING_IN_PROGRESS:
      if (currentTime - startTime >= waitTime)
      {
        currentState = INITIAL_WAIT;
        Serial.println(F("Back to waiting for initial input"));
      }
      else if (readInput())
      {
        startTime = currentTime;
        Serial.println(F("waitTime restarting"));
      }
      break;
  }
}
boolean readInput()
{
  previousInputState = currentInputState;
  currentInputState = digitalRead(inputPin);
  if (currentInputState != previousInputState && currentInputState == LOW)
  {
    return true;
  }
  else
  {
    return false;
  }
}