Using IR Sensors to Detect Fan Motion

Hello all, I am trying to write a code that uses two IR sensors to detect fan motion and lighting up an LED when motion is detected. I am using a black fan with a white strip for detection. Whenever the white strip passes the sensor it activates, lighting the LED. In order to prevent false readings, I am trying to get the LED to turn off after three seconds in case it lands on the white strip. However, my code instead is turning the LED off briefly every three seconds regardless of the sensor input. How can I fix my code so that the LED will turn off only after three seconds and with no change in the sensor? Right now this code is only using one sensor but I would like to use multiple eventually. Any help would be appreciated.

int IRSensor1 = 2;  // connect ir sensor 1 to arduino pin 2
int LED1 = 13;      // connect led1 to arduino pin 13

#define LED1_OFF     LOW                 // digitalWrite value to turn LED off
#define LED1_ON      HIGH                // digitalWrite value to turn LED on


// state machine state names
#define ST_OFF               0
#define ST_TIMING            1
#define ST_NO_MOTION         2


// LED on-time constant
const unsigned long TIME_LED1_ON = 3000ul;   // 3000mS == 3-seconds


void setup() 
{
  Serial.begin(9600);    
  pinMode (IRSensor1, INPUT);  // sensor1 pin INPUT
  pinMode (LED1, OUTPUT);      // LED1 pin OUTPUT

}

void loop()
{
    static byte
        stateLED1 = ST_OFF;
    static unsigned long
        timeLED1;
  

    unsigned long
        timeNow;
   
    timeNow  = millis();

    
  delay(1);
  int statusSensor1 = digitalRead (IRSensor1);

  
  switch( stateLED1 )
    {
        case ST_OFF:
            if ( statusSensor1 == LOW )
               { digitalWrite( LED1, HIGH ); // motion seen; turn on the LED
                 timeLED1 = timeNow;            // set the timeLED1 variable to the "current" time
                 stateLED1 = ST_TIMING;
               }
               break;

        case ST_TIMING:
            if ( timeNow - timeLED1 >= TIME_LED1_ON )     
               { digitalWrite( LED1, LOW );
                 stateLED1 = ST_NO_MOTION;
               }
              
               break;

        case ST_NO_MOTION:
            if ( statusSensor1 == HIGH )
               { digitalWrite( LED1, LOW );
                 stateLED1 = ST_OFF;
               }
               break;
    }
}

Pretty complicated for such a simple task. What maximum RPM is the fan? What is the strip sensor duty cycle (for what proportion of a revolution is the sensor active)?

The max RPM is around 6300, and the strip isn't that big, it takes up about 1/8th of the center part of the fan.

Why not just look for a dark to light transition, and then register a "stop" detection if none has been found after a certain time out interval?

I'm not sure I understand what you mean. I would like the LED to turn on and stay on as long as the fan is moving, and no matter what the status of the sensor is when it stops (high or low) I want the LED to turn off after three seconds. I'm struggling with how to define that in the code. Sorry if I'm being repetitive, but my level of knowledge isn't very high with this stuff just yet.

So something like

sensor ping comes in sets a thingy to 0.

watchdog routine using millis() for timing increments the thingy once a second.

If thingy reaches 3 then turn LED off.

As long as sensor ping comes in and sets thingy to 0 then the millis() time should not reach 3 so the LED stays on but if no pings for 3 seconds then led shuts off.

The gist of the above can be seen in this overcomplicated example

void fmqttWatchDog( void * paramater )
{
  int UpdateImeTrigger = 86400; //seconds in a day
  int UpdateTimeInterval = 85000; // get another reading when = UpdateTimeTrigger
  int maxNonMQTTresponse = 12;
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 5000; //delay for mS
  for (;;)
  {
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    xSemaphoreTake( sema_mqttOK, portMAX_DELAY ); // update mqttOK
    mqttOK++;
    xSemaphoreGive( sema_mqttOK );
    if ( mqttOK >= maxNonMQTTresponse )
    {
      ESP.restart();
    }
    UpdateTimeInterval++; // trigger new time get
    if ( UpdateTimeInterval >= UpdateImeTrigger )
    {
      TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
      UpdateTimeInterval = 0;
    }
  }
  vTaskDelete( NULL );
} //void fmqttWatchDog( void * paramater )

The code is written for an ESP32 but basically the code runs in a loop that increments mqttOK++; and when mqttOK++; reaches a preset value, reset everything. Elsewhere in another function if the function is working mqttOK++; gets reset back to 0.

You didn't write the code?

I wrote most of it myself. Had some help from a coworker and of course some googling too.

What fundamental (i.e. non code) logic does it execute? In other words, how does it work, in plain English?

Do you yet understand the simple alternative solution that two different people have posted here?

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