ラズパイを使って、ステッピングモータを制御するよ

8 min read読了の目安(約7800字

💡やること

ステッピングモータ - 28BYJ-48を使って、回転を制御します。

🏁デモ

302_kiso

🔧パーツ一覧

no 部品名 個数 備考
1 ラズベリーパイ 1 今回は4Bで確認
2 ステッピングモータ+ 28BYJ-48 ULN2003ドライバーボード セット 1 Amazon
3 ジャンパー線 適量 -
4 ブレッドボード 1 -
5 USBケーブル 0.4m TK-USB1 1 接続図 - 外部電源用, Amazon

接続図

モータの駆動は、電流が多く流れるため外部電源から取りましょう。
ラズパイ自体が壊れる恐れがあります。

ピンの接続

Pin ドライバーボード 備考
- 5V USBケーブルより5Vを供給
GND GND USBケーブルのGNDも接続すること
BCM21 PIN1 茶色ケーブル
BCM17 PIN2 青色ケーブル
BCM27 PIN3 紫色ケーブル
BCM22 PIN4 灰色ケーブル

💻環境

開発環境

  • ラズベリーパイ
    • Linux rpi 5.10.17-v7l+ #1403 SMP Mon Feb 22 11:33:35 GMT 2021 armv7l GNU/Linux
  • Python
    • Python 3.7.3 (default, Jan 22 2021, 20:04:44)

ラズベリーパイの設定

特になし

モジュールのインストール

OSのクリーンインストールした前提で記載しています。

apt

pigpioライブラリは、Raspberry PiのGPIOを制御するためのライブラリです。
以下のコマンドは、はじめてインストールする場合のみ必要です。

$ sudo apt install pigpio
$ sudo service pigpiod start
$ sudo systemctl enable pigpiod.service

pip

Pythonに関するモジュールをインストールします。

$ python3 -m venv env
$ source env/bin/activate
(env) $ pip install pigpio
(env) $ pip install gpiozero

📝手順

時計回りに1回転→反時計回りに1回転します。

コード

stepper.py
import time
from gpiozero import OutputDevice
from gpiozero.pins.pigpio import PiGPIOFactory
# import numpy as np

# PIN settings
PIN_MOTOR_1 = (21)
PIN_MOTOR_2 = (17)
PIN_MOTOR_3 = (27)
PIN_MOTOR_4 = (22)

# wave mode
vlist_wave = [
    [1, 0, 0, 0],   # step1
    [0, 1, 0, 0],   # step2
    [0, 0, 1, 0],   # step3
    [0, 0, 0, 1],   # step4
    [1, 0, 0, 0],   # step5(step1)
    [0, 1, 0, 0],   # step6(step2)
    [0, 0, 1, 0],   # step7(step3)
    [0, 0, 0, 1],   # step8(step4)
]

# full mode
vlist_full = [
    [1, 1, 0, 0],   # step1
    [0, 1, 1, 0],   # step2
    [0, 0, 1, 1],   # step3
    [1, 0, 0, 1],   # step4
    [1, 1, 0, 0],   # step5(step1)
    [0, 1, 1, 0],   # step6(step2)
    [0, 0, 1, 1],   # step7(step3)
    [1, 0, 0, 1],   # step8(step4)
]

# half mode
vlist_half = [
    [1, 0, 0, 0],   # step1
    [1, 1, 0, 0],   # step2
    [0, 1, 0, 0],   # step3
    [0, 1, 1, 0],   # step4
    [0, 0, 1, 0],   # step5
    [0, 0, 1, 1],   # step6
    [0, 0, 0, 1],   # step7
    [1, 0, 0, 1],   # step8
]

class Stepper():
    def __init__(self,  number_of_steps, mpins, method_step="half"):
        self.step_number = 0                   # which step the motor is on
        self.direction = 0                     # motor direction
        self.last_step_time = 0                # time stamp in us of the last step taken
        self.number_of_steps = number_of_steps  # total number of steps for this motor

        # stepping method
        self._method_step = method_step
        if "full" == method_step:
            self._vlist = vlist_full
        elif "wave" == method_step:
            self._vlist = vlist_wave
        else:
            self._vlist = vlist_half
            self._method_step = "half"

        # setup the pins on the microcontroller:
        factory = PiGPIOFactory()
        self._mpins = [OutputDevice(pin, pin_factory=factory) for pin in mpins]
        self.set_speed()
        return

    def set_speed(self, what_speed=10):
        ''' Sets the speed in revs per minute
        '''
        self.step_delay = 60 * 1000 * 1000 * 1000 / self.number_of_steps / what_speed
        return

    def step(self, steps_to_move, auto_stop=True):
        ''' Moves the motor steps_to_move steps.  If the number is negative,
            the motor moves in the reverse direction.
        '''
        if "half" == self._method_step:
            steps_to_move *= 2
        steps_left = abs(steps_to_move)  # how many steps to take

        # determine direction based on whether steps_to_mode is + or -:
        self.direction = 1 if steps_to_move > 0 else 0

        # decrement the number of steps, moving one step each time:
        while steps_left > 0:
            now = time.time_ns()
            # move only if the appropriate delay has passed:
            if (now - self.last_step_time) >= self.step_delay:
                # get the timeStamp of when you stepped:
                self.last_step_time = now
                # increment or decrement the step number,
                # depending on direction:
                if self.direction == 1:
                    self.step_number += 1
                    if self.step_number == self.number_of_steps:
                        self.step_number = 0
                else:
                    if self.step_number == 0:
                        self.step_number = self.number_of_steps
                    self.step_number -= 1

                # decrement the steps left:
                steps_left -= 1
                # step the motor to step number 0, 1, 2, ..., 7
                self._step_motor(self.step_number % 8)

        if auto_stop:
            self.stop()
        return

    def _step_motor(self, this_step):
        ''' 各Pinに対し、HIGH/LOW
        '''
        for val, mpin in zip(self._vlist[this_step], self._mpins):
            mpin.on() if val else mpin.off()
        return

    def stop(self):
        for mpin in self._mpins:
            mpin.off()
        return


def main():

    MOTOR_STEPS = (2048)

    # 動作モード指定
    # my_motor = Stepper(MOTOR_STEPS, [PIN_MOTOR_1, PIN_MOTOR_2, PIN_MOTOR_3, PIN_MOTOR_4], "wave")
    # my_motor = Stepper(MOTOR_STEPS, [PIN_MOTOR_1, PIN_MOTOR_2, PIN_MOTOR_3, PIN_MOTOR_4], "full")
    my_motor = Stepper(MOTOR_STEPS, [PIN_MOTOR_1, PIN_MOTOR_2, PIN_MOTOR_3, PIN_MOTOR_4], "half")

    my_motor.set_speed(10)

    # 時計回り -> 反時計回り
    my_motor.step(-2048)
    my_motor.step(2048)


    # 徐々にはやく回転させる
    # for speed in np.arange(5, 16, 0.01):
    #     my_motor.set_speed(speed)
    #     my_motor.step(8)

    return


if __name__ == "__main__":
    main()

実行手順

(env) $ python stepper.py

デモの結果になります。

🔎ポイント

ステッピングモータの動作

ステッピングモーターは、一定の角度ずつ回転するモーターです。
この角度を基本ステップ角度と呼びます。
28BYJ-48 ULN2003には、3つのステップモードが用意されています。
フルステップ、ハーフステップ、ウェーブドライブ方式もあります。

  • フルステップ方式
    • 最大のトルクを提供する
    • PINの制御タイミング - コード上、"full"を指定
  • ハーフステップ方式
    • トルクは低くなるが、精度が高くなる
    • PINの制御タイミング - コード上、"half"を指定
  • ウェーブドライブ方式
    • 低電力アプリケーションに最適
    • PINの制御タイミング - コード上、"wave"を指定

回転のスピードを変更する

my_motor.set_speed(数値)を指定することで、回転のスピードを変更することができます。
コード上の下記の部分のコメントを外すと、徐々に回転を速くすることができます。

import numpy as np
--
    for speed in np.arange(5, 16, 0.01):
        my_motor.set_speed(speed)
        my_motor.step(8)

set_speedに渡す値を小さくしたり、大きくすると動作しないので注意。

ラズパイ制御の注意点

本プログラムは、Linux上での動作を想定しています。

if (now - self.last_step_time) >= self.step_delay:

上記のコードから、各ピンの遷移に時間が関係していることが分かります。
本プロセスとは別のプロセスに時間がとられてしまうと、
時間内に遷移ができないため、そのステップがロスすることがあります。
ステッピングモーターで、正確に制御を行いたい場合は、
ベアメタルやリアルタイムOSで制御することをおすすめします。

さいごに

この記事も含め、ラズパイの活用方法を

https://zenn.dev/kotaproj/books/raspberrypi-tips

としてまとめ中です。