MAiX Qube 奮闘記11 SPI通信で2個のステッピングモーターを制御

今回はMAiX Qubeで2個のステッピングモーターを制御してみます。
応用すればSPI通信を介して3個でも4個でも制御出来ます。
使用するステッピングモータードライバはこれ
秋月電子通商の
「Ｌ６４７０使用　ステッピングモータードライブキット」
https://akizukidenshi.com/catalog/g/gK-07024/
このドライバはとても高性能で、脱調防止に必要な台形制御、1ステップを128分割した角度で動かせるマイクロステップにも対応してます。
投稿したプログラムは目標角度の指定で動かしていますが、位置を指定せず一定速度で回し続ける命令も備えているので車輪を回すときはそちらの命令が良いと思います。

一台のドライバから出てきたSPI通信の信号を次のドライバに渡して最終的にQubeに帰ってくる配線とします。

WaitMotorStop()はモーターのビジーフラグをチェックし続けて、モーターが目標角度に達して停止したら次の角度を送る為のものです。
回転が停止したら即座に次の命令を送るので応答が早いです。
(回転が終わるであろう一定時間待って次の角度を送っていないのです。)
2個のモーターを動かすコードです。

```python:TwoMotorDrive.py
#2つのモーターを異なる角度で回転させるバージョン

from machine import SPI
import utime,ubinascii
import struct
from Maix import GPIO

from fpioa_manager import fm
def CheckStatus():
    buff = spi.read(2, write=0xd0, cs=SPI.CS1)# Reset Device
    a = spi.read(2, write=0x00, cs=SPI.CS1) #Get Status
    b = spi.read(2, write=0x00, cs=SPI.CS1) #Get Status
    c = a + b
    print('status1',ubinascii.hexlify(c))
    return c
def WaitMotorStop():
#ビジーフラグは実行中に0,停止中に1
    c=0
    while(c==0):
        buff = spi.read(2, write=0xd0, cs=SPI.CS1)# チェックステータス
        a = spi.read(2, write=0x00, cs=SPI.CS1) #Get Status
        b = spi.read(2, write=0x00, cs=SPI.CS1) #Get Status
        b1,b2 = struct.unpack('BB', b)[:2]
        c = b1 & b2 & 0x02
def MotorGoto(Pos1,Pos2):
    buff = spi.read(2, write=0x60, cs=SPI.CS1)# Goto command
    VA1=(struct.pack('>I',Pos1))
    VA2=(struct.pack('>I',Pos2))
    for count in range(3):
        buff=(struct.pack('BB',VA1[count+1],VA2[count+1]))
        spi.write(buff, cs=SPI.CS1)
def WriteMotor0byte(command):
    buff = spi.read(2, write=command, cs=SPI.CS1)# Goto command
def WriteMotor1byte(command,Parameter):
    buff = spi.read(2, write=command, cs=SPI.CS1)# Goto command
    buff = spi.read(2, write=Parameter, cs=SPI.CS1)# Goto command
def WriteMotor2byte(command,Parameter):
    buff = spi.read(2, write=command, cs=SPI.CS1)# Goto command
    VA=(struct.pack('>I',Parameter))
    buff = spi.read(2, write=VA[2], cs=SPI.CS1)# Goto command
    buff = spi.read(2, write=VA[3], cs=SPI.CS1)# Goto command

########### start ##############
spi = SPI(SPI.SPI1, mode=SPI.MODE_MASTER, baudrate=10000, polarity=1, phase=1,
    bits=8, firstbit=SPI.MSB, sck=21, mosi=8, miso=7, cs1= 6)
utime.sleep_ms(10)
buf = spi.read(2, write=0xc0, cs=SPI.CS1) # Reset Device
WriteMotor0byte(0xA8)#HardHiZコマンド
WriteMotor1byte(0x16,7)#StepMode7レジスタ ハイインピーダンス時のみ変更可能
WriteMotor2byte(0x05,50)#ACC(12 bit,デフォルト0x008A=DEC 138
WriteMotor2byte(0x06,50)#DEC(12 bit,デフォルト0x008A=DEC 138
WriteMotor2byte(0x07,30)#MAX 回転スピード設定 10 bit,デフォルト0x0041=DEC 65 *2^-18,MINとは2^10重みが違う 200
WriteMotor2byte(0x08,50)#MIN 回転スピード設定(10 bit,デフォルト0x0000=DEC 0 *2^-28,LSPD_OPT ON時はバイト指定を行う。(MINは5となり遅すぎる
WriteMotor1byte(0x09,20)#モータ停止中の電圧設定(8 bit,デフォルト0x29=DEC 41
WriteMotor1byte(0x0A,20)#モータ定速回転時の電圧設定(8 bit,デフォルト0x29=DEC 41
WriteMotor1byte(0x0B,20)#加速中の電圧設定(8 bit,デフォルト0x29=DEC 41
WriteMotor1byte(0x0C,20)#減速中の電圧設定(8 bit,デフォルト0x29=DEC 41
WriteMotor2byte(0x15,39)#FullStepChqnge SPEED(10 bit,デフォルト0x0027=DEC 39 *2^18

for num in range(10):
    CheckStatus()
    MotorGoto(30000,100000)
    WaitMotorStop()
    utime.sleep_ms(20)
    CheckStatus()
    MotorGoto(0,0)
    WaitMotorStop()
    utime.sleep_ms(20)
WriteMotor0byte(0xA8)#HardHiZコマンド
spi.deinit()

#spi.write(0xd0, cs=SPI.CS1)
#b0 = spi.read(1, write=0xd0, cs=SPI.CS1) #Get Status
#b1 = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
#b2 = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
#b3 = spi.read(5, write=0x00, cs=SPI.CS1) #Get Status
#print(b0,b1,b2,b3)

#v = struct.pack('BBB',0x0,0x0,0x60)
#v=v+(struct.pack(">I", 10000))[1:4]
#spi.write(v, cs=SPI.CS1) # Reset Device
#spi.write(0x60, cs=SPI.CS1)
#spi.write(0x00, cs=SPI.CS1)
#spi.write(0xa0, cs=SPI.CS1)
#spi.write(0x00, cs=SPI.CS1)
#utime.sleep_ms(10)
#spi.write(0xd0, cs=SPI.CS1)
#w = b'1234'
#r = bytearray(4)
#spi.write(w)
#spi.write(w, cs=SPI.CS1)
#spi.write_readinto(w, r)
#spi.read(5, write=0x00)
#spi.readinto(r, write=0x00)
```

