部品 · 読了まで19分

KY-008レーザーモジュールとArduino:レーザー侵入警報とタイマー

KY-008レーザーモジュールとArduinoの使い方を解説します。配線、5 mW・650 nmレーザーの目の安全、LDRを使ったレーザー侵入警報、しきい値の自動キャリブレーション、鏡、レースタイマー、ESP32での通知まで扱います。

レーザーモジュールは、Arduinoで使える部品の中でもとりわけ目を引く部品です。細い赤いビームを出し、そのビームは広がらずに何メートルも届きます。電子工作キットに入っているKY-008レーザーモジュールは、約5 mWの650 nmレーザーダイオードを小さな基板に載せたものです。Arduinoのデジタルピン1本につなぎ、digitalWrite()でオン・オフできます。単体ではただのポインターですが、向かい側に光センサーを置けば、映画のようなレーザー侵入警報にも、ドアを通る人を数えるカウンターにも、ミリ秒単位で正確なレースタイマーにもなります。

このガイドでは、KY-008の仕様、5 mWのレーザーが目にとって実際どれほど危険で、どんなルールを守るべきか、そしてArduino Uno、ESP32、Raspberry Pi Picoへの正しい配線を学びます。そのあとLDRでレーザーバリアを作り、しきい値を当て推量ではなくArduinoに自動で測らせ、鏡で1つのレーザーを複数のビームにし、通過を数えて速度を測り、ビームが遮られたらESP32でスマホに通知を送ります。

KY-008レーザーモジュール(650 nm、5 mW)
KY-008レーザーモジュール:6 mmの真ちゅう製レーザーヘッド、その後ろの小さな基板に載った電流制限抵抗、3本のピン(S、中央のピン、−)。

KY-008レーザーモジュールとは?その仕組みは?

モジュールの心臓部は、真ちゅうの筒の中に取り付けられた小さなレーザーダイオードです。普通のLEDと違い、レーザーダイオードは電流があるしきい値を超えると、単一の波長の光をそろった状態(コヒーレント)で出します。筒の先にある小さなレンズが、この光をほぼ平行なビームにします。そのため、LEDの光は数センチで広がってしまいますが、レーザーの点は数メートル先でも直径数ミリにとどまります。650 nmは目によく見える深い赤です。レーザーヘッドの後ろの小さな基板に載った抵抗が、ダイオードに流れる電流を制限しています。レーザーダイオードはLEDよりもはるかに過電流に弱く、この抵抗を飛ばしてダイオードに直接電源をつなぐと、数秒で壊れることがあります。

項目値
型番KY-008(HW-493として売られていることもある)
波長650 nm(可視光の赤)
出力約5 mW
レーザーのクラス3R(IEC 60825-1、日本ではJIS C 6802)、米国ではIIIa
動作電圧5 V(3.3 Vでは暗くなる)
電流40 mA未満、基板によって異なる
レーザーヘッド6 mmの真ちゅうの筒
ピンS(信号)、中央のピン(ほとんどの基板で+5Vまたは未接続)、−(GND)
動作温度−10〜40 °C

目の安全:5 mWのレーザーはどれくらい危険?

レーザーの危険は、全体の出力そのものではなく、その出力がごく小さな点に集中することから生まれます。目のレンズ(水晶体)は平行なビームを網膜上のミクロン単位の点に集めるので、壁に当たると無害に見える5 mWでも、網膜上では太陽を直接見るよりも強い点になりえます。レーザーはこの危険度に応じてクラスに分けられています。1 mW未満のクラス2のレーザーでは、まばたき反射(約0.25秒)でたいてい十分に目が守られます。KY-008が属するクラス3Rはその上限の5倍までの出力です。うっかり一瞬見てしまう程度なら危険は低いですが、ビームを直接または鏡越しにのぞき込むと、目を傷めることがあります。

