infrared receiver/Reading it/08. A beam that breaks
Reading it · 08 of 9

A beam that breaks

A TK63 Infrared Transmitter opposite the TK64 makes a break-beam. The sketch reads SIGNAL with the emitter off, then on, and keeps only the difference: that is the beam alone, whatever the room's infrared is doing. It learns the clear beam at start-up and reports broken when the difference falls under half of it. Sunlight that pins SIGNAL at the ceiling blinds it.

Two blocks, face to face

The TK63 is an infrared LED at 940 nm, the sensor's own peak, switched by a transistor: SIGNAL HIGH and it shines. Both blocks carry their dome standing straight up off the board, so to make a beam, stand them on edge with the domes facing each other, a few centimetres apart to start.

Wire the TK64 as in the first reading. Wire the TK63 the same way, GND and VCC beside the TK64's, and its SIGNAL to a digital output: GPIO 6 on an ESP32-S3, GPIO 22 on an ESP32, D3 on an Uno, GP17 on a Pico, the pins the TK63's own handbook uses.

Measure the room, then the beam

A single reading with the emitter on cannot tell the beam from a sunny window: the sensor adds up every bit of infrared in view. So each round of the sketch reads twice.

A beam that breaks
In the beam
Room
...
Room and beam
...
Beam
...
Press Run it for one round of the sketch. It runs about fifty rounds a second; this is one, slowed down.

Run it with Nothing in the beam. The first reading, with the TK63 off, is the room. The second, with it on, is the room and the beam. On minus off is the beam alone: the room is in both readings and cancels. Run it again with A hand: the room reading is the same, the beam is mostly gone, and the difference drops under the limit.

The limit is half of what the sketch measured at start-up with the path clear. Half leaves room for the beam to wander a little without a false alarm, and a real obstruction takes far more than half.

What subtraction cannot fix

Run it with Nothing, in sunlight. The room reading is already at the ceiling, so switching the beam on changes nothing, the difference is 0, and the sketch reports a break that is not there. Subtracting cancels a bright room; it cannot rescue a sensor that has run out of room. The same happens, more gently, above the LED's knee, where each microamp moves SIGNAL a tenth as far: a sensor sitting in strong light sees a smaller beam.

So shade the sensor: a short black tube over the dome, pointing at the emitter, cuts the room's infrared far more than the beam's.

Waits and speed

The sketch waits 2 ms after each switch. The sensor itself settles in about a tenth of a millisecond here, worked out from the datasheet's timing, so 2 ms is generous. A round and the 10 ms pause after it take under 20 ms, so anything that stays in the beam longer than that is caught.

The code

No library. Each round switches the TK63 off, waits 2 ms and reads the room; switches it on, waits 2 ms and reads the room and the beam; and keeps on minus off. At start-up it takes 20 rounds with the path clear and remembers the mean. A round that gives under half of that is a broken beam.

ir_break_beam.ino
/*
  Infrared Receiver - a beam that breaks                TK64 / /p/tk64

  A TK63 Infrared Transmitter sends the beam; this TK64 reads it.
  Stand them face to face, a few centimetres apart to start.

  Wiring, TK64. Count from the square pad on the TinkerBlock board,
  parts up, header at the bottom:

    GND    -> GND
    VCC    -> 3V3 on an ESP32, ESP32-S3 or Pico; 5V on an Uno.
              Your board's logic voltage: strong infrared takes
              SIGNAL to about VCC - 0.4 V.
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> GPIO 4 on an ESP32-S3, GPIO 34 on an ESP32,
              A0 on an Uno, GP26 on a Raspberry Pi Pico

  Wiring, TK63: GND to GND, VCC to the same supply pin as the
  TK64's, NC to nothing, and its SIGNAL to GPIO 6 on an ESP32-S3,
  GPIO 22 on an ESP32, D3 on an Uno, GP17 on a Pico.

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    No library needed.
*/

// The analog pin the TK64's SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int IR_PIN = 4;

// The pin the TK63's SIGNAL is wired to. HIGH turns its beam on.
// Uno: 3. ESP32: 22. ESP32-S3: 6. Pico: 17.
const int TX_PIN = 6;

const int SETTLE_MS = 2;   // let the sensor settle after a switch

int clearBeam = 0;         // the beam, measured with the path clear
bool wasBroken = false;

int readIr() {
  long sum = 0;
  for (int i = 0; i < 8; i++) {
    sum += analogRead(IR_PIN);
  }
  return sum / 8;
}

// One round: the room alone, then the room and the beam.
int beam() {
  digitalWrite(TX_PIN, LOW);
  delay(SETTLE_MS);
  int off = readIr();              // the room's own infrared
  digitalWrite(TX_PIN, HIGH);
  delay(SETTLE_MS);
  int on = readIr();               // the room and the beam
  digitalWrite(TX_PIN, LOW);
  return on - off;                 // the beam alone
}

void setup() {
  Serial.begin(115200);
  pinMode(TX_PIN, OUTPUT);
  delay(500);

  // Learn the beam with nothing in the way.
  long sum = 0;
  for (int i = 0; i < 20; i++) {
    sum += beam();
  }
  clearBeam = sum / 20;
  Serial.print("clear beam: ");
  Serial.println(clearBeam);
  if (clearBeam < 20) {
    Serial.println("weak beam: move closer, aim, or shade it");
  }
}

void loop() {
  // Under half the clear beam: something is in the way.
  bool broken = beam() < clearBeam / 2;

  if (broken != wasBroken) {
    Serial.println(broken ? "beam broken" : "beam clear");
    wasBroken = broken;
  }
  delay(10);
}

Keep the path clear while it starts: what it measures then is its idea of clear. TX_PIN switches the TK63 through its own transistor, so any output pin will do. The sketch compiles for an ESP32-S3 and an Uno; on an Uno, IR_PIN is A0 and TX_PIN is 3.

View on GitHub · blocks/tk64-ir-photodiode/arduino/ir_break_beam/ir_break_beam.ino @ v1.5

When it does not work

The clear beam prints as 0 or a few counts.

The TK64 is not seeing the TK63. Check the TK63's SIGNAL is on TX_PIN and its VCC and GND are wired, look at its dome through a phone camera for the glow, and stand the blocks closer, domes facing each other. Both look straight up off their boards, so two blocks lying flat side by side do not face each other.

It says beam broken with nothing in the way.

The difference fell under half of what it learned. Either the sensor is at the ceiling (sunlight or a lamp on it: the red LED stays lit), or something moved after start-up. Shade the sensor, then press reset with the path clear so it learns the beam again.

It never says broken, even with my hand in the way.

Something lets the beam through or around. Skin lets some infrared through, and at a few centimetres light leaks round a small object. Block it with something opaque and wider, such as a book, or move the blocks further apart so the beam is weaker and a small object takes more of it.

Can I lay both blocks flat and detect a hand above them?

Yes: that is a reflective sensor, and the same rounds work; only the test changes. Side by side, both domes look up; a hand a few centimetres above reflects some of the beam back. The difference is then larger with a hand than without, so report when it rises well above the clear value instead of falling below half of it.

Where this goes next

Stuck at 0, stuck at the top, or wandering.

When the reading is wrong →

Edit this page — content/books/ir-photodiode/a-beam-that-breaks.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Infrared Receiver

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum →