はじめに
こんにちは。にんじんです🥕
それでは、自作CNC製作記 第2回をはじめます。
なぜ「動く」だけではダメなのか?
前回はArduinoを使って、まずはXYテーブルのステッピングモーターを回転させるところまで進めました。しかし、このままではまだCNCマシンとしては機能が不足しています。機械自身が「自分の現在地」を正確に認識できていないためです。
今回のゴール
・リミットスイッチを使い、原点(0, 0)を確定させる。
リミットスイッチを使用してマシンの「原点(0, 0)」を確定させることを目標にします。これにより、毎回同じ位置から正確に加工を開始できる、実用的なツールへと進化させていきます。
CNCマシンにおけるリミットスイッチの必要性と位置の再現性
CNC(コンピュータ数値制御)の運用において、最も重要となるのが「位置の再現性」です。手動での位置合わせや、基準があいまいな状態では以下のような問題が発生します。
- 寸法のズレ: 穴あけや刻印の位置がわずかにズレるだけで、組み立てパーツとしての実用性が失われてしまいます。
- 誤差の蓄積: モーターの「脱調(ステップ抜け)」や、電源を投入したタイミングのわずかな差異により、位置は少しずつずれていきます。
- 基準の不在: 電源を入れた場所が自動的に「0」座標になってしまうと、起動するたびに手動で正確な位置合わせを行う必要が生じます。
これらの課題を解決するために、リミットスイッチを取り付けます。物理的なスイッチに軸を接触させることで、「ここが本当の0地点である」という明確な基準(機械原点)を作ることができます。
原点出し(ホーミング)の仕組み:なぜリミットスイッチに2回当てるのか
リミットスイッチに接触して軸を停止させ、原点を確定させる一連の動作を、専門用語で「ホーミング(Homing)」と呼びます。このホーミング動作は、単純にスイッチに1回ぶつけて終わりではなく、以下のようなステップを踏んで行われます。
動作のステップ
- 高速アプローチ: 対象の軸をスイッチ方向へ向けて高速で移動させます。
- 接触と停止: スイッチに当たった瞬間に動作を停止します。
- プルオフ(退避): 少しだけ反対方向に軸を引き返させ、スイッチをOFFの状態に戻します。
- 再接触: 1回目よりも非常に遅い速度(低速)で、再度ゆっくりとスイッチに触れます。
💡 なぜ2回も当てるのか?
ここで「なぜ2回もスイッチに当てるのか」という疑問が生じるかと思います。
1回目の高速移動では、機械の慣性(惰性)によって停止する位置にわずかなバラつきが生じてしまいます。そこで、2回目に超低速で優しく触れ直すことにより、機械的な慣性の影響を排除し、高い精度で原点座標を特定できるようにしています。
ハードウェアの準備:マイクロスイッチの選定とプルアップ配線
今回追加するパーツはシンプルです。
用意するもの
配線方法
配線は「プルアップ」という方式を使います。

