Bidirectional Visitor Counter

Hi together,

Currently I am trying to build a bidirectional visitor counter using two HC-SR04 ultrasonic sensors. The number of people is displayed on a little 4 digits 7 segment display.

Once finished the setup is planned to be installed in a doorway to count the number of people in a room. I want to use this information for home automation (light control, pause/resume TV etc.).

Since I am not very good at programming (just learned some basics during collage) I hope you can help me with my code (see below).

I believe the problem is located within the function CountPeople().

I have written several versions of this function without getting close to a solution.

With the current version of the code the display starts with a “0” as intended. But it doesn’t count objects. Sometimes (I have a hard time reproducing the results) the value changes to “F”, “C” or “E”.

Maybe one of you can find the error.

//####################################### LIBRARIES EINBINDEN #######################################
#include <TM1637Display.h>   // 4-Digits, 7Segment Display Library 

//######################################### PINS DEFINIEREN #########################################
#define trigPin1 2           // PIN #1 (Sender)    Sensor #1 (Flur Seite) 
#define echoPin1 3           // PIN #2 (Empfänger) Sensor #1 (Flur Seite) 
#define trigPin2 4           // PIN #1 (Sender)    Sensor #2 (Raum Seite)
#define echoPin2 5           // PIN #2 (Empfänger) Sensor #2 (Raum Seite
const int CLK = 6;           // PIN #1 Display 
const int DIO = 7;           // PIN #2 Display 

//###################################### GLOBALE VARIABLEN ##########################################
int people = 0;             // Anzahl Personen

boolean in;                 // Hat jemand den Raum betreten (True/False)

unsigned long time1;        // Zeit zu der Sensor #1 (Flur Seite) ausgelöst wird
unsigned long time2;        // Zeit zu der Sensor #2 (Raum Seite) ausgelöst wird

double doorWidth = 50;      // Tür Breite

unsigned long duration1;    // Zeit die Signal von Sensor #1 (Flur Seite) bis zum Objekt benötigt 
double distance1;           // Entfernung zwischen Sensor #1 (Flur Seite) und Objekt

unsigned long duration2;    // Zeit die Signal von Sensor #2 (Raum Seite) bis zum Objekt benötigt 
double distance2;           // Entfernung zwischen Sensor #2 (Raum Seite) und Objekt

//################################## DISPLAY INITIALISIEREN #########################################
TM1637Display display(CLK, DIO);

//###################################################################################################
//######################################## FUNKTIONEN ###############################################
//###################################################################################################

//##################################### INITIALISIERUNG #############################################
void setup() 
{
  Serial.begin(9600);           // Startet die serielle Kommunikation

  pinMode(trigPin1, OUTPUT);    // Definiere trigPin1 als Output
  pinMode(echoPin1, INPUT);     // Definiere echoPin1 als Input

  pinMode(trigPin2, OUTPUT);    // Definiere trigPin2 als Output
  pinMode(echoPin2, INPUT);     // Definiere echoPin2 als Input

  display.setBrightness(0x0a);  // Setzt Display Helligkeit auf maximal
}

//#################################### MESSUNG SENSOR 1 ############################################
void Sensor1() 
{
  digitalWrite(trigPin1, LOW);   // Beendet Senden von Sensor #1 (Flur Seite) für 2 micro sec
  delayMicroseconds(2);          
  digitalWrite(trigPin1, HIGH);  // Starten Senden von Sensor #1 (Flur Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);   // Startet Empfangen von Senor #1 (Flur Seite)

  duration1 = pulseIn(echoPin1, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance1 = duration1 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C)

  if (distance1 < doorWidth)    // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time1 = millis();           // Setze time1 = aktueller Zeitpunkt
  }
}

//#################################### MESSUNG SENSOR 2 ############################################
void Sensor2() 
{
  digitalWrite(trigPin2, LOW);   // Beendet Senden von Sensor #2 (Raum Seite) für 2 micro sec
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);  // Starten Senden von Sensor #2 (Raum Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);   // Startet Empfangen von Senor #2 (Raum Seite)

  duration2 = pulseIn(echoPin2, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance2 = duration2 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C)

  if (distance2 < doorWidth)   // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time2 = millis();          // Setze time1 = aktueller Zeitpunkt
  }
}


//######################################## PERSONEN ZÄHLEN ########################################
void CountPeople() 
{
     if (((time1 - time2) < 0)) 
     {
       people ++;
       time1 = 0;
       time2 = 0;
     }
     else if (((time1 - time2) > 0)) 
    {
      people --;
      time1 = 0;
      time2 = 0;
    }
}

