環境光検知の二つのアプローチ
組み込み開発やIoTプロジェクトの初期段階において、周囲の環境情報を取得することは不可欠である。中でも照度検知は、自動照明やスマート農業など応用範囲が広く、入門題材として最適である。micro:bitを用いた光の測定には、特徴の異なる2つの手法が存在する。
一つ目は、基板上の5×5 LEDマトリックスを利用する手法である。LEDに逆バイアス電圧を印加することで光電効果を引き出し、擬似的にフォトダイオードとして動作させる。外部パーツが不要でコストゼロであり、センサの本質である物理量から離散値への変換プロセスを理解するのに役立つ。二つ目は、フォトレジスタ(CdSセル)と固定抵抗を用いて分圧回路を組む標準的な手法である。抵抗の変化を電圧変化に変換し、マイコンのADコンバータ(ADC)で読み取る。アナログセンサの汎用的な動作原理を学べるのが利点である。
センサー動作の原理
内蔵LEDを用いた光検知
micro:bitの内蔵照度測定は、LEDの副次的な物理特性を利用している。LEDに順方向電圧をかけると発光するが、逆方向電圧を印加すると電流は流れず遮断状態となる。しかし、この逆バイアス状態ではPN接合部が微小なコンデンサのように振る舞い、少量の電荷が蓄積される。ここに光が当たると、光子がエネルギーを与えて電子と正孔の対を生成し、蓄積された電荷の放電を促進する。
マイコンのファームウェアは、LED端子を瞬時に切り替え、逆バイアスで充電した直後に高インピーダンス入力に切り替えて、端子電圧が閾値まで低下する時間を計測する。放電時間は光の強さに反比例する。この時間データは0〜255の数値にマッピングされる。ただし、個体差や温度経年変化の影響を受けやすいため、定性的な閾値判定(昼/夜の判別など)に留め、高精度なルクス測定には不向きである。
フォトレジスタと分圧回路
より信頼性の高い手法が分圧回路を用いた測定である。フォトレジスタは、光強度の増加に伴って抵抗値が減少する素子で、暗所では数MΩ、明所では数百Ω程度になる。
マイコンは抵抗値を直接読み取れないため、電圧変化へ変換する分圧回路が必要となる。電源(3V)とGNDの間にフォトレジスタと固定抵抗を直列に接続し、その中間点の電圧V_outをV_out = 3V * (R_fixed / (R_cds + R_fixed))の公式で求める。光が強くなるとR_cdsが低下し、V_outが上昇する。
micro:bitのアナログ入力端子(P0〜P2など)は、0〜3Vの電圧を10ビット精度の0〜1023の整数に変換するADCを内蔵している。固定抵抗の選定は重要で、対象環境下でのフォトレジスタの典型値に近い抵抗値を選ぶことで、中間電圧を1.5V付近に保ち、ADCのダイナミックレンジを最大限に活用できる。
ハードウェアの構築
必要な部品
- micro:bit本体
- フォトレジスタ(例: GL5528)
- 固定抵抗(2.2kΩを推奨。室内環境でCdSセルと相性が良い)
- ブレッドボードおよび接続用ワイヤー(クリップ付ジャンパーワイヤーが便利)
回路の組み立て
ブレッドボード上にフォトレジスタと2.2kΩの固定抵抗を同じ行の異なる列に挿入し、内部の金属ストリップで直列接続させる。電源ライン(+)をmicro:bitの「3V」端子へ、GNDライン(-)を「GND」端子へ接続する。次に、2つの抵抗が交わる分圧出力点からmicro:bitの「P2」端子へ配線する。最後に、フォトレジスタのもう一方の足を電源ライン(+)へ、固定抵抗のもう一方の足をGNDライン(-)へ接続して回路を完成させる。
ブレッドボードの接触不良は読み取り値の乱れの主な原因となる。部品の足を軽く揺らして数値が急変しないか確認し、確実に挿入されていることを確認すること。
ファームウェア実装
P2端子のアナログ値を読み取り、0〜9の数値にスケーリングしてLEDマトリックスに表示する処理を、3つの開発環境で実装する。
MakeCode (JavaScript Blocks) による実装
MakeCodeのブロックエディタでは、無限ループ内でP2のアナログ読み取りを行い、除算でスケーリングした後に表示する。
basic.forever(function () {
let sensorInput = pins.analogReadPin(AnalogPin.P2)
let displayLevel = Math.min(9, Math.floor(sensorInput / 110))
basic.showNumber(displayLevel)
})
除数を110としているのは、ADCの最大値1023を9段階に分割するためである。環境に合わせてこの除数を調整することで感度をチューニングできる。
MicroPython による実装
MicroPythonでは、ノイズを抑えるために指数移動平均(EMA)フィルタを適用する。直接除算する方法よりも滑らかな数値変化が得られる。
from microbit import *
ema_val = 0
smoothing = 0.2
while True:
raw_data = pin2.read_analog()
ema_val = int((raw_data * smoothing) + (ema_val * (1 - smoothing)))
disp_val = min(9, ema_val // 110)
display.show(str(disp_val))
sleep(150)
smoothing係数を小さくするほどノイズ除去効果が高まるが、光の変化への追従が遅くなる。用途に応じて0.1〜0.5の間で調整する。
Arduino による実装
Arduino環境では、Adafruit_Microbit.hライブラリを利用し、シリアルモニタでのデバッグ出力を組み合わせる。
#include <Adafruit_Microbit.h>
const int ANALOG_IN = P2;
Adafruit_Microbit_Matrix disp;
float smoothed = 0.0;
const float ALPHA = 0.1;
void setup() {
Serial.begin(115200);
disp.begin();
}
void loop() {
int raw = analogRead(ANALOG_IN);
smoothed = (smoothed * (1 - ALPHA)) + (raw * ALPHA);
int mapped = constrain((int)(smoothed / 110), 0, 9);
disp.print(mapped);
Serial.print("Raw:"); Serial.print(raw);
Serial.print(" EMA:"); Serial.print((int)smoothed);
Serial.print(" Out:"); Serial.println(mapped);
delay(100);
}
シリアル出力により、実際の生データとフィルタ後のデータを比較できるため、除数の最適化や回路の異常検知が容易になる。
キャリブレーションとトラブルシューティング
動作範囲の調整
実環境に合わせたキャリブレーションを行うには、想定される最暗時と最明時のADC値を計測し、その範囲を0〜9にマッピングする。min_readingとmax_readingが取得できれば、mapped_val = (current_val - min_reading) * 9 / (max_reading - min_reading)の計算式をコードに適用することで、表示解像度を最大限に活用できる。
よくある問題と対処法
| 症状 | 原因 | 対処 |
|---|---|---|
| 常に0が表示される | 回路の断線、またはピン設定の誤り | 配線の接続確認。テスタで分圧点の電圧変化を確認する。 |
| 常に9が表示される | 分圧点が3Vにショート、または固定抵抗値が大きすぎる | 配線ミスの修正。明所でのCdS抵抗値に合わせて固定抵抗を小さくする。 |
| 数値が激しく変動する | 接触不良、電源ノイズ | ブレッドボードの押し込み確認。USB給電を電池駆動に変更。ソフトウェアフィルタの導入。 |
| 光を遮っても数値が変化しない | 固定抵抗とCdSセルのインピーダンス不整合 | 別の抵抗値に交換し、ADCの中間値付近で電圧が推移する組み合わせを探す。 |
応用アイデア
照度データを応用することで、様々なインタラクティブシステムを構築できる。
- 自動照明制御: 取得した照度値が特定の閾値を下回った際、内蔵LEDを全面点灯させる、または外部出力ポートに接続した照明をオンにする。
- 環境データロガー: シリアル通信やBluetoothを用いて、PCやスマートフォンに時系列データを送信し、1日の照度変化のグラフを作成する。
- 複合センサ評価: 内蔵LEDの照度読み取り機能と外付けフォトレジスタの読み取り値を同時にシリアル出力し、応答速度や直線性の違いを定量的に比較・評価する。