リミットツイッチにはまる

ステッピングモーター制御の続きです。
alasixosaka.hatenablog.com
前回はステッピングモーターを単に動かしてみるというところまでやりました。
今回は、CNCシールドにリミットスイッチをとりつけて動作を確認しました。
といってもリミットスイッチがONになったらモーターが止まるというところまでは行きませんでした。
というか、リミットスイッチの動作が謎で色々テストしてようやく何とかつかめたというところまでです。
ja.aliexpress.com
リミットスイッチに付属のケーブルをCNCシールドにつなぎます。つなぐところは、シールドの右上あたり、ENDStopsと書かれているところです。

f:id:alasixOsaka:20201114143041j:plain
右上のEndStopsのところにリミットスイッチを配線する

リミットスイッチからの線は3本ありますが、真ん中の黒い線がGNDのようでこれをCNCシールドの黒色の端子につないで、赤または緑をもう一方の白色の端子につなぐようです。どちらでも結果は同じでした。
X軸、Y軸、Z軸それぞれにプラス(+)とマイナス(-)の2端子がありますが、プラスとマイナスはどちらかがONになったらONになるようです。リミットスイッチなので、どちらかの端に着いたらそこで止まるということなのでしょう。
リミットスイッチのシグナルはArduinoの9番、10番、11番端子につながっているようです。
今回は、X軸で試してみました、なのでArduinoの端子は9番端子になります。シグナルの状態を確認するために簡単なスケッチを書いてシリアルモニターで9番端子の状態を確認しました。

#define PIN_Xlimit 9

void setup() {
  
  pinMode(PIN_Xlimit, INPUT);
  Serial.begin(9600);
}

void loop() {
  
    int x = digitalRead(PIN_Xlimit);
    Serial.println(x);
    delay(100);
    
}

すると、初めは9番端子は”1”で、スイッチを押すと”0”に変わります。問題はここからで、スイッチを離しても”0”のままで元に戻ることがありません。チャタリングを防止するのと、確実に止まるためにラッチ回路が入っているようです。基板を見てもC、R、LEDがあるだけでラッチ回路が入っているように見えないのですが、何度やっても同じ結果でした。
ちなみに、単なるタクトスイッチに繋ぎ変えてみると、また不思議な挙動を示しました。始めは、リミットスイッチと同じで、初めは”1”でスイッチを押すと”0”になり、”0”のまま変わりませんでしたが、何度かやっているうちにスイッチのOn/Offで”1”と”0”が変わるようになりました、しかし、それもしばらくたつとまた元に戻るといったような感じで動作が安定しません。片側をGNDに落としてみたり試してみましたが不安定な動作は解消せず、普通のスイッチではダメで、何らかの回路が必要なのかというのが結論となりました。どうもすっきりしませんが。
そして、テストをしているうちに、もう一つ不可思議な動作を発見しました。
それは、

リセットボタンを押しても端子の状態が元に戻らない

ということです。
これも、何故だかよくわからないのですが、パソコン上で一旦シリアルモニターを閉じて、再度開くと、リセットがかかったのと同じ状態になり、スケッチが初めから走り始めます。始めはこれでテストしていました。
この場合は、再スタートしたときに端子は”1”になってスイッチを押すと”0”に変わります。ところが、基板上のリセットスイッチを押してリスタートをかけても端子の状態は”0”のままで、”1”に戻らないのです。
理由はさっぱりわかりません。シリアルモニターを閉じたり、開いたりすることと、リセットスイッチを押すことに何か違いがあるのか?
もう一つ試してみました、CNCシールド上には、リセットスイッチ以外に、E-STOPという端子があり、回路図ではこれがArduinoのリセット端子と接続されているので、E-STOP端子をGNDに落としてリセットをかけてみました。
結果はリセットスイッチを押したのと同じで、端子の状態は変化がありませんでした。

これでは、リミットスイッチでモーターがストップしたときに端子の状態を元に戻す方法がないので困ったことになります。
ウォッチドッグタイマーを使ってソフト的にリセットをかける方法も試してみましたが結果は同じでした。
最終的には、スケッチを少し修正し、リセットがかかった時に、端子を一旦出力モードにして、ピンに”1”を書き込んで、ピンの状態を元に戻してから、入力モードにしてやることで解決しました。
この方法が正しいのかわかりませんが、とりあえず動作は安定しています。

#define PIN_Xlimit 9

void setup() {
  pinMode(PIN_Xlimit,OUTPUT);
  delay(100);
  digitalWrite(PIN_Xlimit,1);
  delay(100);
  pinMode(PIN_Xlimit, INPUT);
  Serial.begin(9600);
}

void loop() {
  
    int x = digitalRead(PIN_Xlimit);
    Serial.println(x);
    delay(100);
    
}

これはArduinoを破壊する行為

何とか解決したと思って、寝ながらよく考えるとおかしいことに気が付きました。なぜなら、スイッチは片側がArduinoの端子に、もう片側がGNDにつながっているので、端子をOUTPUTにして、状態を”1”にした時に、スイッチを押してしまうと端子が直接GNDとつながってショートしてしまいます。テストのときは端子をINPUTにしてからスイッチを押していたので壊さずに済みました。
単純にArduinoのデジタル端子にスイッチを繋げることを考えたらこんなミスはしなかったと思うのですが、シールドの上の端子で、何らかの回路が載っているものと思い込んでいてやっていはいけないミスを犯してしまいました。

正しくはPULLUPを設定する

Arduinoに使われているAtmega328PのIOピンは内部プルアップという設定があり、今回の場合は内部プルアップを使ってやらないとダメだということです。下の図の左が始めの回路(イメージ)。スイッチがOffの時は端子がオープンになっているため状態が安定せず、”1”になったり”0”になったりする。状態を安定化するためには、端子をプルアップないしプルダウンする必要がある。今回の回路では、スイッチは端子とGNDの間に入る形になるのでプルアップする必要がある。下の図の右のようなイメージ。ただし、基板上の回路にはプルアップ抵抗が無いため、内部プルアップの設定をする。

f:id:alasixOsaka:20201128180741j:plain
Arduinoなどのマイコンの入力端子にスイッチを繋ぐ回路。左のようにすると値が安定しない。プルアップ(又はプルダウン)抵抗が必要

したがって、正しいスケッチは次のようになり、9番端子のモード設定をするときに、INPUT_PULLUPとプルアップを指定してやると内部プルアップになる。

#define PIN_Xlimit 9

void setup() {
  
  pinMode(PIN_Xlimit, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  
    int x = digitalRead(PIN_Xlimit);
    Serial.println(x);
    delay(100);
    
}

これで端子の状態を安定して検出できるようになった。リミットスイッチの基板についていたR.Cはやはりチャタリングを防止するための回路のようだ。

参考にしたサイト
Arduinoの中はどうなっているのか - デジタル入出力について | // もちぶろ