はじめに
第7回では、Pythonプログラムから
XYテーブルを自動で動作させました。
しかし実際の装置では
- 移動量を変更したい
- 動作を停止したい
- 手動操作したい
といった操作が必要になります。
そこで今回は GUI操作ソフト を作成します。
今回作る機能
- 移動量入力
- XY同時制御
- 緊急停止
完成するとこのような操作画面になります。
X移動量(mm) [50]
Xサイクル [3]
Y移動量(mm) [30]
Yサイクル [3]
[XY同時実行]
[緊急停止]
Pythonでtkinter使用することで
簡単な装置操作ソフト(アプリケーション)が作れるのが特徴です。
使用環境
ハードウェア構成
| 項目 | 内容 |
|---|---|
| マイコンボード | Raspberry Pi |
| モータードライバ | A4988 |
| モーター | NEMA17 |
| 電源 | 12V 5A |
| 制御 | GPIO |
| Python | 3.x |




GPIO ピン設定
今回のピン配置です。
X軸
X_STEP = 21
X_DIR = 20
X_EN = 16
X_MS1 = 17
X_MS2 = 27
X_MS3 = 22
X_RESET = 5
X_SLEEP = 6
X_LIMIT = 4
Y軸
Y_STEP = 2
Y_DIR = 26
Y_EN = 18
Y_MS1 = 23
Y_MS2 = 24
Y_MS3 = 25
Y_RESET = 12
Y_SLEEP = 13
Y_LIMIT = 14

■ハードウェアを結線する際にあると便利なツール


