3.15. DCモーター制御

DCブラシ付きモーターは、磁界の中にある軸上の巻線コイルです。コイルに電流を流すと磁界がコイルに力を及ぼし、その力が軸のトルクになります。モーター内部のブラシは軸の回転に合わせてコイル内の電流方向を切り替えるため、トルクは常に軸を同じ方向へ押し続けます。2本のモーターリードに直流電圧を加えると軸が回転し、極性を入れ替えると逆方向に回転します。

モーターは通常、カメラの3.3 Vロジック電源を上回る供給電圧で、数百ミリアンペアから数アンペアの電流を必要とします。GPIOピンが供給できる電流は25 mA程度で、極性を反転することもできません。つまり2つの電源レールを駆動できるだけです。カメラとモーターの間の駆動段は、モーターの電流を流し、より高電圧の別系統のモーター電源を配線し、さらにカメラの指示で極性を反転できる必要があります。4トランジスタ構成のHブリッジが標準的な解決策です。

3.15.1. Hブリッジ

Hブリッジは、モーターの周りにH字状に配置された4つのスイッチです。

Hブリッジの回路図。上部のVmotorはスイッチS1を通って左側のノードAへ下り、スイッチS2を通って右側のノードBへ下る。モーターMはAとBの間に水平に配置される。Aからは別のスイッチS3がグランドへ下り、Bからは別のスイッチS4がグランドへ下る。

Hブリッジ。4つのスイッチ(S1 -- S4)がモーター M をVmotorとグランドの間に接続します。

異なるスイッチの組み合わせを閉じることで、モーターがそのリードで受け取る状態を選択できます。

  • S1 + S4が閉、S2 + S3が開。 電流はVmotorから S1 を通って A に入り、モーターを横切って B へ、そして S4 を通ってグランドへ流れます。モーターは一方向に回転します。

  • S2 + S3が閉、S1 + S4が開。 電流はモーターを反対方向に流れます。モーターは逆方向に回転します。

  • 4つすべてが開。 両方のモーターリードがフローティングになり、モーターは惰性で回転します。

  • S3 + S4が閉(またはS1 + S2が閉)。 両方のモーターリードが同じレールに接続され、モーター自身の運動エネルギーが電流を生み出し、閉じたスイッチ対がそれを熱として短絡消費します。モーターはブレーキがかかります。

許されない組み合わせは、同じ列の両方のスイッチ(S1 + S3 または S2 + S4)を閉じることです。これはVmotorからグランドへ直接つながる短絡を形成します。これが貫通電流(shoot-through)であり、カメラのコードはこれを決して許してはなりません。

実際には、4つのスイッチは集積ドライバICの内部にあるMOSFET(レベルシフト のページで紹介)です。このチップは内部で4つのスイッチに対応する2つまたは3つのロジックレベル入力ピンを公開しており、貫通電流を防ぐインターロックロジックを備えているため、カメラのコードが直接管理する必要はありません。

3.15.2. PWMとモーターのインダクタンス

モーターの速度を設定するには、フルオンとフルオフだけでは不十分です。コツは、PWMによるLED調光 でLEDに使ったものと同じです。すなわち、高い周波数で駆動をパルス化し、負荷に結果を平均させるのです。LEDの場合は目が平均化を行いましたが、モーターの場合はコイル自身がそれを行います。

モーターコイルにはかなりのインダクタンスがあります。インダクタを流れる電流は瞬時に変化することができず、コイル両端の電圧に比例した速さで変化します。20 kHzでブリッジをオンオフにパルス化すると、各オン期間中にコイル電流が上昇し、オフ期間中にも電流は流れ続けなければなりません。コイルはそれを維持するために自身の両端電圧を反転させます。

行き場がなければ、その電流は開いたばかりのスイッチ両端の電圧を急上昇させ、トランジスタを損傷する恐れがあります。各スイッチに並列接続されたフリーホイールダイオード(多くの場合、ドライバチップ内のMOSFET自身のボディダイオード)が、電流に必要な経路を与えます。電流はダイオードを通り、まだ閉じているスイッチの1つを通って戻り、フリーホイールループを形成します。このループ内で電流はブリッジとモーター自身の小さな抵抗を通じて徐々に減衰します。さらにダイオードは、開いたスイッチ両端の電圧を、ループが戻るレールからダイオードの順方向降下分の範囲内に固定し、MOSFETの安全動作領域内に十分収めます。

トルクを生み出すのは各PWM周期にわたる電流の平均であり、その平均はデューティサイクルに線形に追従します。デューティを2倍にすればトルクはほぼ2倍になり、一定負荷では速度もほぼ2倍になります。目の非線形応答のために曲線が必要だったLED調光とは異なり、duty_u16 の線形なスイープはそのままモーターの駆動力の線形なスイープに対応します。

