Min detect time with IR sensor

Right now I have a machine that is not staying down/engaged for the set time 20-30secs.
This machine cycles 1000x per day and is hard to tell when it fails.
My thought process was if the sensor detects something, delay 3 secs and test again.
If there is nothing there send a signal to the led, else do nothing.

The sensor works as intended and flashes when an object does not stay for long enough.

The issue is that if the object is detected for more than 3 secs the light stays on until the object is removed. I have attached the code below. Any suggestion or help would be greatly appreciated.

int SensorPin = 2;
int OutputPin = 13;

void setup() {
  Serial.begin(115200);
  pinMode(OutputPin, OUTPUT);
  pinMode(SensorPin, INPUT);
  
}

void loop() {
  int val = digitalRead(SensorPin);
  
  Serial.print("SensorPin Value: ");
  Serial.println(val);
  delay(10);// wait for 0.01s
    if(val==LOW){
      delay(3000);
        if(val<=HIGH){
       digitalWrite(OutputPin, HIGH);
       
       } 
     }
   else
      {
     digitalWrite(OutputPin, LOW); 
     }
  
 
}

Check WHEN the object is detected (change in state), enable a TIMER Flag, start a 3 second TIMER.

If the object disappears, reset the TIMER Flag.

If the TIMER Flag is set and the TIMER expires, disable the TIMER Flag AND turn on your LED for a period of time.

Okay thank you for that.
I tried that in a earlier iteration, but will try again and post that code if I have an error.

Thank you for the feedback!!!

Updated description:
We have a coating machine uses an arm to dip parts into a bath and holds them there for 30 secs as a voltage is applied to the bath. The control of this arm is PLC ladder logic and does not have a check for short cycling(not staying down for the set time). Using the IR detector I want to identify when the arm comes down that it stays there. If it does not stay down for 3 secs to send signal to the led light and exit the loop.

The failure happens instantaneously, the arm travels down and instantly travels back up.
So If the IR detects the arm(IR=LOW), delay 3 secs and check again if arm has moved(IR=HIGH) send signal to LED. If after 3 secs the arm is still there(IR=LOW) do nothing.

Ideally I would like it to end loop after failure is found and reset the Arduino to continue detecting.

This is meant to be a detection device to signal the operator there is an error. That way we can review the video footage of the PLC, hopefully finding the faulty component or narrowing it down.

Thank you for your patience this is my first time posting.

Please show us.

This is what I had for the switch case. I noticed though that TIME was actually a function, yet i cant find documentation on how to use it.

const int sensorMin = 0;    
const int sensorMax = 1;
int SensorPin = 2;
int OutputPin = 13;

void setup() {
  Serial.begin(115200);
  pinMode(OutputPin, OUTPUT);
  pinMode(SensorPin, INPUT);
    
}