//###################################### AUSGABE AUF DISPLAY ######################################
void DisplayPeople()
{ 
 display.showNumberDec(people);
}

//############################## REGELMÄßIGER AUFRUF ALLER FUNKTIONEN #############################
void loop() 
{
  Sensor1();          // messen mit Sensor #1 
  Sensor2();          // messen mit Sensor #2
  CountPeople();      // Personenanzahl berechnen
  DisplayPeople();    // Ausgabe auf Display
}

Thanks in advance,
Chris

There have been many Forum Threads about systems for counting people entering and leaving a room. I'm not aware of any that worked satisfactorily. It is very easy for sensors to confuse people leaving and entering.

...R

void CountPeople() 

{
    if (((time1 - time2) < 0))
    {
      people ++;
      time1 = 0;
      time2 = 0;
    }
    else if (((time1 - time2) > 0))
    {
      people --;
      time1 = 0;
      time2 = 0;
    }
}

So what happens when somebody has triggered the first timer but not yet reached the second? time1 is greater than zero and time2 is zero. So ((time1 - time2) > 0) is true and it decrements the counter, setting time1 back to zero.

First check that both times are not zero. Also think about what happens after you've detected the person move from sensor 1 to sensor2 but they're still in motion in front of sensor2 after you've successfully counted them.

This looks like a reasonable attempt to solve a very tricky problem. With ultrasonic distance sensors, you will get a lot more useful data than basic beam-break sensors. You are going to have to do a lot more decision-making with the ultrasonic data. Like detect how fast the person is moving when they hit sensor 1 (how round their belly is) and check that sensor2 sees a similar speed.

It is very easy for sensors to confuse people leaving and entering.

The sensor would not get me confused.

How wide is the doorway? Can more than one person get through at the same time? If so, then it's going to be difficult to get a reliable occupancy figure.

One option would be to have small PIR sensors (or beam break sensors) each side of the door so that they cannot interfere with each other and then see what order they trigger in.

Sensor A door Sensor B
(outside room) (inside room)

So if A triggers followed by B then someone has entered the room, if B triggers followed by A then someone has left the room. Only issue might be if 'someone' is 'hanging' in the doorway. But it should get you close to what you want.

:slight_smile:

You are calling CountPeople before you know both time1 and time2 have been set - if only one has
been set then you'll compare it to zero and get a false result.

You need a state machine to handle this kind of problem - once you enter a state that means both
times have been measured, only then can you think about changing people.

Alternatively you can use the state-machine transitions directly to do the counting.

Skywatch, at least glance at the code. The OP is already using all of those ideas.

The code even contains the width of the doorway.

Thanks for all the replies!

So what happens when somebody has triggered the first timer but not yet reached the second? time1 is greater than zero and time2 is zero. So ((time1 - time2) > 0) is true and it decrements the counter, setting time1 back to zero.

You are calling CountPeople before you know both time1 and time2 have been set - if only one has been set then you'll compare it to zero and get a false result.

That was a good hint. Thanks a lot. I have adopted the code accordingly (see below)

With ultrasonic distance sensors, you will get a lot more useful data than basic beam-break sensors.

I considered using beam-break sensors but I am trying to avoid installing electronics on both sides of the doorway.

You are going to have to do a lot more decision-making with the ultrasonic data. Like detect how fast the person is moving when they hit sensor 1 (how round their belly is) and check that sensor2 sees a similar speed.

I know I have a lot more possibilities with an ultrasonic sensor but do I have to use them? I am not interested in the speed/ location etc. of a person. All I want to know is: Has a person passed both sensors and if yes from which direction?

How wide is the doorway? Can more than one person get through at the same time? If so, then it's going to be difficult to get a reliable occupancy figure.

It’s a standard (European) doorway. Approximately 80cm (31,5”) wide. If you try hard to walk through the door side by side with an other person that’s probably possible. Anyhow, this is a situation I do not expect to happen.

One option would be to have small PIR sensors (or beam break sensors) each side of the door so that they cannot interfere with each other and then see what order they trigger in.

I have considered using two PIR sensors but because of the size I decided to go with the ultrasonic ones. Or is there an advantage of PIR over ultrasonic for this purpose?
In case of interference problems I thought about installing the two sensors in an angle and make them point towards the room / floor. In this case I could also measure the distance to the person and use this value to help detecting if a person is entering or exiting. But for aesthetic reasons I am trying to set everything up as compact(/flat) and centralized as possible.

This are the changes I did to the code:

  1. I wrote a function to detect if a something has passed both sensors:
