今回は DCモーターの制御 に挑戦します。
モーターの回転速度を調整するには、一般的に PWM(パルス幅変調) という方法を使います。PWMとは、電源のONとOFFをとても速いスピードで切り替えることで、モーターに流れる電流の平均量をコントロールする技術です。
-
ONの時間が長いほど、モーターは速く回転します。
-
OFFの時間が長くなると、回転はゆっくりになります。
PWMの大きな利点は、常に最大電圧をかけながらも回転速度を調整できる点です。これにより、低速でも**高いトルク(回す力)**を維持することができます。
今回の回路は「まずモーターを動かしてみる」ことを目的としたシンプルな構成にしています。
PWM(パルス幅変調)とは?
用語 | 意味 | モーター制御での役割 |
---|---|---|
パルス (Pulse) | デジタルの ON(High)/OFF(Low) 信号 | モーターへ「電圧をかける/切る」の合図 |
幅 (Width) | ON 状態が続く時間(Duty) | 幅が長いほど平均電圧↑=回転速↑ |
変調 (Modulation) | 幅を変えて平均値を調整 | 幅を短くすれば平均電圧↓=回転速↓ |
周波数
1 kHz と設定すれば 1 秒間に 1,000 回 ON/OFF を繰り返す。
周波数そのものは速度に大きく影響せず「どれだけ細かく刻むか」を決めるパラメータ。
Duty(デューティ比)
0 %=常時 OFF、100 %=常時 ON。
例: 1 kHz で 50 % Duty → 1 ms 中 0.5 ms ON / 0.5 ms OFF。
平均電圧が Vin × Duty になるイメージで、DC モーターは平均電圧に比例して回転速度が変わる。
回路
マブチ製 DC モーター を PWM で駆動します。
モーターには比較的大きな電流が流れるため、スイッチング素子として Nch MOSFET「2SK4017」 を採用します。逆起電力対策としてダイオードを並列に入れ、ゲートの保護やノイズ低減に抵抗とコンデンサを追加します。
モーターには比較的大きな電流が流れるため、スイッチング素子として Nch MOSFET「2SK4017」 を採用します。逆起電力対策としてダイオードを並列に入れ、ゲートの保護やノイズ低減に抵抗とコンデンサを追加します。
役割 | 部品 | 備考 |
---|---|---|
モーター | マブチ DC モーター | |
スイッチング素子 | Nch MOSFET 2SK4017 | 大電流対応 |
フリーホイールダイオード | 1N4007 | 逆起電力吸収 |
ゲート抵抗 | 1 kΩ | ゲート突入電流の抑制 |
ゲートプルダウン抵抗 | 20 kΩ | 誤動作防止(ゲートの浮きを防ぐ) |
デカップリングコンデンサ | 0.1 µF セラミック | 電源ノイズ吸収 |
ソースコード
from machine import Pin, PWM
import time
# PWMを出力するピン(例: GP15)を指定
pwm_pin = PWM(Pin(15))
# PWMの周波数(Hz)を設定(例: 1000Hz = 1kHz)
pwm_pin.freq(1000)
# デューティサイクル(0〜65535)を設定
# 例えば50%出力なら約32768
def set_motor_speed(percent):
# percent: 0〜100
duty = int(65535 * (percent / 100))
pwm_pin.duty_u16(duty)
print(f"Speed: {percent}% → Duty: {duty}")
# 実行例
for speed in range(0, 101, 20):
set_motor_speed(speed)
time.sleep(1)
# 最後に停止
set_motor_speed(0)
>>> %Run -c $EDITOR_CONTENT
MPY: soft reboot
Speed: 0% → Duty: 0
Speed: 20% → Duty: 13107
Speed: 40% → Duty: 26214
Speed: 60% → Duty: 39321
Speed: 80% → Duty: 52428
Speed: 100% → Duty: 65535
Speed: 0% → Duty: 0
>>>
処理の流れ
⚙️ 初期化
Pin(15) を PWM モードに割り当て、1 kHz で動作開始。
まだデューティは 0(暗黙の初期値)なのでモーター停止状態。
🚀 加速テストループ
0 %→20 %→…→100 % と 5 回速度を段階的に変更。
各段階で 1 秒ディレイし、モーターが新しい速度に落ち着くのを待つ。
set_motor_speed() 内部でデューティ値が計算され PWM ハードウェアに書き込まれるため、速度変更は即時。
🛑 停止
最後に set_motor_speed(0) でデューティ 0。電圧 0 V 相当になり、回転が止む。
物理的には慣性で少し回り続けるので、急停止したい場合は逆極性ブレーキや H ブリッジを使う。
長押しボタンでモーター速度を段階制御する PWM プログラム(MicroPython)
# ────────────────────────────────────────────────────────────
# 長押しボタンでモーター速度を段階制御し、
# Ctrl-C で確実に停止する MicroPython スクリプト
# ────────────────────────────────────────────────────────────
from machine import Pin, PWM
import time
# ==== 定数 ====
PWM_PIN = 15 # モーター用 PWM 出力
BTN_PIN = 16 # ボタン入力(LOW = 押下)
FREQ_HZ = 1000 # PWM 周波数 [Hz]
STEP = 5 # 速度の増減幅 [%]
LONG_MS = 500 # 長押し判定時間 [ms]
INTERVAL = 100 # 速度更新周期 [ms]
LOOP_DELAY = 20 # ループ間隔 [ms]
# ==== 初期化 ====
pwm = PWM(Pin(PWM_PIN))
pwm.freq(FREQ_HZ)
button = Pin(BTN_PIN, Pin.IN, Pin.PULL_UP) # 内蔵プルアップ
def set_speed(pct: int) -> int:
"""0–100 % を渡して PWM デューティを更新し、その値を返す"""
pct = max(0, min(100, pct))
duty = int(pct * 65535 / 100)
pwm.duty_u16(duty)
print(f"Speed = {pct:3d}% Duty = {duty}")
return pct
speed = set_speed(0)
# ==== ループ用変数 ====
last_state = button.value()
press_start_ms = time.ticks_ms()
last_update_ms = time.ticks_ms()
print("▶ モーター制御開始(Ctrl-C で停止)")
try:
while True:
state = button.value() # 0 = 押下, 1 = 離脱
now = time.ticks_ms()
# ── エッジ検出 ──────────────────────
if state != last_state:
if state == 0: # 押した瞬間
press_start_ms = now
last_state = state
# ── 押下中(長押し判定込み) ──────────
if state == 0 and time.ticks_diff(now, press_start_ms) > LONG_MS:
if time.ticks_diff(now, last_update_ms) > INTERVAL:
speed = set_speed(speed + STEP)
last_update_ms = now
# ── 離脱中(減速) ──────────────────
if state == 1 and speed > 0 and time.ticks_diff(now, last_update_ms) > INTERVAL:
speed = set_speed(speed - STEP)
last_update_ms = now
time.sleep_ms(LOOP_DELAY)
finally:
# ==== ここは必ず実行される ====
print("\n⏹ 停止処理中 …")
set_speed(0) # デューティ 0 %
pwm.deinit() # PWM モジュール解放
print("✔ モーター停止、プログラム終了")
📝処理の流れ
⚙️ 定数設定
PWM出力ピンやボタンピン、PWM周波数、速度の増減幅、長押し判定時間などを決める
🔧 初期化
PWMピンを指定周波数でセットアップ、ボタン入力をプルアップで初期化
🎛 初期速度設定
モーター速度を0%にセットし停止状態にする
🔄 メインループ開始
ボタン状態を継続的に読み取り、状態変化を監視
🕵️ エッジ検出
ボタンの押し始め(押下時)を検出し、押下時刻を記録
⏱ 長押し判定
押下継続時間が500msを超えたら「長押し」と判断
⬆️ 加速処理
長押し中は100msごとに速度を5%ずつ増やす(最大100%まで)
⬇️ 減速処理
ボタンが離されている間は100msごとに速度を5%ずつ減らす(0%まで)
💤 CPU負荷軽減
ループ末尾で20msスリープして処理を制御
🛑 終了時処理(finally)
Ctrl-Cなどでプログラム終了時に必ず実行され、モーターを停止しPWMを解放
コメント
コメントを投稿