![IMG_0047.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/d002a1c8-640f-11c5-2cd0-06fbd8a443b8.jpeg)
配線はこんな感じ。
![circit.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/4697c44d-2bca-87b7-cbbd-8b19aba8b985.jpeg)
※写真をよく見ると映っていますが試行錯誤途中にドライバ基板の出力ピンとMAiX Qubeのポートが出力となる設定をしてしまい短絡電流でポートを壊さない為にmiso,mosi,sck,csl各ピンにポート保護目的の抵抗が入っています。
安定動作するようになれば不要な抵抗です。

ドライバのジャンパー設定はこう
![IMG_0048.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/b30738bd-75ec-20ec-6ea7-6153ab680e75.jpeg)

![IMG_0049.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606106/0844dd5f-d636-0b45-f1db-3a3080600247.jpeg)

またドライバが1個ならこうなります。
内容は2個版と異なりますが、コードを書く際の参考にはなると思います。

```python:OneMotor.py
from machine import SPI
import utime,ubinascii
import struct
from Maix import GPIO

from fpioa_manager import fm
def CheckStatus():
    spi.write(0xd0, cs=SPI.CS1) # Reset Device
    a = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
    b = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
    c = a + b
    print('status1',ubinascii.hexlify(c))
    return c
def WaitMotorStop():
#ビジーフラグは実行中に0,停止中に1
    c=0
    while(c==0):
        spi.write(0xd0, cs=SPI.CS1) # Reset Device
        a = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
        b = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
        b2 = struct.unpack('B', b)[0]
        c = b2 & 0x02
def MotorGoto(Pos):
    spi.write(0x60, cs=SPI.CS1) # Reset Device
    VA=(struct.pack('>I',Pos))
    print('Pos',ubinascii.hexlify(VA))
    spi.write(VA[1:2], cs=SPI.CS1)
    spi.write(VA[2:3], cs=SPI.CS1)
    spi.write(VA[3:4], cs=SPI.CS1)

spi = SPI(SPI.SPI1, mode=SPI.MODE_MASTER, baudrate=10000, polarity=1, phase=1,
    bits=8, firstbit=SPI.MSB, sck=21, mosi=8, miso=7, cs1= 6)
utime.sleep_ms(10)
spi.write(0xc0, cs=SPI.CS1) # Reset Device
for num in range(10):
    CheckStatus()
    MotorGoto(30000)
    WaitMotorStop()
    utime.sleep_ms(20)
    CheckStatus()
    MotorGoto(0)
    WaitMotorStop()
    utime.sleep_ms(20)
spi.deinit()

fm.register(7, fm.fpioa.GPIO0, force=True)
#input0 = GPIO(GPIO.GPIO0, GPIO.IN)
led_r = GPIO(GPIO.GPIO0, GPIO.OUT)
led_r.value(0)
#spi.write(0xd0, cs=SPI.CS1)
#b0 = spi.read(1, write=0xd0, cs=SPI.CS1) #Get Status
#b1 = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
#b2 = spi.read(1, write=0x00, cs=SPI.CS1) #Get Status
#b3 = spi.read(5, write=0x00, cs=SPI.CS1) #Get Status
#print(b0,b1,b2,b3)

#v = struct.pack('BBB',0x0,0x0,0x60)
#v=v+(struct.pack(">I", 10000))[1:4]
#spi.write(v, cs=SPI.CS1) # Reset Device
#spi.write(0x60, cs=SPI.CS1)
#spi.write(0x00, cs=SPI.CS1)
#spi.write(0xa0, cs=SPI.CS1)
#spi.write(0x00, cs=SPI.CS1)
#utime.sleep_ms(10)
#spi.write(0xd0, cs=SPI.CS1)
#w = b'1234'
#r = bytearray(4)
#spi.write(w)
#spi.write(w, cs=SPI.CS1)
#spi.write_readinto(w, r)
#spi.read(5, write=0x00)
#spi.readinto(r, write=0x00)

```