クラス出力(可視光)危険度
1とても低い、またはビームが機器の内部に閉じ込められている通常の使用では安全
2最大1 mWまばたき反射で守られる。わざと見つめない
3R1〜5 mW(KY-008)直接見ると目を傷めることがある
3B5〜500 mW直接のビームも鏡の反射光も危険
4500 mW超目、皮膚、火災の危険
  • ビームを絶対にのぞき込まない:レーザーの出射口を目に近づけないでください。点灯したままモジュールを手に持って振り回すのもやめましょう。
  • ビームは目の高さより下に:警報やカウンターのビームは床から20〜50 cmの高さに取り付けます。この高さは、はいはいする赤ちゃんや小さな子ども、猫や犬の目の高さと同じなので、そばにいるときはレーザーを点けたままにしないでください。
  • 反射に注意:鏡、ガラス、腕時計の文字盤、光沢のある金属はビームを思わぬ方向に送ります。ビームの経路を最初から最後まで確認し、つや消しの暗い面で終わらせてください。
  • 子どもだけで使わない:レーザーはおもちゃではありません。学校や科学コンテストのプロジェクトでは、大人の監督のもとで作業してください。
  • 表示をうのみにしない:安いモジュールの実際の出力は、表示と違うことがあります。どのモジュールも少なくともクラス3Rとして扱ってください。
  • 紙を使って光軸を合わせる:ビームの前に白い紙をかざし、紙の上の点を追ってください。ビームの行き先を確かめるためにビームをのぞき込むことは絶対にしないでください。
レーザーを人や動物、車の運転手、航空機に向けると、目のけがや重大な事故につながるおそれがあり、多くの国で犯罪になります(日本では、レーザーポインターとして販売できるのは消費生活用製品安全法によりクラス2以下の製品だけです)。どのKY-008のプロジェクトでも、ビームは固定し、目の高さより下に保ち、自分の管理下に置いてください。

KY-008の配線:Arduino Uno、ESP32、Raspberry Pi Pico

KY-008には3本のピンがあります。Sは信号ピンでHIGHにするとレーザーが点灯し、−はGND、印のない中央のピンはほとんどの基板で+5Vにつながっているか、どこにもつながっていません。レーザーはSと−のあいだに入っているので、SにつないだArduinoのピンがレーザーの電流を直接供給します。Arduino Unoなら短いテストには問題ありませんが、モジュールの電流は基板によって違い、40 mA近くになることがあります。これはATmega328Pの1ピンあたりの絶対最大定格で、推奨値は20 mAです。レーザーを何時間も点けたままにする場合、複数のレーザーを使う場合、ESP32やPicoで使う場合は、レーザーを5Vから給電し、NPNトランジスタ(BC547、S8050、2N2222)でスイッチングしてください。トランジスタのピン配置は「トランジスタのピン配置」ツールで確認できます。

接続Arduino UnoESP32Raspberry Pi Pico
KY-008のSD75V(VIN)VBUS(40番ピン)
KY-008の中央のピン未接続(レーザーが点かなければ5V)5V(VIN)VBUS(40番ピン)
KY-008の−GNDNPNのコレクタNPNのコレクタ
NPNのエミッタ―GNDGND(38番ピン)
NPNのベース(1 kΩ経由)―GPIO 26GP15(20番ピン)
LDRの足15V3V33V3(OUT)(36番ピン)
LDRの足2+抵抗の上側A0GPIO 34GP26(31番ピン)
抵抗の下側(3.3〜10 kΩ)GNDGNDGND
アクティブブザーの+D8GPIO 25GP14(19番ピン)
ESP32とPicoのピンは3.3 Vで動作し、供給できる電流も小さいです。PicoのGPIOピンが出せる電流は初期設定で4 mA、最大でも12 mAです。これらのボードでは、ピンから直接レーザーに給電せず、トランジスタを使ってください。また、LDRの分圧回路は必ず3V3ピンから給電します。5Vから給電した分圧回路では、レーザーがLDRに当たったときにアナログピンに3.3 Vを超える電圧がかかり、ピンを傷めるおそれがあります。アクティブブザーも20〜30 mA流れることがあります。ESP32のピンなら直接駆動できますが、PicoではブザーもNPNトランジスタ経由で駆動するか、低電流の3 Vブザーを選んでください。

スケッチに進む前に、次の小さなテストプログラムでレーザーとLDRを一緒に試してみましょう。0.5秒ごとにレーザーをオン・オフし、両方の状態の読み取り値をシリアルモニタに表示します。2つの値の差が大きいほど、バリアの信頼性が高くなります。Unoなら差が300を超えればとても良好です。100未満なら、ビームがLDRにまっすぐ当たっていないか、周囲の光が強すぎます。

