「L6470」タグアーカイブ

Raspberry Pi Pico でL6470ステッピングモータードライバーを使う

1.概要

 RASPBERRY PI PICO で、L6470ステッピングモータードライバーを使ってみます。RASPBERRY PI PICOを使うメリットは価格とサイズです。800円程度で購入できます。
 最初、MicroPythonでのプログラミングを試みました。SPI接続で何らかの通信はしている様ですが、意図するモーター制御が出来ないので、ArduinoIDEでのプログラム開発に切り換えました。
 結果的にはArduinoプログラムが利用できるので、今のところ正解と思っています。

2.環境設定

①「ファイル」-「環境設定」から、下記設定。
 追加のボードマネージャーのURL:
 ”https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json”

②ボードマネージャーからインストール


③ボード、シリアルポート選択

 シリアルポートは、初回認識していませんが、書込を実行すると次回から、認識される様です。

    

3.接続

 接続は次の通りです。いままで、秋月電子のドライバーを使用していましたが、StrawberryLinux取り扱い品が入手できたので、使ってみました。使い方は同じ様ですが、ピン配置が異なっています。また、幾つかアラーム出力がありますが、今回未使用です。
 ステッピングモーター接続、モーター用外部電源接続は省略しています。

  

4.プログラム

 ステッピングモーターを原点方向(ORG_SW)に動かし、原点SW検出時に停止、反対方向移動、SW解除位置で停止・原点情報初期化するプログラムです。
 過去に製作したテーブルで簡易的に動作確認できました。

#include <SPI.h>

// ピン定。
#define PIN_SPI_MOSI 19
#define PIN_SPI_SCK 18
#define PIN_SPI_SS 17
#define PIN_SPI_MISO 16
#define PIN_BUSY 20

#define PIN_LMT_ORG 21
#define PIN_LMT_END 22
#define PIN_LMT_LED 15
#define PIN_DRV_LED 14

int val_org = 0;
int val_end = 0;
int val_bsy = 0;
int sts_origin=0;               // 原点復帰ステータス



// 起動時実行
void setup()
{
  pinMode(PIN_SPI_MOSI, OUTPUT);        // SPI送信
  pinMode(PIN_SPI_MISO, INPUT);         //  SPI受信
  pinMode(PIN_SPI_SCK, OUTPUT);         // SPIクロック
  pinMode(PIN_SPI_SS, OUTPUT);          // SPIスレーブセレクト

  pinMode(PIN_BUSY, INPUT);             //  L6470 BUSY
  pinMode(PIN_LMT_ORG, INPUT_PULLUP);   //  原点SW入力
  pinMode(PIN_LMT_END, INPUT_PULLUP);   //  駆動端SW入力
  
  pinMode(PIN_LMT_LED, OUTPUT);         //  LED出力(リミット入力有)
  pinMode(PIN_DRV_LED, OUTPUT);         // LED出力(L6470ビジー)
   
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(MSBFIRST);
  
  digitalWrite(PIN_SPI_SS, HIGH);

  L6470_rst_device();                       // L6470リセット
  L6470_set_parameter();                    // L6470パラメータ設定
  delay_checking_sw_input( 500 );
}

// メインループ
void loop(){
  val_org = !digitalRead(PIN_LMT_ORG);  // 入力ピンを読む
  val_end = !digitalRead(PIN_LMT_END);  // 入力ピンを読む
  val_bsy = digitalRead(PIN_BUSY);
  
  digitalWrite(PIN_LMT_LED, val_org | val_end); // LEDのピンを読み取った値に変更
  digitalWrite(PIN_DRV_LED, val_bsy);           // LEDのピンを読み取った値に変更

  if (sts_origin==0){
    // 原点復帰処理 400(step/rot)→3200(step/rot) ※マイクロステップ 、 3200X60/16=12000(step/rot)    ※減速
    get_origin();                       // 原点復帰
    sts_origin=1;
  }
}

// 原点復帰動作
void get_origin(){

  if(!digitalRead(PIN_LMT_ORG)){
    L6470_data_transfer(0x51,3,8000);       // 反-原点方向(右)中速移動
    delay_checking_sw_input( 100 );
    
    while(!digitalRead( PIN_LMT_ORG )){ }
    delay_checking_sw_input( 1000 );
    L6470_data_transfer(0xb0,0,0);          // 回転停止(トルク保持)
    L6470_wait_not_busy(500);
  }
  
  L6470_data_transfer(0x50,3,8000);         // 原点方向(左)中速移動
  while(digitalRead( PIN_LMT_ORG )){} 
  L6470_data_transfer(0xb0,0,0);            // 回転停止、保持トルクあり
  L6470_wait_not_busy(500);

  L6470_data_transfer(0x51,3,500);          // 反-原点方向(右)低速移動
  delay_checking_sw_input( 50 );
  while(!digitalRead( PIN_LMT_ORG )){}
  
  L6470_data_transfer(0xb0,0,0);            // 回転停止(トルク保持)
  L6470_wait_not_busy(500);

  L6470_data_transfer(0x41,3,600);          // 反-原点方向(右)長さ指定移動
  L6470_wait_not_busy(100);
  
  L6470_data_transfer(0xd8,0,0);            // 原点情報初期化
  L6470_wait_not_busy(800);
}


