Módulo Láser Arduino KY-008: Alarma Láser, Contador y Cronómetro
Módulo láser KY-008 con Arduino: conexión, seguridad ocular de 5 mW 650 nm, barrera láser con LDR, calibración del umbral, espejos, cronómetro y avisos ESP32.
El módulo láser es una de las piezas más llamativas que puedes usar con Arduino: produce un haz rojo y fino que recorre varios metros sin apenas abrirse. El módulo láser KY-008 que traen muchos kits reúne en una pequeña placa un diodo láser de 650 nm y unos 5 mW; se conecta a un solo pin digital de Arduino y se enciende y apaga con digitalWrite(). Por sí solo es un simple puntero, pero si pones un sensor de luz enfrente se convierte en una alarma láser de película, en un contador de personas que cruzan una puerta o en un cronómetro con precisión de milisegundos.
En este artículo conocerás las características técnicas del KY-008, lo peligroso que es realmente un láser de 5 mW para tus ojos y qué normas debes seguir, y cómo conectar bien el módulo a Arduino Uno, ESP32 y Raspberry Pi Pico. Después montarás una barrera láser con una LDR, harás que Arduino mida el umbral automáticamente en lugar de adivinarlo, convertirás un láser en varios haces con espejos, contarás pasos, medirás velocidades y, con un ESP32, enviarás un aviso a tu móvil cuando se corte el haz.

¿Qué es el módulo láser KY-008 y cómo funciona?
El corazón del módulo es un pequeño diodo láser montado dentro de un tubo de latón. A diferencia de un LED normal, un diodo láser emite luz de una sola longitud de onda y de forma ordenada (coherente) cuando la corriente supera cierto umbral; una pequeña lente en la punta del tubo convierte esa luz en un haz casi paralelo. Por eso la luz de un LED se dispersa en pocos centímetros, mientras que el punto del láser sigue midiendo unos milímetros incluso a varios metros. 650 nm corresponde a un rojo intenso que el ojo ve con facilidad. La resistencia de la pequeña placa situada detrás del cabezal limita la corriente que atraviesa el diodo. Los diodos láser son mucho más sensibles a la sobrecorriente que los LED; si te saltas esa resistencia y alimentas el diodo directamente, puede estropearse en segundos.
| Característica | Valor |
|---|---|
| Modelo | KY-008 (algunos vendedores lo llaman HW-493) |
| Longitud de onda | 650 nm (rojo visible) |
| Potencia de salida | Unos 5 mW |
| Clase láser | 3R (IEC 60825-1), IIIa en EE. UU. |
| Tensión de trabajo | 5 V (a 3,3 V brilla menos) |
| Corriente | Menos de 40 mA; varía de una placa a otra |
| Cabezal láser | Tubo de latón de 6 mm de diámetro |
| Pines | S (señal), pin central (+5V o sin conectar en la mayoría de placas), − (GND) |
| Temperatura de trabajo | De −10 a 40 °C |
Seguridad ocular: ¿qué tan peligroso es un láser de 5 mW?
El peligro de un láser no viene de su potencia total, sino de que esa potencia se concentra en un punto diminuto. El cristalino enfoca un haz paralelo en un punto de pocas micras sobre la retina; por eso 5 mW que parecen inofensivos en una pared pueden convertirse en la retina en un punto más intenso que mirar directamente al sol. Los láseres se dividen en clases según este riesgo. En los láseres de clase 2, por debajo de 1 mW, el parpadeo reflejo del ojo (unos 0,25 segundos) suele bastar como protección. La clase 3R, a la que pertenece el KY-008, llega hasta cinco veces ese límite: una mirada breve y accidental tiene poco riesgo, pero mirar el haz directamente o a través de un espejo puede dañar el ojo.
| Clase | Potencia (luz visible) | Riesgo |
|---|---|---|
| 1 | Muy baja o haz encerrado dentro del aparato | Seguro en uso normal |
| 2 | Hasta 1 mW | El parpadeo protege; no mirar a propósito |
| 3R | 1–5 mW (KY-008) | Mirarlo directamente puede dañar el ojo |
| 3B | 5–500 mW | Peligroso directo y reflejado en espejos |
| 4 | Más de 500 mW | Peligro para ojos y piel, riesgo de incendio |
- Nunca mires al haz: No acerques a tu ojo el extremo por el que sale el láser ni muevas el módulo encendido con la mano.
- Mantén el haz por debajo de los ojos: Monta los haces de alarmas y contadores a 20–50 cm del suelo. Esa altura coincide con los ojos de un bebé que gatea, de un niño pequeño o de un gato o un perro, así que no dejes el láser encendido cuando estén cerca.
- Cuidado con los reflejos: Los espejos, el cristal, las esferas de reloj y los metales brillantes envían el haz en direcciones inesperadas. Revisa el recorrido completo del haz y termínalo en una superficie mate y oscura.
- Que los niños no lo usen solos: Un láser no es un juguete; en proyectos escolares y ferias de ciencias trabaja bajo la supervisión de un adulto.
- No te fíes ciegamente de la etiqueta: En módulos baratos la potencia real puede ser distinta de la indicada; trata cualquier módulo como mínimo como clase 3R.
- Alinea con una hoja de papel: Pon un papel blanco delante del haz y sigue el punto sobre el papel; nunca mires dentro del haz para ver adónde va.
Conexión del KY-008: Arduino Uno, ESP32 y Raspberry Pi Pico
El KY-008 tiene tres pines: S es el pin de señal y enciende el láser cuando está en HIGH, − es GND y el pin central, sin marcar, va a +5V en la mayoría de placas o no está conectado. El láser está entre S y −, así que el pin de Arduino que conectas a S suministra directamente su corriente. En un Arduino Uno no es problema para pruebas cortas, pero la corriente del módulo varía de una placa a otra y puede acercarse a 40 mA. Ese es el máximo absoluto por pin del ATmega328P; lo recomendado son 20 mA. Si vas a tener el láser encendido durante horas, usar más de un láser o trabajar con un ESP32 o una Pico, aliméntalo desde 5V y conmútalo con un transistor NPN (BC547, S8050 o 2N2222). Puedes ver el patillaje del transistor en la guía de transistores.
| Conexión | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| KY-008 S | D7 | 5V (VIN) | VBUS (pin 40) |
| KY-008 pin central | Libre (5V si el láser no enciende) | 5V (VIN) | VBUS (pin 40) |
| KY-008 − | GND | Colector del NPN | Colector del NPN |
| Emisor del NPN | – | GND | GND (pin 38) |
| Base del NPN (con 1 kΩ) | – | GPIO 26 | GP15 (pin 20) |
| Pata 1 de la LDR | 5V | 3V3 | 3V3(OUT) (pin 36) |
| Pata 2 de la LDR + extremo superior de la resistencia | A0 | GPIO 34 | GP26 (pin 31) |
| Extremo inferior de la resistencia (3,3–10 kΩ) | GND | GND | GND |
| Zumbador activo + | D8 | GPIO 25 | GP14 (pin 19) |
Antes de pasar a los programas, prueba el láser y la LDR juntos con el pequeño sketch de abajo. Enciende y apaga el láser cada medio segundo y muestra en el Monitor Serie el valor leído en ambos estados. Cuanto mayor sea la diferencia entre los dos valores, más fiable será tu barrera: en un Uno, una diferencia de más de 300 es muy buena; por debajo de 100, el haz no llega bien a la LDR o la luz ambiente es demasiado fuerte.
1// KY-008 + LDR ilk test: lazer açıkken ve kapalıyken değerleri gör / First test: see readings with the laser on and off
2const int LASER_PIN = 7; // KY-008 S pini / KY-008 S pin
3const int LDR_PIN = A0; // LDR bölücü çıkışı / LDR divider output
4
5void setup() {
6 Serial.begin(9600);
7 pinMode(LASER_PIN, OUTPUT);
8}
9
10void loop() {
11 digitalWrite(LASER_PIN, HIGH); // lazer açık / laser on
12 delay(500); // LDR'nin oturmasını bekle / let the LDR settle
13 int onValue = analogRead(LDR_PIN);
14
15 digitalWrite(LASER_PIN, LOW); // lazer kapalı / laser off
16 delay(500);
17 int offValue = analogRead(LDR_PIN);
18
19 Serial.print(F("Isin var / beam: "));
20 Serial.print(onValue);
21 Serial.print(F(" Isin yok / no beam: "));
22 Serial.print(offValue);
23 Serial.print(F(" Fark / gap: "));
24 Serial.println(onValue - offValue);
25}¿Cómo funciona una barrera láser con LDR?
La idea de una barrera láser es sencilla: el haz del láser incide continuamente sobre una LDR (resistencia dependiente de la luz) situada enfrente. Con el punto del láser encima, la resistencia de la LDR baja a unos cientos de ohmios; cuando se corta el haz, sube a decenas de kiloohmios. Si conectas la LDR con una resistencia fija formando un divisor de tensión, ese cambio de resistencia se convierte en un cambio de tensión en la entrada analógica: con 5V → LDR → A0 → resistencia → GND, A0 lee un valor alto mientras hay haz y bajo cuando se corta. En cuanto alguien cruza el haz, el valor cae y Arduino hace sonar la alarma.



