研究Tips:研究を効率化するためのTipsを紹介しています。

送液ポンプ(ペリスタポンプ ステッピングモーター型)

はじめに

先のページでペリスタポンプの作成方法を説明しました。先に紹介したペリスタポンプはDCモーターが回転することで送液しており、DCモーターの回転数を電圧で調整しました。このページではDCモーターではなく、ステッピングモーターを回転させて送液するペリスタポンプの作成方法を説明します。

DCモーターの場合、電圧調整で簡単に回転速度を制御できる一方、電圧を下げすぎると、ポンプの初動に必要な電圧に満たず、ポンプヘッドが回転しません。これは低速で送液したい場合には致命的です。低速で送液するには、1) DCモーターのペリスタポンプの動作をタイマー駆動(例: 10秒ON、10秒OFF)にするか、2)ステッピングモーターのペリスタポンプを使用します。このページでは後者を説明します。

ステッピングモーターを用いる場合の利点は、1) 低速で連続送液できる(40 microL/minとか)ところと、2) 一定量を正確に送液できる(例えば、1回ボタンを押すと「正確」に●回転するといった動作。分注用ポンプに最適)ところです。一方、面倒なのは、1) 動作させるためにポンプの他にドライバーとArduinoが必要、2) 速度調整をする場合、毎回、Arduinoのスケッチを書き換える必要がある(=パソコンが必要になる)点です。目的に合わせて、DCモーターとステッピングモーターを使い分けるといいです。

材料

  • ポンプヘッド: 小流量で送液する目的で使用するので、おのずとチューブ内径が細いものを使用することになります。以下のポンプヘッドですと、1回転で40 microL相当になります。
    • チュービングポンプWPM1 ステッピングモーター (Welco, WPM1-P1EA-BP) (価格帯: 1.3万円程度)
  • ステッピングモータードライバー (L6470使用 ステッピングモータードライブキット、秋月電子通商、通販コード K-07024)
  • Arduino (例えば、keyestudio UNO R3 開発ボード + USBケーブル UNO R3 Arduino互換、amazon、ASIN B01JRFS1QI)
  • 9V スイッチングACアダプター 2個 (例えば、秋月電子通商、通販コード M-01803)
  • 電線(単芯のワイヤ): 例えば、耐熱通信機器用ビニル電線 2m×10色 (秋月電子通商 P-08996)
  • ワイヤーストリッパー (例えば、ベッセルワイヤーストリッパー 3500E-1)
  • ジャンパワイヤー オス-メス: (例えば、ブレッドボード・ジャンパーワイヤ(オス-メス)、秋月電子通商、通販コードC-08933)
  • DCジャックメス端子: 2.1mm標準DCジャック⇔スクリュー端子台、秋月電子通商、通販コード C-08849)やケース壁固定するなら(2.1mm標準DCジャック パネル取付用 MJ-14, 秋月電子通商、通販コードC-06342)

ケース収納する場合、以下の道具が必要です。

  • 電気ドリルとドリルビット、ホールソー (ポンプヘッドによってサイズが異なります。)
  • ドリルビット、ホールソーは色々とケース加工で使うのでセットで購入しておくとなにかと便利です。例えば、E-Value 鉄工用ドリルセット チタンコーティング 丸軸 21本組 ETD-21S-T (Amazon ASIN B003EIC44K)。MOHOO 13PCS 16-53mm HSSドリルビット ホールソーセット (Amazon ASIN B06XKWNHHR)。
  • M3ネジ(ケースの厚さ次第ですが長さ 5 mm(秋月電子通商, P-10358), 8 mm(P-10359), 10 mm (P-03000)があればおよそ用足ります)、M3ナット(P-03584)。
  • プラス、マイナスドライバー、ノギスなど汎用工具