void loop() {
  int val = digitalRead(SensorPin);
  Serial.print("SensorPin Value: ");
  Serial.println(val);
  int range = map(val, sensorMin, sensorMax, 0, 1);
  
    switch (val) {
  case 0:
     if(val==1);
      delay(3000);
      if (val==0){
    digitalWrite(OutputPin, HIGH);
    break;
  case 1:
    if(val==1);
      delay(3000);
      if (val==1){
    digitalWrite(OutputPin, LOW);
    break;
      
  }
}

That's a complete if statement, as is the other identical line.

They do nothing, remove them to help declarer the code.

Review how switch/case works or for this just use if/else.

The line with range = map... is also not contributing anything, lose it.

I did not study the code, just noticed those harmless but distracting , um, distractions.

a7

Haha okay will do thank you!
The if/else version only is in the first post, would you have any insight on that version?

So after many try's the delay function was stopping my code.
Trying this in switch case form but still not working. As soon as an object is detected the program exits with the light on. Any suggestions.
Hopefully this code is easier to read.

#define IR_SENSOR_PIN 2    // The Infrared sensor is connected to digital pin 2
#define LED_PIN 13         // The LED is connected to digital pin 13

enum State {
  OBJECT_NOT_DETECTED,
  OBJECT_DETECTED_LESS_THAN_5_SEC,
  OBJECT_DETECTED_MORE_THAN_5_SEC
};

State currentState = OBJECT_NOT_DETECTED;
unsigned long objectDetectedTimestamp = 1;

void setup() {
  Serial.begin(9600);
  pinMode(IR_SENSOR_PIN, INPUT);     // Infrared sensor is used as input
  pinMode(LED_PIN, OUTPUT);  // LED is used as output
  
  digitalWrite(LED_PIN, LOW);        // Initial state of LED is off
}

void loop() {
  int sensorValue = digitalRead(IR_SENSOR_PIN);  // Read the value from the sensor

  Serial.print("sensorPin Value: ");
  Serial.println(sensorValue);
  
  switch (currentState) {
    case OBJECT_NOT_DETECTED:
      if (sensorValue == LOW) {
        objectDetectedTimestamp = millis();
        currentState = OBJECT_DETECTED_LESS_THAN_5_SEC;
      }
      break;
    
    case OBJECT_DETECTED_LESS_THAN_5_SEC:
      if (sensorValue == HIGH) {
        currentState = OBJECT_NOT_DETECTED;
      } else if ((millis() - objectDetectedTimestamp) > 5000) {
        currentState = OBJECT_DETECTED_MORE_THAN_5_SEC;
      }
      break;

    case OBJECT_DETECTED_MORE_THAN_5_SEC:
      digitalWrite(LED_PIN, LOW);
      break;
  }

  // Turn on the LED and exit program if an object is detected for less than 5 seconds
  if (currentState == OBJECT_DETECTED_LESS_THAN_5_SEC && (millis() - objectDetectedTimestamp) < 5000) {
    digitalWrite(LED_PIN, HIGH);
    while (true); // Infinite loop to stop the program
  }
}
  if (currentState == OBJECT_DETECTED_LESS_THAN_5_SEC && (millis() - objectDetectedTimestamp) < 5000) {
    digitalWrite(LED_PIN, HIGH);
    while (true); // Infinite loop to stop the program
  }

The moment the switch is LOW this will evaluate and you are in your infinite loop.


Suggest you not use switch/case.

Suggest you place { and } braces on separate lines.

Infinite loops like you are using are a very bad idea.

Okay thank you!
I will remove the infinite loop.
Good to know I tried this with if/else but similar results(but had a infinite loop at the end so I will try without later today).
Thinking the issue is that millis - objectDetectedTimestamp will always be under 5 secs, satisfying both arguments even thou it has not waited long enough, not sure how to get around that.

#define IR_SENSOR_PIN 2    // The Infrared sensor is connected to digital pin 2
#define LED_PIN 13         // The LED is connected to digital pin 13

unsigned long objectDetectedTimestamp;
bool objectDetected = false;

void setup() {
  pinMode(IR_SENSOR_PIN, INPUT);     // Infrared sensor is used as input
  pinMode(LED_PIN, OUTPUT);          // LED is used as output
  
  digitalWrite(LED_PIN, LOW);        // Initial state of LED is off
}

void loop() {
  int sensorValue = digitalRead(IR_SENSOR_PIN);  // Read the value from the sensor

  if (sensorValue == LOW) {                      // If an object is detected
    if (!objectDetected) {                        // If this is the first detection
      objectDetectedTimestamp = millis();         // Record the detection time
      objectDetected = true;
    } 
else if ((millis() - objectDetectedTimestamp) > 5000) { // If the object is detected for more than 5 seconds
      digitalWrite(LED_PIN, LOW);                            // Turn off the LED
    }
  } 
else 
{
  objectDetected = false; // No object is detected, reset the flag
  }

  // If an object is detected for less than 5 seconds
  if (objectDetected && (millis() - objectDetectedTimestamp) < 5000) {
    digitalWrite(LED_PIN, HIGH); // Turn on the LED
  }
}

Okay I removed the infinite loops from both versions and they work great(switch case is clunky)
Thank you for that insight!
So how would you "break" the cycle?
Current state will work for my testing, but would like the light to stay on if under 5 secs until either hitting a button or restarting the loop by hitting the reset button.

Please show us your current sketch.

See if you can work your way through this example.

It should be quite close to what has been discussed.


#define PUSHED            LOW
#define RELEASED          HIGH

#define LEDon             HIGH
#define LEDoff            LOW

#define OBJECTdetected    LOW
#define OBJECTgone        HIGH

#define ENABLED           true
#define DISABLED          false

#define IR_SENSOR_PIN     2    
#define resetSwitch       3
#define heartbeatLED      12
#define LED_PIN           13   

bool detectedFlag       = DISABLED;

byte lastResetSwitch    = RELEASED;
byte lastIRstate        = OBJECTgone;

//timing stuff
unsigned long heartbeatTime;
unsigned long checkSwitchesTime;
unsigned long objectDetectedTime;


//                                      s e t u p ( )
//********************************************^************************************************
void setup()
{
  pinMode(IR_SENSOR_PIN, INPUT_PULLUP);
  pinMode(resetSwitch, INPUT_PULLUP);

  pinMode(heartbeatLED, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  digitalWrite(LED_PIN, LEDoff);

} //END of   setup()


//                                       l o o p ( )
//********************************************^************************************************
void loop()
{
  //************************************************              T I M E R  heartbeatLED
  //is it time to toggle heartbeat LED ?
  if (millis() - heartbeatTime >= 500ul)
  {
    //restart this TIMER
    heartbeatTime = millis();

    //toggle the LED
    digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
  }

  //************************************************              T I M E R  checkSwitchesTime
  //is it time to read the switches and sensors ?
  if (millis() - checkSwitchesTime >= 20ul)
  {
    //restart this TIMER
    checkSwitchesTime = millis();

    checkSwitches();
  }

  //************************************************              T I M E R  object timing
  //if the TIMER is enabled, has the TIMER expired ?
  if (detectedFlag == ENABLED && millis() - objectDetectedTime >= 5000ul)
  {
    //disable this TIMER
    detectedFlag = DISABLED;
    
    digitalWrite(LED_PIN, LEDoff);
  }

  //************************************************
  //other non blocking code goes here
  //************************************************

} //END of   loop()


//                             c h e c k S w i t c h e s ( )
//********************************************^************************************************
void checkSwitches()
{
  byte state;

  //*******************************************                       resetSwitch
  state = digitalRead(resetSwitch);

  //has there been a change reset switch state ?
  if (lastResetSwitch != state)
  {
    //update to this new state
    lastResetSwitch = state;

    //is the reset switch pushed ?
    if (state == PUSHED)
    {
      //disable object TIMER
      detectedFlag = DISABLED;
      
      digitalWrite(LED_PIN, LEDoff);
    }

  } //END of this switch

  //*******************************************                       IR_SENSOR
  state = digitalRead(IR_SENSOR_PIN);

  //has there been a change in the sensor state ?
  if (lastIRstate != state)
  {
    //update to this new state
    lastIRstate = state;

    //do we see an object ?
    if (state == OBJECTdetected)
    {
      digitalWrite(LED_PIN, LEDon);

      //enable TIMER
      detectedFlag = ENABLED;

      //start the detection TIMER
      objectDetectedTime = millis();
    }

    //object has disappeared
    else
    {
      //disable TIMER
      detectedFlag = DISABLED;
      
      digitalWrite(LED_PIN, LEDoff);
    }
    
  } //END of this sensor

} //END of   checkSwitches()



//********************************************^************************************************

EDIT

Added comments.

since the above is outside the condition testing the state of the IR sensor, it will be true as soon as objectDetected is set true. the 5 sec period is almost certainly < 5 sec.

look this over

#define IR_SENSOR_PIN 2
#define LED_PIN 13         // The LED is connected to digital pin 13

unsigned long objectDetectedTimestamp;
bool objectDetected = false;

enum { Idle, Pending, Detected };
int state;

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    int sensorValue = digitalRead (IR_SENSOR_PIN);
    delay (50);                                 // debounce switch

    if (sensorValue == LOW) {
        switch (state)  {
        case Idle:
            Serial.println ("triggered");
            objectDetectedTimestamp = msec;
            state = Pending;
            break;

        case Pending:
            if ((msec - objectDetectedTimestamp) > 5000) {
                digitalWrite (LED_PIN, HIGH);  // Turn on the LED
                Serial.println ("detected");
                state = Detected;
            }
            break;

        case Detected:
            break;
        }
    }

    else if (Idle != state) {
        state = Idle;
        Serial.println ("released");
        digitalWrite (LED_PIN, LOW);            // turn off LED
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode (IR_SENSOR_PIN, INPUT_PULLUP); // Infrared sensor is used as input
    pinMode (LED_PIN, OUTPUT);          // LED is used as output
    digitalWrite (LED_PIN, LOW);        // Initial state of LED is off
}

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