void PassControll()
{
  if (time1 != 0 && time2 != 0)
  {
    pass = true;
  }
  else if (time1 == 0 && time2 != 0)
  {
    pass = false;
  }
  else if (time1 != 0 && time2 == 0)
  {
    pass = false;
  }
    else if (time1 == 0 && time2 == 0)
  {
    pass = false;
  }
}
  1. I modified the Count Function in a way that it only counts in case someone has passed both sensors
void CountPeople() 
{
 if (pass = true)
 {    
     if (((time1 - time2) < 0)) 
     {
       people ++;
       time1 = 0;
       time2 = 0;
     }
     else if (((time1 - time2) > 0)) 
    {
      people --;
      time1 = 0;
      time2 = 0;
    }
 }
 else if (pass = false)
 {
 }
}

My program is still not working probably. I get a reaction every time something passes one(!) sensor. And the display is showing hexadecimal numbers (I guess?). Has anyone an other hint for me?

Additionally I came up with the following scenario which would cause an error:
Person wants to enter the room. Passes sensor #1, changes mind and leaves without triggering sensor #2. Some time later other person wants to exit the room. Passes sensor #2, changes mind and stays inside without triggering sensor #1. Now both sensors have been triggered and the counter will count +1.
I think this problem can be solved by setting both time variables back to zero when the second sensor has not been triggered within 15sec after the initial triggering. I will integrate the according code once the current code is working.

I also plan to add a button to the system for easy correction of the number.

Regrads,
Chris

if (pass = true)

I think you meant to use ==

You should make your PassControl() function one that returns a true or false value. Then you could have written the above as:

if(PassControl())

Since you didn't post any display code, we can't debug your display. It's more helpful if you post all your code. Then we get a complete working program at this end. It also helps because the problem is often elsewhere in the code that you don't think is important because you don't understand what that other code does.

For your second scenario, I would modify PassControl() to do this work - reset any timer if it gets longer than 15 seconds.

Hi,

I think you meant to use ==

Actually, I did this mistake. Since I have corrected it the display changes the value every time something passes both sensors. The values displayed still don’t make sense. Changing between all values of the hexadecimally system.

Here is my full code:

//####################################### LIBRARIES EINBINDEN #######################################
#include <TM1637Display.h>   // 4-Digits, 7Segment Display Library 

//######################################### PINS DEFINIEREN #########################################
#define trigPin1 2           // PIN #1 (Sender)    Sensor #1 (Flur Seite) 
#define echoPin1 3           // PIN #2 (Empfänger) Sensor #1 (Flur Seite) 
#define trigPin2 4           // PIN #1 (Sender)    Sensor #2 (Raum Seite)
#define echoPin2 5           // PIN #2 (Empfänger) Sensor #2 (Raum Seite
const int CLK = 6;           // PIN #1 Display 
const int DIO = 7;           // PIN #2 Display 

//###################################### GLOBALE VARIABLEN ##########################################
int people;                 // Anzahl Personen

boolean pass;               // Hat jemand den Raum betreten (True/False)

unsigned long time1;        // Zeit zu der Sensor #1 (Flur Seite) ausgelöst wird
unsigned long time2;        // Zeit zu der Sensor #2 (Raum Seite) ausgelöst wird

double doorWidth = 50;      // Tür Breite

unsigned long duration1;    // Zeit die Signal von Sensor #1 (Flur Seite) bis zum Objekt benötigt 
double distance1;           // Entfernung zwischen Sensor #1 (Flur Seite) und Objekt

unsigned long duration2;    // Zeit die Signal von Sensor #2 (Raum Seite) bis zum Objekt benötigt 
double distance2;           // Entfernung zwischen Sensor #2 (Raum Seite) und Objekt

//################################## DISPLAY INITIALISIEREN #########################################
TM1637Display display(CLK, DIO);

//###################################################################################################
//######################################## FUNKTIONEN ###############################################
//###################################################################################################

//##################################### INITIALISIERUNG #############################################
void setup() 
{
  Serial.begin(9600);           // Startet die serielle Kommunikation

  pinMode(trigPin1, OUTPUT);    // Definiere trigPin1 als Output
  pinMode(echoPin1, INPUT);     // Definiere echoPin1 als Input

  pinMode(trigPin2, OUTPUT);    // Definiere trigPin2 als Output
  pinMode(echoPin2, INPUT);     // Definiere echoPin2 als Input

  display.setBrightness(0x0a);  // Setzt Display Helligkeit auf maximal
}