作成方法

  1. ステッピングモータードライバーをはんだで組み立てます。モータードライバー付属のジャンパピンは、写真のように左上一箇所に取り付けます。基盤の「JP1」と「EXT」と書いてある箇所の端子台です。また、Arduinoとモータードライバーを接続する端子台は付属のものはオスのピンヘッダですが、2x5のメスのピンソケットに変更しても構いません。変更するとオス-オスのジャンパワイヤが使えるので便利かもしれません。
    電子回路を写真のように組み立てます。Arduinoとモータードライバー間はジャンパワイヤ(オス-メス)で接続します。ACアダプタはDCジャックメス端子およびArduinoのDCジャック端子に接続してください。ステッピングモーターについては4本の配線がモーターから出ており、それぞれ配線番号が決まっています。Welco社のHPに記載されていますが、回路図のような向きでモーターを見た場合に左側から1、3、4、6です。配線の色はロットで変わるかもしれないので、ケーブルの色ではなく、配線番号を確認してください。同じくHPに記載がありますが、1と3番がB相、4と6番がA相とのことですので、モータードライバーの基盤に「B」と記載されているターミナル端子台へ1と3番ケーブルを、「A」と記載された端子台に4と6番ケーブルを接続してください。

    2020年11月追記: モータドライバのピン配置が変更になったようです。図の方は古いピンレイアウトです。ピン番号の対応はこのページ一番下に追記してあります(Dwの使い方がよくわからないので。)

     

     

     

     

     

     

     

     

     

     

     

     

     

    ペリスタ_ステッピングモーター.pdf
  2. 必要に応じて、ケース収納してください。ケース加工については先のDCモーターのペリスタポンプのページが参考になるかと思います 
  3. 以下のスケッチをArduinoへ書き込みます。回転速度はスケッチ内部の赤字の数値(このスケッチだと10000になっています)を変更することで調整します。それ以外の箇所は変更しなくて構いません(逆回転、回転数の指定、回転の停止など回転を制御したければ変更してください。)

#include <SPI.h>
#include <MsTimer2.h>

// ピン定義。
#define PIN_SPI_MOSI 11
#define PIN_SPI_MISO 12
#define PIN_SPI_SCK 13
#define PIN_SPI_SS 10
#define PIN_BUSY 9

void setup()
{
delay(1000);
pinMode(PIN_SPI_MOSI, OUTPUT);
pinMode(PIN_SPI_MISO, INPUT);
pinMode(PIN_SPI_SCK, OUTPUT);
pinMode(PIN_SPI_SS, OUTPUT);
pinMode(PIN_BUSY, INPUT);
SPI.begin();
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
Serial.begin(9600);
digitalWrite(PIN_SPI_SS, HIGH);

L6470_resetdevice(); //L6470リセット
L6470_setup(); //L6470を設定

MsTimer2::set(50, fulash);//シリアルモニター用のタイマー割り込み
MsTimer2::start();
delay(4000);

L6470_run(0,10000);//ここだけ変更する。回転速度の設定。指定方向に連続回転
delay(6000);
}

void loop(){
}

void L6470_setup(){
L6470_setparam_acc(0x40); //[R, WS] 加速度default 0x08A (12bit) (14.55*val+14.55[step/s^2])
L6470_setparam_dec(0x40); //[R, WS] 減速度default 0x08A (12bit) (14.55*val+14.55[step/s^2])
L6470_setparam_maxspeed(0x40); //[R, WR]最大速度default 0x041 (10bit) (15.25*val+15.25[step/s])
L6470_setparam_minspeed(0x01); //[R, WS]最小速度default 0x000 (1+12bit) (0.238*val[step/s])
L6470_setparam_fsspd(0x3ff); //[R, WR]μステップからフルステップへの切替点速度default 0x027 (10bit) (15.25*val+7.63[step/s])
L6470_setparam_kvalhold(0x20); //[R, WR]停止時励磁電圧default 0x29 (8bit) (Vs[V]*val/256)
L6470_setparam_kvalrun(0x20); //[R, WR]定速回転時励磁電圧default 0x29 (8bit) (Vs[V]*val/256)
L6470_setparam_kvalacc(0x20); //[R, WR]加速時励磁電圧default 0x29 (8bit) (Vs[V]*val/256)
L6470_setparam_kvaldec(0x20); //[R, WR]減速時励磁電圧default 0x29 (8bit) (Vs[V]*val/256)

L6470_setparam_stepmood(0x03); //ステップモードdefault 0x07 (1+3+1+3bit)
}

void fulash(){
Serial.print("0x");
Serial.print( L6470_getparam_abspos(),HEX);
Serial.print(" ");
Serial.print("0x");
Serial.println( L6470_getparam_speed(),HEX);
}


//-----------------------RegisterCommand-------------------------