Un cálculo rápido explica por qué el láser afecta tanto a la LDR: si el haz de 5 mW se concentra en un punto de unos 3 mm de diámetro, la intensidad ronda los 700 W por metro cuadrado. Es del mismo orden que el sol del mediodía y cientos de veces más que la luz de una habitación bien iluminada. Aun así, el mayor enemigo de la barrera es la luz ambiente: delante de una ventana soleada la LDR sigue iluminada aunque se corte el haz y la alarma no se entera. La solución es baratísima: coloca la LDR al fondo de un tubo negro de 3–5 cm (el cuerpo vacío de un bolígrafo, una pajita negra o un tubo termorretráctil). El tubo solo deja entrar el láser que llega de frente y bloquea la luz lateral.
| Situación | Resistencia de la LDR (ejemplo) | analogRead con 10 kΩ | analogRead con 3,3 kΩ |
|---|---|---|---|
| Láser sobre la LDR (dentro del tubo) | 300 Ω | 993 | 938 |
| Haz cortado (dentro del tubo) | 30 kΩ | 256 | 101 |
| Haz cortado (sin tubo, habitación iluminada) | 3 kΩ | 787 | 536 |
| Diferencia con y sin haz (dentro del tubo) | – | 737 | 837 |
Paso a paso: alarma láser con Arduino
- Conecta el pin S del KY-008 a D7 y el pin − a GND; deja libre el pin central (conéctalo a 5V si el láser no enciende).
- Conecta una pata de la LDR a 5V y la otra a A0; pon una resistencia de 3,3 kΩ o 10 kΩ entre A0 y GND.
- Coloca la LDR al fondo de un tubo negro y apunta la boca del tubo hacia el láser.
- Conecta la pata + del zumbador activo a D8 y la − a GND. Pon el pulsador para silenciar entre D4 y GND; no hace falta resistencia porque se usa el pull-up interno.
- Fija el láser y la LDR sobre una base firme; primero encuentra el punto del láser con una hoja blanca y luego llévalo dentro del tubo.
- Sube el programa y abre el Monitor Serie a 9600 baudios. Al arrancar no debe haber nadie delante del haz; Arduino se calibra apagando y encendiendo el láser una vez.
1// KY-008 lazer + LDR ile lazerli alarm / Laser tripwire alarm with KY-008 + LDR
2const int LASER_PIN = 7; // KY-008 S pini ya da transistör bazı / KY-008 S pin or transistor base
3const int LDR_PIN = A0; // LDR bölücü çıkışı / LDR divider output
4const int BUZZER_PIN = 8; // aktif buzzer / active buzzer
5const int LED_PIN = 13; // kart üzerindeki LED / on-board LED
6const int RESET_PIN = 4; // susturma butonu, diğer ucu GND / silence button, other leg to GND
7
8const int BREAK_PCT = 40; // %40'ın altı = ışın kesik / below 40% = beam broken
9const int RESTORE_PCT = 60; // %60'ın üstü = ışın sağlam / above 60% = beam intact
10const unsigned long CONFIRM_MS = 30; // en az bu kadar kesik kalmalı / must stay broken this long
11const unsigned long ALARM_MS = 10000; // alarm süresi / alarm duration
12
13int onLevel = 0, offLevel = 0; // ışınlı ve ışınsız ölçüm / reading with and without the beam
14bool beamOk = true;
15bool alarmOn = false;
16unsigned long brokenSince = 0;
17unsigned long alarmStart = 0;
18
19int readAvg() {
20 long sum = 0;
21 for (int i = 0; i < 8; i++) sum += analogRead(LDR_PIN); // 8 ölçüm ortalaması / average of 8 readings
22 return sum / 8;
23}
24
25void calibrate() {
26 while (true) {
27 digitalWrite(LASER_PIN, LOW); // lazer kapalı = kesik ışın / laser off = broken beam
28 delay(300); // LDR yavaştır, bekle / the LDR is slow, wait
29 offLevel = readAvg();
30 digitalWrite(LASER_PIN, HIGH); // lazer açık = sağlam ışın / laser on = intact beam
31 delay(300);
32 onLevel = readAvg();
33 Serial.print(F("Isinli / beam: "));
34 Serial.print(onLevel);
35 Serial.print(F(" Isinsiz / no beam: "));
36 Serial.println(offLevel);
37 if (abs(onLevel - offLevel) >= 100) return; // yeterli fark var / enough difference
38 Serial.println(F("Isin LDR'ye ulasmiyor, hizala! / Beam misses the LDR, align it!"));
39 delay(2000);
40 }
41}
42
43// 100 = ışın tam, 0 = ışın yok; LDR'nin yönü fark etmez / 100 = full beam, 0 = no beam; LDR polarity doesn't matter
44int beamPercent() {
45 return (long)(readAvg() - offLevel) * 100 / (onLevel - offLevel);
46}
47
48void setup() {
49 Serial.begin(9600);
50 pinMode(LASER_PIN, OUTPUT);
51 pinMode(BUZZER_PIN, OUTPUT);
52 pinMode(LED_PIN, OUTPUT);
53 pinMode(RESET_PIN, INPUT_PULLUP);
54 calibrate();
55 Serial.println(F("Alarm hazir / Alarm armed"));
56}
57
58void loop() {
59 unsigned long now = millis();
60 int pct = beamPercent();
61
62 if (beamOk && pct < BREAK_PCT) { // ışın yeni kesildi / beam just broke
63 beamOk = false;
64 brokenSince = now;
65 } else if (!beamOk && pct > RESTORE_PCT) {
66 beamOk = true; // ışın geri geldi / beam restored
67 }
68
69 if (!beamOk && !alarmOn && now - brokenSince >= CONFIRM_MS) {
70 alarmOn = true;
71 alarmStart = now;
72 Serial.println(F("ALARM: isin kesildi! / beam broken!"));
73 }
74
75 if (alarmOn && (now - alarmStart >= ALARM_MS || digitalRead(RESET_PIN) == LOW)) {
76 alarmOn = false; // süre doldu ya da butona basıldı / timeout or button pressed
77 }
78
79 digitalWrite(LED_PIN, beamOk ? LOW : HIGH);
80 digitalWrite(BUZZER_PIN, (alarmOn && (now / 200) % 2) ? HIGH : LOW); // kesik siren / beeping siren
81}El programa no usa un umbral fijo. Al arrancar, calibrate() apaga el láser y mide el valor de la LDR sin haz, y luego lo enciende y mide el valor con haz. beamPercent() convierte cada lectura en un porcentaje entre 0 y 100 a partir de esos dos valores: 100 significa que llega todo el haz y 0 que está totalmente cortado. Este cálculo no depende de si la LDR está arriba o abajo en el divisor; el resultado es el mismo tanto si el valor sube como si baja con la luz. Si el haz baja del 40 % y se mantiene así al menos 30 ms, la alarma pita durante 10 segundos, y el pulsador de D4 la silencia antes. Si el haz sigue cortado, la alarma vuelve a empezar; es decir, el sistema no se calla mientras alguien esté delante del haz.
Calibración del umbral: por qué no deberías escribir un número fijo
Muchos ejemplos de alarma láser en internet usan un umbral fijo como "analogRead(A0) < 500". Funciona la tarde en que lo pruebas en tu mesa, pero falla a la mañana siguiente cuando entra el sol en la habitación, cuando mueves el láser unos milímetros o cuando cambias la LDR. El umbral correcto está justo en el medio entre los valores con y sin haz. Una calibración automática que vuelve a medir ambos valores en cada arranque adapta el sistema a su entorno. En el programa anterior el umbral no es un número sino dos: el haz se considera cortado cuando baja del 40 % y entero cuando sube del 60 %. Ese margen se llama histéresis y evita que la alarma se active y desactive decenas de veces por segundo cuando el valor oscila justo en el umbral.
| Ajuste | Valor en el código | ¿Para qué sirve? | ¿Cuándo cambiarlo? |
|---|---|---|---|
| BREAK_PCT | 40 | Nivel a partir del cual el haz se considera cortado | Súbelo a 60–70 para detectar también objetos semitransparentes (cristal, tela fina) |
| RESTORE_PCT | 60 | Nivel a partir del cual el haz vuelve a estar entero | Mantenlo siempre 15–20 puntos por encima de BREAK_PCT |
| CONFIRM_MS | 30 | Ignora interferencias breves (insectos, polvo, vibraciones) | Súbelo a 100–200 ms si hay falsas alarmas; bájalo si se pierden pasos rápidos |
| Número de lecturas promediadas | 8 | Suaviza el ruido eléctrico y el parpadeo de las lámparas | En un Uno cada lectura tarda unos 0,1 ms; 8 lecturas no llegan a 1 ms |
| Diferencia de calibración | 100 | Detiene el arranque si el haz no llega a la LDR | Puedes bajarla a 50 con distancias muy largas o en sitios muy iluminados |
En un sistema que funciona mucho tiempo, la luz ambiente cambia despacio a lo largo del día. Una forma sencilla de compensarlo es volver a llamar a calibrate() mientras el haz está entero y la alarma no suena (por ejemplo, cada hora en punto). Como es el propio Arduino quien apaga el láser, no confunde esa breve oscuridad con un intruso. Para vigilar las lecturas es muy útil el Serial Plotter del IDE de Arduino: pasa la mano por el haz y verás cuánto cae la gráfica y cuánto tarda en recuperarse.
Varios haces con espejos: una red con un solo láser
Un solo haz se esquiva fácilmente agachándose o pasando por encima. Para montar las redes láser de las películas no necesitas un láser y una LDR por cada haz: puedes hacer rebotar un único láser en zigzag con espejos. Colocas espejos enfrentados a ambos lados de una puerta o un pasillo; el haz rebota de un lado a otro y al final llega a la LDR. Si se corta cualquier tramo, la LDR queda a oscuras, así que una sola LDR y el mismo programa protegen toda la red. Como el ángulo de reflexión es igual al de incidencia, basta con inclinar muy poco cada espejo para que envíe el haz al centro del siguiente.
En cada espejo se pierde parte de la luz. Un espejo de baño normal refleja alrededor del 90 % y genera un segundo punto débil (reflejo fantasma) en el cristal delantero. Los espejos de primera superficie, con la capa reflectante delante del cristal, reflejan el 95 % o más y dan un único punto limpio. Las pérdidas se multiplican, así que la luz que llega a la LDR baja rápidamente al añadir espejos:
| Número de espejos | Espejo normal (90 %) | Espejo de primera superficie (95 %) |
|---|---|---|
| 1 | 90 % | 95 % |
| 2 | 81 % | 90 % |
| 4 | 66 % | 81 % |
| 6 | 53 % | 74 % |
| 8 | 43 % | 66 % |
Esta tabla muestra algo importante: incluso un 43 % es más que suficiente para el programa calibrado, porque el punto del láser es cientos de veces más brillante que la luz ambiente. El verdadero reto no es la pérdida de potencia, sino la alineación. Cuanto más largo es el recorrido, más crece un pequeño error de ángulo: una desviación de 1 grado desplaza el punto unos 9 cm a 5 m. Además, el haz de los láseres baratos se ensancha un poco por el camino; tras unos metros, el punto puede ser mayor que la superficie de 5 mm de la LDR.
- Monta el láser, los espejos y el tubo de la LDR sobre soportes firmes (escuadras atornilladas, soportes impresos en 3D o tacos de madera fijados con silicona caliente); un espejo sujeto con la mano nunca se queda alineado.
- Baja la luz de la habitación y localiza el punto del láser poniendo una hoja blanca delante del primer espejo.
- Alinea los espejos en orden, del primero al último: inclina cada uno muy poco hasta que el punto caiga en el centro del siguiente.
- Dirige el último haz a la boca del tubo de la LDR y ejecuta el programa de prueba para encontrar la posición con la mayor diferencia en el Monitor Serie.
- Cuando todo esté alineado, fija el ángulo de los espejos con silicona caliente o un tornillo de bloqueo; hasta un pequeño golpe en la mesa puede desalinearlos.
- Prueba cada tramo de la red cortándolo uno a uno con la mano y comprueba que la alarma suena cada vez.
Contador de pasos: ¿cuántos han pasado y cuánto han tardado?
La misma barrera sirve para contar personas que cruzan una puerta, cajas en una cinta transportadora o pelotas que caen en un cubo. El truco es contar cada paso una sola vez. El programa de abajo guarda el instante en que se corta el haz y cuenta el paso cuando el haz vuelve; así, alguien que se queda un rato delante del haz cuenta como un solo paso. Los cortes de menos de 15 ms se consideran polvo o ruido eléctrico y se ignoran. Además, el programa muestra cuánto tiempo estuvo cortado el haz: si conoces la longitud del objeto, ese tiempo te da directamente su velocidad (v = L / t). Por ejemplo, si un coche de juguete de 25 cm corta el haz durante 50 ms, su velocidad es 0,25 / 0,05 = 5 m/s.
1// Lazer bariyeriyle geçiş sayacı ve kesilme süresi / Laser barrier pass counter and block time
2const int LASER_PIN = 7; // KY-008 S pini / KY-008 S pin
3const int LDR_PIN = A0; // LDR bölücü çıkışı / LDR divider output
4const unsigned long MIN_BREAK_MS = 15; // daha kısa kesintiler parazittir / shorter breaks are noise
5const float OBJECT_LENGTH_M = 0.0; // cismin boyu biliniyorsa yaz (ör. 0.25) / object length if known (e.g. 0.25)
6
7int onLevel = 0, offLevel = 0;
8bool beamOk = true;
9unsigned long brokenSince = 0;
10unsigned long passCount = 0;
11
12int readAvg() {
13 long sum = 0;
14 for (int i = 0; i < 4; i++) sum += analogRead(LDR_PIN); // 4 ölçüm yeterli ve hızlı / 4 readings: enough and fast
15 return sum / 4;
16}
17
18void calibrate() {
19 while (true) {
20 digitalWrite(LASER_PIN, LOW);
21 delay(300);
22 offLevel = readAvg();
23 digitalWrite(LASER_PIN, HIGH);
24 delay(300);
25 onLevel = readAvg();
26 if (abs(onLevel - offLevel) >= 100) return;
27 Serial.println(F("Isin LDR'ye ulasmiyor / Beam misses the LDR"));
28 delay(2000);
29 }
30}
31
32int beamPercent() {
33 return (long)(readAvg() - offLevel) * 100 / (onLevel - offLevel);
34}
35
36void setup() {
37 Serial.begin(9600);
38 pinMode(LASER_PIN, OUTPUT);
39 calibrate();
40 Serial.println(F("Sayac hazir / Counter ready"));
41}
42
43void loop() {
44 unsigned long now = millis();
45 int pct = beamPercent();
46
47 if (beamOk && pct < 40) {
48 beamOk = false;
49 brokenSince = now; // kesilme anı / moment of the break
50 } else if (!beamOk && pct > 60) {
51 beamOk = true;
52 unsigned long blocked = now - brokenSince; // ışın ne kadar kesik kaldı / how long the beam was blocked
53 if (blocked >= MIN_BREAK_MS) {
54 passCount++;
55 Serial.print(F("Gecis / Pass #"));
56 Serial.print(passCount);
57 Serial.print(F(" Sure / Time: "));
58 Serial.print(blocked);
59 Serial.print(F(" ms"));
60 if (OBJECT_LENGTH_M > 0) {
61 float speed = OBJECT_LENGTH_M / (blocked / 1000.0); // v = L / t
62 Serial.print(F(" Hiz / Speed: "));
63 Serial.print(speed, 2);
64 Serial.print(F(" m/s"));
65 }
66 Serial.println();
67 }
68 }
69}Si quieres saber en qué sentido pasa alguien, usa dos haces paralelos separados 10–15 cm. Si primero se corta el haz exterior A y luego el interior B, la persona está entrando; si primero se corta B y luego A, está saliendo. Si solo se corta A y el haz vuelve sin que B llegue a cortarse, la persona se acercó a la puerta y se arrepintió, y no se cuenta. El número de personas dentro se obtiene restando las salidas a las entradas, y puedes mostrarlo en un display de 7 segmentos o en una pantalla LCD I2C. La separación entre los dos haces debe ser lo bastante pequeña como para que el cuerpo de una persona corte ambos a la vez durante un instante.
Cronómetro de carreras y medición de velocidad
Medir el tiempo entre dos puertas láser te da un cronómetro preciso para carreras, bicicleta, coches de juguete o experimentos de física. Colocas las puertas de salida y de llegada a una distancia conocida (d), y la velocidad es v = d / t. Quien recorre una pista de 10 m en 2,5 segundos corre a 4 m por segundo, es decir, a 14,4 km/h. Para encender y apagar los dos láseres a la vez, conecta el pin − de ambos al colector de un único transistor 2N2222 o S8050; los pines S y central a 5V, el emisor del transistor a GND y su base a D7 a través de 1 kΩ. La LDR de la puerta de salida va a A0 y la de llegada a A1.
1// İki lazer kapılı yarış zamanlayıcı ve hız ölçer / Two-gate laser race timer and speed meter
2const int LASER_PIN = 7; // iki lazer tek transistörle / both lasers through one transistor
3const int START_LDR = A0; // başlangıç kapısı / start gate
4const int FINISH_LDR = A1; // bitiş kapısı / finish gate
5const int BUZZER_PIN = 8; // aktif buzzer / active buzzer
6const float DISTANCE_M = 10.0; // kapılar arası mesafe (metre) / distance between the gates (m)
7const unsigned long TIMEOUT_MS = 60000; // 60 sn'de bitmezse iptal / cancel after 60 s
8
9int onA, offA, onB, offB;
10enum State { READY, RUNNING, DONE };
11State state = READY;
12unsigned long startUs = 0;
13unsigned long startMs = 0;
14unsigned long doneMs = 0;
15
16int readAvg(int pin) {
17 long sum = 0;
18 for (int i = 0; i < 4; i++) sum += analogRead(pin);
19 return sum / 4;
20}
21
22bool isBroken(int pin, int on, int off) {
23 long pct = (long)(readAvg(pin) - off) * 100 / (on - off);
24 return pct < 40; // %40'ın altı = kesik / below 40% = broken
25}
26
27void calibrate() {
28 while (true) {
29 digitalWrite(LASER_PIN, LOW); // iki lazer de kapalı / both lasers off
30 delay(300);
31 offA = readAvg(START_LDR);
32 offB = readAvg(FINISH_LDR);
33 digitalWrite(LASER_PIN, HIGH); // iki lazer de açık / both lasers on
34 delay(300);
35 onA = readAvg(START_LDR);
36 onB = readAvg(FINISH_LDR);
37 if (abs(onA - offA) >= 100 && abs(onB - offB) >= 100) return;
38 Serial.println(F("Kapilardan biri hizali degil / One gate is misaligned"));
39 delay(2000);
40 }
41}
42
43void beep(int ms) {
44 digitalWrite(BUZZER_PIN, HIGH);
45 delay(ms);
46 digitalWrite(BUZZER_PIN, LOW);
47}
48
49void setup() {
50 Serial.begin(9600);
51 pinMode(LASER_PIN, OUTPUT);
52 pinMode(BUZZER_PIN, OUTPUT);
53 calibrate();
54 Serial.println(F("Hazir: baslangic kapisini gec / Ready: cross the start gate"));
55}
56
57void loop() {
58 if (state == READY && isBroken(START_LDR, onA, offA)) {
59 startUs = micros(); // zamanı hemen al / grab the time immediately
60 startMs = millis();
61 state = RUNNING;
62 beep(30);
63 } else if (state == RUNNING) {
64 if (isBroken(FINISH_LDR, onB, offB)) {
65 unsigned long elapsedUs = micros() - startUs;
66 float seconds = elapsedUs / 1000000.0;
67 float speed = DISTANCE_M / seconds; // v = d / t
68 Serial.print(F("Sure / Time: "));
69 Serial.print(seconds, 3);
70 Serial.print(F(" s Hiz / Speed: "));
71 Serial.print(speed, 2);
72 Serial.print(F(" m/s = "));
73 Serial.print(speed * 3.6, 1);
74 Serial.println(F(" km/h"));
75 beep(300);
76 state = DONE;
77 doneMs = millis();
78 } else if (millis() - startMs > TIMEOUT_MS) {
79 Serial.println(F("Zaman asimi / Timeout"));
80 state = READY;
81 }
82 } else if (state == DONE && millis() - doneMs > 3000 &&
83 !isBroken(START_LDR, onA, offA) && !isBroken(FINISH_LDR, onB, offB)) {
84 state = READY; // 3 sn sonra yeni tur / new run after 3 s
85 Serial.println(F("Hazir / Ready"));
86 }
87}El programa funciona como una máquina de estados: en el estado READY, cuando se corta el haz de salida, guarda el tiempo con micros() y pasa a RUNNING; cuando se corta el haz de llegada, muestra el tiempo y la velocidad y, pasados 3 segundos, queda listo para otra carrera. Si no se cruza la llegada en 60 segundos, la carrera se cancela. Seamos sinceros con la precisión: el código mide con una resolución mejor que 1 ms, pero la LDR tarda 10–30 ms en reaccionar a la oscuridad. Por suerte, como usas el mismo tipo de LDR en las dos puertas, ese retraso ocurre en ambos extremos y en gran parte se compensa; para carreras a pie o en bici el resultado es más que suficiente.
Avisos en el móvil con ESP32 (Telegram)
Para que la alarma sirva también cuando no estás en casa, puedes usar un ESP32: en cuanto se corta el haz, te envía un mensaje al móvil por Telegram. Las conexiones son las de la tabla anterior: el láser se alimenta desde 5V y se conmuta con un transistor NPN conectado al GPIO 26, y el divisor de la LDR se alimenta desde 3V3 y va al GPIO 34. No es casualidad: los pines ADC2 del ESP32 no funcionan con el Wi-Fi activado, así que conecta siempre los sensores analógicos a pines ADC1 (GPIO 32–39). El ADC del ESP32 es de 12 bits y devuelve valores de 0 a 4095; por eso la diferencia mínima de calibración en el código es 400. Cómo crear el bot y obtener el token y el chat ID lo explicamos con detalle en el artículo bot de Telegram con ESP32; para este programa instala las librerías UniversalTelegramBot y ArduinoJson desde el Gestor de Librerías.
1// ESP32 lazer bariyeri + Telegram bildirimi / ESP32 laser tripwire + Telegram notification
2#include <WiFi.h>
3#include <WiFiClientSecure.h>
4#include <UniversalTelegramBot.h> // ArduinoJson kütüphanesi de gerekir / also needs the ArduinoJson library
5
6const char* WIFI_SSID = "WIFI_ADI"; // Wi-Fi ağının adı / your Wi-Fi name
7const char* WIFI_PASS = "WIFI_SIFRESI"; // Wi-Fi şifren / your Wi-Fi password
8#define BOT_TOKEN "1234567890:ABCdefGhIJKlmNoPQRstuVWXyz" // BotFather'dan / from BotFather
9#define CHAT_ID "123456789" // senin chat ID'n / your chat ID
10
11const int LASER_PIN = 26; // NPN transistör bazına 1 kΩ ile / to the NPN base via 1 kΩ
12const int LDR_PIN = 34; // ADC1 pini, Wi-Fi ile çalışır / ADC1 pin, works with Wi-Fi
13const int BUZZER_PIN = 25; // aktif buzzer / active buzzer
14const unsigned long CONFIRM_MS = 30; // en az bu kadar kesik kalmalı / must stay broken this long
15const unsigned long SIREN_MS = 5000; // siren süresi / siren duration
16const unsigned long COOLDOWN_MS = 30000; // iki deneme arası en az 30 sn / at least 30 s between attempts
17
18WiFiClientSecure client;
19UniversalTelegramBot bot(BOT_TOKEN, client);
20
21int onLevel = 0, offLevel = 0;
22bool beamOk = true;
23bool counted = false; // bu kesinti sayıldı mı / has this break been counted
24unsigned long brokenSince = 0;
25bool sirenOn = false;
26unsigned long sirenStart = 0;
27unsigned long breakCount = 0;
28bool pending = false; // gönderilecek bildirim var / a notification is waiting
29bool triedOnce = false;
30unsigned long lastTry = 0;
31
32int readAvg() {
33 long sum = 0;
34 for (int i = 0; i < 16; i++) sum += analogRead(LDR_PIN); // 16 ölçüm ortalaması / average of 16 readings
35 return sum / 16;
36}
37
38void calibrate() {
39 while (true) {
40 digitalWrite(LASER_PIN, LOW); // lazer kapalı = kesik ışın / laser off = broken beam
41 delay(300);
42 offLevel = readAvg();
43 digitalWrite(LASER_PIN, HIGH); // lazer açık = sağlam ışın / laser on = intact beam
44 delay(300);
45 onLevel = readAvg();
46 Serial.printf("Isinli / beam: %d Isinsiz / no beam: %d\n", onLevel, offLevel);
47 if (abs(onLevel - offLevel) >= 400) return; // 12 bit ölçekte yeterli fark / enough gap on the 12-bit scale
48 Serial.println("Isin LDR'ye ulasmiyor / Beam misses the LDR");
49 delay(2000);
50 }
51}
52
53int beamPercent() {
54 return (long)(readAvg() - offLevel) * 100 / (onLevel - offLevel);
55}
56
57void setup() {
58 Serial.begin(115200);
59 pinMode(LASER_PIN, OUTPUT);
60 pinMode(BUZZER_PIN, OUTPUT);
61 calibrate();
62
63 WiFi.mode(WIFI_STA);
64 WiFi.begin(WIFI_SSID, WIFI_PASS);
65 client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // api.telegram.org kök sertifikası / root certificate
66 unsigned long start = millis();
67 while (WiFi.status() != WL_CONNECTED && millis() - start < 15000) { // en fazla 15 sn bekle / wait up to 15 s
68 delay(500);
69 Serial.print(".");
70 }
71 if (WiFi.status() == WL_CONNECTED) {
72 Serial.println(WiFi.localIP());
73 bot.sendMessage(CHAT_ID, "Lazer alarmi devrede / Laser alarm armed", "");
74 }
75}
76
77void loop() {
78 unsigned long now = millis();
79 int pct = beamPercent();
80
81 if (beamOk && pct < 40) { // ışın yeni kesildi / beam just broke
82 beamOk = false;
83 counted = false;
84 brokenSince = now;
85 } else if (!beamOk && pct > 60) {
86 beamOk = true; // ışın geri geldi / beam restored
87 }
88
89 if (!beamOk && !counted && now - brokenSince >= CONFIRM_MS) {
90 counted = true; // her kesinti bir kez sayılır / each break counts once
91 breakCount++;
92 pending = true;
93 sirenOn = true;
94 sirenStart = now;
95 Serial.printf("Kesinti / Break #%lu\n", breakCount);
96 }
97
98 if (sirenOn && now - sirenStart >= SIREN_MS) sirenOn = false;
99 digitalWrite(BUZZER_PIN, (sirenOn && (now / 200) % 2) ? HIGH : LOW); // kesik siren / beeping siren
100
101 if (pending && (!triedOnce || now - lastTry >= COOLDOWN_MS)) {
102 triedOnce = true;
103 lastTry = now;
104 if (WiFi.status() == WL_CONNECTED) {
105 String text = "Lazer bariyeri kesildi! / Laser beam broken! Toplam / Total: " + String(breakCount);
106 if (bot.sendMessage(CHAT_ID, text, "")) pending = false; // gitmezse 30 sn sonra yeniden / retry in 30 s if it fails
107 } else {
108 WiFi.reconnect(); // bağlantı koptuysa yeniden dene / reconnect if the link dropped
109 }
110 }
111}Cada corte se cuenta una vez, la sirena suena 5 segundos y se pone un aviso en cola. Los envíos se intentan como mucho una vez cada 30 segundos; los nuevos cortes que se producen mientras tanto se suman al total y aparecen en el siguiente mensaje. Así tu móvil no se llena de mensajes si alguien pasa una y otra vez por el haz. Si un mensaje no se puede enviar, el código lo reintenta 30 segundos después, y si se ha caído el Wi-Fi inicia la reconexión. sendMessage() tarda uno o dos segundos porque abre una conexión HTTPS segura; durante ese tiempo el patrón de la sirena se congela y el haz no se vigila, es normal.
Barrera láser con Raspberry Pi Pico y MicroPython
En la Raspberry Pi Pico puedes montar la misma lógica con unas pocas líneas de MicroPython. El láser se alimenta desde VBUS (los 5 V del USB, pin 40) y se conmuta con un transistor NPN conectado a GP15; el divisor de la LDR se alimenta desde el pin 3V3(OUT) y va a GP26 (ADC0), y el zumbador activo a GP14. Como el ADC de la Pico devuelve valores de 0 a 65535 con read_u16(), la diferencia mínima de calibración es 6000. El código usa el mismo cálculo de porcentaje, la histéresis y el tiempo de confirmación; cuenta cada corte, hace sonar la sirena 5 segundos y muestra cuánto tiempo estuvo cortado el haz. Para que la Pico funcione sin ordenador, guarda el archivo en la placa como main.py con Thonny.
1# Raspberry Pi Pico lazer bariyeri: alarm + geçiş sayacı / Laser barrier: alarm + pass counter
2from machine import Pin, ADC
3import time
4
5laser = Pin(15, Pin.OUT) # NPN transistör bazına 1 kΩ ile / to the NPN base via 1 kΩ
6ldr = ADC(26) # GP26 = ADC0, bölücü 3V3'ten / divider fed from 3V3
7buzzer = Pin(14, Pin.OUT) # aktif buzzer / active buzzer
8
9CONFIRM_MS = 30 # en az bu kadar kesik kalmalı / must stay broken this long
10SIREN_MS = 5000 # siren süresi / siren duration
11
12
13def read_avg(n=8):
14 total = 0
15 for _ in range(n):
16 total += ldr.read_u16()
17 return total // n
18
19
20def calibrate():
21 while True:
22 laser.value(0) # lazer kapalı = kesik ışın / laser off = broken beam
23 time.sleep_ms(300)
24 off = read_avg(32)
25 laser.value(1) # lazer açık = sağlam ışın / laser on = intact beam
26 time.sleep_ms(300)
27 on = read_avg(32)
28 print("Isinli / beam:", on, " Isinsiz / no beam:", off)
29 if abs(on - off) > 6000: # 16 bit ölçekte yeterli fark / enough gap on the 16-bit scale
30 return on, off
31 print("Isin LDR'ye ulasmiyor / Beam misses the LDR")
32 time.sleep(2)
33
34
35on_level, off_level = calibrate()
36beam_ok = True
37counted = False
38broken_at = time.ticks_ms()
39siren_until = time.ticks_ms()
40count = 0
41
42while True:
43 now = time.ticks_ms()
44 pct = (read_avg() - off_level) * 100 // (on_level - off_level) # 100 = ışın tam / full beam
45
46 if beam_ok and pct < 40: # ışın yeni kesildi / beam just broke
47 beam_ok = False
48 counted = False
49 broken_at = now
50 elif not beam_ok and pct > 60: # ışın geri geldi / beam restored
51 beam_ok = True
52 print("Kesik kaldigi sure / blocked for", time.ticks_diff(now, broken_at), "ms")
53
54 if not beam_ok and not counted and time.ticks_diff(now, broken_at) >= CONFIRM_MS:
55 counted = True # her kesinti bir kez sayılır / each break counts once
56 count += 1
57 siren_until = time.ticks_add(now, SIREN_MS)
58 print("Gecis / Pass:", count)
59
60 siren = time.ticks_diff(siren_until, now) > 0
61 buzzer.value(1 if siren and (now // 200) % 2 else 0) # kesik siren / beeping sirenIdeas de proyectos con el módulo láser
- Alarma láser para casa: Combina los haces de puertas y pasillos con un sensor de movimiento PIR y reúne todas las entradas en una central; más detalles en el artículo sistema de alarma con Arduino.
- Arpa láser: Monta 5–7 haces en paralelo y toca una nota distinta con un zumbador pasivo cada vez que se corte uno.
- Contador de visitantes: Distingue entradas y salidas con dos haces y muestra en una pantalla cuántas personas hay dentro.
- Medidor de velocidad para la feria de ciencias: Mide con dos puertas la velocidad de objetos que bajan por un plano inclinado y compara el rozamiento; para más ideas mira el artículo de ideas de proyectos para ferias de ciencias.
- Juego del laberinto láser: Monta con espejos una red de haces por debajo de la rodilla; cronometra a quien intente cruzarla sin tocarla y suma una penalización por cada contacto.
- Protección de cajones y cajas fuertes: Detecta el corte del haz al abrir la tapa y envía un aviso al móvil con el ESP32.
Errores frecuentes y cómo solucionarlos
| Síntoma | Causa probable | Solución |
|---|---|---|
| El láser no enciende | S y − invertidos o una placa cuyo pin central necesita alimentación | Revisa las marcas de los pines, conecta el pin central a 5V y vuelve a probar |
| El láser brilla muy poco | El módulo está a 3,3 V o el pin no da suficiente corriente | Alimenta el láser desde 5V y conmútalo con un transistor |
| Mensaje "Isin LDR'ye ulasmiyor" (el haz no llega a la LDR) | El punto no cae sobre la LDR o la luz ambiente es demasiado fuerte | Busca el punto con un papel y mete la LDR en un tubo negro |
| La alarma no para de sonar | Se ha perdido la alineación, el láser o un espejo se mueven | Fija bien los soportes y observa el valor en el Serial Plotter |
| La alarma no suena nunca | Aunque se corte el haz, el sol o una lámpara iluminan la LDR | Añade un tubo y orienta el sensor lejos de la ventana |
| No se cuentan los pasos rápidos | El tiempo de respuesta de la LDR (10–30 ms) no basta | Baja CONFIRM_MS y MIN_BREAK_MS o usa un fototransistor |
| Arduino se reinicia o un pin se calienta | Varios láseres conectados a un solo pin | Alimenta los láseres desde 5V y conmútalos con un transistor |
| En el ESP32 el valor se vuelve loco al activar el Wi-Fi | La LDR está en un pin ADC2 | Pasa la LDR a un pin ADC1 entre GPIO 32 y 39 |
| No llega el mensaje de Telegram | Token o chat ID incorrectos, o nunca has escrito al bot | Envía /start al bot y revisa de nuevo el token y el chat ID |
El módulo láser KY-008 hace posible uno de esos pocos proyectos que, con una sola pieza barata, enseñan a la vez óptica, divisores de tensión, calibración y medición de tiempos. Empieza viendo la diferencia con el programa de prueba, monta después la alarma y amplía tu proyecto con espejos, un contador y un cronómetro. En la app BlueGrays encontrarás paso a paso, con esquemas y código, el sistema de aviso y de seguridad láser, la medición de luz y la luz nocturna con LDR, la alarma de movimiento con ESP32 y proyectos con avisos por Telegram.
Preguntas frecuentes
¿Con cuántos voltios funciona el módulo láser KY-008?
El KY-008 está pensado para 5 V y, gracias a la resistencia limitadora del módulo, puede conectarse directamente a un pin digital de Arduino Uno. A 3,3 V también enciende, pero con menos brillo. Nunca le apliques más de 5 V ni alimentes el diodo láser sin su resistencia.
¿Un láser de 5 mW puede dañar la vista?
Un láser rojo de 5 mW es de clase 3R: una exposición breve y accidental no suele dejar daños permanentes, pero mirar el haz a propósito o recibir en el ojo un reflejo de un espejo puede dañar la retina. Mantén el haz por debajo de la altura de los ojos, no apuntes nunca a personas ni animales y revisa todo el recorrido del haz en montajes con espejos.
¿A qué distancia funciona una alarma láser?
La distancia la limitan más la alineación y la luz ambiente que la potencia del láser. Con soportes firmes y una LDR dentro de un tubo negro funciona sin problemas a 10–20 m en interiores; a más distancia el punto crece y llega menos luz a la LDR. En exteriores, el sol, la niebla y las vibraciones del viento reducen mucho el alcance.
¿Qué puedo usar en lugar de una LDR en una barrera láser?
La LDR es barata y sencilla, pero su tiempo de respuesta es de 10–30 ms. En cronómetros y contadores que necesitan medir más rápido se usan fototransistores o fotodiodos, que responden en microsegundos. También existen módulos receptores láser ya montados: dan una salida digital cuando reciben luz y se conectan directamente a un pin digital.
¿El módulo láser funciona con ESP32 y Raspberry Pi Pico?
Sí, pero en lugar de alimentar el láser directamente desde un pin es mejor hacerlo desde 5V y conmutarlo con un transistor NPN; los pines de la Pico solo dan 4 mA por defecto. En estas placas alimenta el divisor de la LDR desde 3V3 y, en el ESP32, usa un pin ADC1 (GPIO 32–39), que funciona junto con el Wi-Fi.
¿Es mejor una barrera infrarroja que una alarma láser?
Los sistemas de seguridad profesionales usan haces infrarrojos invisibles y receptores modulados: el haz no se ve y, gracias a la modulación, apenas le afecta la luz del sol. El láser rojo, en cambio, es visible y por eso muy fácil de alinear, lo que lo hace ideal para proyectos de aprendizaje, contadores y cronómetros.
Proyectos para hacer después de leer esto
Ver todos los proyectos
Medir la intensidad de luz con LDR
¿Quieres ver en números cuánta luz hay en tu habitación? El LDR, una pequeña pieza sensible a la luz, mide la luz ambiente y el Arduino escribe el valor en la pantalla del ordenador cada medio segundo

Luz nocturna con LDR
Una pequeña lamparita que se enciende sola cuando oscurece y se apaga cuando llega la mañana. Un sensor de luz mide la claridad de la habitación, y el Arduino enciende el LED cuando está lo bastante o

Lectura de la intensidad luminosa con el módulo LDR del ESP32
Visualización en tiempo real en el monitor serie del valor bruto del ADC del módulo LDR y del porcentaje relativo de luz calculado a partir de referencias de oscuridad y claridad. Este porcentaje no es una medición en lux. Explica el funcionamiento de la calibración del módulo. Es recomendable realizarlo antes del Proyecto 10, ya que se utiliza para determinar el valor umbral.

Sistema de alerta láser
Montas una valla de rayos invisible, como en las películas. Un láser apunta a un sensor de luz al otro lado; en cuanto alguien pasa y corta el rayo, se enciende el LED y suena el zumbador, y cuando el

Sistema de seguridad láser
Como las escenas de robos con láser de las películas: un rayo láser apunta a un sensor de luz, y en cuanto alguien se cruza y corta el rayo, se enciende el LED rojo y el zumbador empieza a sonar. La a

ESP32 Luz de Noche con LDR
Luz nocturna en la que el LED se enciende automáticamente en la oscuridad y se apaga con la luz. Se utiliza el pin D0 (digital out) del módulo sensor LDR - el umbral de oscuridad se ajusta con el pequeño potenciómetro del módulo, el propio módulo genera la salida HIGH/LOW. ESP32 sólo lee esta señal con digitalRead(), el código es muy simple.

Sistema de Alarma de Movimiento ESP32 (PIR + Buzzer + LED + Telegram)
Un sistema inteligente de alarma de seguridad que activa el buzzer y el LED cuando el sensor PIR detecta movimiento, y envía simultáneamente una notificación instantánea al propietario vía Telegram. Cuenta con un tiempo de espera de 30 segundos para limitar la frecuencia de las alarmas repetidas; este mecanismo no comprueba la validez de las detecciones del sensor PIR ni elimina las falsas detecciones. Ideal para seguridad del hogar, vigilancia de garajes, almacenes o salas de trabajo. Con ESP32
Más artículos
App BlueGrays
Monta este circuito paso a paso en tu teléfono
Esquema, código y lista de piezas en una sola pantalla. Más de 200 proyectos de Arduino, ESP32 y Pico listos para montar.
Escanea con tu teléfono
Apunta la cámara al código y se abrirá la tienda de apps de tu teléfono.
o ábrela en la tienda

