ラズパイPicoでLチカはできたけど、その先に何をしようか迷っていませんか。
LEDがただ点いたり消えたりするだけだと、少し物足りなく感じるタイミングが来ます。
そこで次の一歩としておすすめなのが、LEDの明るさを滑らかにフェードイン・フェードアウトさせる動きです。
映画のエンディングのように、じわっと明るくなったり、ふわっと暗くなったりする光は、見ているだけで楽しいです。
しかもこのフェード表現は、Raspberry Pi Pico と MicroPython だけで、意外とシンプルなコードで実現できます。
この記事では、すでにLチカとPWMの基礎を一度触ったことがある電子工作初心者を想定しています。
「Lチカはできた」「PWMもなんとなく分かった」「次のステップに行きたい」という人向けの内容です。
完成イメージとして、1つのLEDが暗いところから少しずつ明るくなり、今度はゆっくり暗くなる、という動きを繰り返します。
この記事を読み終わるころには、自分の手でLEDの明るさを滑らかにコントロールできるようになります。
Raspberry Pi Pico でも Pico2 でも、MicroPython の環境さえあれば基本の考え方は同じです。
完成イメージ
LEDが滑らかに点灯消灯を繰り返すよ
この記事でできること(目的とゴール)
この記事では、Raspberry Pi Pico と MicroPython を使って、LED1個の明るさを滑らかに変えるプログラムを作ります。
- PWM(パルス幅変調)の基本的な考え方
- Raspberry Pi PicoでLEDの明るさを制御する方法
- 初心者向けコード → リファクタリング済みコードへの流れ
PWMは「電気のON/OFFを高速で切り替えて、平均電力で明るさを調整する」技術なんだよ。電気を弱めてるわけじゃないの!
準備:必要な道具と環境
パーツ一覧
| 品名 | 役割 | 代替案 |
|---|---|---|
| Raspberry Pi Pico W | マイコン本体 | Pico(無印)でも可 |
| Micro USBケーブル | データ通信・電源供給 | Type-A to Micro USB(データ通信対応) |
| ブレッドボード | 配線用の土台 | 小型でもOK |
| ジャンパワイヤ(オス-オス) | 接続ケーブル | 色違いで用意すると便利 |
| LED(赤・黄・緑など) | 点灯テスト用 | 単色1つでも可 |
| 抵抗(220〜330Ω) | 電流制限 | 470Ωでも可 |
動作環境(筆者の検証環境)
- PC:MacBook Air (M1, macOS 15.5 arm64)
- エディタ:Thonny 4.1.6(Python 3.10.11, Tk 8.6.13)
- デバイス:Raspberry Pi Pico W(MicroPython)
もちろん、Windows や Linux 環境でも動作します。MicroPythonを導入していれば同じコードで実行可能です。
配線図


