ESP32 - MicroPythonを使い、ステッピングモータを制御する


はじめに

ステッピングモータを使いたくなったので、購入をしました。
Arduinoスケッチで制御している記事は多くあるのですが、
MicroPythonで制御しているものがなかったので、
紹介させていただきます。

作業環境

  • ホストPC
    • windows10 64bit Home
    • VSCode - 1.47.3
    • NodeJS - 12.14.1 LTS
  • ターゲットボード
    • ESP32-WROOM-32 開発ボード
    • MicroPython 1.12(esp32-idf4-20191220-v1.12.bin)

ESP32におけるMicroPythonの環境構築は、以前記載した
- [備忘録]ESP32-VSCode-microPythonでの開発環境の構築
を参考にしてください。

機材

部品名 説明 備考
ESP32-WROOM-32 開発ボード 5V
ステッピングモーター 型番:28BYJ-48、12V駆動 購入先Amazon
ULN2003ステッピングモーター駆動テストモジュールボード モータ駆動のためのボード モータとセット買い
DCアダプタ 12V モータが12V駆動のため 購入先Amazon
ジャンパーケーブル 10本程度

接続

部品名 説明 備考
ESP32-PIN25 テストモジュールボード - IN1 -
ESP32-PIN26 テストモジュールボード - IN2 -
ESP32-PIN27 テストモジュールボード - IN3 -
ESP32-PIN13 テストモジュールボード - IN4 -
ACアダプタ - GND テストモジュールボード - GND ESP32-GND
ACアダプタ - 12V テストモジュールボード - 12V
テストモジュールボード - モータコネクタ ステッピングモータ -

コードの作成

Arduino - StepperライブラリをベースにMicroPythonに移植します。

本ライブラリをベースしようと思ったのは、

  • Arduinoサイトでよく使われているため、極力インタフェースを同じにしたい
  • (そこまで)シビアなタイミングがない

となります。

また、本家との違いは以下となります。

  • stop()メソッドを追加している
  • step()にて、動作させた後、stop()メソッドをコール
    • 本家のライブラリでは、ユーザが能動的にstopさせないと常に電流が流れ続ける
    • 熱くなってしまうので、stop()をコールしている
  • 5pinモータ機能を削除
    • 今回は4pin構成なので、5pin部分は移植なし

ステッピングモータを制御するためのコード

以下がステッピングモータを制御するためのクラスとなります。

stepper.py
import time
from machine import Pin


class Stepper():
    def __init__(self,  number_of_steps,
                 motor_pin_1, motor_pin_2, motor_pin_3, motor_pin_4):
        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

        # setup the pins on the microcontroller:
        self.motor_pin_1 = Pin(motor_pin_1, Pin.OUT)
        self.motor_pin_2 = Pin(motor_pin_2, Pin.OUT)
        self.motor_pin_3 = Pin(motor_pin_3, Pin.OUT)
        self.motor_pin_4 = Pin(motor_pin_4, Pin.OUT)

        # pin_count is used by the stepMotor() method:
        self.pin_count = 4

        self.set_speed()
        return

    def set_speed(self, what_speed=10):
        ''' Sets the speed in revs per minute
        '''
        self.step_delay = 60 * 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.
        '''
        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.ticks_us()
            # move only if the appropriate delay has passed:
            if time.ticks_diff(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, 3
                self._step_motor(self.step_number % 4)

        if auto_stop:
            self.stop()
        return

    def _step_motor(self, this_step):
        ''' Moves the motor forward or backwards.
              if (this->pin_count == 4) {
        '''
        # 1010
        if this_step == 0:
            self.motor_pin_1.value(True)
            self.motor_pin_2.value(False)
            self.motor_pin_3.value(True)
            self.motor_pin_4.value(False)
        # 0110
        elif this_step == 1:
            self.motor_pin_1.value(False)
            self.motor_pin_2.value(True)
            self.motor_pin_3.value(True)
            self.motor_pin_4.value(False)
        # 0101
        elif this_step == 2:
            self.motor_pin_1.value(False)
            self.motor_pin_2.value(True)
            self.motor_pin_3.value(False)
            self.motor_pin_4.value(True)
        # 1001
        elif this_step == 3:
            self.motor_pin_1.value(True)
            self.motor_pin_2.value(False)
            self.motor_pin_3.value(False)
            self.motor_pin_4.value(True)
        return

    def stop(self):
        self.motor_pin_1.value(False)
        self.motor_pin_2.value(False)
        self.motor_pin_3.value(False)
        self.motor_pin_4.value(False)
        return

使い方

使用するための準備

>> from stepper import Stepper

>> MOTOR_STEPS = (2048)
>> PIN_MOTOR_1 = (25)
>> PIN_MOTOR_2 = (26)
>> PIN_MOTOR_3 = (27)
>> PIN_MOTOR_4 = (13)

>> my_motor = Stepper(MOTOR_STEPS, PIN_MOTOR_1,
                   PIN_MOTOR_3, PIN_MOTOR_2, PIN_MOTOR_4)
>> my_motor.set_speed(10)

回転させる

my_moter.step(512)
# =>ステッピングモータが90度、時計回りに回転
my_moter.step(2048)
# =>ステッピングモータが360度、時計回りに回転
my_moter.step(-512)
# =>ステッピングモータが90度、反時計回りに回転
  • MOTOR_STEPSを2048としているため、一回転あたり2048となる
  • step()にマイナス方向を指定すると反時計回りになる
  • set_speed()には、1-20あたりまでが有効

さいごに

  • 現状、回転を実行すると、止めることができません

参考