ラズパイPicoステッピングモーターの使い方 Python編

Raspberry Pi Pico ステッピングモータ アイキャッチ

Raspberry Pi Pico(PicoW)を使用したステッピングモーターの使い方を詳しく紹介します。

プログラミング言語は今回は「Python」を使用し「MicroPython」と「CircuitPython」のサンプルプログラム(コピペ)を準備していますので、「コピペ」で実行して動作確認してみましょう。


「ラズパイPico」の開発環境の準備や端子配列等の基本情報、基本的なプログラムについては、以下のリンクで詳しく紹介しています。

ラズパイPico/PicoWの使い方を3つの開発環境Python、ArduinoIDE、PlatformIOで紹介
Raspberry Pi Pico/Pico Wの使い方を端子配列からPython(MicroPython)とC言語の開発環境、Lチカ方法まで紹介。PythonはTonny、C言語はArduinoIDEとPlatformIOの3種類で詳しく紹介します。
ラズパイPico基本プログラムPython編(Lチカ,入出力,アナログ,PWM)
Raspberry Pi Picoの基本的なLチカや入出力,アナログ入力(ADC),PWM出力を行うPythonのコピペ用サンプルプログラムをまとめました。
スポンサーリンク

1.準備するもの

・Raspberry Pi Pico(PicoW)

「Raspberry Pi Pico(PicoW)」とは、電源投入ですぐに使用できて初心者でも比較的簡単にプログラミングが体験できるマイコンボードです。

「Raspberry Pi Pico(PicoW)」の外観は下画像のようになります。

ラズパイPico/Pico Wの使い方、機能