//################################### Durchgangs Kontrolle ###########################################
void PassControll()
{
  if (time1 != 0 && time2 != 0)
  {
    pass = true;
  }
  else if (time1 == 0 && time2 != 0)
  {
    pass = false;
  }
  else if (time1 != 0 && time2 == 0)
  {
    pass = false;
  }
    else if (time1 == 0 && time2 == 0)
  {
    pass = false;
  }
}
//#################################### MESSUNG SENSOR 1 ############################################
void Sensor1() 
{
  digitalWrite(trigPin1, LOW);   // Beendet Senden von Sensor #1 (Flur Seite) für 2 micro sec
  delayMicroseconds(2);          
  digitalWrite(trigPin1, HIGH);  // Starten Senden von Sensor #1 (Flur Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);   // Startet Empfangen von Senor #1 (Flur Seite)

  duration1 = pulseIn(echoPin1, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance1 = duration1 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C)

  if (distance1 < doorWidth)    // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time1 = millis();           // Setze time1 = aktueller Zeitpunkt
  }
}

//#################################### MESSUNG SENSOR 2 ############################################
void Sensor2() 
{
  digitalWrite(trigPin2, LOW);   // Beendet Senden von Sensor #2 (Raum Seite) für 2 micro sec
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);  // Starten Senden von Sensor #2 (Raum Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);   // Startet Empfangen von Senor #2 (Raum Seite)

  duration2 = pulseIn(echoPin2, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance2 = duration2 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C)

  if (distance2 < doorWidth)   // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time2 = millis();          // Setze time1 = aktueller Zeitpunkt
  }
}


//######################################## PERSONEN ZÄHLEN ########################################
void CountPeople() 
{
 if (pass == true)
 {    
     if (((time1 - time2) < 0)) 
     {
       people ++;
       time1 = 0;
       time2 = 0;
     }
     else if (((time1 - time2) > 0)) 
    {
      people --;
      time1 = 0;
      time2 = 0;
    }
 }
 else if (pass == false)
 {
 }
}

//###################################### AUSGABE AUF DISPLAY ######################################
void DisplayPeople()
{ 
 display.showNumberDec(people);
}

//############################## REGELMÄßIGER AUFRUF ALLER FUNKTIONEN #############################
void loop() 
{
  PassControll();     // Durchgangs Kontrolle
  Sensor1();          // messen mit Sensor #1 
  Sensor2();          // messen mit Sensor #2
  CountPeople();      // Personenanzahl berechnen
  DisplayPeople();    // Ausgabe auf Display
}

Everything affecting the display should be:

#include <TM1637Display.h> //worked fine on other projects
const int CLK = 6;           // PIN #1 Display 
const int DIO = 7;           // PIN #2 Display
TM1637Display display(CLK, DIO);
int people; //global
void setup()
  {
  display.setBrightness(0x0a);  // Set Brightness to max
  }
void DisplayPeople()
  { 
  display.showNumberDec(people); //function worked fine on other projects
  }
void loop() 
  {
  DisplayPeople();    // Ausgabe auf Display
  }

Is there any chance this display is wired incorrectly?

Hi,

thanks for the response. I double checked the wiring and it's correct.

I did some trouble shooting but without success.

But I have ordered some PIR sensors (HC-SR501) and some radar sensors (RCWL-0516) and as soon as I receive the parts and get the code running I will set them up side by side and evaluate which one is the best for the intended purpose.

Regards,
Chris

Update:
This is what the serial output looks like:

time2 = 34597
duration1 = 9952
duration2 = 10002
distance1 = 169.18
distance2 = 170.03
people = 0
pass = 0
time1 = 0

time2 = 34597
duration1 = 9951
duration2 = 10003
distance1 = 169.17
distance2 = 170.05
people = 0
pass = 0
time1 = 37689

time2 = 34597
duration1 = 397
duration2 = 9187
distance1 = 6.75
distance2 = 156.18
people = 0
pass = 1
time1 = 0

time2 = 0
duration1 = 473
duration2 = 388
distance1 = 8.04
distance2 = 6.60
people = -1
pass = 0
time1 = 0

time2 = 37924
duration1 = 9976
duration2 = 413
distance1 = 169.59
distance2 = 7.02
people = -1
pass = 0
time1 = 0

time2 = 37924
duration1 = 9975
duration2 = 9976
distance1 = 169.58
distance2 = 169.59
people = -1
pass = 0
time1 = 0

time2 = 37924
duration1 = 9957
duration2 = 9978
distance1 = 169.27
distance2 = 169.63
people = -1
pass = 0
time1 = 0

The values in the first two blocks are constantly repeated when nothing happens. The next three blocks show the event of something crossing the sensors. The values in the last two blocks are then constantly repeated until the next event.

I don't understand why time2 is not 0. Because the variable shall only be set in case distance2 < doorwidth (50). I also discovered that the counter is always counting downwards no matter from which direction the objects are crossing.
Therefore, the value supposed to be shown on the display is always negative. The display is not capable of showing negative numbers and for this reason its showing hexadecimal values, I guess.

