PR

【第8回】【Python × Raspberry Pi】XYテーブルをGUI操作する(Tkinter)(XYテーブル製作シリーズ)

スポンサーリンク
RaspberryPi
スポンサーリンク

はじめに

第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
Python3.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テーブル製作シリーズはこちらから

コメント