🚗
ラズパイを使って、ステッピングモータを制御するよ
💡やること
ステッピングモータ - 28BYJ-48を使って、回転を制御します。
🏁デモ
🔧パーツ一覧
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)
ラズベリーパイの設定
特になし
モジュールのインストール
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)
ラズパイ制御の注意点
本プログラムは、Linux上での動作を想定しています。
if (now - self.last_step_time) >= self.step_delay:
上記のコードから、各ピンの遷移に時間が関係していることが分かります。
本プロセスとは別のプロセスに時間がとられてしまうと、
時間内に遷移ができないため、そのステップがロスすることがあります。
ステッピングモーターで、正確に制御を行いたい場合は、
ベアメタルやリアルタイムOSで制御することをおすすめします。
さいごに
この記事も含め、ラズパイの活用方法を
としてまとめ中です。
Discussion