PWM で明るさを変える高速な ON/OFF で LED の明るさとサーボの角度を制御する
GPIO は 3.3V か 0V しか出せませんが、高速に ON/OFF を繰り返してその比率を変えると、平均として「中間の明るさ」を作れます。これが PWM。LED の調光、モーターの速度、サーボの角度、すべて同じ仕組みです。
- ESP32-S3
- Raspberry Pi 5 8GB
CONTENTSこの記事の目次+
01 — WHAT IS PWM
PWM とは
PWMデューティ比の波形。1周期のうちHIGH(3.3V)を出力する時間の割合(デューティ比)を変えることで、見かけ上の平均電圧を連続的に変化させます。
- 周波数:1 秒に何回 ON/OFF するか。LED なら 1kHz 以上あればちらつかない
- デューティ比:1 周期のうち ON の割合。0%(消灯)〜 100%(全点灯)
- 分解能:デューティ比を何段階で指定できるか。8bit なら 0〜255
L チカで sleep を短くしたときに「暗く点灯」に見えたのが、まさに PWM です。
02 — ESP32-S3
ESP32-S3 で LED を調光する
ESP32 の Arduino では analogWrite(pin, 0〜255) がそのまま使えます(esp32 core 3.x)。内部では LEDC という PWM 回路が動いています。配線は L チカと同じ(GPIO4 → 220Ω → LED → GND)。
const int LED_PIN = 4;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
for (int duty = 0; duty <= 255; duty++) { // だんだん明るく
analogWrite(LED_PIN, duty);
delay(5);
}
for (int duty = 255; duty >= 0; duty--) { // だんだん暗く
analogWrite(LED_PIN, duty);
delay(5);
}
}周波数や分解能を指定したいときは ledcAttach(pin, 5000, 8) で設定して ledcWrite(pin, duty) で書きます(esp32 core 3.x の書き方。2.x では ledcSetup / ledcAttachPin)。
人の目は明るさを対数的に感じるので、duty を一定に増やしても「最初に急に明るくなって、後半は変化が分かりにくい」と感じます。duty = (i * i) / 255 のように二乗にすると自然に見えます。
03 — PI 5
Raspberry Pi 5 で調光する
from gpiozero import PWMLED
from time import sleep
led = PWMLED(17)
while True:
for i in range(0, 101):
led.value = i / 100 # 0.0(消灯)〜 1.0(全点灯)
sleep(0.01)
for i in range(100, -1, -1):
led.value = i / 100
sleep(0.01)led.pulse() と書くだけでも同じ動きをします。Pi 5 の PWM はソフトウェアで作っているので、OS の都合で少しふらつきます。LED なら気になりませんが、サーボを精密に動かすならマイコン向きです。
04 — SERVO
サーボを PWM で動かす
ホビー用サーボ(SG90 など)は、20ms 周期(50Hz)のパルスの「幅」で角度を決めます。0.5ms で 0°、1.5ms で 90°、2.5ms で 180°(製品で少し違う)。スタックチャンの首がうなずいたり振り向いたりするのも、この 2 本のサーボです。
周期は 20ms(50Hz)固定。HIGH の時間幅だけでサーボの目標角度が決まります。
- 配線:茶 = GND、赤 = 5V、橙 = 信号(GPIO)。信号は 3.3V で OK
- 電源:動く瞬間に数百 mA 流れる。USB 給電のボードの 5V ピンから 1 個なら動くが、リセットするなら別電源 + GND 共通(→ 電源と電池)
- ESP32:ライブラリマネージャで「ESP32Servo」を入れる
- Pi 5:gpiozero の
AngularServo(17, min_pulse_width=0.0005, max_pulse_width=0.0025)
#include <ESP32Servo.h>
Servo servo;
void setup() {
servo.attach(6); // 信号線を GPIO6 に
}
void loop() {
servo.write(0);
delay(1000);
servo.write(90);
delay(1000);
servo.write(180);
delay(1000);
}05 — MOTOR
DC モーターの速度
モーターはトランジスタ(MOSFET)経由で PWM をかけると速度が変わります(→ トランジスタでスイッチする)。周波数は 1kHz 以上にすると「キーン」という音が減り、20kHz 以上なら聞こえなくなります。逆回転もさせたいならモータードライバ(DRV8833 など)を使います。
06 — WATCH OUT
注意点
レギュレータの容量を超えてマイコンがリセットします。5V ピンか別電源にします。
LED は数 kHz、サーボは 50Hz 固定、モーターは可聴域を避けて 20kHz 以上。同じ PWM でも設定が違います。
ソフトウェア生成なので、サーボがぴくぴく震えることがあります。精密に動かすなら ESP32 に任せます。
07 — CHECK YOURSELF
理解チェック
Q1デューティ比 25% の LED はどう見える?答えを見る
全点灯の約 1/4 の明るさ(目にはもう少し明るく感じる)。
Q2サーボを 90° にするパルス幅は?答えを見る
約 1.5ms(20ms 周期のうち)。