C++ (Arduino IDE)
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}

LDRを使ったレーザーバリアの仕組みは?

レーザーバリアの考え方はシンプルです。レーザーのビームが、反対側にあるLDR(光によって抵抗値が変わる抵抗)に当たり続けます。レーザーの点が当たっているとLDRの抵抗値は数百オームまで下がり、ビームが遮られると数十キロオームまで上がります。LDRを固定抵抗と組み合わせて分圧回路にすると、この抵抗値の変化がアナログピンの電圧の変化になります。5V → LDR → A0 → 抵抗 → GNDの配線では、ビームが当たっているあいだA0の値は高く、遮られると低くなります。誰かがビームを横切った瞬間に値が下がり、Arduinoが警報を鳴らします。

LDR(フォトレジスタ)
LDR(フォトレジスタ)
NPNトランジスタ(S8050)
NPNトランジスタ(S8050)
アクティブブザー
アクティブブザー

簡単な計算で、レーザーがLDRにこれほど強く効く理由がわかります。5 mWのビームが直径約3 mmの点に集まると、強さは1平方メートルあたりおよそ700 Wになります。これは真昼の日光と同じくらいで、明るく照らした部屋の数百倍です。それでも、バリアの最大の敵は周囲の光です。日の当たる窓の前では、ビームが遮られてもLDRは明るいままで、警報は何も気づきません。対策はとても安上がりです。LDRを長さ3〜5 cmの黒い筒(空のボールペンの軸、黒いストロー、熱収縮チューブ)の奥に入れます。筒は正面から来るレーザーだけを通し、横からの周囲の光をさえぎります。

状態LDRの抵抗値(例)10 kΩでのanalogRead3.3 kΩでのanalogRead
レーザーがLDRに当たっている(筒の中)300 Ω993938
ビームが遮られている(筒の中)30 kΩ256101
ビームが遮られている(筒なし、明るい部屋)3 kΩ787536
ビームありとビームなしの差(筒の中)―737837
分圧回路の固定抵抗に最適な値は、ビームがあるときとないときのLDRの抵抗値の幾何平均です。R = √(R_beam × R_broken)。表の300 Ωと30 kΩなら、√(300 × 30,000) = 3,000 Ωで、いちばん近い標準値は3.3 kΩです。手元のLDRの両方の抵抗値をテスターで測り、結果を分圧計算ツールで試し、「標準抵抗値」ツールでいちばん近い値を探してください。

ステップごとに:Arduinoでレーザー侵入警報を作る

  1. KY-008のSピンをD7に、−ピンをGNDにつなぎます。中央のピンは未接続のままにします(レーザーが点かなければ5Vにつなぎます)。
  2. LDRの片方の足を5Vに、もう片方をA0につなぎ、A0とGNDのあいだに3.3 kΩまたは10 kΩの抵抗を入れます。
  3. LDRを黒い筒の奥に入れ、筒の口をレーザーに向けます。
  4. アクティブブザーの+の足をD8に、−の足をGNDにつなぎます。消音ボタンはD4とGNDのあいだに取り付けます。内部プルアップを使うので、追加の抵抗は不要です。
  5. レーザーとLDRをしっかりした土台に固定します。まず白い紙でレーザーの点を見つけ、それから筒の中に導きます。
  6. スケッチを書き込み、シリアルモニタを9600ボーで開きます。起動時にはビームの前に誰もいないようにしてください。Arduinoはレーザーを一度オフにしてからオンにして、自分でキャリブレーションします。
C++ (Arduino IDE)
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}

このスケッチは固定のしきい値を使いません。起動時にcalibrate()がレーザーをオフにして、ビームがないときのLDRの値を測り、次にオンにしてビームがあるときの値を測ります。beamPercent()は、この2つの値をもとに各読み取り値を0〜100のパーセントに変換します。100はビームが完全に届いている状態、0は完全に遮られている状態です。この計算は、LDRが分圧回路の上側にあっても下側にあっても関係ありません。光で値が上がる場合でも下がる場合でも、結果は同じです。ビームが40%を下回り、その状態が少なくとも30 ms続くと、警報が10秒間鳴り、D4のボタンで早めに止められます。ビームがまだ遮られていれば警報は再び鳴り始めるので、誰かがビームの中に立っているかぎりシステムは静かになりません。