安全上の注意
- LEDには極性(+と−)があります。長い脚が+側です。
- 抵抗を必ず直列に入れましょう。入れ忘れるとLEDが焼ける危険があります。
- 静電気が強い日や金属テーブル上では、手で基板を触る前に放電しておきましょう。
まずは動かすためのコードから
このコードは、「とにかく分かりやすさ優先」で書いています。
多少冗長でも、挙動がイメージしやすいようにコメントをたくさん入れています。
from machine import Pin, PWM
from time import sleep
# ==========================
# 定数定義
# ==========================
LED_PIN = 15 # LED接続ピン
PWM_FREQ_HZ = 1000 # PWM周波数(Hz)
MAX_DUTY = 65535 # 16bitスケールの最大値
FADE_STEP_SECONDS = 0.01 # 1ステップごとの待ち時間(秒)
# ==========================
# 関数定義
# ==========================
# ===================================================
# 関数名:
# set_brightness
#
# 役割:
# LEDの明るさをパーセンテージ(0〜100)で指定し、
# 指定した明るさでLEDを点灯(または消灯)させる
#
# 引数:
# <PWM> pwm / 制御対象となるPWMオブジェクト
# <int> percent / LEDの明るさを0〜100のパーセンテージで指定
#
# 戻り値:
# なし / 画面には何も返さず、pwmのデューティ比を変更するだけ
#
# ローカル変数:
# ratio: percentを0.0〜1.0の比率に変換した値
# duty_value: duty_u16に渡す0〜MAX_DUTYの整数値
#
# 使用する定数:
# MAX_DUTY: PWMのデューティ比を16bitスケールで表したときの最大値(65535)
#
# グローバル変数:
# なし
#
# 注意点:
# ・percentは0〜100の範囲を想定している(それ以外を渡すと想定外の明るさになる)
# ・pwmは事前にPWM(Pin(LED_PIN))で初期化され、freqも設定済みであること
# ・MAX_DUTYなどの定数はモジュール先頭で定義しておくこと
# ===================================================
def set_brightness(pwm, percent):
ratio = percent / 100.0
duty_value = int(MAX_DUTY * ratio)
pwm.duty_u16(duty_value)
# ==========================
# メイン処理
# ==========================
def main():
pwm = PWM(Pin(LED_PIN))
pwm.freq(PWM_FREQ_HZ)
while True:
# ------------------------------
# フェードイン(0% → 100%)
# ------------------------------
# 下の for 文は、ざっくり書くと
# set_brightness(pwm, 0)
# set_brightness(pwm, 1)
# set_brightness(pwm, 2)
# ...
# set_brightness(pwm, 100)
# を順番に実行しているイメージです。
for percent in range(0, 101): # 0,1,2,...,100
set_brightness(pwm, percent)
sleep(FADE_STEP_SECONDS)
# ------------------------------
# フェードアウト(100% → 0%)
# ------------------------------
# こちらは逆向きに
# 100, 99, 98, ..., 0
# という順番で set_brightness を呼び出しています。
for percent in range(100, -1, -1): # 100,99,98,...,0
set_brightness(pwm, percent)
sleep(FADE_STEP_SECONDS)
# ==========================
# 実行部
# ==========================
if __name__ == "__main__":
main()
このコードを保存し、Picoに書き込んで実行すると、LEDがゆっくり明るくなり、またゆっくり暗くなる様子が見られるはずです。
「あ、ちゃんと滑らかに変わってる!」と感じられたら成功です。
こうやってコード内に書くと後で見返したときにわかりやすいよ
リファクタリングコード
こちらが、定数や関数を整理したリファクタリング済みのコードです。
中身は同じ「フェードイン・フェードアウト」ですが、設定を変えやすく、読みやすい構造になっています。
from machine import Pin, PWM
from time import sleep
# ==========================
# 定数定義
# ==========================
LED_PIN = 15 # LED接続ピン
PWM_FREQ_HZ = 1000 # PWM周波数(Hz)
MAX_DUTY = 65535 # 16bitスケールの最大値
MIN_DUTY_PERCENT = 0 # 最小の明るさ(0%)
MAX_DUTY_PERCENT = 100 # 最大の明るさ(100%)
FADE_STEPS = 100 # フェードの分割数(多いほどなめらか)
STEP_SECONDS = 0.01 # 1ステップごとの待ち時間(秒)
HOLD_TOP_SECONDS = 0.5 # 最大輝度でキープする時間(秒)
HOLD_BOTTOM_SECONDS = 0.5 # 最小輝度でキープする時間(秒)
# ==========================
# 関数定義
# ==========================
def set_brightness(pwm, percent):
ratio = percent / 100.0
duty_value = int(MAX_DUTY * ratio)
pwm.duty_u16(duty_value)
# 関数名:
# fade
#
# 役割:
# LED の明るさを「スタート → ゴール」へ向けて
# 少しずつ変化(フェード)させる
#
# 引数:
# <PWM> pwm / 制御対象となる PWM オブジェクト
# <int> start_percent / フェード開始時の明るさ(0〜100%)
# <int> end_percent / フェード終了時の明るさ(0〜100%)
# <int> steps / 何段階に分けて変化させるか(多いほど滑らか)
# <float> step_delay / 各ステップごとの待ち時間(秒)
#
# 戻り値:
# なし / 明るさを変化させるだけで、値は返さない
#
# ローカル変数:
# step_size: 1ステップごとに変化させる明るさの量(%)
# current: 現時点の明るさ(ループ中で更新される)
#
# 使用する定数:
# なし(ただし set_brightness 内で MAX_DUTY を使用)
#
# グローバル変数:
# なし
#
# 注意点:
# ・start_percent と end_percent の値は 0〜100 の範囲を想定している
# ・steps が小さすぎると変化がカクカクになる
# ・pwm は事前に PWM(Pin(x)) で初期化し、freq が設定されている必要がある
# ===================================================
def fade(pwm, start_percent, end_percent, steps, step_delay):
step_size = (end_percent - start_percent) / steps
current = start_percent
for _ in range(steps + 1):
set_brightness(pwm, current) # ← percentのまま呼べる
sleep(step_delay)
current += step_size
# ==========================
# メイン処理
# ==========================
def main():
pwm = PWM(Pin(LED_PIN))
pwm.freq(PWM_FREQ_HZ)
while True:
# フェードイン(暗い → 明るい)
fade(
pwm,
MIN_DUTY_PERCENT,
MAX_DUTY_PERCENT,
FADE_STEPS,
STEP_SECONDS,
)
sleep(HOLD_TOP_SECONDS)
# フェードアウト(明るい → 暗い)
fade(
pwm,
MAX_DUTY_PERCENT,
MIN_DUTY_PERCENT,
FADE_STEPS,
STEP_SECONDS,
)
sleep(HOLD_BOTTOM_SECONDS)
# ==========================
# 実行部
# ==========================
if __name__ == "__main__":
main()
比率やステップ数、キープ時間を定数で管理しているので、好みに合わせた光り方を試しやすくなっています。
ここまで来ると、他のGPIOピンや複数のLEDにも応用しやすくなります。
仕組みを理解する(技術解説)
ここからは、コードの裏側で何が起きているのかを、初心者向けに整理してみます。
なんとなく動かすだけでなく、仕組みをイメージできると、次のステップに進みやすくなります。
PWMで明るさが変わる理由
PWM(Pulse Width Modulation)は、電圧をアナログ的に変えているわけではありません。
実際には、高速にONとOFFを繰り返して、平均のON時間を変えることで明るさを調整しています。
たとえば1kHzのPWMなら、1秒間に1000回ON/OFFを切り替えています。
そのうち80%をONにすれば、LEDは「8割の明るさ」に感じられます。
duty_u16とデューティ比
MicroPythonのPWMでは、duty_u16 という16bitスケールの値でON時間の割合を指定します。
0〜65535の整数で、0なら完全OFF、65535なら常にONというイメージです。
リファクタリング前のコードでは、パーセントから比率を計算して、MAX_DUTYを掛けていました。
リファクタリング後のコードでは、明るさを 0〜100% のパーセント表記に統一しています。
これにより、初心者でも直感的に理解しやすくなり、コード内の計算も比較的シンプルになります。
for文で滑らかさを作る
LEDが滑らかに変化して見えるのは、for文で少しずつ明るさの値を変えているからです。
ステップ数を増やすと、より細かく変化するので、目にはよりなめらかに映ります。
逆にステップ数を減らすと、「カクカク」した変化になり、フェードというより段階的な点灯になります。
FADE_STEPS と STEP_SECONDS の組み合わせを変えることで、雰囲気の違う光り方を作れます。
関数化のメリット
set_brightness や fade のように、処理を関数にまとめると、コードの見通しが良くなります。
同じ処理を何度もコピペする必要がなくなるので、バグも入りにくくなります。
将来的にRaspberry Pi Pico で複数のLEDや、Pico2で別のPWM出力を扱うときにも、この考え方はそのまま使えます。
トラブルシューティング(チェックリスト)
うまく動かないときは、落ち着いて1つずつ確認していくのがコツです。
よくある症状を表にまとめたので、チェックリストとして使ってください。
| 症状 | 考えられる原因 | 対処方法 |
|---|---|---|
| LEDがまったく光らない | 配線ミス/LEDの極性逆/GPIO番号の不一致 | LEDの足の向きと抵抗の位置、LED_PINの値を見直す |
| 点くがフェードしない | PWMではなくPin出力を使っている | 必ずPWM(Pin(LED_PIN)) を使っているか確認する |
| チカチカ点滅して見える | PWMの周波数が低すぎる | pwm.freq(PWM_FREQ_HZ) で1000Hz程度に設定する |
| 明るさの変化がカクカクしている | FADE_STEPS が少なすぎる | FADE_STEPS を増やして、STEP_SECONDSも調整する |
| すごくゆっくり変化してしまう | STEP_SECONDS が大きすぎる | STEP_SECONDS を0.01など小さめに設定する |
| エラーで止まってしまう | インデントやコロンの打ち間違い | エラーメッセージの行番号を見て、該当行を慎重に見直す |
配線写真が無くても、上の表を上から順に確認していけば、多くのトラブルは解消できます。
特にGPIO番号とGNDの接続は、落ち着いて見直してみてください。
まとめと次のステップ
ここまで、Raspberry Pi Pico と MicroPython を使って、LEDの明るさを滑らかに変える方法を見てきました。
Lチカから一歩進んで、PWMを使ったフェードイン・フェードアウトが自分で書けるようになっていればバッチリです。
この記事のポイントを3行で振り返ってみます。
- PWMは「ON時間の割合」で明るさを調整する仕組み
- for文でデューティ比を少しずつ変えるとフェードが作れる
- 定数と関数で整理すると、調整・再利用がぐっと楽になる
次のステップとしては、例えばこんな応用が考えられます。
- 3色LEDを使って、信号機のように順番にフェードさせる
- ボタン入力と組み合わせて、明るさを手動で変える
- 複数のPWMチャンネルで、複数のLEDを別々に制御する
Raspberry Pi Pico でも Pico2 でも、今回のような基本的なPWM制御はほぼ共通です。
この先、センサーやモーター制御に進むときも、今回の「比率で考える」「関数でまとめる」という考え方はそのまま活かせます。
-160x90.png)
-160x90.png)
-120x68.png)
-120x68.png)
コメント