Count when a sensor value is above a threshold

Hi to all,

probably, the solution is stupid, but I'm struggling finding how to be able to count how many times a sensor value is above a specific threshold.

I'm using Arduino UNO and a laser pointer and a OPT101 light sensor to detect when the laser beam is pointed towards the sensor.
I have a flat perforated bar which is moved by a DC motor and I need to stop it every time the OPT101 sensor detects two consecutive holes.

When the laser beam goes through the hole and it is read by the OPT101, then the sensor outputs values above 750.
While the bar moves, the sensor readings go from 0-50 when no holes is detected and above 750 when the hole is found.

void loop() {
  int opt101 = analogRead(A0);
  
  if (opt101 > 750){
  Serial.println("Hole detected!");
 }
  delay(5);       
}

I hope someone can help me! Thank you!

EDIT: I need to stop counting as soon as I read a value above 750 since if the bar move slowly, the light sensor could stay above 750 longer than usual.

1 Like

This is a state change detection problem. You have 2 states. Let's call them "no hole detected" and "hole detected". You simply need to count the number of times the state moves from "no hole detected" to "hole detected". When that is 2 then stop the motor. Now you just have to select reasonable thresholds to detect those states. It sounds you can base "no hole detected" on values less than some value and "hole detected" based on values greater than some value.

This is similar to performing state change detection with a digital input as described in the following tutorial:

StateChangeDetection

2 Likes

You need to add to your logic a flag/boolean to tell you that you have detected that particular hole already and don't want to detect it again until the sensor reading has gone back to 50 or below. When it does go low, reset your flag/boolean so you can process the next detection.

2 Likes

Then you probably don't need to use a precious analog pin for this, you can use any digital pin and use digitalRead().

2 Likes

Thank you a lot for all your suggestions!

I tried to change my code to reflect your tips in this way:

const int light_sensor = A0; // the pin that the pushbutton is attached to
const int ledPin = 13; // the pin that the LED is attached to


// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int hole_detected = 0;         // current state of the button
int lasthole_detected = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(light_sensor, INPUT);
   // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the pushbutton input pin:
  hole_detected = analogRead(light_sensor);
  // compare the hole_detected to its previous state
  if (hole_detected != lasthole_detected) {
    // if the state has changed, increment the counter
    if (hole_detected > 750) {
      // if > 750 than we found a hole!
      buttonPushCounter++;
      Serial.println("HOLE DETECTED! Holes Counter: ");
      Serial.println(buttonPushCounter);
    } else {
      // if the current state is LOW then no hole 
      Serial.println("NO HOLE");
    }
 
    delay(20);
  }

  lasthole_detected = hole_detected;

  if (buttonPushCounter % 2 == 0) {
   // do something
  } else {
   // do something
  }

}

The problem is that the hole counter continue to grow even if the bar is not moving.
For example, this is the output when the bar is not moving and the sensor is detecting a hole: the counter increments since it continues to detect the same hole.

NO HOLE
NO HOLE
NO HOLE
NO HOLE
HOLE DETECTED! Holes Counter:
1
HOLE DETECTED! Holes Counter:
2
HOLE DETECTED! Holes Counter:
3
HOLE DETECTED! Holes Counter:
4
HOLE DETECTED! Holes Counter:
5

The light sensor is placed at the bottom of the metal plate. You can find a video here.

You are re-detecting the hole whenever the light changes with any ADC noise. If you Serial.print(hole_detected); I'd bet you see different numbers each detection. Using just one threshold will make your system vulnerable to electrical/light noise. You can make it more robust by using two thresholds to give some hysteresis for latching between hole/not hole states.

I'd try a function that tracks when there is a hole and when there is not, and only counts up when it first sees a particular hole:

int checkHole(void) {
  static int state = 0; // private state variable
  if (state == 0 && analogRead(light_sensor) > 750)
  { // we found a hole!
    state = 1;
    buttonPushCounter++; // update global
  }
  if ( state == 1 && analogRead(light_sensor) < 50)
  { // no hole!
    state = 0;
  }
  return state;
}

void loop() {
  static int lastCount = 0 ;
  checkHole();
  if (buttonPushCounter != lastCount) {
    Serial.println("NEW HOLE DETECTED! Holes Counter: ");
    Serial.println(buttonPushCounter);
    lastCount = buttonPushCounter;
  }

  if (buttonPushCounter % 2 == 0) {
    // do something
  } else {
    // do something
  }

}
1 Like

Yes. My suggestion of using digitalRead() would also fix that. Why not try it out. You don't have to change the wiring to another pin, you can use digitalRead(light_sensor) and compare it to HIGH rather than 750.

2 Likes

I tried to use your code as you suggested, but it still increments the counter when it detects the first hole.


const int  light_sensor = A0;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int hole_detected = 0;         // current state of the button
int lasthole_detected = 0;     // previous state of the button

int checkHole(void) {
  static int state = 0; // private state variable
  if (state == 0 && analogRead(light_sensor) > 750)
  { // we found a hole!
    state == 1;
    buttonPushCounter++; // update global
  }
  if ( state == 1 && analogRead(light_sensor) < 100)
  { // no hole!
    state == 0;
  }
  return state;
}


void setup() {
  // initialize the button pin as a input:
  pinMode(light_sensor, INPUT);
   // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  static int lastCount = 0 ;
  checkHole();
  if (buttonPushCounter != lastCount) {
    Serial.println("NEW HOLE DETECTED! Holes Counter: ");
    Serial.println(buttonPushCounter);
    lastCount = buttonPushCounter;
  }

  if (buttonPushCounter % 2 == 0) {
    // do something
  } else {
    // do something
  }
  delay(10);
}

This is the output that I get as soon as it finds the first hole and the bar is stopped:

NEW HOLE DETECTED! Holes Counter:
1
NEW HOLE DETECTED! Holes Counter:
2
NEW HOLE DETECTED! Holes Counter:
3
NEW HOLE DETECTED! Holes Counter:
4
NEW HOLE DETECTED! Holes Counter:
5
NEW HOLE DETECTED! Holes Counter:
6
NEW HOLE DETECTED! Holes Counter:
7
NEW HOLE DETECTED! Holes Counter:
8
NEW HOLE DETECTED! Holes Counter:
9
NEW HOLE DETECTED! Holes Counter:

I tried to use digitalRead() and I get 1 when there is the hole and 0 otherwise.
However, this doesn't change the fast that it still increments the counter as soon as it gets the first hole.

Sorry, guys, it works!

I just copied and pasted the code without checking that there was a typos in the hole detecting loop.

1 Like

What were the typos? My code was completely untested, since I don't have a circuit configured like yours.

This

{ // we found a hole!
    state == 1;
    buttonPushCounter++; // update global
  }

Should I say oops! ? <-- IDK whose "typo" that be

Here it works good

https://wokwi.com/arduino/projects/322060672740360788

The delay(10); is entirely unnecessary.

a7

2 Likes

Aw, that was me -- with the double-equals, instead of assigning, it does a test and silently discards the result. I'll go up and edit my original error away.... I made the same mistake on the state = 0; transition as well.

1 Like

Yes, it was that one!
I didn't notice it at first glance, however, your code works perfectly now!
Thank you!

You're welcome.

I like these little state-machine functions for encapsulating features. You might extend it to track the pairs of holes, so it counts parts rather than holes.

1 Like

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