しきい値のキャリブレーション:数値を直接書き込むべきでない理由

ネット上のレーザー警報の例の多くは、「analogRead(A0) < 500」のような固定のしきい値を使っています。机でテストしたその晩は動きますが、翌朝部屋に日が差し込んだとき、レーザーを数ミリ動かしてしまったとき、LDRを交換したときには失敗します。正しいしきい値は、ビームがあるときとないときの読み取り値のちょうど中間です。起動のたびに両方の値を測り直す自動キャリブレーションなら、システムが周囲の環境に合わせて調整されます。上のスケッチでは、しきい値は1つの数値ではなく2つです。40%を下回るとビームが遮られたとみなし、60%を上回るとビームが戻ったとみなします。この差をヒステリシスといいます。読み取り値がしきい値のすぐ近くで揺れているときに、警報が1秒に何十回もオン・オフするのを防ぎます。

設定コード内の値役割変えるべきとき
BREAK_PCT40ビームが遮られたとみなすレベル半透明の物体(ガラス、薄い布)も検出したいなら60〜70に上げる
RESTORE_PCT60ビームが戻ったとみなすレベル常にBREAK_PCTより15〜20ポイント高くしておく
CONFIRM_MS30短い乱れ(虫、ほこり、振動)を無視する誤報が出るなら100〜200 msに上げる。速い通過を見逃すなら下げる
平均する読み取り回数8電気的なノイズや照明のちらつきをならすUnoでは1回の読み取りに約0.1 msかかる。8回でも1 ms未満
キャリブレーションの差100ビームがLDRに届かなければセットアップを止めるとても長い距離やとても明るい部屋では50まで下げてもよい

長時間動かすシステムでは、周囲の光が1日のうちにゆっくり変わります。簡単に補正するには、ビームが当たっていて警報が鳴っていないときに、calibrate()を再び呼び出します(たとえば1時間ごと)。レーザーをオフにするのはArduino自身なので、この短い暗さを侵入者と間違えることはありません。読み取り値を見るには、Arduino IDEのシリアルプロッタがとても便利です。ビームの中で手を振ると、グラフがどこまで下がり、戻るまでにどれくらいかかるかがわかります。

鏡で複数のビーム:1つのレーザーで網を張る

ビームが1本だけだと、しゃがんでくぐったりまたいだりして簡単に通り抜けられます。映画で見るようなレーザーの網を作るには、ビームごとにレーザーとLDRを用意する代わりに、鏡で1つのレーザーをジグザグに反射させます。ドアや廊下の両側に鏡を向かい合わせに置くと、ビームが左右に反射を繰り返し、最後にLDRに届きます。どこか1か所でも遮られればLDRが暗くなるので、1つのLDRと同じスケッチで網全体を守れます。反射角は入射角と等しいので、それぞれの鏡をほんの少し傾けて、ビームを次の鏡の中心に送るだけです。

鏡はどれも光の一部を失います。普通の洗面所の鏡は約90%を反射し、前面のガラスでかすかな2つ目の点(ゴースト反射)ができます。反射層がガラスの表面にある表面鏡は95%以上を反射し、きれいな点が1つだけできます。損失は掛け算で重なるので、鏡を増やすとLDRに届く光はどんどん減っていきます。

鏡の枚数普通の鏡(90%)表面鏡(95%)
190%95%
281%90%
466%81%
653%74%
843%66%