Even with this new information I can’t find the mistake in my code. Maybe one of has more luck

Update:
This is what the serial output looks like:

That is NOT the serial output from the code you last posted.

If you want help understanding the output with respect to the code, it just seems obvious that you need to POST THE CODE.

That serial output was definitely created by the posted code. I just added a function for the serial output.

So here is my code (including the function for the serial output):

//####################################### LIBRARIES EINBINDEN #######################################
#include <TM1637Display.h>   // 4-Digits, 7Segment Display Library 

//######################################### PINS DEFINIEREN #########################################
#define trigPin1 2           // PIN #1 (Sender)    Sensor #1 (Flur Seite) 
#define echoPin1 3           // PIN #2 (Empfänger) Sensor #1 (Flur Seite) 
#define trigPin2 4           // PIN #1 (Sender)    Sensor #2 (Raum Seite)
#define echoPin2 5           // PIN #2 (Empfänger) Sensor #2 (Raum Seite
const int CLK = 6;           // PIN #1 Display 
const int DIO = 7;           // PIN #2 Display 

//###################################### GLOBALE VARIABLEN ##########################################
int people = 0;             // Anzahl Personen

double doorWidth = 50;      // Tür Breite

boolean pass;               // Hat jemand den Raum betreten (True/False)

unsigned long time1;        // Zeit zu der Sensor #1 (Flur Seite) ausgelöst wird
unsigned long time2;        // Zeit zu der Sensor #2 (Raum Seite) ausgelöst wird

unsigned long duration1;    // Zeit die Signal von Sensor #1 (Flur Seite) bis zum Objekt benötigt 
unsigned long duration2;    // Zeit die Signal von Sensor #2 (Raum Seite) bis zum Objekt benötigt 

long distance1;             // aktuelle Entfernung zwischen Sensor #1 (Flur Seite) und Objekt [cm]
long distance2;             // aktuelle Entfernung zwischen Sensor #2 (Raum Seite) und Objekt [cm]


//################################## DISPLAY INITIALISIEREN #########################################
TM1637Display display(CLK, DIO);

//###################################################################################################
//######################################## FUNKTIONEN ###############################################
//###################################################################################################

//##################################### INITIALISIERUNG #############################################
void setup() 
{
  Serial.begin(9600);         // Startet die serielle Kommunikation [bit/s]

  pinMode(trigPin1, OUTPUT);    // Definiere trigPin1 als Output (Sender)
  pinMode(echoPin1, INPUT);     // Definiere echoPin1 als Input (Empfänger)

  pinMode(trigPin2, OUTPUT);    // Definiere trigPin2 als Output (Sender)
  pinMode(echoPin2, INPUT);     // Definiere echoPin2 als Input (Empfänger)

  display.setBrightness(0x0a);  // Setzt Display Helligkeit auf maximal
}

//################################### Durchgangs Kontrolle ###########################################
void PassControll()
{
  if (time1 != 0 && time2 != 0)
  {
    pass = true;
  }
  else if (time1 == 0 && time2 != 0)
  {
    pass = false;
  }
  else if (time1 != 0 && time2 == 0)
  {
    pass = false;
  }
    else if (time1 == 0 && time2 == 0)
  {
    pass = false;
  }
}

/*void PassControll()
{
  if (distance1 < doorWidth && distance2 < doorWidth)
  {
    pass = true;
  }
  else if (distance1 < doorWidth && distance2 >= doorWidth)
  {
    pass = false;
  }
  else if (distance1 >= doorWidth && distance2 < doorWidth)
  {
    pass = false;
  }
    else if (distance1 >= doorWidth && distance2 >= doorWidth)
  {
    pass = false;
  }
}*/

//#################################### MESSUNG SENSOR 1 ############################################
void Sensor1() 
{
  digitalWrite(trigPin1, LOW);   // Beendet Senden von Sensor #1 (Flur Seite) für 2 micro sec
  delayMicroseconds(2);          
  digitalWrite(trigPin1, HIGH);  // Starten Senden von Sensor #1 (Flur Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);   // Startet Empfangen von Senor #1 (Flur Seite)

  duration1 = pulseIn(echoPin1, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance1 = duration1 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C) [cm]

  if (distance1 < doorWidth)    // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time1 = millis();           // Setze time1 = aktueller Zeitpunkt
  }
}

