「SPI」タグアーカイブ

ラズパイ4 ステップモーターを動かす(L6470 SPI接続)

概要

 ArduinoUnoからL6470ドライバーを利用したステッピングモーター制御について投稿したことがあります。
 今回はRaspberryPi4 ModelB(ラズパイ)からの制御について調査しました。プログラムは python です。

結果

 次の3つの運転モードを確認した動画です。(2倍速再生)
  ①回転方向・速度を指定するJOG運転 
  ②移動量を指定するステップ運転 
  ③基準に対する絶対位置指定する位置決め運転

 画面上にある主な構成機器は次の通りです。
  ①RaspberryPi Model B (画面左前)
  ②ステッピングモーター(画面中央)
   (秋月電子:SM-42BYG011-25)
  ③L6470 ドライバー(画面中央奥)
   (秋月電子:AE-L6470DRV)
  ④直流12V電源(画面右奥)

配線接続

 配線接続は次の図の通りにしています。

  ※ L6470 JP1 :3 – 4 pin 短絡 (EXT-VDD 端子から外部電圧供給)

 参考に RaspberryPi Model B ピンアサインを掲載します。範囲が狭いので、ピンソケット(2X5=10P [FH-2x5SG] )で接続しました。

ラズパイ側のSPI設定

 ラズパイ設定用ウィンドウで SPI 設定を有効にします。
 Windowsでいうスタートメニュー(?)から、「設定」ー「Raspberry Piの設定」で設定ウィンドウを開きます。
「インターフェース」タブで SPI を有効にし「OK」します。

  

 ターミナルから「lsmod | grep spi」コマンドで「spi_bcm2835」が表示されれば、SPI接続は有効になっている様です。

 次に下記コマンドで「wiringpi」をインストールします。python から SPI 接続する為に使いました。

sudo pip3 install wiringpi

 ターミナルからの SPI 有効確認と「wiringpi」インストールの状況を次の図に示します。

※ SPI 有効確認と「wiringpi」インストール

プログラム

 プログラムです。

import wiringpi as wp                   
import RPi.GPIO as GPIO
import struct
import time
import sys

SPI_CH = 0                              # SPI チャンネル
SPI_HZ = 1000000                        # SPI 通信速度

GPIO_Nbr = 25                           # GPIO-NO
GPIO.setmode(GPIO.BCM)                  # GPIO-NO 指定
GPIO.setup(GPIO_Nbr,GPIO.IN)            # GPIO INPUT 指定

# L6470初期設定    
def INIT_L6470():
    spi_send([0x00,0x00,0x00,0xc0])     # Reset Device
    spi_send([0x05,0x00,0x0e])          # Acceleration (12)
    spi_send([0x06,0x00,0x0e])          # Deceleration (12)
    spi_send([0x07,0x00,0x0e])          # Maximum speed (10)
    spi_send([0x08,0x00,0x01])          # Minimum speed (13)
    spi_send([0x15,0x03,0xFF])          # Full-step speed (10)
    spi_send([0x16,0x03])               # Micro Step (8)
    spi_send([0x09,0x50])               # Holding Kval (8)
    spi_send([0x0A,0x50])               # Constant Speed Kval (8)
    spi_send([0x0B,0x50])               # Acceleration starting Kval (8)
    spi_send([0x0C,0x50])               # Deceleration starting Kbal (8)

# SPI データ送信
def spi_send(spi_dat_ary):
    for itm in spi_dat_ary:
        tmp=struct.pack("B",itm)
        wp.wiringPiSPIDataRW(SPI_CH, tmp)

# JOG (SPEED指定 : 0---30000)
def L6470_run(run_spd):
    # 方向検出
    if (run_spd > 0):
        dir = 0x50
        spd = run_spd
    else:
        dir = 0x51
        spd = -1 * run_spd
        
    L6470_SEND_MOVE_CMD( dir , spd )

