PWMの概要
PWM(パルス幅変調)は一定周期の中でHIGHの時間(デューティ比)を変えることで、LEDの明るさやモータの速度、サーボの角度を擬似的にアナログ制御する手法です。Linuxでは /sys/class/pwm 以下のチャネルを export し、period(周期)と duty_cycle(HIGH時間)をナノ秒で設定して enable します。ハードウェアPWMはCPU負荷をかけずに正確な波形を出せますが、利用できるピンが限られます。サーボ制御では周期20ms前後でデューティを変える、といった具体的な数値設計が必要です。
PWM(Pulse Width Modulation、パルス幅変調)は、デジタルの出力しかできないピンで、擬似的にアナログのような制御を実現する手法です。GPIOの出力はHIGHかLOWの2値しか取れませんが、これを一定の周期で高速にON/OFFし、1周期の中でHIGHでいる時間の割合を変えることで、「実効的な強さ」を連続的に調整します。このHIGH時間の割合をデューティ比と呼びます。たとえばデューティ比50%なら半分の時間だけ電力が供給され、LEDなら中くらいの明るさに、デューティ比10%なら暗く、90%ならほぼ最大の明るさに見えます。人間の目や、モータの回転、サーボの機構は、十分速いON/OFFを平均化して受け取るため、あたかも電圧を連続的に変えたかのように振る舞います。GPIOの基本だけでは出せない「中間の強さ」を作り出せるのが、PWMの価値です。
PWMの代表的な用途は3つあります。LEDの調光(デューティ比を上げるほど明るく見える)、DCモータの速度制御(デューティ比が回転の勢いに対応する)、そしてサーボモータの角度制御です。LED調光では、人間の目がちらつきを感じない程度に速くON/OFFすれば、デューティ比がそのまま明るさとして知覚されます。DCモータでは、速いON/OFFをモータの巻線とイナーシャが平均化するため、デューティ比で回転数を滑らかに変えられます。とくにサーボは特殊で、「一定周期の中でのHIGHパルスの長さそのもの」で角度を指示します。一般的なサーボは周期20ms(=50Hz)で、HIGHの幅がおよそ1.0msなら一方の端、1.5msで中央、2.0msでもう一方の端、という具合に角度が決まります。このように、PWMでは「周期」と「HIGH時間」という2つの数値の設計が制御の本質になります。用途によって最適な周期が異なる点も、ここで意識しておきたいところです。
sysfsインターフェースで操作する
LinuxではハードウェアPWMを /sys/class/pwm 以下のファイル操作で扱えます。手順はGPIOのsysfs方式と似ています。まず使いたいPWMチャネルを export します。`echo 0 > /sys/class/pwm/pwmchip0/export` とすると pwm0 というディレクトリが現れます。次に period(1周期の長さ)と duty_cycle(1周期のうちHIGHでいる時間)を、いずれもナノ秒単位で設定します。たとえば周期20ms・HIGH1.5msのサーボ中央位置なら、`echo 20000000 > .../pwm0/period`(20ms=20,000,000ns)と `echo 1500000 > .../pwm0/duty_cycle`(1.5ms=1,500,000ns)を書き込みます。最後に `echo 1 > .../pwm0/enable` で出力を開始します。duty_cycle は period 以下でなければならない点に注意してください。
数値の関係を整理すると、デューティ比=duty_cycle ÷ period です。LEDの明るさを半分にしたいなら、period はそのままに duty_cycle を period の半分にします。明るさを連続的に変えたいときは、period を固定したまま duty_cycle だけを 0 から period まで動かせばよく、これがLEDのフェードイン・フェードアウトの実装になります。周波数(1秒あたりの周期数)は 1 ÷ period で求まり、period を 20,000,000ns(20ms)にすれば 50Hz になります。LED調光では人間にちらつきが見えないよう数百Hz〜数kHz程度の周波数(=短めの period)を選び、サーボでは規格どおり50Hz前後(=20msの period)にする、というように用途で周期を決めます。ナノ秒という細かい単位で指定するぶん桁を間違えやすいので、ミリ秒・マイクロ秒からの換算(1ms=1,000,000ns、1μs=1,000ns)を意識して書くと事故が減ります。
ハードウェアPWMとソフトウェアPWM
PWMには大きく2種類あります。専用回路が波形を生成するハードウェアPWMは、CPUの介在なしに正確で安定した波形を出し続けられます。一方、CPUがGPIOを高速にON/OFFして波形を作るソフトウェアPWMは、任意のピンで使える手軽さがある反面、CPUが他の処理で忙しくなるとタイミングが揺らぎ、波形が乱れます。サーボのように幅の精度が角度に直結する用途では、揺らぎが微妙な震えや位置ずれになって現れるため、可能ならハードウェアPWMを使うのが望ましい選択です。Raspberry PiでハードウェアPWMが出せるピンは限られており、どのピンが対応するかは raspi-gpio などでピンの機能(ALT機能の割り当て)を確認します。`raspi-gpio get` で各ピンの現在の機能を見て、PWM機能に割り当てられているかを確かめられます。
配線と事故の注意、実務の勘どころ
配線面では、駆動する対象に応じた注意が要ります。LED1個程度ならGPIOから直接でも構いませんが、DCモータやサーボはGPIOが供給できる電流をはるかに超えるため、信号線だけをPiにつなぎ、電源は別系統から取って、間にモータドライバを挟むのが鉄則です。サーボやモータの電源をPiの3.3Vや非力な5Vから直接取ると、突入電流で電圧が落ちてPiが再起動したり、最悪壊れたりします。信号は3.3V系である点も忘れず、5V論理のデバイスとはレベル変換を検討します。実務の流れは「export → period と duty_cycle をナノ秒で設定 → enable」で波形を出し、サーボなら 1.0ms/1.5ms/2.0ms 付近で角度の対応を実測してから、目的の制御範囲をプログラムに落とし込む、という進め方が確実です。GPIOでは出せない滑らかな強弱を、安全な配線とともに実現するのがPWMの勘どころです。