//#################################### MESSUNG SENSOR 2 ############################################
void Sensor2() 
{
  digitalWrite(trigPin2, LOW);   // Beendet Senden von Sensor #2 (Raum Seite) für 2 micro sec
  delayMicroseconds(2);
  digitalWrite(trigPin2, HIGH);  // Starten Senden von Sensor #2 (Raum Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);   // Startet Empfangen von Senor #2 (Raum Seite)

  duration2 = pulseIn(echoPin2, HIGH);  // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance2 = duration2 * 0.034 / 2;    // Berechnet die Distanz zum Objekt (Näherung für 20°C) [cm]

  if (distance2 < doorWidth)   // Wenn Entfernung zum Objekt < Entfernung bis zum Türrahmen
  {
    time2 = millis();          // Setze time1 = aktueller Zeitpunkt
  }
}


//######################################## PERSONEN ZÄHLEN ########################################
void CountPeople() 
{
 if (pass == true)
 {    
     if (((time1 - time2) < 0)) 
     {
       people ++;
       time1 = 0;
       time2 = 0;
     }
     else if (((time1 - time2) > 0)) 
    {
      people --;
      time1 = 0;
      time2 = 0;
    }
 }
 else if (pass == false)
 {
 }
}

//###################################### AUSGABE AUF DISPLAY ######################################
void DisplayPeople()
{ 
 display.showNumberDec(people);   // gibt den Wert von people auf display aus
}

//######################################## SERIELLE AUSGABE #######################################
void SerialOutput ()
{
  Serial.print ("\n pass = ");
  Serial.println (pass);
  Serial.print ("\n time1 = ");
  Serial.println (time1);
  Serial.print (" time2 = ");
  Serial.print (time2);
  Serial.print ("\n duration1 = ");
  Serial.print (duration1);  
  Serial.print ("\n duration2 = ");
  Serial.print (duration2);
  Serial.print ("\n distance1 = ");
  Serial.print (distance1 );
  Serial.print ("\n distance2 = ");
  Serial.print (distance2);
  Serial.print ("\n people = ");
  Serial.print (people);
}

//############################## REGELMÄßIGER AUFRUF ALLER FUNKTIONEN #############################
void loop() 
{
  PassControll();     // Durchgangs Kontrolle
  Sensor1();          // messen mit Sensor #1 
  Sensor2();          // messen mit Sensor #2
  CountPeople();      // Personenanzahl berechnen
  DisplayPeople();    // Ausgabe auf Display
  SerialOutput ();    // Ausgabe auf Seriellem Monitor (Software)
}

You know that there is a direct correlation between duration and distance, so once you know that the sensors are working correctly, it is not necessary to print both values.

The time to print time1, distance1, etc. is when the 1st sensor detects a value less than the doorwidth value.

The same is true for time2, distance2, etc.

Make sure that those values print only when they are supposed to. Then, it will be a lot simpler to figure out why the rest of the code doesn't seem to be working the way that you expect.

I also wrote an other program (see below). But this program is also not working as intended. It is also counting only in one direction (this time upwards) no matter from which side the objects are passing. Additionally, it only recognizes an object passing now and then and not reliable.

//####################################### LIBRARIES EINBINDEN #######################################
#include <TM1637Display.h>   // 4-Digits, 7Segment Display Library 

//######################################### PINS DEFINIEREN #########################################
#define trigPin1 2           // PIN #1 (Sender)    Sensor #1 (Flur Seite) 
#define echoPin1 3           // PIN #2 (Empfänger) Sensor #1 (Flur Seite) 
#define trigPin2 4           // PIN #1 (Sender)    Sensor #2 (Raum Seite)
#define echoPin2 5           // PIN #2 (Empfänger) Sensor #2 (Raum Seite
const int CLK = 6;           // PIN #1 Display 
const int DIO = 7;           // PIN #2 Display 

//###################################### GLOBALE VARIABLEN ##########################################
int people;                 // Anzahl Personen

double doorWidth = 50;      // Tür Breite

int firstTime = 0;          //we need to declare firstTime outside the loop 

long Distance1 = 0;
long oldDistance1 = 0;
long gap1 = 0;

long Distance2 = 0;
long oldDistance2 = 0;
long gap2 = 0;

//################################## DISPLAY INITIALISIEREN #########################################
TM1637Display display(CLK, DIO);

//###################################################################################################
//######################################## FUNKTIONEN ###############################################
//###################################################################################################

//##################################### INITIALISIERUNG #############################################
void setup()
  {
  Serial.begin(9600);         // Startet die serielle Kommunikation [bit/s]

  pinMode(trigPin1, OUTPUT);    // Definiere trigPin1 als Output (Sender)
  pinMode(echoPin1, INPUT);     // Definiere echoPin1 als Input (Empfänger)

  pinMode(trigPin2, OUTPUT);    // Definiere trigPin2 als Output (Sender)
  pinMode(echoPin2, INPUT);     // Definiere echoPin2 als Input (Empfänger)

  display.setBrightness(0x0a);  // Setzt Display Helligkeit auf maximal
  }

