A beam you can break
A TK64 facing the TK63 sees its beam, and a hand in between takes it away. The catch is the room: daylight and lamps are infrared too, and the TK64 sees them just as well. So the sketch reads the TK64 with the TK63 off, then on, and keeps only the difference, which is the TK63's light and nothing else.
The partner is a TK64
The TK64 is a phototransistor with a 10 kΩ to GND on its SIGNAL, so SIGNAL rises with the infrared that reaches it, steady or not. That is what a break-beam needs, and what a TK15 cannot do: the TK15 only hears 38 kHz. Stand the two blocks face to face, the TK63's LED pointing at the TK64's lens, a hand's width apart to start.
Wire the TK63 as before. Wire the TK64's SIGNAL to an analog pin: A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3, GP26 on a Pico. Its VCC goes to your board's logic voltage, 5V on an Uno and 3V3 on the others, because its SIGNAL can rise close to VCC and your pin reads it.
Off, on, and the difference
A sketch that turned the TK63 on and read the TK64 once would work on the bench and fail by a window: sunlight is full of infrared, and the TK64 cannot tell it from the beam. So the sketch reads twice, 2 ms after switching the TK63 off and 2 ms after switching it on. The room is in both readings. The difference is the TK63 alone.
Pick what is between the blocks. The numbers are illustrative, but the arithmetic is the sketch's. A hand takes the difference away. A bright room lifts both readings and leaves it. Only light strong enough to drive the TK64 to the top of its range beats it, because then switching the TK63 on has nowhere to go.
What you should see
clear beam: 1780
beam broken
beam clearThe first number is the clear-beam difference it measured at start; yours will differ with the distance and your board's ADC. Then one line each time your hand goes in and comes out. The TK63's red LED glows dimly the whole time: it is on for a couple of milliseconds in every check.
The code
No library. beam() reads the TK64 with the TK63 off, then on, and returns the difference. setup() averages sixteen of those with the beam clear; loop() calls the beam broken when the difference falls under half of that, and prints only when it changes.
/*
Infrared Transmitter - a beam you can break TK63 + TK64 / /p/tk63
Wiring. Count from the square pad on each TinkerBlock board, parts
up, header at the bottom:
TK63 transmitter
GND -> GND
VCC -> 5V, or VBUS on a Pico (only feeds the LEDs)
NC -> nothing (unconnected on the board)
SIGNAL -> D3, GPIO 22, GPIO 6 or GP17
TK64 receiver
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
NC -> nothing (unconnected on the board)
SIGNAL -> A0, GPIO 34, GPIO 4 or GP26
Uno, ESP32, ESP32-S3, Pico, in that order. Stand the two blocks
face to face, the TK63's LED pointing at the TK64's, and keep the
beam clear while the sketch starts: it measures the clear beam.
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.
Serial Monitor 115200
*/
// The pin the TK63's SIGNAL is wired to.
// Uno: 3. ESP32: 22. ESP32-S3: 6. Pico: 17.
const int IR_PIN = 6;
// The pin the TK64's SIGNAL is wired to: an analog input.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int SENSE_PIN = 4;
int clearBeam = 0; // the TK63's own light, beam clear
bool broken = false;
// Read the TK64 with the TK63 off, then on. The room's infrared is
// in both readings; the difference is the TK63's light alone.
int beam() {
digitalWrite(IR_PIN, LOW);
delay(2);
int dark = analogRead(SENSE_PIN);
digitalWrite(IR_PIN, HIGH);
delay(2);
int lit = analogRead(SENSE_PIN);
digitalWrite(IR_PIN, LOW);
return lit - dark;
}
void setup() {
pinMode(IR_PIN, OUTPUT);
digitalWrite(IR_PIN, LOW);
Serial.begin(115200);
delay(500);
long sum = 0;
for (int i = 0; i < 16; i++) sum += beam();
clearBeam = sum / 16;
Serial.print("clear beam: ");
Serial.println(clearBeam);
}
void loop() {
// Broken when less than half the clear beam gets through.
bool now = beam() < clearBeam / 2;
if (now != broken) {
broken = now;
Serial.println(broken ? "beam broken" : "beam clear");
}
delay(20);
}Keep the beam clear for the half second after reset: that is when it measures. analogRead gives 0 to 1023 on an Uno and 0 to 4095 on an ESP32, which does not matter here, because the sketch only compares its own readings. It compiles for an ESP32-S3 and an Uno.
View on GitHub · blocks/tk63-ir-transmitter/arduino/ir_break_beam/ir_break_beam.ino @ v1.5The same in MicroPython. read_u16() gives 0 to 65535 on the ESP32 and the Pico alike; on the ESP32 and S3 the sketch sets the ADC's attenuation so it reads up to about 3.1 V.
"""
Infrared Transmitter - a beam you can break TK63 + TK64 / /p/tk63
Wiring. Count from the square pad on each TinkerBlock board, parts
up, header at the bottom:
TK63 transmitter
GND -> GND
VCC -> 5V, or VBUS on a Pico (only feeds the LEDs)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 22, GPIO 6 or GP17
TK64 receiver
GND -> GND
VCC -> 3V3
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 34, GPIO 4 or GP26
ESP32, ESP32-S3, Pico, in that order. Stand the two blocks face
to face and keep the beam clear while it starts.
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
"""
import time
from machine import ADC, Pin
# TK63: ESP32 22, ESP32-S3 6, Pico 17.
IR_PIN = 6
# TK64: ESP32 34, ESP32-S3 4, Pico 26.
SENSE_PIN = 4
ir = Pin(IR_PIN, Pin.OUT, value=0) # LOW: LEDs off
adc = ADC(Pin(SENSE_PIN))
try:
adc.atten(ADC.ATTN_11DB) # ESP32 and S3: read to about 3.1 V
except AttributeError:
pass # the Pico has no attenuator
def beam():
# Off, then on: the difference is the TK63's light alone.
ir.value(0)
time.sleep_ms(2)
dark = adc.read_u16()
ir.value(1)
time.sleep_ms(2)
lit = adc.read_u16()
ir.value(0)
return lit - dark
time.sleep_ms(500)
clear = sum(beam() for _ in range(16)) // 16
print("clear beam:", clear)
broken = False
while True:
now = beam() < clear // 2 # under half the clear beam
if now != broken:
broken = now
print("beam broken" if broken else "beam clear")
time.sleep_ms(20)The Pico's ADC has no attenuation setting, so the sketch skips it there. No library to install. Keep the beam clear while it starts.
View on GitHub · blocks/tk63-ir-transmitter/micropython/ir_break_beam.py @ v1.5When it does not work
Either too little of the TK63 reaches the TK64, or daylight drives the TK64 so high that switching the TK63 on cannot raise it further. Aim the TK63's LED straight at the TK64's lens, closer, and keep the TK64 out of the sun. Then press reset: the sketch measures the clear beam when it starts.
The TK64 is getting little of the TK63's light. Stand them face to face, lens to lens, and move them closer; the TK63's beam is only 20° across. Put its VCC on 5V if it is on 3V3.
The sketch checks about forty times a second: two readings with a 2 ms wait each, then a 20 ms pause. Anything that crosses the beam in less than that can slip between checks. Shorten the pause at the end of loop() if you need to catch it.
A TK15 only sees light flashing at 38 kHz. A steady beam, or this sketch's slow off-and-on, is invisible to it. It would need the TK63 to send a carrier all the time and would still report only whether it heard it.
Edit this page — content/books/ir-transmitter/a-beam-you-can-break.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Infrared Transmitter
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.