Tkinterとは
Python標準のGUIライブラリです。
特徴
- 追加インストール不要
- 軽量
- Raspberry Piで使いやすい
インポート分
import tkinter as tk
GUIの基本
Tkinterの基本要素
| 部品 | 用途 |
|---|---|
| Label | 文字表示 |
| Entry | 入力欄 |
| Button | ボタン |
例
root = tk.Tk()tk.
Label(root,text="X移動量").grid(row=0,column=0)
entry = tk.Entry(root)
entry.grid(row=0,column=1)
root.mainloop()
移動量入力
入力欄から値を取得します。
distance = float(entry_x.get())
この値をモーター関数に渡します。
XY同時制御
XとYを同時に動かすには
Thread(スレッド)を使います。
理由「GUIがフリーズしなようにする」です
例
tx = threading.Thread(target=run_motor,args=(...))
ty = threading.Thread(target=run_motor,args=(...))
tx.start()
ty.start()
これでXとYが同時に動きます。
緊急停止
装置制御では必須機能です。
フラグ方式で停止します。
stop_flag = True
モーター側
if stop_flag:
return
さらにA4988の電流をOFFにします。
GPIO.output(X_EN,GPIO.HIGH)
第8回 完成コード
Pythonフルコードを表示する
# ============================================
# 第8回
# XYテーブルGUI操作
# ============================================
import RPi.GPIO as GPIO
import time
import threading
import tkinter as tk
GPIO.setmode(GPIO.BCM)
# ============================================
# GPIO設定
# ============================================
X_STEP = 21
X_DIR = 20
X_EN = 16
X_MS1 = 17
X_MS2 = 27
X_MS3 = 22
X_RESET = 5
X_SLEEP = 6
X_LIMIT = 4
Y_STEP = 2
Y_DIR = 26
Y_EN = 18
Y_MS1 = 23
Y_MS2 = 24
Y_MS3 = 25
Y_RESET = 12
Y_SLEEP = 13
Y_LIMIT = 14
# ============================================
# モーション設定
# ============================================
BELT_PITCH = 2.0
PULLEY_TEETH = 32
MM_PER_REV = BELT_PITCH * PULLEY_TEETH
FULL_STEPS = 200
MICROSTEP = 16
STEPS_PER_REV = FULL_STEPS * MICROSTEP
STEPS_PER_MM = STEPS_PER_REV / MM_PER_REV
ACC_DEC_STEPS = 100
stop_flag = False
# ============================================
# GPIO初期化
# ============================================
def gpio_init_axis(STEP,DIR,EN,MS1,MS2,MS3,RESET,SLEEP):
pins=[STEP,DIR,EN,MS1,MS2,MS3,RESET,SLEEP]
for p in pins:
GPIO.setup(p,GPIO.OUT)
GPIO.output(RESET,GPIO.HIGH)
GPIO.output(SLEEP,GPIO.HIGH)
GPIO.output(MS1,GPIO.HIGH)
GPIO.output(MS2,GPIO.HIGH)
GPIO.output(MS3,GPIO.HIGH)
GPIO.output(EN,GPIO.LOW)
# ============================================
# 加減速
# ============================================
def get_intervals(total_steps,acc_steps,total_time):
const_steps=max(total_steps-acc_steps*2,1)
total_ratio=acc_steps*0.5+const_steps+acc_steps*0.5
base_interval=total_time/total_ratio/2
intervals=[]
for i in range(acc_steps):
intervals.append(base_interval*(acc_steps-i)/acc_steps)
for i in range(const_steps):
intervals.append(base_interval)
for i in range(acc_steps):
intervals.append(base_interval*(i+1)/acc_steps)
return intervals
# ============================================
# モーター制御
# ============================================
def run_motor(axis_name,
STEP,DIR,EN,
MS1,MS2,MS3,
RESET,SLEEP,
distance_mm,
cycles):
global stop_flag
gpio_init_axis(STEP,DIR,EN,MS1,MS2,MS3,RESET,SLEEP)
steps=int(distance_mm*STEPS_PER_MM)
intervals=get_intervals(steps,ACC_DEC_STEPS,1.5)
for c in range(cycles):
if stop_flag:
return
if axis_name=="X軸":
GPIO.output(DIR,GPIO.LOW)
else:
GPIO.output(DIR,GPIO.HIGH)
for t in intervals:
if stop_flag:
return
GPIO.output(STEP,GPIO.HIGH)
time.sleep(t)
GPIO.output(STEP,GPIO.LOW)
time.sleep(t)
GPIO.output(EN,GPIO.HIGH)
# ============================================
# XY同時実行
# ============================================
def start_xy():
x_dist=float(entry_x_dist.get())
x_cycle=int(entry_x_cycle.get())
y_dist=float(entry_y_dist.get())
y_cycle=int(entry_y_cycle.get())
tx=threading.Thread(
target=run_motor,
args=("X軸",
X_STEP,X_DIR,X_EN,
X_MS1,X_MS2,X_MS3,
X_RESET,X_SLEEP,
x_dist,x_cycle)
)
ty=threading.Thread(
target=run_motor,
args=("Y軸",
Y_STEP,Y_DIR,Y_EN,
Y_MS1,Y_MS2,Y_MS3,
Y_RESET,Y_SLEEP,
y_dist,y_cycle)
)
tx.start()
ty.start()
# ============================================
# 緊急停止
# ============================================
def stop_motor():
global stop_flag
stop_flag=True
GPIO.output(X_EN,GPIO.HIGH)
GPIO.output(Y_EN,GPIO.HIGH)
# ============================================
# GUI
# ============================================
root=tk.Tk()
root.title("XY Table Controller")
tk.Label(root,text="X移動量(mm)").grid(row=0,column=0)
entry_x_dist=tk.Entry(root)
entry_x_dist.grid(row=0,column=1)
tk.Label(root,text="Xサイクル").grid(row=1,column=0)
entry_x_cycle=tk.Entry(root)
entry_x_cycle.grid(row=1,column=1)
tk.Label(root,text="Y移動量(mm)").grid(row=2,column=0)
entry_y_dist=tk.Entry(root)
entry_y_dist.grid(row=2,column=1)
tk.Label(root,text="Yサイクル").grid(row=3,column=0)
entry_y_cycle=tk.Entry(root)
entry_y_cycle.grid(row=3,column=1)
tk.Button(root,
text="XY同時実行",
command=start_xy,
bg="lightblue").grid(row=4,column=0,columnspan=2,pady=10)
tk.Button(root,
text="緊急停止",
command=stop_motor,
bg="red",
fg="white").grid(row=5,column=0,columnspan=2,pady=10)
root.mainloop()
この記事で使用したコードはこちらからダウンロードも可能です。
XY_gui.py をダウンロード(ZIP)動作手順
1 Raspberry Piで実行
python xy_gui.py
2 GUI起動

3 移動量入力
4 実行
動作動画
工事中(Youtubeで公開予定)
まとめ
今回作ったもの
- GUI操作
- 移動量入力
- XY同時制御
- 緊急停止
Pythonだけで
装置操作ソフトの基礎が完成しました。
次回予告
次回はさらに装置として完成度を上げます。
追加する機能
- 原点復帰GUI
- 現在位置表示
- ソフトリミット
いよいよ
本格XYテーブルコントローラになります。
過去のXYテーブル製作シリーズはこちらから
- 【第0回】Raspberry PiのOSインストール完全ガイド|初心者向けにゼロから解説
- 【第1回】PythonでLEDを光らせる|GPIOの基本をやさしく解説
- 【第2回】ラズパイ+A4988でステッピングモーターを回す
- 【第3回】ステッピングモーターをmm単位で動かす|ベルト駆動の計算方法まで解説
- 【第1.5回】 A4988のVref調整手順(XYテーブル製作シリーズ)
- 【番外編】L6470が動かない?A4988と同じ感覚で使ってハマった話
- 【第4回】XYテーブル化の第一歩|X軸とY軸を2台動かす
- 【第5回】Pythonでステッピングモーターの加減速制御を実装する
- 【第6回】Pythonでステッピングモーターを2軸同時に動かす
- 【第7回】Raspberry PiでXYテーブル制御|リミットスイッチと原点復帰(Homing)の実装


コメント