💡 なぜ「プルアップ」なのか?
配線が浮いている状態(どこにも繋がっていない状態)だと、ノイズを拾って勝手にスイッチが押されたと誤検認することがあります。プログラム側で「常にHIGH(電圧あり)」にしておき、スイッチが押されたときだけ「LOW(0V)」に落とすことで、ノイズに強い確実な検出が可能になります。
テストコードによる動作確認とArduino Unoへの書き込み手順
結線が完了しましたら、テスト用のプログラム(スケッチ)を書き込んで実際の動作を確認します。検証用のテストコード(test_code_XY_switch.ino)は、以下のリンクよりZIP形式でダウンロード可能です。
クリックしてテストコードを表示する
// テストコード test_code_XY_SWITCH.ino
#define X_STEP 2
#define X_DIR 5
#define Y_STEP 3
#define Y_DIR 6
#define ENABLE 8
#define X_LIMIT 9
#define Y_LIMIT 10
// ===== 調整パラメータ =====
#define BACKOFF_STEPS 250
#define HOMING_FAST 800
#define HOMING_SLOW 2000
// ===== ホーミング方向 =====
#define X_HOME_DIR HIGH // ← Xだけ逆にした
#define Y_HOME_DIR LOW // Yはそのまま
bool stopFlag = false;
void setup() {
pinMode(X_STEP, OUTPUT);
pinMode(X_DIR, OUTPUT);
pinMode(Y_STEP, OUTPUT);
pinMode(Y_DIR, OUTPUT);
pinMode(ENABLE, OUTPUT);
pinMode(X_LIMIT, INPUT_PULLUP);
pinMode(Y_LIMIT, INPUT_PULLUP);
digitalWrite(ENABLE, LOW);
Serial.begin(115200);
Serial.println("Press 's' to STOP, 'g' to HOME");
}
// ===== 入力チェック =====
void checkInput() {
if (Serial.available()) {
char c = Serial.read();
if (c == 's' || c == 'S') stopFlag = true;
if (c == 'g' || c == 'G') homeXY();
}
}
// ===== 停止処理 =====
void stopAll() {
Serial.println("STOPPED");
digitalWrite(ENABLE, HIGH);
while (1);
}
// ===== 1軸ホーミング =====
void homeAxis(int stepPin, int dirPin, int limitPin, bool homeDir) {
// ① 高速で当たる
digitalWrite(dirPin, homeDir);
while (digitalRead(limitPin) == LOW) {
checkInput();
if (stopFlag) stopAll();
digitalWrite(stepPin, HIGH);
delayMicroseconds(HOMING_FAST);
digitalWrite(stepPin, LOW);
delayMicroseconds(HOMING_FAST);
}
delay(100);
// ② BACKOFF(逆方向)
digitalWrite(dirPin, !homeDir);
for (int i = 0; i < BACKOFF_STEPS; i++) {
digitalWrite(stepPin, HIGH);
delayMicroseconds(HOMING_FAST);
digitalWrite(stepPin, LOW);
delayMicroseconds(HOMING_FAST);
}
delay(200);
// ③ ゆっくり再接触
digitalWrite(dirPin, homeDir);
while (digitalRead(limitPin) == LOW) {
checkInput();
if (stopFlag) stopAll();
digitalWrite(stepPin, HIGH);
delayMicroseconds(HOMING_SLOW);
digitalWrite(stepPin, LOW);
delayMicroseconds(HOMING_SLOW);
}
delay(100);
}
// ===== XYホーミング =====
void homeXY() {
Serial.println("HOMING START");
homeAxis(X_STEP, X_DIR, X_LIMIT, X_HOME_DIR);
homeAxis(Y_STEP, Y_DIR, Y_LIMIT, Y_HOME_DIR);
Serial.println("HOMING DONE");
}
// ===== モーター動作 =====
void moveMotor(int stepPin, int dirPin, bool dir, int steps) {
digitalWrite(dirPin, dir);
for (int i = 0; i < steps; i++) {
checkInput();
if (stopFlag) stopAll();
digitalWrite(stepPin, HIGH);
delayMicroseconds(1000);
digitalWrite(stepPin, LOW);
delayMicroseconds(1000);
}
}
void loop() {
checkInput();
stopFlag = false;
// ===== X軸 =====
moveMotor(X_STEP, X_DIR, LOW, 300);
delay(500);
moveMotor(X_STEP, X_DIR, HIGH, 300);
delay(1000);
// ===== Y軸 =====
moveMotor(Y_STEP, Y_DIR, HIGH, 300);
delay(500);
moveMotor(Y_STEP, Y_DIR, LOW, 300);
delay(2000);
}
👇リンクよりダウンロードできます。
test_code_XY_switch.ino をダウンロード(ZIP)
- Arduino IDEを開く
- 上部のプルダウンよりArduinoが接続されているポートを選択します。
- デフォルトで入力されているコードを削除する。
- テストコードを張り付ける
- 画面左上の→矢印をクリックし、Arduino Uno R3に書き込まれます。
- 自動でX軸Y軸の動作が実行されます。
※アプリ画面右上の「シリアルモニタ」のボタンをクリックし、シリアルモニタを開く
・キーボードの「S」を入力しEnterで動作がストップされます
・キーボードの「g」を入力しEnterで原点復帰が開始されます。
動作動画
ホーミング実装時におけるよくあるトラブルとノイズ対策
実際にシステムを動かしてみると、想定通りに動作しないケースがあります。代表的なトラブルとその原因、および対策をまとめました。
| トラブル内容 | 原因と対策 |
| チャタリング | スイッチの接点が細かくバタつく現象。ソフト側で「数ミリ秒待つ」か、コンデンサを入れて電気的に平滑化します。 |
| ノイズで勝手に止まる | モーターの配線からノイズを拾っている可能性。配線をツイストするか、シールド線を使うのが効果的です。 |
| 位置が毎回数ミリズレる | スイッチの固定が甘い(剛性不足)かもしれません。ネジの緩みや、ステーのたわみをチェックしましょう。 |
まとめと次回予告:制御ソフト「GRBL」の導入と「CNCjs」の設定へ
リミットスイッチが正常に機能するようになれば、XYテーブルは自身の初期位置を正確に把握できるようになります。これで工作機械としてのハードウェアの土台が整いました。
現在の開発進捗は以下の通りです。
- [x] モーターの回転動作
- [x] 機械原点の確定(←今回はここまで完了)
次回の記事では、このハードウェア環境をPCの画面から自在にコントロールできるようにするため、専用ファームウェアである「GRBL」の導入手順と、操作画面となる「CNCjs」の初期設定について詳しく解説していきます。本格的な工作機械の完成に向けて進めていきましょう。
いよいよ「本格的な工作機械」になっていきますよ!
CNC自作シリーズ
【CNC自作①】Arduino+GRBLでXYテーブルをCNC化してみた
【CNC自作②】リミットスイッチ実装|原点出し(ホーミング)で精度を出す
【CNC自作③】GRBL+CNCjsでPC制御に挑戦!動いたけれど見えてきた「精度の壁」
【CNC自作 ④】ついに届いた本命モーター!精度ブレの解決とGコード初テスト
【CNC自作】2軸同期走行テスト成功!…と思いきや、中華製基板の「致命的な罠」にハマる(第5回)
【CNC自作】ホーミング失敗(ALARM:8)の原因はこれ!4ステップ動作とZ軸未連動での突破方法(第6回)
【CNC自作】本番アルミ筐体完成!CNCjs(GRBL)でのテストと「Check Door」エラーの意外すぎる罠(第7回)
自作CNC 1064nm赤外線レーザーで金属刻印!GRBL設定変更とLightBurn素材テスト(第8回)








コメント