スキップしてメイン コンテンツに移動

DCモータを動かす(PWM)

 今回は 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」 を採用します。逆起電力対策としてダイオードを並列に入れ、ゲートの保護やノイズ低減に抵抗とコンデンサを追加します。

役割 部品 備考
モーター マブチ 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)

# デューティサイクル(065535)を設定
# 例えば50%出力なら約32768
def set_motor_speed(percent):
    # percent: 0100
    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を解放




コメント

このブログの人気の投稿

Raspberry Pi Pico Wを使ってみよう

   Raspberry Pi Pico W(ラズベリーパイ ピコ ダブリュー) は、英国 Raspberry Pi 財団が 2022 年に発売した Wi-Fi 搭載マイコンボードです。従来の「Raspberry Pi」と聞くと Linux が動くシングルボードコンピュータ(SBC)を思い浮かべがちですが、Pico W は マイクロコントローラ (MCU)に分類され、いわゆる “組み込み開発” を手軽に始められるデバイスです。搭載 MCU はデュアルコア Arm Cortex-M0+(133 MHz 動作)の RP2040 。ここに Infineon 製 CYW43439 チップが追加され、 2.4 GHz IEEE 802.11 b/g/n Wi-Fi(BLE 対応 FW も提供中) が使えるのが最大の特徴です。  開発言語は MicroPython や CircuitPython が真っ先に紹介されることが多いのですが、 公式 Pico SDK を使えば C/C++ でも本格的に開発 できます。SDK は CMake ベースで Windows/macOS/Linux いずれでも利用可能。さらに、Arduino Core RP2040 が整備されたことで Arduino IDE 2.x からも “スケッチ感覚” で書き込みが可能 になりました。したがって、 「まずは Python でサッと試す」 「より高速化や省メモリ化が必要になったら C/C++ へ移行」 といった二段構えの学習ルートが取れるのが魅力です。 メニュー(基礎編) 01. Raspberry Pi Pico Wの開発環境を整える。 02. スイッチで 発光ダイオード(LED) を点灯・消灯させる 03. タイマーで発光ダイオード(LED)を1秒ごとに点滅させる 04. シリアル通信(オウム返し ) 05. シリアル通信(発光ダイオードの点灯・消灯) 06. サーボモーターを動かしてみよう(SG90制御入門) 07. DCモータを動かす(PWM) 08. IRリモートでRGBLED点灯 09. アナログ電圧を測定する(ADCの基本) 10. GPIO割り込み処理 11. リレーを駆動してLEDを制御する 12. DFPlayer で MP3 再生 13. 7 セグ 4 ...

スイッチで発光ダイオード(LED)を点灯・消灯させる

 スイッチを使って発光ダイオード(LED)を制御してみましょう。今回は、スイッチをオンにすると LED が点灯し、オフにすると消灯するように動作させます。もちろん、スイッチと LED を直接接続するのではなく、適切な回路を介して制御します。 1.回路 GPIO16 はデジタル入力として使用し、内部プルアップを有効にします。GPIO15 は出力として設定します。なお、接続には 1kΩ(1キロオーム)の抵抗を使用します。 【ソースコード】 # スイッチで LED を ON / OFF する簡単な例 #   GPIO15 : LED(出力)— LOW で消灯、HIGH で点灯 #   GPIO16 : スイッチ(入力)— 内部プルアップ抵抗を使用 # # ※ 配線例 #   LED のアノード → 1 kΩ 抵抗 → GPIO15 #   LED のカソード → GND #   スイッチ片側   → GPIO16 #   スイッチ反対側 → GND # # ★ 動作 #   スイッチを押す(GPIO16 が LOW)   → LED 点灯 #   スイッチを離す(GPIO16 が HIGH) → LED 消灯 from machine import Pin    # GPIO 制御ライブラリ import utime               # 時間関連(今回は使用しないが拡張用に読み込み) led = Pin ( 15 , Pin.OUT)                 # GPIO15 を出力モードに設定(LED 用) sw   = Pin ( 16 , Pin.IN, Pin.PULL_UP)     # GPIO16 を入力モード+内部プルアップ有効 while True:     if sw. value () == 1 :      # プルアップなので押していないときは 1   ...

シリアル通信(オウム返し)

 Raspberry Pi Pico Wは単体で使うのも便利ですが、パソコンや他のマイコンなど、さまざまな機器と通信できるとさらに活用の幅が広がります。 そこで今回は「シリアル通信」について紹介します。 まずは、パソコンから送られてきたデータをPico Wが受け取り、同じデータをそのままパソコンに送り返す、いわゆる「オウム返し(エコー)」を実装してみましょう。 シリアル通信とは? シリアル通信は、マイコンとパソコンや他の機器がデータを1ビットずつ順番に送受信する通信方式です。Raspberry Pi Pico WではUART(Universal Asynchronous Receiver/Transmitter)というハードウェアを使って実現します。 接続回路  id      TX       RX        baudrate     parity    stopbit  0  GPIO0 GPIO1   9600  なし  1  1  GPIO4 GPIO5   9600  なし  1 今回はUART1(GPIO4:TX、GPIO5:RX)を使用します。 ソースコード例 from machine import UART, Pin # UART1ポートを9600bpsで初期化(ボーレートを指定) sirial = UART ( 1 , 9600 ) # UARTの詳細設定: 9600bps 、データビット8、パリティ無し、ストップビット1で初期化 sirial. init ( 9600 , bits = 8 , parity = None, stop = 1 ) # UARTで文字列を送信する(※MicroPythonではバイト列で送るのが正しいため b '' にしたほうが安全) sirial. write (b 'Hello World \n\r ' )  # 起動時に「Hello World」を送信 # メインループ while True:     # 受信バッファにデータが存在するかチェック     if sirial. any () > 0 : ...