void L6470_setparam_abspos(long val){L6470_transfer(0x01,3,val);}
void L6470_setparam_elpos(long val){L6470_transfer(0x02,2,val);}
void L6470_setparam_mark(long val){L6470_transfer(0x03,3,val);}
void L6470_setparam_acc(long val){L6470_transfer(0x05,2,val);}
void L6470_setparam_dec(long val){L6470_transfer(0x06,2,val);}
void L6470_setparam_maxspeed(long val){L6470_transfer(0x07,2,val);}
void L6470_setparam_minspeed(long val){L6470_transfer(0x08,2,val);}
void L6470_setparam_fsspd(long val){L6470_transfer(0x15,2,val);}
void L6470_setparam_kvalhold(long val){L6470_transfer(0x09,1,val);}
void L6470_setparam_kvalrun(long val){L6470_transfer(0x0a,1,val);}
void L6470_setparam_kvalacc(long val){L6470_transfer(0x0b,1,val);}
void L6470_setparam_kvaldec(long val){L6470_transfer(0x0c,1,val);}
void L6470_setparam_intspd(long val){L6470_transfer(0x0d,2,val);}
void L6470_setparam_stslp(long val){L6470_transfer(0x0e,1,val);}
void L6470_setparam_fnslpacc(long val){L6470_transfer(0x0f,1,val);}
void L6470_setparam_fnslpdec(long val){L6470_transfer(0x10,1,val);}
void L6470_setparam_ktherm(long val){L6470_transfer(0x11,1,val);}
void L6470_setparam_ocdth(long val){L6470_transfer(0x13,1,val);}
void L6470_setparam_stallth(long val){L6470_transfer(0x14,1,val);}
void L6470_setparam_stepmood(long val){L6470_transfer(0x16,1,val);}
void L6470_setparam_alareen(long val){L6470_transfer(0x17,1,val);}
void L6470_setparam_config(long val){L6470_transfer(0x18,2,val);}

long L6470_getparam_abspos(){return L6470_getparam(0x01,3);}
long L6470_getparam_elpos(){return L6470_getparam(0x02,2);}
long L6470_getparam_mark(){return L6470_getparam(0x03,3);}
long L6470_getparam_speed(){return L6470_getparam(0x04,3);}
long L6470_getparam_acc(){return L6470_getparam(0x05,2);}
long L6470_getparam_dec(){return L6470_getparam(0x06,2);}
long L6470_getparam_maxspeed(){return L6470_getparam(0x07,2);}
long L6470_getparam_minspeed(){return L6470_getparam(0x08,2);}
long L6470_getparam_fsspd(){return L6470_getparam(0x15,2);}
long L6470_getparam_kvalhold(){return L6470_getparam(0x09,1);}
long L6470_getparam_kvalrun(){return L6470_getparam(0x0a,1);}
long L6470_getparam_kvalacc(){return L6470_getparam(0x0b,1);}
long L6470_getparam_kvaldec(){return L6470_getparam(0x0c,1);}
long L6470_getparam_intspd(){return L6470_getparam(0x0d,2);}
long L6470_getparam_stslp(){return L6470_getparam(0x0e,1);}
long L6470_getparam_fnslpacc(){return L6470_getparam(0x0f,1);}
long L6470_getparam_fnslpdec(){return L6470_getparam(0x10,1);}
long L6470_getparam_ktherm(){return L6470_getparam(0x11,1);}
long L6470_getparam_adcout(){return L6470_getparam(0x12,1);}
long L6470_getparam_ocdth(){return L6470_getparam(0x13,1);}
long L6470_getparam_stallth(){return L6470_getparam(0x14,1);}
long L6470_getparam_stepmood(){return L6470_getparam(0x16,1);}
long L6470_getparam_alareen(){return L6470_getparam(0x17,1);}
long L6470_getparam_config(){return L6470_getparam(0x18,2);}
long L6470_getparam_status(){return L6470_getparam(0x19,2);}

//-----------------------CommandSet----------------------------------