端子配列は以下のようになります。(公式サイトより抜粋

ラズパイ(Raspberry Pi) Pico 端子配列
「Pico」と「Pico W」で端子配列は同じで、LEDの端子番号のみ異なります。
「PicoW」には「Wi-Fi通信」の機能があります。

・開発環境(Thonny)

プログラムを書き込むための開発環境として「Thonny」を使用します。

「Raspberry Pi Pico(PicoW)」の開発環境はいくつかありますが「Thonny」はプログラミング言語として「Python(MicroPython & CircuitPython)」が使用でき、手軽にプログラムの作成、実行ができます。

ラズパイPicoの使い方、micropython、開発環境Thonny

開発環境の準備については、以下のリンクで詳しく紹介しています。

ラズパイPicoの使い方 MicroPython&開発環境Thonny、SSLエラーの対処方法も紹介
Raspberry Pi Picoので開発環境Thonnyを使用した「Python(MicroPython)」でのプログラミング方法について初期設定からパッケージ(ライブラリ)の追加、動作確認の方法まで詳しく紹介します。
ラズパイPicoの使い方 CircuitPython&開発環境Thonny
Raspberry Pi PicoでCircuitPythonを使ったプログラミング方法を開発環境Thonnyを使用してインストールからライブラリの追加、サンプルプログラム(コピペ)による動作確認(液晶表示SSD1306を例に)まで詳しく紹介します。
・MicroPythonとはマイクロコントローラ上で最適に動作するように開発された「Python3」と高い互換性を持つプログラミング言語です。
・CircuitPythonとはMicroPythonから派生してAdafruit社が開発を支援している言語で、マイコンボードをUSBメモリのように認識してデータの操作ができることが特徴です。

・ステッピングモーター(28BYJ-48)

ステッピングモーターは5Vで駆動できるものとして最も入手性の良い「28BYJ-48」を使用します。
マイコンボードでのステッピングモータの動作紹介では、ほぼコレが使われてますね。

安くて駆動用の基板もセットで売られていることがほとんどなので、ステッピングモータの動作確認には最適です。

制御パルスを入力するごとに一定の角度でモーターが回転動作するため、簡易的な位置決め動作用に使用できます。
減速比1/64のギヤも内蔵されているため大きな回転トルクを得ることができますが、その分回転速度は遅いため、ラジコンの走行用に使用するには動作が遅くて物足りないと思います。

外観

外観は下写真のようになります。

Raspberry Pi Pico ステッピングモータの使い方
Raspberry Pi Pico ステッピングモータの使い方
写真のように、駆動用の基板とセットで売られていることがほとんどです。
ギヤ比1/64のギヤが内蔵されていて、出力軸径はφ5mmで2面幅3mmで平取りされています。

仕様

主な仕様は以下の通りです。

項目仕様
相数4相(2相ユニポーラ)
制御方法1-2相励磁(1相、2相励磁可)
ギヤ比1/64
電圧DC5V
巻線抵抗22Ω±7%/相
1パルス(ステップ)
駆動角度
1-2相励磁:モーター単体 5.625°
 ※出力軸 5.625°/64 ≒ 0.088°
1相、2相励磁:モーター単体 11.25°
 ※出力軸 11.25°/64 ≒ 0.176°
モータ単体1回転
パルス(ステップ)数
1-2相励磁:64パルス
1相、2相励磁:32パルス
出力軸1回転
パルス(ステップ)数
1-2相励磁:4096パルス
1相、2相励磁:2048パルス
無負荷最大応答周波数1000pps(1ms)※1-2相励磁
無負荷起動最大応答周波数500pps(2ms)※1-2相励磁
起動トルク800gf.cm / 5VDC
400pps(2.5ms)※1-2相励磁
回転数について、1-2相励磁で出力軸1回転に必要なパルス数は4096パルスで、無負荷最大応答周波数は1秒間に1000パルスのため、約4秒で1回転とかなり遅いです。

制御方法について

今回使用するステッピングモーター(28BYJ-48)の構造は「2相ユニポーラ型」と呼ばれ以下のようなモデル図で表されます。

2相ユニポーラ型のモデル図

モーターの中央には回転するローターがあり、これは磁石になっています。
ローターの周りには2相のコイルがあり、コイルの中央(センタータップ)からは配線が引き出されています。

中央の配線には「電源+(5V)」を接続し、A〜Dの各配線を「電源ー(0V)」にすることで、各コイルに流れる電流を制御することができます。

コイルに電流を流すと磁力が発生します。各コイルの電流を効率よくON/OFFすることで「回転磁界」を発生させ、ローター(磁石)を回転させることができます。

電流の流れ(ON/OFF)を切り替えて「回転磁界」を発生させる「制御方法」には「1相励磁」「2相励磁」「1-2相励磁」があり、コイルA〜Dの配線を「電源ー(0V)」にするタイミングを以下表のように制御することで、モーターを回転させています。

1相励磁
ステッピングモーター1相励磁

消費電力は小さいがトルクが低く高速回転には向かない、振動も発生しやすく実用的ではない。

2相励磁
ステッピングモーター2相励磁

1相励磁に比べて回転が安定して、大きなトルクが得られるが消費電力は2倍になる。

1-2相励磁
ステッピングモーター1-2相励磁

1パルスごとの回転角度が「1相、2相励磁」に比べて半分になり、細かい制御が可能で振動も少ないため、基本的にこの制御が使用される。

サンプルプログラムでは3つの制御方法ごとに動作確認ができます。
応用編として、3つの制御方法を比較しながら、正逆転で回転速度を変えながら動作確認ができるものも準備してますので、それぞれの動作の違いも確認してみましょう。

・駆動基板(トランジスタアレーULN2003AN搭載)

今回使用する「ステッピングモーター(28BYJ-48)」を動作させるためには、このモーターとほぼセット販売されている下写真のような基板を使用します。

Raspberry Pi Pico ステッピングモータの使い方

モーターのドライバ基板というほどでもないですが、トランジスタアレー「ULN2003AN」が実装されていて、どのコイルが励磁されているかを確認できる「LED(赤)」もコイルごとに4つ実装されています。

モーター(28BYJ-48)の配線に付属のコネクタ(JST製XH)をそのまま挿して使用できます。

「ラズパイPico」の出力端子で扱える電流は小さいため、直接モーターを駆動することはできません。
トランジスタアレー「ULN2003AN」を使用することで、モーター駆動のための大きな電流を流すことができるようになります。
スポンサーリンク

2.配線図

配線図は下図のようになります。
モーター用の電源「5V」は「ラズパイPico」とは別で取るようにしています。

Raspberry Pi Pico ステッピングモータの使い方、配線図
「スイッチ(SW1〜4)」と「ボリューム」はサンプルプログラムの応用編でのみ使用します。モーターを動作させるだけなら無くても動作確認はできます。

実際にブレッドボードを使用して各部品を接続したものは下写真のようになります。

Raspberry Pi Pico ステッピングモータの使い方、配線図
ブレッドボードの左上には「USB microB → DIP5ピン変換基板」を使用して、モバイルバッテリーからモーター駆動用の5Vを取れるようにして、その横のLED(緑)で電源が来ていることを確認できるようにしています。
スポンサーリンク

3.MicroPythoのサンプルプログラム(コピペ)

「MicroPython」を使用したサンプルプログラムは以下になります。
コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

パソコンに接続せずに「ラズパイPico」単体で動作させる場合は、ファイル名を「main.py」として本体に保存してください。

・1相励磁

「MicroPython」を使用した「1相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。

10行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
from machine import Pin  # 入出力用モジュールを準備
import utime             # タイマーモジュールを準備

# 出力ピン設定
outA = Pin(18, Pin.OUT)  # コイル出力A
outB = Pin(19, Pin.OUT)  # コイル出力B
outC = Pin(20, Pin.OUT)  # コイル出力C
outD = Pin(21, Pin.OUT)  # コイル出力D

interval_time = 10  # インターバル時間設定(ms)

# 1相励磁 動作(1ステップ動作角度 11.25°)
while(True):  # ずっと実行
    outA.value(1)  # パルス出力実行A〜D
    outB.value(0)
    outC.value(0)
    outD.value(0)
    utime.sleep_ms(interval_time) # 出力インターバル時間(ms)

    outA.value(0)
    outB.value(1)
    outC.value(0)
    outD.value(0)
    utime.sleep_ms(interval_time)
    
    outA.value(0)
    outB.value(0)
    outC.value(1)
    outD.value(0)
    utime.sleep_ms(interval_time)
    
    outA.value(0)
    outB.value(0)
    outC.value(0)
    outD.value(1)
    utime.sleep_ms(interval_time)

・2相励磁

「MicroPython」を使用した「2相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。「1相励磁」よりトルクが大きくなります。

10行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
from machine import Pin  # 入出力用モジュールを準備
import utime             # タイマーモジュールを準備

# 出力ピン設定
outA = Pin(18, Pin.OUT)  # コイル出力A
outB = Pin(19, Pin.OUT)  # コイル出力B
outC = Pin(20, Pin.OUT)  # コイル出力C
outD = Pin(21, Pin.OUT)  # コイル出力D

interval_time = 10  # インターバル時間設定(ms)

# 1相励磁 動作(1ステップ動作角度 11.25°)
while(True):  # ずっと実行
    outA.value(1)  # パルス出力実行A〜D
    outB.value(1)
    outC.value(0)
    outD.value(0)
    utime.sleep_ms(interval_time) # 出力インターバル時間(ms)
    
    outA.value(0)
    outB.value(1)
    outC.value(1)
    outD.value(0)
    utime.sleep_ms(interval_time)
    
    outA.value(0)
    outB.value(0)
    outC.value(1)
    outD.value(1)
    utime.sleep_ms(interval_time)

    outA.value(1)
    outB.value(0)
    outC.value(0)
    outD.value(1)
    utime.sleep_ms(interval_time)

・1-2相励磁(二次元配列で励磁パターン指定)

「MicroPython」を使用した「1-2相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。「1相、2相励磁」より滑らかに回転します。

励磁パターンが8パターンに増えたので「二次元配列」に格納して指定するようにしています。

11行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
from machine import Pin  # 入出力用モジュールを準備
import utime             # タイマーモジュールを準備

# 出力ピン設定
outA = Pin(18, Pin.OUT)  # コイル出力A
outB = Pin(19, Pin.OUT)  # コイル出力B
outC = Pin(20, Pin.OUT)  # コイル出力C
outD = Pin(21, Pin.OUT)  # コイル出力D

# 変数宣言
interval_time = 10  # インターバル時間設定(ms)
pattern_number = 0  # 励磁パターン番号

# 励磁パターン指定二次元配列
puls_pattern = [[1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0],[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [1, 0, 0, 1]]
last_index = len(puls_pattern) - 1  # 励磁パターン配列の要素数を取得

# 1-2相励磁 動作(1ステップ動作角度 5.625°)
while(True):
    # 励磁パターン切り替え処理
    if pattern_number != last_index:  # パターン番号が励磁パターン配列の要素数でなければ
        pattern_number += 1           # パターン番号 +1
    else:                             # パターン番号が励磁パターン配列の要素数なら
        pattern_number = 0            # パターン番号0リセット

    # 出力実行
    outA.value(puls_pattern[pattern_number][0])  # パルス出力実行A〜D
    outB.value(puls_pattern[pattern_number][1])
    outC.value(puls_pattern[pattern_number][2])
    outD.value(puls_pattern[pattern_number][3])
    utime.sleep_ms(interval_time)                # 出力インターバル時間(ms)

・応用編、全励磁パターン動作確認(正逆、可変速)

「MicroPython」を使用して「全励磁パターン」の動作確認ができるプログラムは以下になります。

「sw1(赤)」を押すと回転方向を切り替えることができます。(本体LEDのON/OFFも切り替わる)
「sw2(白)」を押すと「1相励磁」、「sw3(青)」を押すと「2相励磁」、「sw4(黄)」を押すと「1-2相励磁」で動作します。
「ボリューム」を回すことで回転速度を変えることができます。

54〜55行目」で「ボリューム」のアナログ入力値を「interval_time(インターバル時間)」に換算して使用しています。この時間を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
from machine import Pin, ADC  # 入出力とアナログ入出力用モジュールを準備
import utime                  # タイマーモジュールを準備

# 入力ピン設定(スイッチ1〜4の入力設定)
sw1 = Pin(0, Pin.IN, Pin.PULL_UP)  # スイッチのピン番号を指定してswとして入力設定(プルアップ)
sw2 = Pin(4, Pin.IN, Pin.PULL_UP)
sw3 = Pin(11, Pin.IN, Pin.PULL_UP)
sw4 = Pin(15, Pin.IN, Pin.PULL_UP)

# アナログ入力ピン設定
adc_speed = ADC(Pin(28))   # モータ速度指示電圧用アナログ入力番号を設定

# 出力ピン設定
led = Pin("LED", Pin.OUT)  # 本体LEDピンをledとして出力に設定
out1 = Pin(18, Pin.OUT)    # コイル出力A
out2 = Pin(19, Pin.OUT)    # コイル出力B
out3 = Pin(20, Pin.OUT)    # コイル出力C
out4 = Pin(21, Pin.OUT)    # コイル出力D

# 変数宣言
sw1_state = False   # SW1の状態保持用
direction = True    # 回転方向(True:正転、False:逆転)
pattern_number = 0  # 励磁パターン番号

#  モーター制御パルス出力関数 **************************************
def outputPuls(direction, interval_time):
    print(interval_time)   # インターバル時間(ms)表示
    global pattern_number  # 励磁パターン番号指定用
    last_index = len(puls_pattern) - 1  # 励磁パターン配列の要素数を取得

    # 回転方向切り替え処理
    if direction:              # 回転方向が正転なら
      if pattern_number != last_index:  # パターン番号が励磁パターン配列の要素数でなければ
          pattern_number += 1           # パターン番号 +1
      else:                             # パターン番号が励磁パターン配列の要素数なら
          pattern_number = 0            # パターン番号0リセット
    else:                      # 回転方向が正転なら
      if pattern_number != 0:           # パターン番号が0でなければ
          pattern_number -= 1           # パターン番号 -1
      else:                             # パターン番号が0なら
          pattern_number = last_index   # パターン番号に最終要素番号をセット

    # 出力実行
    out1.value(puls_pattern[pattern_number][0])  # パルス出力実行1〜4
    out2.value(puls_pattern[pattern_number][1])
    out3.value(puls_pattern[pattern_number][2])
    out4.value(puls_pattern[pattern_number][3])
    utime.sleep_ms(interval_time)                # 出力インターバル時間(ms)

# メイン処理 ---------------------------------------------------------
led.value(1)  # 本体LEDを点灯

while(True):
    adc_val = adc_speed.read_u16()                 # ボリュームのアナログ入力(ADC)値を取得
    interval_time = int((adc_val * 1000) / 65536)  # アナログ値をインターバル時間に換算(0〜1000)

    # スイッチ1:モーター回転方向切り替え
    if not sw1.value() and sw1_state == False:  # スイッチ1が押されていて、スイッチ1の状態がFalseなら
        sw1_state = True                        # スイッチ1の状態をTrueへ
        direction = not direction               # 回転方向切り替え
        led.value(direction)                    # 回転方向性点なら本体LED点灯
        print("Direction", direction)
    if sw1.value():                             # スイッチ1が押されてなければ
        sw1_state = False                       # スイッチ1の状態をFalseへ

    # スイッチ2:1相励磁 動作
    if not sw2.value():  # スイッチ2が押されていれば
        if pattern_number > 3:
            pattern_number = int(pattern_number / 2)
        puls_pattern = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

    # スイッチ3:2相励磁 動作
    if not sw3.value():  # スイッチ3が押されていれば
        if pattern_number > 3:
            pattern_number = int(pattern_number / 2)
        puls_pattern = [[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [1, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

    # スイッチ4:1-2相励磁 動作
    if not sw4.value():  # スイッチ4が押されていれば
        puls_pattern = [[1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0],[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [1, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

4.CircuitPythonのサンプルプログラム(コピペ)

「CircuitPython」を使用したサンプルプログラムは以下になります。
コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

パソコンに接続せずに「ラズパイPico」単体で動作させる場合は、ファイル名を「code.py」として本体に保存してください。

・1相励磁

「CircuitPython」を使用した「1相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。

15行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
import digitalio      # 入出力ピン制御用モジュールを準備
from board import *   # boardモジュールからすべてのピンの定義を準備
import time           # 時間に関連する操作を行うためのモジュールを準備

# 出力ピン設定
outA = digitalio.DigitalInOut(GP18)          # コイル出力A
outA.direction = digitalio.Direction.OUTPUT
outB = digitalio.DigitalInOut(GP19)          # コイル出力B
outB.direction = digitalio.Direction.OUTPUT
outC = digitalio.DigitalInOut(GP20)          # コイル出力C
outC.direction = digitalio.Direction.OUTPUT
outD = digitalio.DigitalInOut(GP21)          # コイル出力D
outD.direction = digitalio.Direction.OUTPUT

interval_time = 0.01  # インターバル時間設定(sec)

# 1相励磁 動作(1ステップ動作角度 11.25°)
while(True):  # ずっと実行
    outA.value = True  # パルス出力実行A〜D
    outB.value = False
    outC.value = False
    outD.value = False
    time.sleep(interval_time) # 出力インターバル時間(ms)

    outA.value = False
    outB.value = True
    outC.value = False
    outD.value = False
    time.sleep(interval_time)
    
    outA.value = False
    outB.value = False
    outC.value = True
    outD.value = False
    time.sleep(interval_time)
    
    outA.value = False
    outB.value = False
    outC.value = False
    outD.value = True
    time.sleep(interval_time)

・2相励磁

「CircuitPython」を使用した「2相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。「1相励磁」よりトルクが大きくなります。

15行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
import digitalio      # 入出力ピン制御用モジュールを準備
from board import *   # boardモジュールからすべてのピンの定義を準備
import time           # 時間に関連する操作を行うためのモジュールを準備

# 出力ピン設定
outA = digitalio.DigitalInOut(GP18)          # コイル出力A
outA.direction = digitalio.Direction.OUTPUT
outB = digitalio.DigitalInOut(GP19)          # コイル出力B
outB.direction = digitalio.Direction.OUTPUT
outC = digitalio.DigitalInOut(GP20)          # コイル出力C
outC.direction = digitalio.Direction.OUTPUT
outD = digitalio.DigitalInOut(GP21)          # コイル出力D
outD.direction = digitalio.Direction.OUTPUT

interval_time = 0.01  # インターバル時間設定(sec)

# 2相励磁 動作(1ステップ動作角度 11.25°)
while(True):  # ずっと実行
    outA.value = True  # パルス出力実行A〜D
    outB.value = True
    outC.value = False
    outD.value = False
    time.sleep(interval_time) # 出力インターバル時間(ms)

    outA.value = False
    outB.value = True
    outC.value = True
    outD.value = False
    time.sleep(interval_time)
    
    outA.value = False
    outB.value = False
    outC.value = True
    outD.value = True
    time.sleep(interval_time)
    
    outA.value = True
    outB.value = False
    outC.value = False
    outD.value = True
    time.sleep(interval_time)

・1-2相励磁(二次元配列で励磁パターン指定)

「CircuitPython」を使用した「1-2相励磁」のプログラムは以下になります。
実行するとすぐにモーターは回転し続けます。「1相、2相励磁」より滑らかに回転します。

励磁パターンが8パターンに増えたので「二次元配列」に格納して指定するようにしています。

16行目」の「interval_time(インターバル時間)」を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
import digitalio      # 入出力ピン制御用モジュールを準備
from board import *   # boardモジュールからすべてのピンの定義を準備
import time           # 時間に関連する操作を行うためのモジュールを準備

# 出力ピン設定
outA = digitalio.DigitalInOut(GP18)          # コイル出力A
outA.direction = digitalio.Direction.OUTPUT
outB = digitalio.DigitalInOut(GP19)          # コイル出力B
outB.direction = digitalio.Direction.OUTPUT
outC = digitalio.DigitalInOut(GP20)          # コイル出力C
outC.direction = digitalio.Direction.OUTPUT
outD = digitalio.DigitalInOut(GP21)          # コイル出力D
outD.direction = digitalio.Direction.OUTPUT
    
# 変数宣言
interval_time = 0.01  # インターバル時間設定(sec)
pattern_number = 0    # 励磁パターン番号

# 励磁パターン指定二次元配列
puls_pattern = [[1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0],[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [1, 0, 0, 1]]
last_index = len(puls_pattern) - 1  # 励磁パターン配列の要素数を取得

# 1-2相励磁 動作(1ステップ動作角度 5.625°)
while(True):
    # 励磁パターン切り替え処理
    if pattern_number != last_index:  # パターン番号が励磁パターン配列の要素数でなければ
        pattern_number += 1           # パターン番号 +1
    else:                             # パターン番号が励磁パターン配列の要素数なら
        pattern_number = 0            # パターン番号0リセット

    # 出力実行
    outA.value = puls_pattern[pattern_number][0]  # パルス出力実行A〜D
    outB.value = puls_pattern[pattern_number][1]
    outC.value = puls_pattern[pattern_number][2]
    outD.value = puls_pattern[pattern_number][3]
    time.sleep(interval_time) # 出力インターバル時間(ms)

・応用編、全励磁パターン動作確認(正逆、可変速)

「CircuitPython」を使用して「全励磁パターン」の動作確認ができるプログラムは以下になります。

「sw1(赤)」を押すと回転方向を切り替えることができます。(本体LEDのON/OFFも切り替わる)
「sw2(白)」を押すと「1相励磁」、「sw3(青)」を押すと「2相励磁」、「sw4(黄)」を押すと「1-2相励磁」で動作します。
「ボリューム」を回すことで回転速度を変えることができます。

69〜70行目」で「ボリューム」のアナログ入力値を「interval_time(インターバル時間)」に換算して使用しています。この時間を長くして、回転速度を遅くすると動作する様子がわかりやすくなります。
import digitalio      # 入出力ピン制御用モジュールを準備
import analogio       # アナログ入出力制御用モジュールを準備
from board import *   # boardモジュールからすべてのピンの定義を準備
import time           # 時間に関連する操作を行うためのモジュールを準備

# 入力ピン設定(スイッチ1〜4の入力設定)
sw1 = digitalio.DigitalInOut(GP0)          # スイッチのピン番号を指定してsw1〜4として設定
sw1.direction = digitalio.Direction.INPUT  # sw1〜4を入力モードに設定
sw1.pull = digitalio.Pull.UP               # 内部プルアップ抵抗を有効化
sw2 = digitalio.DigitalInOut(GP4)
sw2.direction = digitalio.Direction.INPUT
sw2.pull = digitalio.Pull.UP
sw3 = digitalio.DigitalInOut(GP11)
sw3.direction = digitalio.Direction.INPUT
sw3.pull = digitalio.Pull.UP
sw4 = digitalio.DigitalInOut(GP15)
sw4.direction = digitalio.Direction.INPUT
sw4.pull = digitalio.Pull.UP

# 出力ピン設定
led = digitalio.DigitalInOut(LED)            # 本体LEDのピンをledに設定
led.direction = digitalio.Direction.OUTPUT   # ledを出力モードに設定
outA = digitalio.DigitalInOut(GP18)          # コイル出力A
outA.direction = digitalio.Direction.OUTPUT
outB = digitalio.DigitalInOut(GP19)          # コイル出力B
outB.direction = digitalio.Direction.OUTPUT
outC = digitalio.DigitalInOut(GP20)          # コイル出力C
outC.direction = digitalio.Direction.OUTPUT
outD = digitalio.DigitalInOut(GP21)          # コイル出力D
outD.direction = digitalio.Direction.OUTPUT

# アナログ入力ピン設定
adc_speed = analogio.AnalogIn(A2)   # モータ速度指示電圧用アナログ入力番号を設定

# 変数宣言
sw1_state = False   # SW1の状態保持用
direction = True    # 回転方向(True:正転、False:逆転)
pattern_number = 0  # 励磁パターン番号

#  モーター制御パルス出力関数 **************************************
def outputPuls(direction, interval_time):
    print(interval_time)   # インターバル時間(ms)表示
    global pattern_number  # 励磁パターン番号指定用
    last_index = len(puls_pattern) - 1  # 励磁パターン配列の要素数を取得

    # 回転方向切り替え処理
    if direction:              # 回転方向が正転なら
      if pattern_number != last_index:  # パターン番号が励磁パターン配列の要素数でなければ
          pattern_number += 1           # パターン番号 +1
      else:                             # パターン番号が励磁パターン配列の要素数なら
          pattern_number = 0            # パターン番号0リセット
    else:                      # 回転方向が正転なら
      if pattern_number != 0:           # パターン番号が0でなければ
          pattern_number -= 1           # パターン番号 -1
      else:                             # パターン番号が0なら
          pattern_number = last_index   # パターン番号に最終要素番号をセット

    # 出力実行
    outA.value = puls_pattern[pattern_number][0]  # パルス出力実行A〜D
    outB.value = puls_pattern[pattern_number][1]
    outC.value = puls_pattern[pattern_number][2]
    outD.value = puls_pattern[pattern_number][3]
    time.sleep(interval_time) # 出力インターバル時間(ms)

# メイン処理 ---------------------------------------------------------
led.value = True  # 本体LEDを点灯

while(True):
    adc_val = adc_speed.value        # ボリュームのアナログ入力(ADC)値を取得
    interval_time = adc_val / 65536  # アナログ値をインターバル時間に換算(0〜1000)

    # スイッチ1:モーター回転方向切り替え
    if not sw1.value and sw1_state == False:  # スイッチ1が押されていて、スイッチ1の状態がFalseなら
        sw1_state = True                      # スイッチ1の状態をTrueへ
        direction = not direction             # 回転方向切り替え
        led.value = direction                 # 回転方向性点なら本体LED点灯
        print("Direction", direction)
    if sw1.value:                             # スイッチ1が押されてなければ
        sw1_state = False                     # スイッチ1の状態をFalseへ

    # スイッチ2:1相励磁 動作
    if not sw2.value:  # スイッチ2が押されていれば
        if pattern_number > 3:
            pattern_number = int(pattern_number / 2)
        puls_pattern = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

    # スイッチ3:2相励磁 動作
    if not sw3.value:  # スイッチ3が押されていれば
        if pattern_number > 3:
            pattern_number = int(pattern_number / 2)
        puls_pattern = [[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 1], [1, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

    # スイッチ4:1-2相励磁 動作
    if not sw4.value:  # スイッチ4が押されていれば
        puls_pattern = [[1, 0, 0, 0], [1, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0],[0, 0, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1], [1, 0, 0, 1]] # 励磁パターン指定二次元配列
        outputPuls(direction, interval_time)  # モーター制御パルス出力関数(回転方向,インターバル時間)

5.動作確認

サンプルプログラムの「応用編」以外は、実行するとすぐにモーターが動作し始めます。

Raspberry Pi Pico ステッピングモータの使い方、動作確認

駆動基板上の4つのLEDで、どのコイルが励磁されているかが確認できるので、プログラム内の「interval_time(インターバル時間)」を長くすることで、コイルへの出力が切り替わる様子が確認できます。

応用編では「スイッチ2〜3」で3つの励磁パターンの動作の違いが確認できます。
「スイッチ1(赤)」では正転/逆転を切り替えられるので、動作中に切り替えると瞬時に反転することも確認できます。
ボリュームで「interval_time(インターバル時間)」を変更して回転速度を変えながら動作確認してみましょう。

今回使用したステッピングモーターの出力軸はギヤ比が1/64で回転が遅く変化がわかりにくいため、下写真のように分解してモーター単体で動作確認した動画を用意しました。

ステッピングモータ分解写真

写真左上のモーター本体中央にあるのが回転する磁石のローター(φ10mm程)です。
「interval_time(インターバル時間)」を長くすると、1ステップごとに「1相、2相励磁」は「11.25°」、「1-2相励磁」は「5.625°」で動作していることが確認できます。

ステッピングモーターの動作確認
「1相、2相励磁」の1ステップの回転角は11.25°(32ステップで1回転)
「1-2相励磁」は1ステップの回転角は5.625°(64ステップで1回転)
無負荷最大応答周波数は1000pps(1000パルス/秒)のため、1ステップは1msecまでです。
プログラムの「interval_time(インターバル時間)」を1msec以下にすると回転しない可能性があります。また「1相、2相励磁」の場合も回転しない可能性があるため、この場合は1msecより大きくしてください。
「2相励磁」は「1相励磁」よりトルクが大きくなりますが、消費電力が大きくなり発熱も大きくなります。
停止中も回転角度を保持しているため、回転していなくてもモーターはそれなりに熱くなるのでご注意ください。
「1相励磁」でも停止中は電流を消費するため、使用しない時はモーターへの電源をOFFにしておきましょう。

6.まとめ

「Raspberry Pi Pico(PicoW)」を使用したステッピングモーターの使い方を「Python」のサンプルプログラムを使って詳しく紹介しました。

ステッピングモーターにもいくつか種類がありますが、今回使用したものはPM(パーマネントマグネット)型の「2相ユニポーラ型」で、制御方法には「1相励磁」「2相励磁」「1-2相励磁」があります。

構造がシンプルで制御も比較的簡単なため、基本的なステッピングモータの動作原理の確認には最適です。
今回使用したステッピングモーター「28BYJ-48」は安価で入手でき、簡単なプログラムで動作確認できるため、実際に動かしながら動作確認してみると、その仕組みがよく理解できると思います。

エンコーダーで現在位置を確認しながら制御できるサーボモーターには劣りますが、ステッピングモーターはエンコーダー無しでコイルへの励磁パターンを切り替えるだけで一定の角度で動作させることができます。

簡易的な位置決め動作を安価でシンプルに実現したい場合はステッピングモーターで十分な用途も多いので、用途に応じて使い分けていきましょう。

コメント

タイトルとURLをコピーしました