# 移動量指定移動
def L6470_POSITIONING(MV_DIST):
    # 方向検出
    if (MV_DIST > 0):
        dir = 0x40
    else:
        dir = 0x41
        MV_DIST = -1 * MV_DIST
        
    L6470_SEND_MOVE_CMD( dir , MV_DIST )

# 絶対位置指定移動
def L6470_MOVE_ABS(MV_DIST):
    dir = 0x60
    if (MV_DIST < 0):
        MV_DIST = -1 * MV_DIST
        
    L6470_SEND_MOVE_CMD( dir , MV_DIST )
        
# データ加工・送信(共通)
def L6470_SEND_MOVE_CMD( cmd , DAT ):
    tmp=[]
    tmp.append(cmd)
    tmp.append((0x0F0000 & DAT) >> 16)
    tmp.append((0x00FF00 & DAT) >> 8)
    tmp.append((0x00FF & DAT))
    spi_send(tmp)
        
# テスト運転(JOG運転)
def L6470_DEMO():
    spd_run = 0
    inc_spd = 8000
    print("DEMO STARTED")
    while True:
        rng = 4
        for i in range(rng):
            inc_spd_d = inc_spd
            if i >= int(rng/2):
                inc_spd_d = -1 * inc_spd
                
            spd_run = spd_run + inc_spd_d
            if spd_run <= 0:
                break
            L6470_run(spd_run)
            print("Speed : %d" % spd_run)
            time.sleep(2)

        L6470_STOP()
        print("DEMO FINISHED")
        print("")
        time.sleep(1)
        break

# 停止指令
def L6470_STOP():
    spi_send([0xB0])                    # SOFT STOP
    time.sleep(0.2)
    spi_send([0xA8])                    # Hard HiZ
    time.sleep(0.2)

# 原点設定
def L6470_SET_ORIGIN():
    spi_send([0xD8])                    # Reset Position
    time.sleep(0.5)

# 原点移動
def L6470_MOVE_ORIGIN():
    spi_send([0x70])                    # Go Home
    time.sleep(0.5)

# ドライバーBUSY解除待ち
def wait_until_not_busy():
    while True:
        time.sleep(0.2)
        mtr_sts = GPIO.input(GPIO_Nbr)
        #print(mtr_sts)
        
        if GPIO.input(GPIO_Nbr) == GPIO.HIGH :
            print("L6470 NOT BUSY")
            break    
    time.sleep(0.2)

##################################
# メインプログラム
##################################
if __name__ == "__main__":
    wp.wiringPiSPISetup(SPI_CH,SPI_HZ)  # SPI 接続
    
    INIT_L6470()                        # L6470初期設定
    
    # テスト運転(JOG運転)
    L6470_DEMO()                        # テスト運転(JOG運転)

    # 移動量指定移動   
    print("STEP ROTATION START")
    rng=10
    step = int(1600 / rng)
    for i in range(rng):
        L6470_POSITIONING(step)         # 移動量指定移動
        wait_until_not_busy()           # ドライバーBUSY解除待ち
    print("STEP ROTATION FINISHED")
    print("")

    # 絶対位置指定移動
    print("ABS ROTATION START")
    L6470_SET_ORIGIN()                  # 原点位置設定(0)
    rng=10
    step = int(3*(1600 / rng))
    for i in range(rng):
        L6470_MOVE_ABS((i+1)*step)      # 絶対位置指定移動
        wait_until_not_busy()           # ドライバーBUSY解除待ち

    L6470_MOVE_ORIGIN()                 # 原点位置移動
    print("ABS ROTATION FINISHED")
    
    GPIO.cleanup() 

まとめ

 最初、「spidev」というライブラリを試したところ、正確に動かなかったので「wiringpi」を使ってみました。 データ形式等が異なるのだと思いますが、基礎知識欠如により対応できませんでした。時間があればまた試してみたいと思います。
 一方、ラズパイは多用途で利用できるので、組み合せた使い方も検討していきたいと思います。