ハードウェア技術者のスキルアップ日誌

某家電メーカーの技術者がスキルアップのために勉強したことを記録するブログです

ラズパイでステッピングモーターを動かす

前回、ラズパイでDCモーターを動かしてみました。

masaeng.hatenablog.com

DCモーターでは回転角度を制御できないため、今回はステッピングモーターを制御することに挑戦しました。事前に他の方がどのように制御されているかを調べたところ、ライブラリを使用している例が多い印象でした。具体的な制御手順を理解するため、ライブラリを使わずにやってみたいと思います!

ステッピングモーターとは?

直流のパルス電圧を印加して駆動するモーターで、DCモーターとは異なり、正確に回転を制御できます。例えば90度回したい、30度回したいといったことが容易にできます。

内部構成は以下のようになっています。周囲のコイルに電流を流すことでコイルがS極となり、中央の磁石のN極を近づけます。電流を流すコイルをL1, L2, L3, L4, L1・・・と変えることで、中央の磁石が回転します。

駆動方法はいくつかの手法がありますが、安定的に駆動できると言われる二相励磁を用います。電流を流す区間を1ステップ分、隣のコイルと重複させます。

      

f:id:masashi_k:20200623225754p:plain f:id:masashi_k:20200623225820p:plain

        画像引用:https://dotstud.io/blog/stepper-motor-nefrybt-control/

回路設計

 今回準備した部品はこちらです。
  ステッピングモーター28BYJ-48:http://akizukidenshi.com/catalog/g/gP-13256/
  モータードライバー TB6612FNG:http://akizukidenshi.com/catalog/g/gK-11219/
TB6612は本来DCモーター用のドライバーですが、ステッピングモーターにも使用できました。(DCモーター用に買ったものを流用するため、動かし方を調べました)

モーターの配線図はこんな感じ。3番端子(赤)には電源5Vを入力します。二相励磁で動かすためには2-A, 5-B, 4-A', 1-B'に対して右図のようにパルス電圧を印加する必要があります。

f:id:masashi_k:20200623230828p:plain  f:id:masashi_k:20200623231019p:plain

画像引用:http://akizukidenshi.com/download/ds/akizuki/28byj-48.pdf


電圧を供給するのはモータードライバーTB6612です。ドライバーモジュールの回路図は以下左図のようになっており、AIN1,2, BIN1,2が入力、A01,A02,B01,B02が出力です。ドライバーの真理値表で注目すべきところは赤枠で囲んだところです。OUT1,2がH/LまたはL/Hとなっているところを二相励磁のパルスに当てはめます。

f:id:masashi_k:20200623231439p:plain f:id:masashi_k:20200623231611p:plain

       画像引用:http://akizukidenshi.com/download/ds/akizuki/AE-TB6612.pdf

 

モーター端子、即ちTB6612の出力端子を上図の二相励磁の方式で動かそうとするとTB6612の入力は右のようにH/Lを制御すればよいことになります。これら入力AIN1,2,BIN1,2をラズパイのGPIOポートに接続して制御します。
 f:id:masashi_k:20200623232231p:plain

最終的に回路図は以下のようになります。モーターには乾電池で作ったDC5Vを入力。モータードライバーのPWM端子はVCC(3.3V)と接続しています。

f:id:masashi_k:20200623232620p:plain

こんな感じで回路を組みました。

f:id:masashi_k:20200623234101j:plain

ソースコード

Pythonでコードを書いていきます。回転角と回転方向を引数として与えるようにします。

まずはライブラリのインポートとGPIOピンの指定です。上の回路図に合わせて変数にGPIO番号を入力します。

import argparse
import time
import RPi.GPIO as GPIO
AIN1 = 2 AIN2 = 3 BIN1 = 4 BIN2 = 14 STBY = 15

 

ここで、回転速度を指定します。
ステップ角とは回転角の最小単位、ステップとは二相励磁の図における、縦の点線の区間1つ分です。モーターの回転速度(1秒に何回転するか)から1ステップの待ち時間を計算しています。ステップ角と1回転のステップ数はモーターの仕様です。購入サイトで確認できます。

