PWM の基礎
デジタルピンで「擬似アナログ」を作る技術。 無線ラジコンカーでは サーボの角度 と モータの速度 の両方で使いました。
① PWM とは?
Chocofon(B):
GPIO は HIGH か LOW しかないのに、どうやってモータの速さを変えるの?
GPIO は HIGH か LOW しかないのに、どうやってモータの速さを変えるの?
AIチューター:
答えが PWM(Pulse Width Modulation=パルス幅変調) です。 ON/OFF を高速で切り替え、ON の割合(デューティ比)で「平均としてどれくらい効いているか」を変えます。
答えが PWM(Pulse Width Modulation=パルス幅変調) です。 ON/OFF を高速で切り替え、ON の割合(デューティ比)で「平均としてどれくらい効いているか」を変えます。
キーワード
- 周波数(Hz) — 1 秒間に何回パルスを繰り返すか(例: モータ 1 kHz、サーボ 50 Hz)
- 周期(period) — 1 パルスの長さ。サーボならだいたい 20 ms(= 50 Hz)
- デューティ比(duty) — 周期のうち HIGH の割合。0%=ずっと OFF、100%=ずっと ON
- パルス幅(µs) — サーボでは「HIGH が何マイクロ秒続くか」で角度を決めることが多い
このラボでの使い分け
| 用途 | 周波数の目安 | 何を変えるか | 例 |
|---|---|---|---|
| DC モータ速度 | 〜1 kHz | デューティ比(0〜255 など) | DRV8833 の AIN に PWM |
| サーボ角度 | 50 Hz(周期 20 ms) | パルス幅(例: 1200〜1800 µs) | AS0022 / FS90 |
| ブザー音 | 可聴域(例: 1〜2 kHz) | 周波数やデューティ | 公式 PWM サンプル |
周期 20 ms(サーボ)のイメージ: |****|................|****|................| <-- パルス幅 --> 残りは LOW (例 1500 µs = 中央)
② プログラミングの基礎(ESP32 / M5)
M5StickC 系では、Arduino コアの LEDC(ハードウェア PWM)を使います。 公式ドキュメント: StickC PWM — m5-docs
基本 3 ステップ
ledcSetup(channel, freq, resolution_bits)— チャンネル・周波数・分解能を決めるledcAttachPin(pin, channel)— そのチャンネルを GPIO に結びつけるledcWrite(channel, duty)— デューティを書き込む
AIチューター:
resolution_bits = 8 なら duty は 0〜255、10 なら 0〜1023。
「何段階で滑らかに変えたいか」が分解能です。
公式サンプル(ブザー)に近い形
#include <M5StickC.h> // 公式例。ラボでは M5Unified が多い
int freq = 1800;
int channel = 0;
int resolution_bits = 8;
int buzzer = 2; // Plus / Plus2 のブザーピン例
void setup() {
M5.begin();
ledcSetup(channel, freq, resolution_bits);
ledcAttachPin(buzzer, channel);
}
void loop() {
ledcWrite(channel, 128); // 約 50%
delay(1000);
ledcWrite(channel, 0); // OFF
delay(1000);
}
このラボ(サーボ)でのイメージ
// 50 Hz・14bit などで周期を作り、パルス幅(µs)を duty に換算して書く ledcSetup(SERVO_LEDC_CH, 50, 14); ledcAttachPin(PIN_SERVO, SERVO_LEDC_CH); // writeServoUs(1500); → 中央 // writeServoUs(1200〜1800); → AS0022 安全範囲(ミニ⑤)
実務メモ
- チャンネル番号は用途ごとに分ける(モータ用とサーボ用を共用しない)
- サーボは「デューティ%」より µs で考えると仕様表と対応しやすい
- 新しい Arduino-ESP32 コアでは API 名が変わる場合あり。動かなければ公式とコア版を確認
- G0 などブートピンに PWM を出すときは起動時の挙動に注意( M5StickC ピン配置)
③ おまけ:ESP32系 / Arduino系 / Raspi系
Chocofon(B):
Uno の
Uno の
analogWrite と、ESP32 の LEDC、ラズパイの PWM、全部おんなじ?
AIチューター:
「デューティで平均電圧っぽくする」思想は同じですが、ハードウェアと API の自由度が違います。
「デューティで平均電圧っぽくする」思想は同じですが、ハードウェアと API の自由度が違います。
ざっくり比較
| ESP32 系(M5 含む) | Arduino 系(Uno など) | Raspberry Pi 系 | |
|---|---|---|---|
| 仕組み | LEDC などハード PWMが充実 | 特定ピンのハード PWM(タイマ) | ハード PWM はピン数が限られる。ソフト PWM も多用 |
| 代表 API | ledcSetup / ledcWrite |
analogWrite(pin, 0〜255) |
RPi.GPIO / gpiozero / pigpio など |
| 周波数 | チャンネルごとに比較的自由 | ピンごとにだいたい固定(〜490/980 Hz など) | ソフトなら可変だが CPU 負荷・ジッタに注意 |
| サーボ向き | 50 Hz + µs 制御がやりやすい | Servo ライブラリが定番 | リアルタイム性が弱い環境ではジッタに注意。pigpio 等が有利 |
| 向いている用途 | IoT・無線・多ch PWM(このラボ) | 学習・単純なモータ/LED | カメラ・Linux・高機能アプリ+GPIO |
覚え方
- Arduino Uno — 「決まったピンで、決まった感じの PWM」が簡単
- ESP32 — 「チャンネルを自分で設計する」代わりに自由度が高い
- Raspberry Pi — OS 上のソフト制御が基本になりがち。厳密なパルス幅はハード支援や専用ライブラリを検討
関連ページ
- モータードライバの仕組み — PWM の先にある H ブリッジ
- M5StickC ピン配置と比較 — どの GPIO に出せるか
- ミニ① / ミニ③ — 実機でのサーボ&モータ PWM
- 公式: StickC PWM