Object detection- help

Hello all,

I have been tasked with creating a part counter. They way in which I have made it so far is by using an arduino with an Ultrasonic sensor, along with a keypad and an LCD. Right now, I am using state detection to tell whether or not something is in the range or not in the range of the sensor. I want it to add to my count by one every time an object is detected in its range. Right now sometimes the count will go up by more than one when an object enters the range. How do I fix this? It almost feels as though the sensor doesn't know what to detect. Would an IR sensor work for this instead?

#include <Keypad.h> //libraries
#include <Adafruit_LiquidCrystal.h>

static int count = 0; //variable used as first number
Adafruit_LiquidCrystal lcd_1(0);

bool sensorState = true;

//used for the 4x4
const byte ROWS = 4;  
const byte COLS = 4; 

bool blinking = false; // if TRUE, this will turn blinking on

//Pins for UltraSonic Sensor
const int TRIG = 13;
const int ECHO = 12;

long duration; // sets time used for UltraSonic Sensor
int cmdistance; //Gives the distance from sensor in cm

//used in state detection for the sensor to trigger countUp()
int buttonState=0;  
int lastButtonState=0;
int buttonPushCounter=0;

//tells the location the part number on the LCD
  void partLoc(){
      lcd_1.setCursor(7,1);
    }

//tells the location of the fab cell number on the LCD
  void fabLoc(){
      lcd_1.setCursor(11,0);
    }

//clears the lcd screen of numbers
  void clearScreen(){
      lcd_1.print("     ");
    }

//counts up the part number
  void countUp(){        
      ++count;
      partLoc();
      clearScreen();
        partLoc();
      lcd_1.print(count);
    for (int i = 7; i <= 16; i++) {  //turns off blinking in LCD spots 7-16 
      blinking=false;
        lcd_1.setCursor(i,1);
        }
    }

//counts down the part number
  void countDown(){
      if(count!=0){
          --count;
          partLoc();
        clearScreen();
          partLoc();
        lcd_1.print(count);
            partLoc();
            lcd_1.print(count);
          for (int i = 0; i <= 16; i++) {
        blinking=false;
          lcd_1.setCursor(i,1);
          }
          }
      }

//tells which buttons are the inputs for the 4x4
char hexaKeys [ROWS][COLS] ={
        {'1','2','3','A'},
        {'4','5','6','B'},
        {'7','8','9','C'},
        {'*','0','#','D'}
      };

//tells which pins are used for the 4x4
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};

Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup()
{ pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  Serial.begin(9600);
  lcd_1.begin(16, 2);
  lcd_1.print("Fab Cell #");
  lcd_1.setCursor(0,1);
  lcd_1.print("Part #");
  lcd_1.setCursor(11,0);
  lcd_1.blink();
}





void loop(){
  
  char customKey = customKeypad.getKey();
  
  // state detection system, detects how often an object is removed from the point of view
  //of the sensor.  Triggers count up every other time an input is read.  
  
  if (cmdistance ==10){
    buttonState = 1;
  }else{
    buttonState=0;
  }

  if (buttonState != lastButtonState) {
    if (buttonState == 1)  {
      buttonPushCounter++;
      //Serial.println("on");
      //Serial.print("number of button pushes: ");
      //Serial.println(buttonPushCounter);
    } else {
      //Serial.println("off");
      if (buttonPushCounter % 1 == 0){
      countUp();
      Serial.println(count);
      }
      ;
    }
  lastButtonState = buttonState;
  delay(50);
}

  //determines the distance away an object is, used in the state detection system
  digitalWrite(TRIG, LOW);                                                           
  delayMicroseconds(2);                                                             
  digitalWrite(TRIG, HIGH);                                                        
  delayMicroseconds(10);                                                               
  digitalWrite(TRIG, LOW);                                                             
  duration = pulseIn(ECHO, HIGH);   
  cmdistance = duration * (0.034 / 2)+1;
  //Serial.print("Distance in cm: ");
  //Serial.print (cmdistance);
  //Serial.println();                                                                    
  
  if (blinking){
    lcd_1.blink();
    }
  
  //Switchcase Statements

  switch (customKey){
    
    case 'C':
      countUp();
      break;

    case 'D':
      countDown();
      break;

    case '#':
      fabLoc();
      clearScreen();
      fabLoc();
      blinking = true;
      break;    
    }

  // Allows button input from buttons 0 - 9
  if ((customKey>='0') && (customKey <= '9')){
      lcd_1.print(customKey);
      for (int i = 7; i <= 16; i++) {
        blinking=false;
          lcd_1.setCursor(i,1);
          }
    }
  
  //When B is pressed the count resets to zero
    if (customKey=='*'){
      count=0;
      partLoc();
      lcd_1.print(count);
        lcd_1.setCursor(8,1);
        lcd_1.print("      ");
    for (int i = 0; i <= 16; i++) {
      blinking=false;
        lcd_1.setCursor(i,1);
        }
        Serial.print("good");
  }
}