PWM周波数は、2つのしきい値を超えればよいだけです。

  • 約20 kHzより上では、キャリアは人間の可聴域の外になります。それより下では、コイルにかかる磁力が各PWMパルスごとに上下し、巻線と積層鉄心がキャリア周波数で物理的に振動します。つまりモーターは事実上、PWMの音程の音を出す小さなスピーカーになります。

  • 約50 kHzをはるかに超えると、MOSFETとそのゲートドライバはスイッチング損失によって効率が低下し始めます。各オンオフ遷移の間、MOSFETは一瞬だけ大きな電圧と大きな電流の両方を負担し、わずかな電力を熱として消費します。またMOSFETのゲート容量も各サイクルで充放電する必要があり、その負担はドライバチップが担います。どちらのコストもPWM周波数に比例して増大するため、高い周波数ではスイッチングによる発熱がモーター電流を流すことによる発熱に匹敵することがあります。

20 kHzは、ホビーサイズのモーターにとって無難なデフォルト値です。

3.15.3. Hブリッジの駆動

2入力のHブリッジドライバチップは、IN1IN2 を4つのスイッチにおおよそ次のように対応させます。

  • IN1 = 0, IN2 = 0 -- 惰性走行(4つのスイッチすべてが開)。

  • IN1 = 1, IN2 = 0 -- 一方向に駆動。

  • IN1 = 0, IN2 = 1 -- もう一方向に駆動。

  • IN1 = 1, IN2 = 1 -- ブレーキ。

2つの入力をPWM出力として駆動すると、カメラはどちらのピンがデューティを担うかを選ぶことで方向を、デューティ値そのもので速度を設定できます。

import time
from machine import PWM, Pin

in1 = PWM(Pin("P7"), freq=20_000, duty_u16=0)
in2 = PWM(Pin("P8"), freq=20_000, duty_u16=0)

def drive_a(speed):       # speed: 0..65535
    in1.duty_u16(speed)
    in2.duty_u16(0)

def drive_b(speed):
    in1.duty_u16(0)
    in2.duty_u16(speed)

def coast():
    in1.duty_u16(0)
    in2.duty_u16(0)

def brake():
    in1.duty_u16(65535)
    in2.duty_u16(65535)

drive_a(32768)    # half speed in direction A
time.sleep(2)
drive_b(16384)    # quarter speed in direction B
time.sleep(2)
coast()

オフからフルまで、そして戻るランプにより、滑らかな始動と停止が得られます。

for d in range(0, 65535, 256):
    in1.duty_u16(d)
    time.sleep_ms(10)
for d in range(65535, 0, -256):
    in1.duty_u16(d)
    time.sleep_ms(10)

3.15.4. 方向・速度型ドライバ

もう1つのHブリッジチップのファミリーは、より便利なインターフェースを公開しています。1つのデジタル方向入力(しばしば DIR または「位相」を意味する PH と表記)に加えて、1つの速度入力(しばしば「イネーブル」を意味する PWM または EN)です。方向ピンがブリッジの駆動方向を選び、速度ピンのデューティサイクルが平均電流を設定します。

これは2つのPWM入力方式よりもソフトウェアから駆動しやすい方式です。2つの信号は問題が通常言い表される形(「この方向に、この速度で回す」)に一致するため、コードは in1in2 の間で分岐する代わりに set_direction(forward); set_speed(50) と書けます。必要なPWMチャンネルは1つだけなので、同じタイマー上のもう一方のチャンネルを別の用途に解放できます。さらに方向ピンは変更の合間にブリッジを再トリガーすることなく保持できるため、固定方向で速度を変えるときは1つのレジスタを操作するだけで済みます。

import time
from machine import PWM, Pin

dir_pin = Pin("P8", Pin.OUT)
speed = PWM(Pin("P7"), freq=20_000, duty_u16=0)

def drive(direction, speed_u16):
    dir_pin.value(direction)         # 0 or 1
    speed.duty_u16(speed_u16)        # 0..65535

drive(0, 32768)     # direction A at half speed
time.sleep(2)
drive(1, 16384)     # direction B at quarter speed
time.sleep(2)
speed.duty_u16(0)   # stop

この種のドライバで「停止」が実際に何を行うか(惰性走行かブレーキか)は、チップに依存します。2入力ドライバではカメラのコードが選択します(両入力をローにすれば惰性走行、両方をハイにすればブレーキ)。方向・速度型ドライバではチップが決めるため、どちらの動作に頼るにせよ事前にデータシートを一読する価値があります。