この表から大切なことがわかります。レーザーの点は周囲の光の数百倍明るいので、キャリブレーションするスケッチなら43%でも十分すぎるほどです。本当の難題は光の損失ではなく光軸合わせです。ビームの経路が長いほど、小さな角度のずれが大きくなります。1度のずれで、5 m先では点が約9 cmずれます。安いレーザーのビームは途中で少しずつ広がるので、数メートル先では点がLDRの5 mmの受光面より大きくなることもあります。

  1. レーザー、鏡、LDRの筒は、しっかりしたホルダー(ネジ止めのL字金具、3Dプリントしたホルダー、ホットボンドで固定した木のブロック)に取り付けます。手で持った鏡では、光軸は決して合ったままになりません。
  2. 部屋を暗くし、最初の鏡の前に白い紙をかざしてレーザーの点を見つけます。
  3. 最初から最後まで順番に鏡の向きを合わせます。点が次の鏡の中心に来るまで、それぞれの鏡をほんの少しずつ傾けます。
  4. 最後のビームをLDRの筒の口に向け、テスト用のスケッチを実行して、シリアルモニタの差がいちばん大きくなる位置を探します。
  5. すべての光軸が合ったら、ホットボンドか固定用のネジで鏡の角度を固定します。机を少しぶつけただけでも、光軸がずれることがあります。
  6. 網の各区間を1つずつ手で遮ってテストし、毎回警報が鳴ることを確認します。
配線をすべて片側にまとめたいなら、向かいの壁の鏡でビームを折り返します。レーザーとLDRが並んで置かれ、反対側には電源のいらない鏡だけが残ります。きれいな空気の中では、横からレーザーのビームは見えず、見えるのは当たった先の点だけです。ビームの経路を見たいなら、空気に少し水蒸気や霧を加えてください。

通過カウンター:何人通った?どれくらいの時間?

同じバリアで、ドアを通る人、コンベヤーで運ばれる箱、ゴミ箱に落ちるボールを数えられます。コツは、1回の通過を1回だけ数えることです。次のスケッチはビームが遮られた瞬間を記録し、ビームが戻ったときに通過を数えるので、しばらくビームの中に立っている人も1回の通過として数えられます。15 msより短い遮断は、ほこりや電気的なノイズとみなして無視します。スケッチはビームが遮られていた時間も表示します。物体の長さがわかっていれば、この時間からそのまま速度が求められます(v = L / t)。たとえば25 cmのおもちゃの車が50 msビームを遮ったなら、速度は0.25 / 0.05 = 5 m/sです。

C++ (Arduino IDE)
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}

人がどちら向きに通ったかを知りたいなら、10〜15 cm離した平行な2本のビームを使います。外側のビームAが先に遮られ、次に内側のビームBが遮られれば入ってきたことになり、Bが先でAが後なら出ていったことになります。Aだけが遮られ、Bが一度も遮られないままビームが戻った場合は、ドアに近づいたものの気が変わったということなので、数えません。入った人数から出た人数を引くと中にいる人数がわかり、7セグメントディスプレイやI2C LCDディスプレイに表示できます。2本のビームの間隔は、人の体が同時に両方を遮れるくらい狭くしてください。

レースタイマーと速度の測定

2つのレーザーゲートのあいだの時間を測れば、ランニング、自転車、おもちゃの車、物理の実験に使える正確なストップウォッチになります。スタートとゴールのゲートを既知の距離(d)だけ離して設置すれば、速度はv = d / tです。10 mのコースを2.5秒で走る人は秒速4 m、つまり時速14.4 kmで走っています。2つのレーザーを一緒にオン・オフするには、それぞれの−ピンを1つの2N2222またはS8050トランジスタのコレクタにつなぎます。Sピンと中央のピンは5Vに、トランジスタのエミッタはGNDに、ベースは1 kΩを介してD7につなぎます。スタートゲートのLDRはA0に、ゴールゲートのLDRはA1につなぎます。

C++ (Arduino IDE)
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}

このスケッチはステートマシンとして動きます。READY状態でスタートのビームが遮られるとmicros()で時刻を記録してRUNNINGに移り、ゴールのビームが遮られると経過時間と速度を表示し、3秒後に次の走行の準備をします。60秒以内にゴールのゲートを通過しなければ、その走行は取り消されます。精度について正直に言うと、コード自体は1 msより細かい分解能で測りますが、LDRが暗さに反応するには10〜30 msかかります。幸い、両方のゲートで同じ種類のLDRを使うので、この遅れは両端で起こってほぼ打ち消し合います。ランニングや自転車なら、結果は十分すぎるほどです。

