Raspberry Pi Pico Wを使用してステッピングモータ3軸の原点復帰を行う実験をしました。
今までRaspberry Pi Pico Wにステッピングモータを接続して、直線補間、円弧補間、ヘリカル補間等、CNCの軸制御のプログラムを作成してきました。主な要素はそろったと思いますが、ステッピングモータを使用したCNCは電源を投入した時に各軸の位置が分からないので原点復帰が必要です。よってCNCの要素技術として原点復帰のテストプログラムを作成してみました。(2軸の直線補間の記事はこちら、3軸の直線補間の記事はこちら、円弧補間の記事はこちら、ヘリカル補間の記事はこちら)
尚、プログラミングツールとしてはArduino IDEを使用し、ステッピングモータの駆動にArduino言語のStepperライブラリを使用しています。
原点復帰に関して
原点復帰とは工作機械等の装置で電源投入時に各ユニットの位置が分からないので、各ユニットを1度原点に戻す動作のことです。
現在の多くのCNCは絶対位置エンコーダ付のACサーボモータをアクチュエータとして使用しており、原点復帰は不要な物が多いです。
ここでは、ステッピングモータを使用したCNCを作ることを目指しているので、ステッピングモータの場合には電源投入時の位置が分からないので原点復帰が必要です。
原点復帰の方法は様々あります、簡単なのは工作機械の各軸の原点に、原点センサ(リミットスイッチ等)を設けておいて、各軸を原点方向に移動させてその原点センサがONする位置で止め、その位置を原点(0)とする方法です。(原点の精度は原点センサの精度で決まってしまいます)
実際には、リミットスイッチがONしてからOFFする位置を原点としたり、モータが1回転に1度ONするセンサを別に設けて置き、原点のリミットスイッチとモータの1回転信号が共にONになった時に原点とする方法等があります。
今回の実験プログラムは、簡単にリミットスイッチがOFF→ONする位置を原点とします。実験装置としてはリミットスイッチの代わりに押し釦スイッチを取り付けて押し釦スイッチを押した位置を原点とします。
原点復帰時はセンサがONしたら直ちに軸を停止させて、座標をゼロにしなければならないんで割り込み処理を使用します。
割り込み処理に関して
今回は原点センサの代わりに3個の押し釦スイッチを使用します。それぞれのスイッチが押された時に、割り込みを発生させて割り込み関数が呼び出されるようにattachInterrupt()関数を使用して呼び出し関数を設定します。その呼び出された関数で、それぞれの軸停止用のフラグを立てます。
表1にArduino言語で割り込み処理関係の関数を示します。
関数 | 役割 |
attachInterrupt(interrupt,function,mode) | 外部割込みが発生したときに実行する関数を指定します。 パラメータ interrupt: 割り込み番号 尚ピン番号と割り込み番号が異なるのでdigitalPinToInterrupt()関数を使用します function: 割り込み発生時に呼び出す関数 mode: 割り込みを発生させるトリガ LOW ピンがLOWの時発生 CHANGE ピンの状態が変化したときに発生 RISING ピンの状態がLOWからHOGHに変わったときに発生 FALLING ピンの状態がHIGHからLOWに変わったときに発生 |
detachInterrupt(interrupt) | 指定した割り込みを停止します。 パラメータ interrupt: 停止したい割り込みの番号 尚ピン番号と割り込み番号が異なるのでdigitalPinToInterrupt()関数を使用します |
interrupts() | noInterrupts関数によって停止した割り込みを有効にします。 |
noInterrupts() | 割り込みを無効にします。interrupts関数でまた有効に出来ます。 |
実験装置
X、Y、Z軸のステッピングモータは28BYJ-48とそのドライバーボードのセットを使用しました。このステッピングモータとドライバーボードは複数のネット通販から購入することが出来ます。
コントローラとしてはRaspberry Pi Pico Wを使用して実験装置を組みました。
今回使用したステッピングモータの主な仕様は表2の通りです。このモータは1/64のギアで減速されていて、1-2相励磁の場合にステップ角は5.625°/64なので4096ステップでモータ軸が1回転します。最大自起動周波数が500ppsなので、500パルス/sec以下で起動する必要があります。起動後は徐々に加速を行った場合に、最大で1000パルス/secまで仕様上は可能と思われます。
ただし、Stepperライブラリーのstep()関数を使用した場合の励磁方式は2相励磁のようです。そのため2048ステップでモータ1回転となります。
項目 | 仕様 |
相数 | 4相 |
励磁方式 | 1-2相励磁方式 |
ステップ角 | 5.625°/64 (減速比1/64) |
電圧 | 5VDC |
相抵抗 | 22Ω ± 7% 25°C |
最大応答周波数 | 1000pps |
最大自起動周波数 | 500pps |
引き込みトルク | 800gf.cm / 5VDC 400pps |
実験装置回路図
図1に実験装置の回路図を示します。実験用なのでX、Y、Z軸の原点センサの代わりにそれぞれスイッチを使用しています。それぞれのスイッチを押した時に原点に到達して原点センサがONしたとします。
28BYJ-48ステッピングモータのドライバーボードはテキサスインスツルメンツのULN2003ANと言うダーリントントランジスタアレイが使用されています。ドライバーボード自体の資料が無かったので、テスタと基板のパターンを見て回路を調べました。
X軸用のステッピングモータのドライバーボードの入力信号IN1~IN4をRaspberry Pi Pico WのGP0~GP3に接続しました。
Y軸用のステッピングモータのドライバーボードの入力信号IN1~IN4をRaspberry Pi Pico WのGP4~GP7に接続しました。
Z軸用のステッピングモータのドライバーボードの入力信号IN1~IN4をRaspberry Pi Pico WのGP8~GP11に接続しました。
原点復帰開始用のスイッチをRaspberry Pi Pico WのGP12に接続しました。
X軸の原点センサの代わりにX軸の原点信号入力用スイッチをRaspberry Pi Pico WのGP13に接続しました。
Y軸の原点センサの代わりにY軸の原点信号入力用スイッチをRaspberry Pi Pico WのGP14に接続しました。
Z軸の原点センサの代わりにZ軸の原点信号入力用スイッチをRaspberry Pi Pico WのGP15に接続しました。
ステッピングモータの駆動に関して
今回使用したステッピングモータ28BYJ-48は1-2相励磁の場合、1回転4096ステップとなります。ただStepperライブラリのstep()関数は2相励磁方式です。2相励磁の場合1回転2048ステップとなります。
Stepper(step2, pin1, pin2, pin3, pin4)
関数でI/Oピンを割り振った場合の励磁順序は表3の様になっています。
引数 | 1ステップ | 2ステップ | 3ステップ | 4ステップ |
pin1 | HIGH | LOW | LOW | HIGH |
pin2 | LOW | HIGH | HIGH | LOW |
pin3 | HIGH | HIGH | LOW | LOW |
pin4 | LOW | LOW | HIGH | HIGH |
また、ステッピングモータ28BYJ-48の仕様書では1-2相励磁方式の励磁順序の表が載っていますが、それから推測した2相励磁の場合の励磁順序は表4の通りです。(時計方向回り時)
ドライバボード入力 | モータリード線 | 1ステップ | 2ステップ | 3ステップ | 4ステップ |
+ (5V) | リード線色 赤 | 5Vに接続 | 5Vに接続 | 5Vに接続 | 5Vに接続 |
IN1 | リード線色 青 | HIGH | LOW | LOW | HIGH |
IN2 | リード線色 桃 | HIGH | HIGH | LOW | LOW |
IN3 | リード線色 黄 | LOW | HIGH | HIGH | LOW |
IN4 | リード線色 橙 | LOW | LOW | HIGH | HIGH |
以上からpin1~pin4とドライバボードIN1~IN4の関係は次の様になります。
pin1: リード線色 青 (ドライバボード入力 IN1)
pin2: リード線色 桃 (ドライバボード入力 IN3)
pin3: リード線色 黄 (ドライバボード入力 IN2)
pin4: リード線色 橙 (ドライバボード入力 IN4)
ドライバボード入力にIN2とIN3がひっくり返っていることに注意が必要です。
動作動画
以下動画は、X、Y、Z軸原点復帰のプログラムを作成して実行した様子です。
3軸が原点復帰動作開始後、原点センサに見立てたスイッチを押すことによって、それぞれの軸が停止して現在位置が0(原点)となります。
パソコンの画面は、Raspberry Pi Pico WからUSBシリアル通信を使用してX、Y、Z軸の位置データを「X:位置,Y:位置,Z:位置」の形式で送信して、Arduino IDEのシリアルモニタ機能で表示した画面です。原点復帰が終了すると全軸の位置が0となります。
プログラム
Raspberry Pi Pico Wのプログラム開発ツールとして、Arduino IDEを使用しました。
GP12に接続されたスイッチを押すとX、Y、Z軸ステッピングモータが回転し始めます。(原点復帰開始)
GP13に接続されたスイッチ(X軸原点スイッチ)を押すとX軸のステッピングモータが停止して、X軸の現在位置が0になります。
GP14に接続されたスイッチ(Y軸原点スイッチ)を押すとY軸のステッピングモータが停止して、Y軸の現在位置が0になります。
GP15に接続されたスイッチ(Z軸原点スイッチ)を押すとZ軸のステッピングモータが停止して、Z軸の現在位置が0になります。
移動中はAnduino IDEのシリアルモニタ機能等で、X、Y、Z軸の各位置を表示できるように、パソコンへUSBシリアルポートを使用して、現在位置を以下の形式で送信しています。
X:「X軸パルス位置」,Y:「Y軸パルス位置」,Z:「Z軸パルス位置」
例
X:45,Y:22,Z:100
以下に全ソースコードを6個の部分に分割して説明します。
1.初期処理 setup()関数
初期処理を行うsetup()関数のソースコードを以下に示します。
ステッピングモータを起動するのにArduino言語のStepperライブラリーを使用しています。ステッピングモータの回転速度をsetSpeed()関数で500rpmに設定していますが、実際には1ステップづつの送りしかしないので、setSpeed()関数では回転速度は決まりません。1パルス送る毎にdelayMicroseconds()関数による待ちを入れて、このディレイ時間で送り速度を決めています。step()関数からは出来るだけ速く抜け出るようにsetSpeed(rpms)のrpmsの値は大きめにセットしています。
スイッチが接続されたGP13,GP14,GP15で各スイッチが押されて信号がHIGH→LOWになった時に、それぞれ割り込み関数が呼び出されるようにattachInterrupt()関数を使用して割り込み関数を定義しています。
attachInterrupt(interrupt,function,mode)の引数interruptは割り込み番号を設定しますが、digitalPinToInterrupt()関数を使用してI/O番号から割り込み番号に変換しています。
現在位置を都度パソコンへUSBシリアル通信を使用して送るので、USBシリアル通信の設定をしています。
//------Raspberry Pi Pico W 原点復帰テストソフト------------------
#include <Stepper.h>
Stepper stepper_x(2048, 0, 2, 1, 3); //X軸モータ設定(1回転2048ステップ)
Stepper stepper_y(2048, 4, 6, 5, 7); //Y軸モータ設定(1回転2048ステップ)
Stepper stepper_z(2048, 8, 10, 9, 11);//Z軸モータ設定(1回転2048ステップ)
long x_cur_pos = 0; //X軸の現在位置(符号付き絶対座標のパルス位置)
long y_cur_pos = 0; //Y軸の現在位置(符号付き絶対座標のパルス位置)
long z_cur_pos = 0; //Z軸の現在位置(符号付き絶対座標のパルス位置)
bool x_stop_flag = false; //X軸停止要求フラグ true: 停止要求
bool y_stop_flag = false; //Y軸停止要求フラグ true: 停止要求
bool z_stop_flag = false; //Z軸停止要求フラグ true: 停止要求
void setup() {
Serial.begin(9600); //USBシリアル通信初期化
pinMode(12, INPUT_PULLUP);//GP12を入力端子に設定(スタートスイッチ接続)
pinMode(13, INPUT_PULLUP);//GP13を入力端子に設定(X軸停止スイッチ接続))
pinMode(14, INPUT_PULLUP);//GP14を入力端子に設定(Y軸停止スイッチ接続)
pinMode(15, INPUT_PULLUP);//GP15を入力端子に設定(Z軸停止スイッチ接続)
pinMode(0, OUTPUT); //ステッピングモータ(青線)
pinMode(1, OUTPUT); //ステッピングモータ(桃線)
pinMode(2, OUTPUT); //ステッピングモータ(黄線)
pinMode(3, OUTPUT); //ステッピングモータ(橙線)
pinMode(4, OUTPUT); //Y軸ステッピングモータ(青線)
pinMode(5, OUTPUT); //Y軸ステッピングモータ(桃線)
pinMode(6, OUTPUT); //Y軸ステッピングモータ(黄線)
pinMode(7, OUTPUT); //Y軸ステッピングモータ(橙線)
pinMode(8, OUTPUT); //Z軸ステッピングモータ(青線)
pinMode(9, OUTPUT); //Z軸ステッピングモータ(桃線)
pinMode(10, OUTPUT); //Z軸ステッピングモータ(黄線)
pinMode(11, OUTPUT); //Z軸ステッピングモータ(橙線)
//ステッピングモータの初期設定
stepper_x.setSpeed(500); //X軸ステッピングモータの回転速度500rpm
stepper_y.setSpeed(500); //Y軸ステッピングモータの回転速度500rpm
stepper_z.setSpeed(500); //Z軸ステッピングモータの回転速度500rpm
//割り込みの設定(PG13に接続されたスイッチがHIGH→LOWになると割り込み発生)
attachInterrupt(digitalPinToInterrupt(13), stopInt_x, FALLING);
//割り込みの設定(PG14に接続されたスイッチがHIGH→LOWになると割り込み発生)
attachInterrupt(digitalPinToInterrupt(14), stopInt_y, FALLING);
//割り込みの設定(PG15に接続されたスイッチがHIGH→LOWになると割り込み発生)
attachInterrupt(digitalPinToInterrupt(15), stopInt_z, FALLING);
}
2.メイン処理 loop()関数と割り込み関数
メインの処理を行うloop()関数と各スイッチが押された時に呼び出される割り込み関数のソースコードを以下に示します。
loop()関数で実際のステッピングモータの動作を行います。
スタートスイッチが押されるとX、Y、Z軸が1ステップづつ繰り返し回転します。
x_stop_flag, y_stop_flag, z_stop_flagはGP13,GP14,GP15に接続されたスイッチが、それぞれ押された時に割り込みプログラムでtrueに設定されるフラグで、それらのフラグを見て、それぞれのモータの駆動を停止して現在位置を0としています。
スイッチによる割り込みが入った時にフラグ類(x_stop_flag, y_stop_flag, z_stop_flag)を操作中に、さらに割り込みが入ることを阻止するためにフラグを書き換える前にnoInterrupts()関数を実施して割り込み禁止にしています。またloop()関数内でこれらのフラグの状態を確認する時もnoInterrupts()関数で割り込みを禁止しています。
void loop() {
while (true){
//スタートスイッチ(GP12)読込(LOW判断)
if (digitalRead(12) == LOW){
noInterrupts();
x_stop_flag = false;
y_stop_flag = false;
z_stop_flag = false;
interrupts();
break;
}
}
while (true){
noInterrupts(); //割り込み禁止
if (x_stop_flag == false){ //X軸停止要求無?
interrupts(); //割り込み許可
stepper_x.step(1); //X軸1ステップ回転
x_cur_pos++; //X現在位置プラス
}else{
interrupts(); //割り込み許可
x_cur_pos = 0;
}
noInterrupts(); //割り込み禁止
if (y_stop_flag == false){ //Y軸停止要求無?
interrupts(); //割り込み許可
stepper_y.step(1); //Y軸1ステップ回転
y_cur_pos++; //Y軸現在位置プラス
}else{
interrupts(); //割り込み許可
y_cur_pos = 0;
}
noInterrupts(); //割り込み禁止
if (z_stop_flag == false){ //Z軸停止要求無?
interrupts(); //割り込み許可
stepper_z.step(1); //Z軸1ステップ回転
z_cur_pos++; //Z軸現在位置プラス
}else{
interrupts(); //割り込み許可
z_cur_pos = 0;
}
delay(10); //次のパルス出力(10msec)待ち
//現在位置をPCへシリアル通信
String text_x = String(x_cur_pos);
String text_y = String(y_cur_pos);
String text_z = String(z_cur_pos);
String text = String("X:" + text_x +",Y:" + text_y + ",Z:" + text_z);
Serial.println(text); //現在位置をPCへ送信
//停止判断処理
noInterrupts(); //割り込み禁止
if ((x_stop_flag == true) && (y_stop_flag == true) && (z_stop_flag == true)){ //停止要求有り?
x_stop_flag = false;
y_stop_flag = false;
z_stop_flag = false;
interrupts(); //割り込み許可
break;
}
interrupts(); //割り込み許可
}
x_cur_pos = 0;
y_cur_pos = 0;
z_cur_pos = 0;
//現在位置をPCへシリアル通信
String text_x = String(x_cur_pos);
String text_y = String(y_cur_pos);
String text_z = String(z_cur_pos);
String text = String("X:" + text_x +",Y:" + text_y + ",Z:" + text_z);
Serial.println(text); //現在位置をPCへ送信
}
//X軸停止スイッチ(GP13)の割り込み関数
void stopInt_x(){
noInterrupts(); //割り込み禁止
x_stop_flag = true; //X軸停止フラグセット
interrupts(); //割り込み許可
}
//Y軸停止スイッチ(GP14)の割り込み関数
void stopInt_y(){
noInterrupts(); //割り込み禁止
y_stop_flag = true; //Y軸停止フラグセット
interrupts(); //割り込み許可
}
//Z軸停止スイッチ(GP15)の割り込み関数
void stopInt_z(){
noInterrupts(); //割り込み禁止
z_stop_flag = true; //Z軸停止フラグセット
interrupts(); //割り込み許可
}
最後に
Raspberry Pi Pico Wを使用して3個のステッピングモータを原点復帰させるプログラムを作りました。ここでは原点センサに相当するスイッチ信号を読み込むのに割り込みを使用してみましたが、原点復帰中のステッピングモータの動作は1ステップづつ送る方式なので、1ステップ送る毎にスイッチの状態を見るようなプログラムでも実現可能だと思います。