void L6470_run(int dia,long spd){
if(dia==1)
L6470_transfer(0x51,3,spd);
else
L6470_transfer(0x50,3,spd);
}
void L6470_stepclock(int dia){
if(dia==1)
L6470_transfer(0x59,0,0);
else
L6470_transfer(0x58,0,0);
}
void L6470_move(int dia,long n_step){
if(dia==1)
L6470_transfer(0x41,3,n_step);
else
L6470_transfer(0x40,3,n_step);
}
void L6470_goto(long pos){
L6470_transfer(0x60,3,pos);
}
void L6470_gotodia(int dia,int pos){
if(dia==1)
L6470_transfer(0x69,3,pos);
else
L6470_transfer(0x68,3,pos);
}
void L6470_gountil(int act,int dia,long spd){
if(act==1)
if(dia==1)
L6470_transfer(0x8b,3,spd);
else
L6470_transfer(0x8a,3,spd);
else
if(dia==1)
L6470_transfer(0x83,3,spd);
else
L6470_transfer(0x82,3,spd);
}
void L6470_relesesw(int act,int dia){
if(act==1)
if(dia==1)
L6470_transfer(0x9b,0,0);
else
L6470_transfer(0x9a,0,0);
else
if(dia==1)
L6470_transfer(0x93,0,0);
else
L6470_transfer(0x92,0,0);
}
void L6470_gohome(){
L6470_transfer(0x70,0,0);
}
void L6470_gomark(){
L6470_transfer(0x78,0,0);
}
void L6470_resetpos(){
L6470_transfer(0xd8,0,0);
}
void L6470_resetdevice(){
L6470_send_u(0x00);//nop命令
L6470_send_u(0x00);
L6470_send_u(0x00);
L6470_send_u(0x00);
L6470_send_u(0xc0);
}
void L6470_softstop(){
L6470_transfer(0xb0,0,0);
}
void L6470_hardstop(){
L6470_transfer(0xb8,0,0);
}
void L6470_softhiz(){
L6470_transfer(0xa0,0,0);
}
void L6470_hardhiz(){
L6470_transfer(0xa8,0,0);
}
long L6470_getstatus(){
long val=0;
L6470_send_u(0xd0);
for(int i=0;i<=1;i++){
val = val << 8;
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
val = val | SPI.transfer(0x00); // アドレスもしくはデータ送信。
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル
}
return val;
}

void L6470_transfer(int add,int bytes,long val){
int data[3];
L6470_send(add);
for(int i=0;i<=bytes-1;i++){
data[i] = val & 0xff;
val = val >> 8;
}
if(bytes==3){
L6470_send(data[2]);
}
if(bytes>=2){
L6470_send(data[1]);
}
if(bytes>=1){
L6470_send(data[0]);
}
}
void L6470_send(unsigned char add_or_val){
while(!digitalRead(PIN_BUSY)){
} //BESYが解除されるまで待機
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
SPI.transfer(add_or_val); // アドレスもしくはデータ送信。
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル。
}
void L6470_send_u(unsigned char add_or_val){//busyを確認せず送信するため用
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
SPI.transfer(add_or_val); // アドレスもしくはデータ送信。
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル。
}
void L6470_busydelay(long time){//BESYが解除されるまで待機
while(!digitalRead(PIN_BUSY)){
}
delay(time);
}
long L6470_getparam(int add,int bytes){
long val=0;
int send_add = add | 0x20;
L6470_send_u(send_add);
for(int i=0;i<=bytes-1;i++){
val = val << 8;
digitalWrite(PIN_SPI_SS, LOW); // ~SSイネーブル。
val = val | SPI.transfer(0x00); // アドレスもしくはデータ送信。
digitalWrite(PIN_SPI_SS, HIGH); // ~SSディスエーブル
}
return val;
}


5. ArduinoおよびモータードライバーそれぞれのACアダプタを電源に接続すると回転開始です。私の手元のポンプヘッドでは回転数の設定値を10,000にすると、1分間で約2回転(= 80 microL/min)でした。まずは大きめの数値を入れて、モーターが回転することを確認し、その後、低速の設定を試みるのがよいかと思います。

2020年11月追記 モータドライバーのピン配置

左側モータドライバピン  |   右側Arduinoピン

1 #BUSY/SYNC   |  Arduino 9 pin

2 接続なし

3 GND   |   GND

4 EXT-VDD  | Arduino 5V

5 SDO  | Arduino 12 pin

6  CK   | Arduino 13 pin

7 SDI |  Arduino 11 pin

8 #CS | Arduino 10 pin

9, 10 接続なし 

なお、ジャンパ接続についてはJP1の3-4を接続させます。