ビームを50 ms未満しか遮らない速い物体(投げたボール、速いおもちゃの車)には、LDRでは足りません。読み取り値が下がる前にビームが戻ってしまうからです。その場合は、LDRの代わりにマイクロ秒単位で反応するフォトトランジスタやフォトダイオードを使い、出力をデジタルピンにつないで、割り込みで時刻をとらえます。タイミングをdelay()ではなくmillis()とmicros()で処理すべき理由は、「millis()とdelay()の違い」のガイドで確認できます。

ESP32でスマホに通知(Telegram)

家にいないときにも警報を役立てたいなら、ESP32を使えます。ビームが遮られた瞬間に、Telegram経由でスマホにメッセージを送ります。配線は上の表のとおりです。レーザーは5Vから給電し、GPIO 26につないだNPNトランジスタでスイッチングします。LDRの分圧回路は3V3から給電し、GPIO 34につなぎます。このピンの選択には理由があります。ESP32のADC2のピンはWi-Fiがオンのあいだ使えないので、アナログセンサーは必ずADC1のピン(GPIO 32〜39)につなぎます。ESP32のADCは12ビットで0〜4095の値を返すため、コード内のキャリブレーションの最小差は400になっています。ボットの作成とトークン・チャットIDの取得は「ESP32のTelegramボット」のガイドで詳しく解説しています。スケッチのために、ライブラリマネージャからUniversalTelegramBotとArduinoJsonライブラリをインストールしてください。

C++ (Arduino IDE)
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}

遮断は1回ごとに1回だけ数えられ、サイレンが5秒間鳴り、通知が送信待ちに入ります。通知を試みるのは最大でも30秒に1回で、そのあいだに起きた新しい遮断は合計に加えられ、次のメッセージに表示されます。こうすれば、誰かがビームの中を行ったり来たりしても、スマホがメッセージであふれることはありません。メッセージを送れなかった場合、コードは30秒後に再試行し、Wi-Fiが切れていれば再接続を始めます。sendMessage()は安全なHTTPS接続を開くので1〜2秒かかり、そのあいだサイレンのパターンは止まり、ビームも監視されませんが、これは正常な動作です。

Raspberry Pi PicoとMicroPythonでレーザーバリア

Raspberry Pi Picoでは、同じロジックを数行のMicroPythonで作れます。レーザーはVBUS(USBの5 V、40番ピン)から給電し、GP15につないだNPNトランジスタでスイッチングします。LDRの分圧回路は3V3(OUT)ピンから給電してGP26(ADC0)につなぎ、アクティブブザーはGP14につなぎます。PicoのADCはread_u16()で0〜65535の値を返すので、キャリブレーションの最小差は6000です。コードは同じパーセントの計算、ヒステリシス、確認時間を使い、遮断をすべて数え、サイレンを5秒間鳴らし、ビームが遮られていた時間を表示します。パソコンなしでPicoを動かすには、Thonnyでファイルをmain.pyとしてボードに保存してください。

MicroPython
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 siren

レーザーモジュールを使ったプロジェクトのアイデア

  • レーザーのホームアラーム:ドアと廊下のビームをPIR人感センサーと組み合わせ、すべての入力を1つの制御ユニットにまとめます。詳しくは「Arduinoのアラームシステム」のガイドで解説しています。
  • レーザーハープ:5〜7本のビームを並べ、ビームが遮られるたびにパッシブブザーで違う音を鳴らします。
  • 来場者カウンター:2本のビームで入場と退場を区別し、中にいる人数をディスプレイに表示します。
  • 科学コンテスト向けの速度計:2つのゲートで斜面を滑り落ちる物体の速度を測り、摩擦を比べます。ほかのアイデアは「Arduinoの科学コンテスト向けプロジェクトアイデア」のガイドをご覧ください。
  • レーザー迷路ゲーム:鏡を使ってひざより低い位置にビームの網を張り、触れずに通り抜けようとするプレイヤーのタイムを測り、触れるたびにペナルティを加えます。
  • 引き出しや金庫の見張り:ふたが開いてビームが遮られたことを検知し、ESP32でスマホに通知を送ります。

よくある間違いと対処法

