Creating an alarm for detecting objects that are stuck for a period of time

Hey there! I am trying to build an alarm system in tinkercad that detects objects if they are in that position for a period of time. Everytime I bring the object close to range( I have set it to 200 cm), I want the alarm to wait for 10 secs and then set of periodically for 0.5 seconds. But the alarm is beeping at a loop for 10 secs. It would be very helpful if I can get some suggestions. The tinkercad simulation link with code is attached. Thanks!
https://www.tinkercad.com/things/dnkUZEQhIWz?sharecode=1rG0Rxcs6A7tsZ2DTLUQFh0X34JyDiy7lqiCpsVcYvw

Better to post the code here. I'll do that for you below.

The sketch is doing what you told it to. If an object is in range it waits 10 seconds and sounds the alarm. How do you want it to act differently? Did you want it to sound the alarm only if the object has been there for 10 seconds?

Note: If there is no object in range, the 'distance' will be zero. You may want to treat that as "out of range" rather than "very close".

Note: The default pulseIn() timeout is 1 second. You can specify a shorter timeout as a third argument. I like a timeout of 30000 microseconds which allows measurements out to about 6 meters. That's beyond the usual range of the HC-SR04 so you will get faster response without missing any data.
duration = pulseIn(echo, HIGH, 30000);

// C++ code
#define LED 2
#define trig 4
#define echo 7
#define piezo 8
long distance;
long duration;

void setup()
{
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(7, INPUT);
  pinMode(8, OUTPUT);
  Serial.begin(9600);
  delay(10000);
}

void loop()
{
  digitalWrite(trig, LOW);
  delay(2);
  digitalWrite(trig, HIGH);
  delay(10);
  digitalWrite(trig, LOW);
  duration = pulseIn(echo, HIGH);
  distance = duration * 0.034 / 2;
  Serial.println("Distance:");
  Serial.print(distance);
  if (distance > 200)
  {
    digitalWrite(2, LOW);
    noTone(8);
    delay(1);
    digitalWrite(2, LOW);
    noTone(8);
    Serial.println("Out of range");
  }
  else if (distance < 200)
  {
    delay(10000);
    digitalWrite(2, HIGH);
    tone(8, 200);
    delay(500);
    digitalWrite(2, LOW);
    noTone(8);
    delay(500);
    Serial.println("Object detected");
  }
  else  // If distance is exctly 200
  {
    digitalWrite(2, LOW);
    noTone(8);
  }
}

What I want to do is everytime I bring the object within range it should wait 10 secs and then beep every 0.5 seconds till it is taken out. Instead the output is the alarm beeps every ten seconds.

You'll have to get rid of the delay() statements to achieve all that. For example, during the 10 seconds delay, the program can do nothing. Look at the example "blink without delay" sketch to see how using millis() timers can replace delay() but without blocking the rest of the activities.
Your problem, with these states and transitions, could be solved with something similar to a simple finite state machine:

Waiting_for_object
Object_Detected
Waiting_for_object_movement (up to 10 seconds)
timeout (no movement in previous 10 seconds)
in_alarm_cycle ( beep once per 0.5 seconds) until problem cleared.

I think one solution is to add a flag ('alarm') to distinguish between the first beep (after a 10-second delay) and subsequent beeps (after a 1/2-second delay).

// C++ code
#define LED 2
#define trig 4
#define echo 7
#define piezo 8
long distance;
unsigned long duration;
boolean alarm = false;

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(piezo, OUTPUT);
  Serial.begin(9600);
  delay(10000);
}

void loop()
{
  digitalWrite(trig, LOW);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duration = pulseIn(echo, HIGH, 30000);
  distance = duration * 0.034 / 2;
  Serial.print("Distance: ");
  Serial.println(distance);
  
  if (distance == 0 || distance > 200)
  {
    if (alarm)
    {
      Serial.println("Out of range");
    }
    alarm = false;
    digitalWrite(LED, LOW);
    noTone(piezo);
  }
  else // Object closer than 200 cm
  {
    if (!alarm)
    {
      Serial.println("Object detected");
      delay(10000); // Ten second delay before first beep
      alarm = true;
    }
    digitalWrite(LED, HIGH);
    tone(piezo, 200);
    delay(500);
    digitalWrite(LED, LOW);
    noTone(piezo);
    delay(500);  // Half-second delay between beeps
  }
}
// C++ code
#define LED 2
#define trig 4
#define echo 7
#define piezo 8
long distance;
unsigned long duration;
unsigned long startDetect = 0;
unsigned long previousMillis = 0;
const long timeLimit = 10000;
boolean alarm = false;


void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(trig, OUTPUT);
  pinMode(echo, INPUT);
  pinMode(piezo, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  digitalWrite(trig, LOW);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);
  duration = pulseIn(echo, HIGH, 30000);
  distance = duration * 0.034 / 2;
  Serial.print("Distance: ");
  Serial.println(distance);

  if (distance == 0 || distance > 200)
  {
    if (alarm)
    {
      Serial.println("Out of range");
    }
    alarm = false;
    digitalWrite(LED, LOW);
    noTone(piezo);
  }
  else // Object closer than 200 cm
  {
    if (!alarm)
    {
      Serial.println("Object detected");
      startDetect = millis();
      alarm = true;
    }
    else
    {
      unsigned long currentMillis = millis();
      if (currentMillis - startDetect >= timeLimit) {
        digitalWrite(LED, HIGH);
        tone(piezo, 200);
        delay(500);
        digitalWrite(LED, LOW);
        noTone(piezo);
        delay(500);  // Half-second delay between beeps
      }
    }
  }
}

not tested

It would be possible to use a ESP32-CAM aimed at a location and determine if an object has entered the field of view.

I have a solar powered weather station. I use an ESP32-CAM to take regular pictures of the weather stations general location. The ESP32-CAM downsizes the images and sends them to another ESP32. The other ESP32 uses a ML algorithm, Simple machine learning with Arduino KNN | Arduino Blog to compare multiple captured images to determine if an object has entered or left the field of view.

Something to consider after realizing that SR04's are less than ideal.

Also consider using LIDAR. I have used a TFMini on a hexapod to create 'images' that were used to navigate a hexapod around obstacles.

Your sketch in Wokwi simulation:

Click the start button to start the simulation. During running, click on the sensor to change it. To be able to save a copy to your own projects, you have to log in (it's free).

The code does work well. But when the object is within 200cm when the simulation is started, it takes an initial 20 secs for the alarm to set off. Also, irrespective of whether HC-SR04 is selected for changing the object position, the alarm automatically sets of after 20 secs. When take out the delay() in void setup(), it is cut to 10 secs. I don't know if this is a real issue or thats just how tinkerCAD works.

Noted. What I am working on is an alarm system for fixing in roadside drain covers and outlets to detect solid waste clog. The tinkerCAD simulation is just a basic understanding. For application, I am planning to wirelessly send sensor data through lora module to mobile phones so that the device gets a notification if a clog is detected. I should also design a water flow sensor specifically for this application.

2 water flow sensors one upstream and one downstream of the drainage thingy should register near same flow if not clogged?

The alarm automatically sets of after 20 secs without clicking the sensor. I guess its just how simulation works?

Well I havent gotten to that part yet.

I faced the same problem I did for the other solutions.

It works rather well in Wokwi.

void setup()
{
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(7, INPUT);
  pinMode(8, OUTPUT);
  Serial.begin(9600);
  delay(10000);
}

See that 10-second delay you put at the end of setup()? Remove that if you don't want to wait 10 seconds before waiting 10 seconds.

Yeah I got it. Thanks a lot!

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