ステッピングモーターその1 モーターとドライバ(L6470)を試す
ステッピングモーターを試します。
モーター、ドライバー、ネジをセットで変えるストロベリーリナックスから購入しました。
L6470 ステッピングモータ・ドライバキット - L6470 - ネット販売
L6470/42x34mmステッピングモーター用ネジセット - ネット販売
別に、ネジを使用する予定はないのですが、買ってみました。
ドキュメントがしっかりしているのが決め手でした。
https://strawberry-linux.com/pub/l6470-manual.pdf
モーター
そもそも、ステッピングモーターの、1相、2相など、コントロールの種類に関しては、事前に勉強が必要。
仕様 ・2相バイポーラ ステッピングモータ ・推奨動作電圧:DC12V ・ステップ数:200ステップ(1.8度) ・電流:0.33A/相 ・シャフト径:5mm ・シャフト長さ:24mm(方軸) ・コイル抵抗:34Ω ・重量:200g ・保持トルク:0.23N・m ・絶縁抵抗:100MΩ以上(500VDC) ・サイズ:42(W)x42(H)x34(D)mm
モータードライバ
仕様 コントローラ STMicroelectronics L6470 対応モータ バイポーラ(2相)ステッピングモータ モータ電源 DC8V~45V ロジック電源 DC3.3V~5V 最大モータ電流 3A rms (ピーク7A) インターフェース SPI(4線式) マイクロステップ数 1/1~1/128の間で設定ができます。 自己消費電流 約5mA(3.3V 動作時) 約1mA(5V動作時) ※実測値 その他機能 3.0Vレギュレータ内蔵,パワーダウンモード,オシレータスリープモード サイズ 約40x40mm ※このドライバは基本的にモータ電源とロジック電源の2系統の電源を必要とします。 ※製作・使用にあたり巻末の使用上の注意をよく読んでお使いください。
SPI の準備
raspi-config から、SPI を有効にします。
9 Advanced option > A5 API から、設定します。
$ lsmod | grep spi spi_bcm2835 7286 0 $ ls /dev/spidev* /dev/spidev0.0 /dev/spidev0.1
配線
GPIO 9(SPI MISO) 3(SDO) GPIO11(SPI SCLK) 5(SCK) GPIO10(SPI MOSI) 6(DSI) GPIO 8(SPI CE0) 7(~CS)
なお、CN1インターフェースに、RPIの3.3vとGNDだけをつなぐと、配線した際にOSが落ちました。
モーター電源に電源をつないだ状態で抜き差ししても、落ちません。
配線してある状態でモーターへの給電を止めても、落ちません。
なんとなくですが、ジャンパー設定が「3.3vを給電可能」モードと共通なので、
モーター電源が来ていない場合、その辺がゴニョゴニョしているのかなーと思います。
wiringPi を準備する
インストール
$ git clone git://git.drogon.net/wiringPi $ cd wiringPi/ $ ./build
コーディング
慣れない C です。
こちらを元に、書き換えました。
起動、加速、減速、解放・・・のつもりです。
http://junkroom2cyberrobotics.blogspot.jp/2012/09/raspberry-pi-spi.html
#include <stdio.h> #include <stdlib.h> #include <wiringPi.h> #include <wiringPiSPI.h> #define L6470_SPI_CHANNEL 0 // 関数プロトタイプ。 void L6470_write(unsigned char data); void L6470_init(void); void L6470_run(long speed); void L6470_softstop(); void L6470_softhiz(); int main(int argc, char **argv) { int i; long speed = 0; printf("***** start spi test program *****\n"); // SPI channel 0 を 1MHz で開始。 if (wiringPiSPISetup(L6470_SPI_CHANNEL, 1000000) < 0) { printf("SPI Setup failed:\n"); } // L6470の初期化。 L6470_init(); while(1) { for (i = 0; i < 10; i++) { speed += 2000; // 30000 位まで L6470_run(speed); printf("*** Speed %d ***\n", speed); delay (1000); } for (i= 0; i < 10; i++) { speed -= 2000; L6470_run(speed); printf("*** Speed %d ***\n", speed); delay (1000); } L6470_softstop(); L6470_softhiz(); return 0; } return 0; } void L6470_write(unsigned char data) { wiringPiSPIDataRW(L6470_SPI_CHANNEL, &data, 1); } void L6470_init() { // MAX_SPEED設定。 /// レジスタアドレス。 L6470_write(0x07); // 最大回転スピード値(10bit) 初期値は 0x41 L6470_write(0x00); L6470_write(0x41); // KVAL_HOLD設定。 /// レジスタアドレス。 L6470_write(0x09); // モータ停止中の電圧設定(8bit) L6470_write(0xFF); // KVAL_RUN設定。 /// レジスタアドレス。 L6470_write(0x0A); // モータ定速回転中の電圧設定(8bit) L6470_write(0xFF); // KVAL_ACC設定。 /// レジスタアドレス。 L6470_write(0x0B); // モータ加速中の電圧設定(8bit) L6470_write(0xFF); // KVAL_DEC設定。 /// レジスタアドレス。 L6470_write(0x0C); // モータ減速中の電圧設定(8bit) 初期値は 0x8A L6470_write(0x40); // OCD_TH設定。 /// レジスタアドレス。 L6470_write(0x13); // オーバーカレントスレッショルド設定(4bit) L6470_write(0x0F); // STALL_TH設定。 /// レジスタアドレス。 L6470_write(0x14); // ストール電流スレッショルド設定(4bit) L6470_write(0x7F); } void L6470_run(long speed) { unsigned short dir; unsigned long spd; unsigned char spd_h; unsigned char spd_m; unsigned char spd_l; // 方向検出。 if (speed < 0) { dir = 0x50; spd = -1 * speed; } else { dir = 0x51; spd = speed; } // 送信バイトデータ生成。 spd_h = (unsigned char)((0x0F0000 & spd) >> 16); spd_m = (unsigned char)((0x00FF00 & spd) >> 8); spd_l = (unsigned char)(0x00FF & spd); // コマンド(レジスタアドレス)送信。 L6470_write(dir); // データ送信。 L6470_write(spd_h); L6470_write(spd_m); L6470_write(spd_l); } void L6470_softstop() { unsigned short dir; printf("***** SoftStop. *****\n"); dir = 0xB0; // コマンド(レジスタアドレス)送信。 L6470_write(dir); delay(1000); } void L6470_softhiz() { unsigned short dir; printf("***** Softhiz. *****\n"); dir = 0xA8; // コマンド(レジスタアドレス)送信。 L6470_write(dir); delay(1000); }
gcc -o wir wir.c -I /usr/local/include -L /usr/local/lib -l wiringPi
最後のsoftstopは、意味ないですし、whileも意味ないですが、
動作差テストには成るかなと。
softstop/hardstop の状態は、トルクを維持しますので、電磁石はONの状態。
発熱します。
HiZ します。
データシート曰く、softhiz は、 10100000
なので、16進数に直すと、A8
に成ります。
wiringpi2 を Python で使う
インストール
$ sudo pip install wiringpi2
動作チェック
$ sudo python Python 2.7.9 (default, Mar 8 2015, 00:52:26) [GCC 4.9.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import wiringpi >>> wiringpi.piBoardRev() 2 >>> wiringpi.wiringPiSetup() 0 >>> quit()
コーディング
wiringpi wiringPiSPIDataRW が、2つの引数のみを受け付けるのだが、一体何を渡せばいいのかわからず、調べた。
ソースを読むと、Cにそのまま第2変数を投げているだけに見える・・・。
Gadgetoid commented on 2 Apr 2013 Amazingly late to the game here, but I have started maintaining WiringPi again in the form of a new version which you can find here: https://github.com/WiringPi/WiringPi2-Python The function wiringPiSPIDataRW now takes two arguments, pin and the string. Length and conversion to the correct datatype is handled internally. You should be able to call it thus: wiringPiSPIDataRW(1,'badger') I am the sole maintainer of this package, and had more pressing distractions. I'm tremendously late in getting it updated and offer my apologies. I'd love to see you guys come back to WiringPi2-Python and test it out; I'll be around to attempt to fix any problems you might have.
Pin, String らしい。
別のスレッドも探してみたら、
Python 2.7 なら、 (Int Pin, Str Data ) もしくは (Int Pin, Chr Data )で、
Python 3 なら、(Int Pin, Bytes Data)
らしい。
2.7 系で、 Str Data とうことだが、255 = 0xFF を Strで渡すというのは、"0xFF" を渡すのか、 "FF" を渡すのか、、、。
試行錯誤の結果として、
とりあえず、0xFF (int型)を、struct.pack で、ununsigned char型に変換して投げるようにしたら、動いた・・・。
これで正しいのだろうか。
#!/usr/bin/env python # -*- coding: utf-8 -*- import wiringpi as wp import time import struct L6470_SPI_CHANNEL = 0 L6470_SPI_SPEED = 1000000 def L6470_write(data): data = struct.pack("B", data) wp.wiringPiSPIDataRW(L6470_SPI_CHANNEL, data) def L6470_init(): # MAX_SPEED設定。 # レジスタアドレス。 L6470_write(0x07) # 最大回転スピード値(10bit) 初期値は 0x41 L6470_write(0x00) L6470_write(0x41) # KVAL_HOLD設定。 # レジスタアドレス。 L6470_write(0x09) # モータ停止中の電圧設定(8bit) L6470_write(0xFF) # KVAL_RUN設定。 # レジスタアドレス。 L6470_write(0x0A) # モータ定速回転中の電圧設定(8bit) L6470_write(0xFF) # KVAL_ACC設定。 # レジスタアドレス。 L6470_write(0x0B) # モータ加速中の電圧設定(8bit) L6470_write(0xFF) # KVAL_DEC設定。 # レジスタアドレス。 L6470_write(0x0C) # モータ減速中の電圧設定(8bit) 初期値は 0x8A L6470_write(0x40) # OCD_TH設定。 # レジスタアドレス。 L6470_write(0x13) # オーバーカレントスレッショルド設定(4bit) L6470_write(0x0F) # STALL_TH設定。 # レジスタアドレス。 L6470_write(0x14) # ストール電流スレッショルド設定(4bit) L6470_write(0x7F) def L6470_run(speed): # 方向検出。 if (speed < 0): dir = 0x50 spd = -1 * speed else: dir = 0x51 spd = speed # 送信バイトデータ生成。 spd_h = (0x0F0000 & spd) >> 16 spd_m = (0x00FF00 & spd) >> 8 spd_l = (0x00FF & spd) # コマンド(レジスタアドレス)送信。 L6470_write(dir) # データ送信。 L6470_write(spd_h) L6470_write(spd_m) L6470_write(spd_l) def L6470_softstop(): print("***** SoftStop. *****") dir = 0xB0 # コマンド(レジスタアドレス)送信。 L6470_write(dir) time.sleep(1) def L6470_softhiz(): print("***** Softhiz. *****") dir = 0xA8 # コマンド(レジスタアドレス)送信。 L6470_write(dir) time.sleep(1) if __name__=="__main__": speed = 0 print("***** start spi test program *****") # SPI channel 0 を 1MHz で開始。 #wp.wiringPiSetupGpio() wp.wiringPiSPISetup (L6470_SPI_CHANNEL, L6470_SPI_SPEED) # L6470の初期化。 L6470_init() while True: for i in range(0, 10): speed = speed + 2000 # 30000 位まで L6470_run(speed) print("*** Speed %d ***" % speed) time.sleep(1) for i in range(0, 10): speed = speed - 2000 L6470_run(speed) print("*** Speed %d ***" % speed) time.sleep(1) L6470_softstop() L6470_softhiz() quit() quit()