症状考えられる原因対処法
レーザーがまったく点かないSと−が逆、または中央のピンに電源が必要な基板ピンの表示を確認し、中央のピンを5Vにつないでもう一度試す
レーザーがとても暗いモジュールを3.3 Vで給電している、またはピンの電流が足りないレーザーを5Vから給電し、トランジスタでスイッチングする
「Isin LDR'ye ulasmiyor」(トルコ語で「ビームがLDRに届かない」)というメッセージ点がLDRに当たっていない、または周囲の光が強すぎる紙で点を見つけ、LDRを黒い筒に入れる
警報が鳴りっぱなしになる光軸がずれた、レーザーや鏡がぐらついているホルダーをしっかり固定し、シリアルプロッタで読み取り値を確認する
警報がまったく鳴らないビームが遮られても、日光や照明でLDRが明るいまま筒を付け、センサーを窓と反対に向ける
速い通過が数えられないLDRの応答時間(10〜30 ms)が遅すぎるCONFIRM_MSとMIN_BREAK_MSを下げるか、フォトトランジスタを使う
Arduinoがリセットする、またはピンが熱くなる1本のピンで複数のレーザーを駆動しているレーザーを5Vから給電し、トランジスタでスイッチングする
ESP32でWi-Fiが始まると読み取り値がおかしくなるLDRがADC2のピンにつながっているLDRをGPIO 32〜39のADC1のピンに移す
Telegramのメッセージが届かないトークンかチャットIDの間違い、またはボットに一度もメッセージを送っていないボットに/startを送り、トークンとチャットIDをもう一度確認する
設置したら、実際の条件でシステムをテストしましょう。部屋を暗くする、照明を点ける、カーテンを開けるたびに、シリアルモニタでビームありとビームなしの読み取り値の差をメモします。最悪の場合でも差が100を超えていれば、バリアは信頼できます。このプロジェクトは学習と趣味のための警報と考えてください。プロの防犯システムでは、目に見えない赤外線のビームと変調方式の受光器が使われています。

KY-008レーザーモジュールは、安い部品1つで光学、分圧回路、キャリブレーション、時間の測定をまとめて学べる、数少ないプロジェクトを可能にしてくれます。まずテスト用のスケッチで差を確かめ、次に警報を作り、鏡、カウンター、タイマーでプロジェクトを広げていきましょう。BlueGraysアプリでは、レーザー警報システム、LDRで光の強さを測定、LDRで作る常夜灯、ESP32の動体検知アラーム、Telegramで通知するプロジェクトを、回路図とコードつきでステップごとに見つけられます。

よくある質問

KY-008レーザーモジュールには何Vの電圧が必要ですか?

KY-008は5 V用に設計されていて、モジュールの電流制限抵抗のおかげでArduino Unoのデジタルピンに直接つなげます。3.3 Vでも点灯しますが、暗くなります。モジュールに5 Vを超える電圧をかけたり、抵抗なしでレーザーダイオードに給電したりすることは絶対にしないでください。

5 mWのレーザーで目を傷めることはありますか?

5 mWの赤色レーザーはクラス3Rです。短時間うっかり当たる程度なら、たいてい後遺症は残りませんが、ビームを見つめたり鏡の反射光が目に入ったりすると、網膜を傷めることがあります。ビームは目の高さより下に保ち、人や動物には決して向けず、鏡を使う構成ではビームの経路全体を確認してください。

レーザー侵入警報はどれくらいの距離で使えますか?

距離を制限するのは、レーザーの出力よりも光軸合わせと周囲の光です。しっかりしたホルダーと黒い筒に入れたLDRがあれば、屋内では10〜20 mでも問題なく動きます。それより長い距離では点が大きくなり、LDRに当たる光が減ります。屋外では日光、霧、風による揺れで、使える距離がはっきり短くなります。

レーザーバリアでLDRの代わりに使えるものは?

LDRは安くて手軽ですが、応答時間は10〜30 msです。より速い測定が必要なタイマーやカウンターには、マイクロ秒単位で反応するフォトトランジスタやフォトダイオードが使われます。市販のレーザー受光モジュールもあり、光を受けるとデジタル出力を出すので、デジタルピンに直接つなげます。

レーザーモジュールはESP32やRaspberry Pi Picoでも使えますか?

