Trying to Make Photogate With Ultrasonic Sensors

I'm sure this is easier to do with IR sensors but I'm working with what I have.

What I'm Stuck On: measuring the time it takes an object to pass through the two ultrasonic sensors.

Essentially what I have set up right now is:

  • two ultrasonic sensors on a track constantly measuring distance
  • the distance between both sensors and a wall is 6 cm

When a toy car passes though sensor1, distance1 is not 6 and the timer is started (find timeBegin using micros()). When the car passes through sensor2, distance2 is not 6 and the timer ends (find timeEnd using micros() again).
The difference in timeEnd and timeEnd should give me the the total time it takes the object to move past both sensors.

However, the code, as I have written it, does not do just that.
I'm a total beginner and hardly know what I'm doing, so I'd appreciate any helpful advice on how to fix my code.

const int trigPin1 = 9;
const int echoPin1 = 10;
const int trigPin2 = 5;
const int echoPin2 = 6;

long duration1;
int distance1;
long duration2;
int distance2;

unsigned long timeBegin;
unsigned long timeEnd;
unsigned long duration = timeEnd - timeBegin;

void setup() 
{
// put your setup code here, to run once:
pinMode(trigPin1, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin1, INPUT); // Sets the echoPin as an Input
pinMode(trigPin2, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin2, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}

void loop() 
{// put your main code here, to run repeatedly:
  if (distance1 != 6)
  {
    timeBegin = micros();
  }
  else
  {
  digitalWrite(trigPin1, LOW);// Clears the trigPin
  delayMicroseconds(2);

  digitalWrite(trigPin1, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);
  
  duration1 = pulseIn(echoPin1, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
  distance1 = duration1 * 0.034 / 2;// Calculating the distance
  
  Serial.print("Distance1: ");// Prints the distance on the Serial Monitor
  Serial.println(distance1);
  }
  //------------------------------------------------------------------------------------------
  if (distance2 != 6)
  {
    timeEnd = micros();
  }
  else
  {
  digitalWrite(trigPin2, LOW);// Clears the trigPin
  delayMicroseconds(2);

  digitalWrite(trigPin2, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  
  duration2 = pulseIn(echoPin2, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
  distance2 = duration2 * 0.034 / 2;// Calculating the distance
  
  Serial.print("Distance2: ");// Prints the distance on the Serial Monitor
  Serial.println(distance2);
  }
  if (duration !=0)
  {
    Serial.println("time " + duration);
  }
  
}

The loop function starts with this, but (at least initially) distance1 has not yet been measured, and is still equal to zero from the initialization process.

The loop function needs to be reorganized.

void loop() 
{// put your main code here, to run repeatedly:
  if (distance1 != 6)

I suggest to check whether the distances are actually constant at 6 over the long term, with no intervening object.

Thanks for replying so soon. I have been messing around with the structure of the loop function. This is what I had before:

const int trigPin1 = 9;
const int echoPin1 = 10;
const int trigPin2 = 5;
const int echoPin2 = 6;

long duration1;
int distance1;
long duration2;
int distance2;

unsigned long timeBegin;
unsigned long timeEnd;
unsigned long duration = timeEnd - timeBegin;

void setup() 
{
// put your setup code here, to run once:
pinMode(trigPin1, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin1, INPUT); // Sets the echoPin as an Input
pinMode(trigPin2, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin2, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}

void loop() 
{// put your main code here, to run repeatedly:
  digitalWrite(trigPin1, LOW);// Clears the trigPin
  delayMicroseconds(2);

  digitalWrite(trigPin1, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);
  
  duration1 = pulseIn(echoPin1, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
  distance1 = duration1 * 0.034 / 2;// Calculating the distance
  
  Serial.print("Distance1: ");// Prints the distance on the Serial Monitor
  Serial.println(distance1);
    if (distance1 != 6)
  {
    timeBegin = micros();
  }
  //------------------------------------------------------------------------------------------
  digitalWrite(trigPin2, LOW);// Clears the trigPin
  delayMicroseconds(2);

  digitalWrite(trigPin2, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin2, LOW);
  
  duration2 = pulseIn(echoPin2, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
  distance2 = duration2 * 0.034 / 2;// Calculating the distance
  
  Serial.print("Distance2: ");// Prints the distance on the Serial Monitor
  Serial.println(distance2);
    if (distance2 != 6)
  {
    timeEnd = micros();
  }
  if (duration !=0)
  {
    Serial.println("time " + duration);
  } 
}

and the distance does always seem to be six when i test the sensors
image

To time an event, you need to start timing when the event starts. In your case, the timing should start when a distance less than 6 is first detected.

Most people use a state variable. Study the Arduino State Change Detection example to see how that is done. With Arduino IDE 1.8.x, go to File>Examples>02.Digital>StateChangeDetection

In the future, please post the code relevant to the question. You have now posted two different code examples.

You only let it do a "time" + duration after distance = 6.

I made a simulation that starts timing at 200cm and stops timing at 100cm. I then have Start T, Stop T, Start D and Stop D. Velocity is found using change in distance over change in time. My serial monitor reads (including instructions):

1. Start with the HC-SC04 near 300cm.
2. Move the HC-SR04 distance to 100cm.
3. Timing will start at 200cm and finish at 100cm.
     Start time: 1521.00ms | Start distance: 200cm
      Stop time: 1607.00ms |  Stop distance: 100cm
Time difference: 86.00ms | Travle Distance: 100cm
Average velocity: 11.63m/s.  Return HC-SR04 puck to 300cm.

At 11m/s, you can see I "zooomed" the simulation.

Thanks for replying. I think I understood what you meant and rearranged the code a bit so that the second sensor only starts running only once the first gate is broken and returns a time only once its gate is broken. However, I'm now getting a strange output on the serial monitor.

const int trigPin1 = 9;
const int echoPin1 = 10;
const int trigPin2 = 5;
const int echoPin2 = 6;

long duration1;
int distance1;
long duration2;
int distance2;

unsigned long timeBegin;
unsigned long timeEnd;


void setup() 
{
// put your setup code here, to run once:
pinMode(trigPin1, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin1, INPUT); // Sets the echoPin as an Input
pinMode(trigPin2, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin2, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}

void loop() 
{// put your main code here, to run repeatedly:
  digitalWrite(trigPin1, LOW);// Clears the trigPin
  delayMicroseconds(2);

  digitalWrite(trigPin1, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin1, LOW);
  
  duration1 = pulseIn(echoPin1, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
  distance1 = duration1 * 0.034 / 2;// Calculating the distance
  
  //Serial.print("Distance1: ");// Prints the distance on the Serial Monitor
  //Serial.println(distance1);
    if (distance1 != 6)
  {
    timeBegin = micros();
    digitalWrite(trigPin2, LOW);// Clears the trigPin
    delayMicroseconds(2);

    digitalWrite(trigPin2, HIGH);// Sets the trigPin on HIGH state for 10 micro seconds
    delayMicroseconds(10);
    digitalWrite(trigPin2, LOW);
  
    duration2 = pulseIn(echoPin2, HIGH);// Reads the echoPin, returns the sound wave travel time in microseconds
  
    distance2 = duration2 * 0.034 / 2;// Calculating the distance
  
    //Serial.print("Distance2: ");// Prints the distance on the Serial Monitor
    //Serial.println(distance2);
    if (distance2 != 6)
    {
      timeEnd = micros();
      unsigned long duration = timeEnd - timeBegin;
      Serial.println("time " + duration);
    }
  }
}

The strange characters are a baud mismatch (your sketch and the IDE serial monitor). Verify your Serial.begin(????) value matches the baud in the lower-right of your IDE.

Both are 9600

The following line is a problem, and is not allowed unless you use the (not recommended) String class. In Arduino IDE Preferences, turn on "verbose" for compiler messages, so that you see warnings about such illegal constructions.

Use separate print statements instead.

      Serial.print("time ");
      Serial.println(duration);

Comment-out one SR04, run the sketch.
Comment-out the other SR04, run the sketch.
Do you have the strange characters on either or both of these tests?
I think pin 9 is going to be an issue... something about PORTx and TIMERy

I used separate statements like you said and I finally got time numbers. However, the time is consistently ~2712 microseconds no matter how fast I, for example, swipe my finger past both sensors.

The second sensor also seems to be running even though the program doesn't let it send any signals until the first one detects a change in distance.

One sensor might be reading the other sensor's ping.

Use ONE SR04... face it along the vehicle path... start the timer when the distance is X, stop the timer when the distance is Y.

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