Library

PWM の基礎

デジタルピンで「擬似アナログ」を作る技術。 無線ラジコンカーでは サーボの角度モータの速度 の両方で使いました。

関連: ミニ①〜③ / ESP32 LEDC / M5 StickC PWM(公式)

① PWM とは?

Chocofon(B):
GPIO は HIGH か LOW しかないのに、どうやってモータの速さを変えるの?
AIチューター:
答えが 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 ステップ
  1. ledcSetup(channel, freq, resolution_bits) — チャンネル・周波数・分解能を決める
  2. ledcAttachPin(pin, channel) — そのチャンネルを GPIO に結びつける
  3. 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);
}

出典の考え方: docs.m5stack.com — StickC PWMledcSetup / ledcAttachPin / ledcWrite

このラボ(サーボ)でのイメージ

// 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 の analogWrite と、ESP32 の LEDC、ラズパイの PWM、全部おんなじ?
AIチューター:
「デューティで平均電圧っぽくする」思想は同じですが、ハードウェアと 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 上のソフト制御が基本になりがち。厳密なパルス幅はハード支援や専用ライブラリを検討

関連ページ