はい。ただし、ピンから直接レーザーに給電するより、5Vから給電してNPNトランジスタでスイッチングするほうがよいです。Picoのピンが出せる電流は初期設定で4 mAしかありません。これらのボードではLDRの分圧回路を3V3から給電し、ESP32ではWi-Fiと同時に使えるADC1のピン(GPIO 32〜39)を使ってください。

赤外線のビームバリアはレーザー警報より優れていますか?

プロの防犯システムでは、目に見えない赤外線のビームと変調方式の受光器が使われています。ビームを見つけられず、変調のおかげで日光の影響もほとんど受けません。一方、赤色レーザーは目に見えるので光軸合わせがとても簡単で、学習用のプロジェクトやカウンター、タイマーに最適です。

全プロジェクトを見る
LDRで光の強さを測定
#11初級

LDRで光の強さを測定

部屋の明るさを数値で見てみませんか?光に反応する小さな部品、LDRで周囲の光を測定し、Arduinoが0.5秒ごとにその値をコンピューターの画面に表示します。手で覆うと数値が変わる様子を確認できます。自動で点灯する常夜灯などのプロジェクトへの第一歩です。

4.6(81)
139
LDRで作る常夜灯
#12初級

LDRで作る常夜灯

暗くなると自動で点灯し、朝になると消灯する小さな常夜灯です。光センサーが部屋の明るさを測定し、Arduinoが十分に暗くなったらLEDを点灯させ、明るくなったら消灯させます。街灯が夕方になると自動で点灯する仕組みも理解できます。

4.8(102)
205
ESP32とLDRモジュールで光の強さを読み取る
#113初級

ESP32とLDRモジュールで光の強さを読み取る

LDRモジュールの生のADC値と、暗い状態・明るい状態の基準値から計算した相対的な明るさの割合を、シリアルモニタでリアルタイムに確認します。この割合はルクスの測定値ではありません。モジュールの校正の仕組みを学べます。しきい値の決定に使うため、プロジェクト10の前に取り組むのが適しています。

4.6(36)
55
レーザー警報システム
#22中級
プレミアム

レーザー警報システム

映画のような、目に見えない光のフェンスを作ります。向かい側の光センサーにレーザーを当て、人が通って光を遮るとすぐにLEDが点灯し、ブザーが鳴ります。光が再び届くと、LEDが消灯し、ブザーも止まります。ドアや廊下に使える、シンプルながら印象的な警報装置です。

4.8(64)
83
レーザー防犯システム
#23上級
プレミアム

レーザー防犯システム

映画のレーザーを使った強盗シーンのように、光センサーにレーザー光を当て、人が間に入って光を遮ると、赤いLEDが点灯してブザーが鳴り始めます。警報は自動では止まらず、ボタンやリモコンの電源ボタンで停止します。異常がないときは緑のLEDが点灯します。ドアや引き出しに、目に見えない見張り役を置くユニークな方法です。

4.8(60)
77
ESP32とLDRで作るナイトライト
#112初級
プレミアム

ESP32とLDRで作るナイトライト

暗くなるとLEDが自動で点灯し、明るくなると消灯するナイトライトです。LDRセンサーモジュールのD0(デジタル出力)ピンを使います。モジュール上の小さな可変抵抗で暗さのしきい値を設定すると、モジュール自体がHIGH/LOWを出力します。ESP32はdigitalRead()でこの信号を読み取るだけなので、コードはとてもシンプルです。

4.6(17)
30
ESP32動体検知アラーム(PIR + ブザー + LED + Telegram)
#145上級
プレミアム

ESP32動体検知アラーム(PIR + ブザー + LED + Telegram)

PIRセンサーが動きを検知するとブザーとLEDを作動させ、同時にTelegramで持ち主に即座に通知するスマート防犯アラームです。アラームが繰り返される頻度を抑えるため、30秒のクールダウン(待ち時間)を設けています。この仕組みはPIRの検知が正しいかを確認したり、誤検知をなくしたりするものではありません。家の防犯、ガレージの監視、倉庫や作業部屋などに使えます。ESP32-CAMなら写真付きの通知を追加でき、通常のESP32 DevKit V1ではテキストで通知します。

0.0(0)
9