XYテーブル製作シリーズ 第10回
はじめに:現場で欲しくなる4つの機能を追加する
第9回で原点復帰やソフトリミットを実装しました。実際に運用すると、さらに踏み込んだ機能が欲しくなります。「X軸だけ微調整したい」「往復ではなく決まった位置へ移動させたい」「今何mmの位置か一目で知りたい」「×ボタンで閉じたら裏でモーターが変な動きをした」——今回はこれらを解決し、実用的な制御アプリに仕上げます。
この記事で分かること
- X軸だけ/Y軸だけ動かす単軸動作関数とGUIボタン
- 往復ではなく指定距離だけ動いて止まる片道移動(位置決め)と、移動後の
current_pos更新 - ステップ数から現在位置を計算し、
% 50で間引いてリアルタイム表示する - 右上の「×」ボタンを無効化し、GPIO解放を必ず通る安全な終了ボタン
単軸動作の実装
「X軸だけ動かしてセンサー位置を確認する」といった単独操作は運用で頻出します。
def start_x_cycle():
distance = float(entry_X_dist.get())
cycles = int(entry_X_cycle.get())
threading.Thread(
target=run_motor,
args=("X軸", X_STEP, X_DIR, X_EN, X_MS1, X_MS2, X_MS3,
X_RESET, X_SLEEP, distance, cycles),
daemon=True
).start()
# Y軸も同様(引数をY軸用に変更)tk.Button(root, text="X軸サイクル実行", command=start_x_cycle, bg="lightblue")\
.grid(row=10, column=0, pady=5)
tk.Button(root, text="Y軸サイクル実行", command=start_y_cycle, bg="lightblue")\
.grid(row=10, column=1, pady=5)片道移動(位置決め)機能
「往復」ではなく「指定した距離だけ移動して止まる」機能です。ワークのセットや位置決めに欠かせません。第10回で追加した run_motor_oneway() のポイントは、移動後に current_pos を更新することです。
# ============================================
# 片道運動の関数(第10回追加)
# ============================================
def run_motor_oneway(axis_name, STEP, DIR, EN, MS1, MS2, MS3, RESET, SLEEP,
distance_mm):
global stop_flag,current_pos
stop_flag = False
start_pos =current_pos[axis_name]
target_pos = start_pos + distance_mm
# -----------------------------------------------
# ソフトリミットチェック
if axis_name == "X軸":
if not (X_MIN_MM <= target_pos <= X_MAX_MM):
message_queue.put(("error", f"{axis_name}移動範囲外:{target_pos:.2f}mm"))
return
else:
if not (Y_MIN_MM <= target_pos <= Y_MAX_MM):
message_queue.put(("error", f"{axis_name}移動範囲外:{target_pos:.2f}mm"))
return
steps = int(distance_mm * STEPS_PER_MM)
if steps < 1:
return
intervales = get_intervals(steps,ACC_DEC_STEPS,1.5)
gpio_init_axis(STEP,DIR,EN,MS1,MS2,MS3,RESET,SLEEP)
step_count = 0 # ★ 現在位置(ステップ数)
try:
#-----正転のみ-----
if axis_name =="X軸":
GPIO.output(DIR,GPIO.LOW)
else:
GPIO.output(DIR,GPIO.HIGH)
for t in intervales:
if stop_flag:
break
GPIO.output(STEP,GPIO.HIGH)
time.sleep(t)
GPIO.output(STEP,GPIO.LOW)
time.sleep(t)
step_count += 1
if step_count % 50 ==0:
current_mm = step_count / STEPS_PER_MM
message_queue.put(("pos",axis_name,current_mm))
GPIO.output(EN,GPIO.HIGH)
#★片道なので位置を更新
current_pos[axis_name]=target_pos
message_queue.put(("pos",axis_name,current_pos[axis_name]))
message_queue.put(("info",f"{axis_name}片道移動完了"))
finally:
print(f"[{axis_name}]片道終了")
#片道運動の関数===================================tk.Button(root, text="X軸 片道", command=start_x_oneway, bg="lightblue")\
.grid(row=11, column=0, pady=5)
tk.Button(root, text="Y軸 片道", command=start_y_oneway, bg="lightblue")\
.grid(row=11, column=1, pady=5)現在位置のリアルタイム表示
ステッピングモーターは送ったパルス数で移動距離が分かります。ステップを数えて位置を計算し、Queueで表示を更新します。
step_count += 1
if step_count % 50 == 0: # 50ステップごとに送る(間引き)
current_mm = step_count / STEPS_PER_MM
message_queue.put(("pos", axis_name, current_mm))ポイント:すべてのステップでGUIを更新しようとすると通信過多でアプリがフリーズします。% 50(剰余演算)で適度に間引くのがスムーズな表示のコツです。
# GUI側(Queueから受信)
if msg[0] == "pos":
_, axis, pos_mm = msg
if axis == "X軸":
x_pos_var.set(f"x:{pos_mm:.2f}mm")
else:
y_pos_var.set(f"y:{pos_mm:.2f}mm")安全なGUI終了(最重要)
装置制御では、右上の「×」ボタンでいきなり閉じるのは厳禁です。
なぜ「×」ボタンが危険なのか
- GPIOの保持:強制終了されると出力ピンがHIGHのまま固定され、モーターに電流が流れ続けたり異音が出る
- ゾンビスレッド:GUIは消えてもバックグラウンドのスレッドが生き残り、予期せぬ動作を続ける
対策:×ボタンの無効化と終了ボタン
root.protocol("WM_DELETE_WINDOW", disable_close) # ×ボタンを無効化
def quit_program():
global stop_flag
stop_flag = True
GPIO.output(X_EN, GPIO.HIGH)
GPIO.output(Y_EN, GPIO.HIGH)
root.destroy()
btn_quit = tk.Button(root, text="プログラム終了", command=quit_program,
bg="gray", fg="white")
btn_quit.grid(row=7, column=0, columnspan=2, pady=15)これで「モーター停止 → GPIO解放 → GUI終了」という安全な終了ができます。
まとめと次回予告
- 単軸操作で細かな調整が可能に
- 片道移動で正確な位置決めを実現
- リアルタイム表示で動作状況を把握
- 安全終了でハードウェアを保護
次回・第11回(完結編)では、これまでのコードを整理した完成版フルコードと、XYテーブルの完成構成・設計資料(図面・BOM)を公開します。
次に読む記事
🏁 次回はこちら(第11回・完結編) 自作XYテーブルの完成構成と設計資料(図面・BOM・結線図)|完成版Pythonコード配布 完成版コードと機械設計資料。 → 🏠 前回(第9回) XYテーブルGUIに原点復帰・現在位置表示・ソフトリミットを実装|Queueでスレッド安全にGUI更新 今回のベースになったGUI。 → 🗺️ 全体像 自作XYテーブルの全手順ロードマップ|Raspberry Pi+ステッピングモーターで2軸制御 第0回〜第11回の全工程をまとめたロードマップ。 →よくある質問(FAQ)
Q片道移動と往復サイクルはコード上どう違いますか?
A往復(run_motor)は正転ループ→逆転ループを cycles 回繰り返し、開始位置に戻ります。片道(run_motor_oneway)は正転ループのみで、移動後に current_pos[axis] = target_pos と位置を更新します。位置決めでは片道、動作確認では往復を使い分けます。
Q現在位置表示がカクカクします/飛びます。
Astep_count % 50 の 50 を大きくすると更新頻度が下がりカクつき、小さくすると通信過多でフリーズ気味になります。剰余の値と root.after の間隔(100ms程度)をセットで調整します。
Q×ボタンを無効化したらウィンドウが閉じられなくて困ります。
Aそれが狙いです。必ず「プログラム終了」ボタンから quit_program() を通し、stop_flag=True → GPIO.output(EN, HIGH) → root.destroy() の順で安全に終了させます。開発中に手早く閉じたいときだけ一時的に protocol の行をコメントアウトします。
Qプログラム終了後もモーターが少し熱いままです。
Aquit_program で EN を HIGH にすればコイル電流は切れますが、直前まで通電していた熱は残ります。異常な高温でなければ問題ありません。恒常的に熱いならA4988のVref(電流制限)が過大なので下げます。
Qdaemon=True のスレッドと通常スレッドの使い分けは?
A単発の動作(単軸サイクル・片道)は daemon=True にして、プログラム終了時に道連れで終わるようにします。確実に完了させたい処理は daemon を付けず join() で待ちます。緊急停止は stop_flag で協調的にキャンセルします。
XYテーブル製作シリーズ(全12回)
- Raspberry Pi ImagerでのOSインストール手順|microSD書き込みから初期設定まで
- ラズパイでLチカ|PythonとRPi.GPIOでLEDを点灯・点滅させる方法
- ラズパイでステッピングモーターを回す方法|A4988の配線とPython制御・Vref調整
- ステッピングモーターをmm単位で動かす計算式とPython実装|step/mmの求め方
- PythonでX軸・Y軸のステッピングモーターを2軸制御する方法|A4988ドライバー2台
- ステッピングモーターの脱調を防ぐ加減速制御(台形駆動)をPythonで実装する方法
- Raspberry PiでXYテーブルを2軸同時制御|Pythonのthreadingでステッピングモーターを同時に動かす
- Raspberry Pi+PythonでXYテーブルの原点復帰(Homing)を実装|リミットスイッチ・バックオフ処理
- PythonのTkinterでXYテーブルをGUI操作する|移動量入力・XY同時実行・緊急停止ボタン
- PythonのGUIが固まる理由とThreadの使い方|Tkinterでモーター制御中もボタンを効かせる
- XYテーブルGUIに原点復帰・現在位置表示・ソフトリミットを実装|Queueでスレッド安全にGUI更新
- XYテーブル制御GUIに単軸動作・片道移動・安全なプログラム終了を実装(この記事)
- 自作XYテーブルの完成構成と設計資料(図面・BOM・結線図)|完成版Pythonコード配布
補足記事
⚡ 第1.5回・補足 A4988の電流制限(Vref)調整方法|焼損を防ぐ計算式とテスターでの設定手順 モーターを回す前に必ずやる A4988 の電流調整。 → 🔀 番外編 L6470が動かない原因|A4988との違いとSPI通信・デイジーチェーンの罠 高機能ドライバ L6470 を A4988 と同じ感覚で使ってハマった話。 → 🗺️ 全体像 自作XYテーブルの全手順ロードマップ|Raspberry Pi+ステッピングモーターで2軸制御 第0回〜第11回の全工程をまとめたロードマップ。 →Follow me on X
本ブログの中の人「ニンジン🥕」はXやってます。新着記事はいち早くポストでお知らせしているので、見逃したくない方は @ninjin_py_vba をフォローしてみてください🥕
@ninjin_py_vba をフォローシリーズ記事一覧
電子工作・自動化ツールの製作記録をシリーズごとにまとめています。気になるテーマからお読みください。
-
FILE.01 — IoT
Raspberry Pi Pico W × GASラズパイPico W×GASで自作!「LINEで動く温湿度&スマートリモコン」完全ロードマップ
「外出中のペットの室温が心配…」そんな思いからスタートしたIoT自作プロジェクトの総集編。温湿度監視からエアコン遠隔操作まで、仕組みをゼロから作りたい方のための全5回の開発記録です。
シリーズを読む -
FILE.02 — CNC
Arduino × レーザー刻印CNCCNC自作シリーズ
高精度な加工を目指し、本格的な自作CNC製作に挑戦中。現在は基幹パーツであるオリエンタルモーターの納品を待つ「設計・準備編」を公開。ハードとソフトの両面から、理想のマシンを形にする過程をリアルタイムにお届けします。
シリーズを読む -
FILE.03 — XY軸制御
Raspberry Pi × ステッピングモーターXYテーブルシリーズ
Raspberry Piとステッパモーターを使い、ゼロから2軸制御に挑む記録。OS設定から回路設計、多軸制御のPythonコードまで、躓きやすいポイントを徹底図解。電子工作初心者が「動く感動」を味わうための実戦ガイドです。
シリーズを読む -
FILE.04 — 業務自動化
Python × Excel × CustomTkinter【Python開発記】NINJIN Mail制作記
PythonとExcelを連携させ、実務で即戦力となるメール送信ツールを開発。CustomTkinterによるUI構築や、ミスを防ぐテンプレート活用術など、現場の「痒い所に手が届く」自動化ノウハウを細部まで丁寧に解説します。
シリーズを読む -
FILE.05 — 業務自動化
Python × Excel × GUIアプリ化Invoice Maker(請求書・見積書自動作成)
手作業の請求書作成から卒業!PythonでExcelデータを読み込み一括PDF化する「Invoice_Maker」の作り方を全3回で解説。基本ロジックからGUIアプリ化まで、実務で役立つ自動化ノウハウが満載です。
シリーズを読む

コメント