f = 0.1 # 回転速度[rps] 1秒に何回転するか
s_angle = 5.625 # ステップ角[deg]
step_360 = 2048 # 1回転のステップ数
unit_step = step_360 * s_angle / 360 # ステップ角当たりのステップ数
wait = (1/f)*(s_angle/360)/unit_step # 1ステップの待ち時間

 

main関数です。
引数として回転角度と回転方向(0:時計回り、1:反時計回り)を受け取ります。
GPIOの初期設定後、回転方向が時計回りならforward()を、反時計回りならbackward()を実行して、停止処理を行います。forward/backward関数の引数はステップ数のため、回転角度からステップ数に変換して渡します。モーターに電圧をかけたままだと熱くなるため、最後にモータードライバーをスタンバイモードに入れます。

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('angle', type=float, help='rotation angle') 
    parser.add_argument('--dir', default=0, choices=["0","1"], help='rotate direction, 0=CW, 1=CCW')
    args = parser.parse_args()

    #GPIO初期化
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(AIN1, GPIO.OUT)
    GPIO.setup(AIN2, GPIO.OUT)
    GPIO.setup(BIN1, GPIO.OUT)
    GPIO.setup(BIN2, GPIO.OUT)
    GPIO.setup(STBY, GPIO.OUT)

    #モータードライバースタンバイ解除
    GPIO.output(STBY,1)

    if args.dir == "0":
        forward(int(args.angle / s_angle * unit_step))
    else :
        backward(int(args.angle / s_angle * unit_step))

    #停止処理
    print("stop!!")
    GPIO.output(AIN1,0)
    GPIO.output(AIN2,0)
    GPIO.output(BIN1,0)
    GPIO.output(BIN2,0)
    GPIO.output(STBY,0)   

 

時計回りの回転の場合は、各ポートの状態が左から右に遷移するようにGPIOを制御します。二相励磁の場合は4ステップ周期で同じ状態となるため、step/4回分だけforループを回します。

f:id:masashi_k:20200623225820p:plain

def forward(step):
    print("move forward")
    for i in range(step/4): # stepが4周期のため4で割る
        GPIO.output(AIN1,1)
        GPIO.output(AIN2,0)
        GPIO.output(BIN1,0)
        GPIO.output(BIN2,1)
        time.sleep(wait)

        GPIO.output(AIN1,1)
        GPIO.output(AIN2,0)
        GPIO.output(BIN1,1)
        GPIO.output(BIN2,0)
        time.sleep(wait)

        GPIO.output(AIN1,0)
        GPIO.output(AIN2,1)
        GPIO.output(BIN1,1)
        GPIO.output(BIN2,0)
        time.sleep(wait)

        GPIO.output(AIN1,0)
        GPIO.output(AIN2,1)
        GPIO.output(BIN1,0)
        GPIO.output(BIN2,1)
        time.sleep(wait)

def backward(step): print("move backward") for i in range(step/4): # stepが4周期のため4で割る GPIO.output(AIN1,0) GPIO.output(AIN2,1) GPIO.output(BIN1,0) GPIO.output(BIN2,1) time.sleep(wait) GPIO.output(AIN1,0) GPIO.output(AIN2,1) GPIO.output(BIN1,1) GPIO.output(BIN2,0) time.sleep(wait) GPIO.output(AIN1,1) GPIO.output(AIN2,0) GPIO.output(BIN1,1) GPIO.output(BIN2,0) time.sleep(wait) GPIO.output(AIN1,1) GPIO.output(AIN2,0) GPIO.output(BIN1,0) GPIO.output(BIN2,1) time.sleep(wait)

動作確認

こちらのソースコードで実際にモーターが回っている様子です。角度と回転方向の指定を変えることで、自在にモーターの回転が制御できています。


ラズパイ/TB6612でステッピングモーターを動かしてみた

まとめ

ライブラリを使わずにラズパイのGPIO制御でステッピングモーターを動かすことができました。動作原理を元に制御を考え、その結果、うまく動くと理解が正しかったことが確認でき、非常に勉強になると感じました。これが自分で手を動かす強みですね。

次回はステッピングモーターを使って何か作ってみたいと思います。