What is the maximum rate that items might need to be counted? For example 2 items per second which is one item every 500ms. Then you can capture the time (using millis()) at which an object is detected, and ignore any further detections within 500ms of that time.

That is a good idea, I prefer a solution that isn't time based however because I need it to work with different kinds of objects.

Could it be set up to where the object breaks a IR light beam? That may be more reliable and easier to program.

Very vague.  Are the objects automobiles?  Insects?  Baked goods?

That does sound much easier. Unfortunately I am unfamiliar with exactly what you are talking about. It there an example that you could share with me.

cmdistance is a variable calculated from an analog sensor. It is not a good idea to compare it to an exact value, there is a good chance there will an error in the measurement or the float calculations. Better to compare it to a range of values close to the expected value. For example is it between 9 and 11.

Also, your code appears to be using the value of cmdistance before it is calculated. So in the first execution of loop(), cmdistance will probably be zero, and on subsequent executions of loop() it will be using the value calculated on the previous execution.

I suggest you review the sequence of your code lines in loop() and collect them into a sensible order. Also please use Tools->Auto Format before you post the updated code.

The objects are typically air conditioning covers that can range in size. They are placed into a fixture and fabricated to have all of their holes. This is where I would like to place the counter.

This code line is strange. The condition will always be true because any number modulo 1 is always 0. What is the purpose of this line of code?

It was previously a 2, because I initially thought I wanted it to trigger every other time the sensor was triggered. I have realized that it will not work for what I want. Because I first thought that the object passed through the sensor twice but it only does it once. I know it is unnecessary.

I faced a similar problem when I was designing a visitor counter. The problem was, when someone stood in front of the sensor, the visitor count kept on increasing by one continuously until the person moved away. But that was of course not what I wanted. I wanted to increase the count only by 1, for each person. To solve this problem, I calculated a threshold value of the nearest object's distance at the beginning of my code. In the loop function, there was always a comparison between the threshold value and the current value. The visitor count only increased by one, when the nearest object distance calculated by the SONAR was less than 10 cm and also the difference between the current value was less than a particular range. I am sharing some parts of my code. You can apply this method.

#define trigPin 8
#define echoPin 9
#define pinIR 7
// Define variables:
float duration=0.00;
float distance=0.00;
int visitor,sum,threshold,temp;

// declaring variables to hold the new and old IR states
boolean oldIRState = LOW;
boolean newIRState = LOW;


#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
  // Define inputs and outputs:
  pinMode(pinIR, INPUT);
  pinMode(trigPin, OUTPUT);
 
  pinMode(echoPin, INPUT);
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Visitor=");
  lcd.print(visitor);

  //Begin Serial communication at a baudrate of 9600:
  Serial.begin(9600);
}

void loop() {
  // Clear the trigPin by setting it LOW:
  newIRState = digitalRead(pinIR);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);

  // Trigger the sensor by setting the trigPin high for 10 microseconds:
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Read the echoPin, pulseIn() returns the duration (length of the pulse) in microseconds:
  duration = pulseIn(echoPin, HIGH);
  // Calculate the distance:
  distance = duration /58.82 ;

  // Print the distance on the Serial Monitor (Ctrl+Shift+M):
  Serial.print("Distance = ");
  Serial.print(distance);
  Serial.println(" cm");

  delay(1000);
  if(distance<=10 && abs(temp)>=70)
  {
    visitor++;
    lcd.clear();
    lcd.print("Visitor=");
    lcd.print(visitor);
   
  
  for(int i=0;i<500;i++)
 {

 sum +=distance;
 delay(5);

 }
 threshold = sum/500;
  }

temp=threshold-distance;

Thanks I appreciate it!