Two photogates with OLED for rolling ball

Hello,
I am setting up an UNO R3 using IDE 1.8.9 for a student experiment. This is for a metal ball rolling down a slightly inclined one-meter-long guide. Rather than using a stopwatch or camera, I am trying to set-up a pair of IR emitters and receivers at either end of the guide. The difference in time between the two photogates is to be displayed on an OLED. I am stuck on the OLED displaying 'Time difference : 0' on testing. I have adjusted the code many times but cannot have a time displayed. Any troubleshooting ideas would be highly appreciated. Thank you.

`#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int photogate1Pin = 2; // Photogate sensor 1 connected to digital pin 2
const int photogate2Pin = 4; // Photogate sensor 2 connected to digital pin 3

unsigned long photogate1Time = 0;
unsigned long photogate2Time = 0;
unsigned long timeDifference = 0;

void setup() {
pinMode(photogate1Pin, INPUT);
pinMode(photogate2Pin, INPUT);

Serial.begin(9600);

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(2000);
display.clearDisplay();
display.display();
}

void loop() {

photogate1Time = pulseIn(photogate1Pin, HIGH); // Measure time for photogate 1
photogate2Time = pulseIn(photogate2Pin, HIGH); // Measure time for photogate 2
timeDifference = photogate2Time - photogate1Time; // Calculate time difference

// Display measurement on OLED
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Time difference (us): ");
display.println(timeDifference);
display.display();

}`

Please add code tags to your post, and post a hand drawn wiring diagram or schematic, with pins and parts clearly labeled. Post a link to the photogate product page.

Instructions can be found in the "How to get the best out of this forum" post.

Fritzing diagrams are generally not appreciated on this forum, because they are usually unclear or misleading, and often wrong, but yours does suggest that the circuit lacks the required current limiting resistor in series with each of the LEDs, which can result in destruction of Arduino output pins and the LEDs.

Hint: start with one photogate, properly wired, and write simple code to make sure it works correctly before adding another.

I don't think this is doing what you want. Both of those lines will wait for 1 second for the signal to go high and then time out and return a -1 value in microseconds. Do you ever set the pin to low before these two lines? Don't see it.

To do what your post says you want, you need to save the time in milliseconds or microseconds when the ball breaks the first beam and again to a different variable when the second beam is broken. Subtract the first from the second variable and that is the time to transit from the first to the second beam.

Hi @jonwood99 ,

Welcome to the forum..
code tags bit you some..

you know i'm thinking those are just switches, expecting a LOW when no light..
can probably just digitalRead them..

maybe something like this..

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int photogate1Pin = 2; // Photogate sensor 1 connected to digital pin 2
const int photogate2Pin = 4; // Photogate sensor 2 connected to digital pin 3

unsigned long photogate1Time = 0;
unsigned long photogate2Time = 0;
unsigned long timeDifference = 0;

bool triggered, fin = false;

void setup() {
  pinMode(photogate1Pin, INPUT);
  pinMode(photogate2Pin, INPUT);

  Serial.begin(9600);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(2000);
  display.clearDisplay();
  display.display();
}

void loop() {

  unsigned long now = millis();
  byte a = digitalRead(photogate1Pin);
  if ( a == LOW && !triggered) {
    photogate1Time = now;
    triggered = true;
  }
  byte b = digitalRead(photogate2Pin);
  if ( b == LOW && triggered && !fin) {
    photogate2Time = now;
    fin = true;
  }

  if (fin) {
    timeDifference = photogate2Time - photogate1Time; // Calculate time difference
    // Display measurement on OLED
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    display.print("Time difference (us): ");
    display.println(timeDifference);
    display.display();
    //setup next shot
    triggered = false;
    fin = false;
  }
}

good luck.. ~q

With the LED’s connected to pins 12 and13 of the Uno, those pins will have to be set to output and set high. Most likely you don’t need to turn the LED’s on an off so they can be powered directly from the 5 volt supply using the correct current limiting resistor as mentioned above by @jremington .

Depending on the timing required you ma want to use micros() funtion instead of millis().

The receivers you show,
image

look like the ones used for receiving a modulated (38KHz) signal from a TV type remote. Can you clarify exactly what you have, ie. a part number?

