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を入力設定し、確認しましたが、相互に影響はしない様でした。
時間のある時にシリアル通信で外部コマンドで制御できるか、確認したいと思っています。