//####################################### DISTANZ MESSEN ############################################
long measureDistance(int trigger,int echo)
{
  long duration;
  long distance;
  
  digitalWrite(trigPin1, LOW);      // Beendet Senden von Sensor #1 (Flur Seite) für 2 micro sec
  delayMicroseconds(2);          
  digitalWrite(trigPin1, HIGH);     // Starten Senden von Sensor #1 (Flur Seite) für 10 micro sec
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);      // Startet Empfangen von Senor #1 (Flur Seite)
  
  duration = pulseIn(echo, HIGH);   // Liefert die Zeit, die das Signal unterwegs war [ms]
  distance = (duration/2) / 29.1;   // Berechnet die Distanz zum Objekt (Näherung für 20°C) [cm]

  return distance;
}

//############################################## SCHLEIFE ##########################################
void loop() 
{ 
  Distance1 = measureDistance(trigPin1,echoPin1);       // Berechnet die Distanz von Sensor #1 zum Objekt (Näherung für 20°C) [cm]
  Distance2 = measureDistance(trigPin2,echoPin2);     // Berechnet die Distanz von Sensor #2 zum Objekt (Näherung für 20°C) [cm]
  
  gap1 = abs(Distance1-oldDistance1);                 // Berechnet Differenz zwischen letzter und aktueller Messung Sensor #1
  gap2 = abs(Distance2-oldDistance2);                 // Berechnet Differenz zwischen letzter und aktueller Messung Sensor #2

  if (firstTime == 0)                                  // Für Programm Stabilität
  {
    oldDistance1 = Distance1;
    oldDistance2 = Distance2;

    gap1=0;
    gap2=0;
    
    firstTime++; 
    //delay(2000);
  }

  if (gap1 > 20 and gap2 < 20)
  {          
    people++;                                           // Person den Raum betreten
    firstTime = 0;                                      // Fehlervorbeugung
    Serial.println ("PERSON HAT DEN RAUM BETRETEN");
    //delay(2000); 
  } 
 
 if (gap1 < 20 and gap2 > 20)
 { 
    people--;                                           // Person hat den Raum verlassen
    firstTime = 0;                                      // Fehlervorbeugung
    Serial.println("PERSON HAT DEN RAUM VERLASSEN");
    //delay(2000); 
  } 
  
  Serial.println("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
  Serial.print(" New Distace1:  ");
  Serial.print(Distance1);
  Serial.print("\n Old Distance1: ");
  Serial.print(oldDistance1);
  Serial.print("\n Gap1:           ");
  Serial.println(gap1);

  Serial.print(" New Distace2:   ");
  Serial.print(Distance2);
  Serial.print("\n Old Distance2:  ");
  Serial.print(oldDistance2);
  Serial.print("\n Gap2:           ");
  Serial.println(gap2);
  Serial.print("PERSONEN ANZAHL: ");
  Serial.println(people);
  Serial.println("\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
  //delay(300);
 
  oldDistance1 = Distance1;                                // Speichert aktuellen Distanzwert als alten Distnzwert für nächste Schleife
  oldDistance2 = Distance2;                               // Speichert aktuellen Distanzwert als alten Distnzwert für nächste Schleife

  display.showNumberDec(people);   // gibt den Wert von people auf display aus
}

This is what the serial output of this program looks like:

\\\\\\\\\\\\\\\\\\\\\\\\\
 New Distace1:  2315
 Old Distance1: 2315
 Gap1:           0
 New Distace2:   0
 Old Distance2:  0
 Gap2:           0
PERSONEN ANZAHL: 0
\\\\\\\\\\\\\\\\\\\\\\\\\
PERSON HAT DEN RAUM BETRETEN
\\\\\\\\\\\\\\\\\\\\\\\\\
 New Distace1:  11
 Old Distance1: 2315
 Gap1:           2304
 New Distace2:   0
 Old Distance2:  0
 Gap2:           0
PERSONEN ANZAHL: 1
\\\\\\\\\\\\\\\\\\\\\\\\\
\\\\\\\\\\\\\\\\\\\\\\\\\
 New Distace1:  2314
 Old Distance1: 2314
 Gap1:           0
 New Distace2:   0
 Old Distance2:  0
 Gap2:           0
PERSONEN ANZAHL: 1
\\\\\\\\\\\\\\\\\\\\\\\\\
\\\\\\\\\\\\\\\\\\\\\\\\\
 New Distace1:  2314
 Old Distance1: 2314
 Gap1:           0
 New Distace2:   0
 Old Distance2:  0
 Gap2:           0
PERSONEN ANZAHL: 1
\\\\\\\\\\\\\\\\\\\\\\\\\

My understanding is that there are two sensors, one inside the room and one outside the room and there will be some time that passes between a person walking past one then the other.

When someone enters the room they will trigger the outside sensor then the inside sensor. When someone leaves the room they will trigger the inside sensor then the outside sensor.

It seems to me all you care about is pairs of readings and the order the sensors were triggered. The readings can be either outside-inside if a person came into the room or inside-outside if a person left the room. You could also get a pair of the same sensor if a person started to enter or leave the room then changed their mind.

It would get tricky if someone stood in front of one sensor then moved back into or out of the room without triggering the other sensor and of course two people crossing would mess up everything.

I sketched out some code to better explain this scheme, it is not meant to be complete but might lead to another way of thinking about the problem.

char sensSequence[2];   // sequence of sensor readings - either I or O for In or Out
byte seqIdx = 0;        // index into readings

void setCount()
{
  // if in then out triggered
  if ( (sensSequence[0] == 'I') && (sensSequence[1] == 'O') )
  {
    people--;     // someone left

    // if out then in triggered
  } else if ( (sensSequence[0] == 'O') && (sensSequence[1] == 'I') ) {

    people++;     // someone came in

  }

  Serial.print(people);
  Serial.println("  people");

}

const long THRESHOLD = 100L;  // readings under this value indicate someone in front of sensor

void loop()
{

  // read sensor inside room
  Distance1 = measureDistance(trigPin1, echoPin1);

  // if someone is passing it
  if ( Distance1 < THRESHOLD )
  {
    // mark that they walked by
    sensSequence[seqIdx++] = "I";

    Serial.println("In");

    // wait for them to pass, let pins settle
    while (measureDistance(trigPin1, echoPin1) < THRESHOLD) delay(10);;

    // if we have a 2 sensor sequence
    if ( seqIdx == 2 )
    {
      // update count
      setCount();

      // ready for next sequence
      seqIdx = 0;
    }
  }

  // read sensor outside room
  Distance2 = measureDistance(trigPin2, echoPin2);

  // mark sensor reading and update count if necessary
  if ( Distance2 < THRESHOLD )
  {
    sensSequence[seqIdx++] = "O";

    Serial.println("Out");

    while (measureDistance(trigPin2, echoPin2) < THRESHOLD) delay(10);

    if ( seqIdx == 2 )
    {
      setCount();
      seqIdx = 0;
    }
  }
  

}

You still have WAY too much code. Get rid of oldDistance1, oldDistance2, gap1, gap2, firstTime, people, etc.

ALL you should have is Distance1 and Distance2 as LOCAL variables, NOT global variables.

Until you KNOW you are getting good readings from the sensors, you are pissing into the wind.

My understanding is that there are two sensors, one inside the room and one outside the room and there will be some time that passes between a person walking past one then the other.

Almost. Both sensors are installed in the doorway parallel to each other. The distance between the Sensors is approximately 10cm (4"). I could install them outside and inside the room or keep them in the doorway but install them in an angle so they are facing the hallway / the room. But I think the main problem is inside the code and not within the hardware setup.

It seems to me all you care about is pairs of readings and the order the sensors were triggered. The readings can be either outside-inside if a person came into the room or inside-outside if a person left the room.

Exactly. That is all I want. And I don’t understand why this simple problem is causing so much trouble.

You could also get a pair of the same sensor if a person started to enter or leave the room then changed their mind. It would get tricky if someone stood in front of one sensor then moved back into or out of the room without triggering the other sensor and of course two people crossing would mess up everything.

Yes, I have already thought about these two situations. And I am expecting even more unforeseen situations when the setup is running. (E.g. A Person carrying an/ multiple object(s)). But since I feel like I am still far away from handling the standard situation I don’t want to implement any of these scenarios in the code right now.

I sketched out some code to better explain this scheme, it is not meant to be complete but might lead to another way of thinking about the problem.

Thanks for the code. This looks like a promising way. I have played around with the code a little bit but without any luck. I will try again tomorrow and upload the code afterwards.

You still have WAY too much code. Get rid of oldDistance1, oldDistance2, gap1, gap2, firstTime, people, etc.
ALL you should have is Distance1 and Distance2 as LOCAL variables, NOT global variables.

I tried it. Didn’t solve the problem. Same problem as before.

Until you KNOW you are getting good readings from the sensors, you are pissing into the wind.

I am not sure if I understand what you mean. I have tested both sensors. They are both capable of measuring distances correctly.