// 初期設定
void L6470_set_parameter(){
  L6470_data_transfer(0x05,2,0x0e);  
  L6470_data_transfer(0x06,2,0x0e);   
  L6470_data_transfer(0x07,2,0x0e);    
  L6470_data_transfer(0x08,2,0x01);  
  L6470_data_transfer(0x15,2,0x3ff); 
  L6470_data_transfer(0x09,1,0x50);   
  L6470_data_transfer(0x0a,1,0x50);   
  L6470_data_transfer(0x0b,1,0x50);   
  L6470_data_transfer(0x0c,1,0x50);   

  // マクロステップ指定( 0x03 : 1/8 )
  // 実測値:16000step=20.8cm → 15385step=20.0cm →  77step=1mm(→15400step=20.0cm)
  // 計算値:1/8マイクロステップ→400*8(STEP/ROT)→3200(STEP/ROT))/40(mm/rot)=80(STEP/ROT)
  L6470_data_transfer(0x16,1,0x03);
}

// L6470リセット
void L6470_rst_device(){
  L6470_data_send_u(0x00);      //nop命令
  L6470_data_send_u(0x00);
  L6470_data_send_u(0x00);
  L6470_data_send_u(0x00);
  L6470_data_send_u(0xc0);
}

// L6470送信データ加工
void L6470_data_transfer(int add,int bytes,long val){
  int data[3];
  L6470_data_send(add);
  for(int i=0;i<=bytes-1;i++){
    data[i] = val & 0xff;  
    val = val >> 8;
  }
  if(bytes==3){
    L6470_data_send(data[2]);
  }
  if(bytes>=2){
    L6470_data_send(data[1]);
  }  
  if(bytes>=1){
    L6470_data_send(data[0]);
  }  
}

// L6470データ送信(BUSY解除待機)
void L6470_data_send(unsigned char add_or_val){
  while(!digitalRead(PIN_BUSY)){}
  
  digitalWrite(PIN_SPI_SS, LOW);          // ~SSイネーブル。
  SPI.transfer(add_or_val);              // アドレスもしくはデータ送信。
  Serial.println(add_or_val,HEX);
  digitalWrite(PIN_SPI_SS, HIGH);         // ~SSディスエーブル。
}

// L6470データ送信(BUSY状態関係なし)
void L6470_data_send_u(unsigned char add_or_val){
  digitalWrite(PIN_SPI_SS, LOW);          // ~SSイネーブル。
  SPI.transfer(add_or_val);               // アドレスもしくはデータ送信。
  digitalWrite(PIN_SPI_SS, HIGH);         // ~SSディスエーブル。
}

// BUSY解除待機
void L6470_wait_not_busy(long time){
  // BUSY解除待機
  while(!digitalRead(PIN_BUSY)){
    chk_sw_input();
  }  
  delay_checking_sw_input( time );
}

// 指定時間待機
void delay_checking_sw_input(unsigned long time ){
  // BUSY解除待機
  unsigned long tm_bgn = millis();
  unsigned long tm_now = millis();
  unsigned long tm_dif = tm_now - tm_bgn ; 

  while( tm_dif < time ){
    chk_sw_input();
    
    tm_now = millis();
    tm_dif = tm_now - tm_bgn ; 
  }
  
}

//SW入力確認・LED出力
void chk_sw_input(){
  val_bsy = digitalRead(PIN_BUSY);
  val_org = !digitalRead(PIN_LMT_ORG);
  val_end = !digitalRead(PIN_LMT_END);
  digitalWrite(PIN_DRV_LED, val_bsy);     // LEDのピンを読み取った値に変更
  digitalWrite(PIN_LMT_LED, val_org | val_end );     // LEDのピンを読み取った値に変更
}

5.まとめ

 SPI接続時に同じ0系列の他のGPIOを使えるのかという疑問がありましたので、GP2,3,4,5を入力設定し、確認しましたが、相互に影響はしない様でした。
 時間のある時にシリアル通信で外部コマンドで制御できるか、確認したいと思っています。