Thank you for this information and quick response. I did a hand drawn version, but instead I did an online version as I felt my drawing was a bit unclear. Will do a hand drawing next time.
I read the 'how to post' info, and put the code between the code tags, but I will review again as I have done it wrong.
I will add a resistor, maybe I have damaged the IR emitters-receivers I have installed.

As you can see, others want to know exactly what you mean by "photogate", so please post links to the product page(s) or data sheet(s).

If you bought 38 kHz IR sensors, those won't work with IR emitters in your setup unless you modulate the emitter output at 38 kHz.

The Fritzing diagram is not useful.

Hi,
The 1838 receiver is an IR diode 3-5 V, VS1838B.
Brought through Amazon.

Here is the data sheet for the IR receiver. http://eeshop.unl.edu/pdf/VS1838-Infrared-Receiver-datasheet.pdf

It is a complex IC (not a diode or a photogate) and won't work with your setup, because it requires the IR light source to be modulated at 38 kHz.

Thank you for letting me know that. What would be a compatible IR emitter and receiver to use?
Thank you.

You can buy actual photogates, which consist of an IR LED and an IR phototransistor or IR photodiode.

IR phototransistors can be bought separately and should work with the LEDs you have (if the LEDs are still functional). They are easier than photodiodes to interface with Arduino.

Very simple DIY example

Thank you.

Thank you will adjust my code.

Thank you. That looks better than what I had.

1 Like

Thank you.

Thank you to everyone who has helped me with this project so far.
After adjusting my code many times I am not outputting any response on the attached OLED or the Serial monitor. My code and (terribly) drawn schematic is attached.
Does anyone have an idea why I am not outputting anything?

I have connected 220 Ohm resistors to the IR emitters and 10 k Ohm to the IR receivers.
I have tested the OLED and board with a simple OLED output program and that showed output on the OLED.
I have removed and reinstalled the libraries, and checked the connections and replaced the wires.
The board is an Uno R3, the OLED is a DWEII OLED 128x64, running the IDE on a Windows desktop.
Code:

// add in all libraries

#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>


// OLED screen size

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

// Setting up OLED initial paramters

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// declare variables for PGs

int IRDetectorStart = 2;
int IRDetectorFinish = 3;
int IRLEDStart = 13;
int IRLEDFinish = 12;
int IRDetectorVal;
bool photoGate1;
bool photoGate2;
float eventTime;
float rounded_up = ceilf(IRDetectorVal * 100) / 100; // restricts value to 2 decimal places, rounding up

void setup() {

  //Set baud rate
  Serial.begin(9600);
  // connect arduino to OLED and set OLED state
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))  {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay (5000);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  display.display();

  // Initial state of pins starting low
  pinMode(IRDetectorStart, INPUT_PULLUP);
  pinMode(IRDetectorFinish, INPUT_PULLUP);
  pinMode(IRDetectorStart, INPUT);
  pinMode(IRDetectorFinish, INPUT);
  pinMode(IRLEDStart, OUTPUT);
  pinMode(IRLEDFinish, OUTPUT);
  digitalWrite(IRLEDStart, LOW);
  digitalWrite(IRLEDFinish, LOW);

  // Reading and print IRDetector values
  photoGate1 = digitalRead(IRDetectorStart);
  digitalWrite(IRDetectorStart, HIGH);
  IRDetectorStart = millis();
  {
    display.println("Start time");
    display.println(photoGate1);

  }

  photoGate2 = digitalRead(IRDetectorFinish);
  digitalWrite(IRDetectorFinish, HIGH);
  IRDetectorFinish = millis();
  {
    display.println("Finish time");
    display.println(IRDetectorFinish);

  }
  eventTime = IRDetectorFinish - IRDetectorStart;
  eventTime = millis();
  display.println(eventTime);

}

DO NOT hook up the circuit as shown in your diagram, it will DESTROY pins 12 and 13 when they are set to output.

Pin 13 is directly connected to +5V.
Pin 12 is connected, through the emitter LED, to ground, with no current limiting resistor.

Thanks for that David. I did know that, but I didn't pay attentions to what pins I was using.

Another way to measure speed as distance over time is with a transceiver like a VL53L0X. As the object approaches, time is stored at two known distances. Delta T (measured) over delta D (known) gives average speed.