Tkinter GUI中机械臂多线程急停功能失效问题排查
问题分析与解决方案
核心问题点
- 线程启动语法错误:
t1.start和t2.start缺少括号,线程实际未启动;且初始化时就调用run_thread,导致未点击Run按钮就执行移动逻辑。 - 急停逻辑错误:
e_stop里用keyboard.is_pressed("a")检测键盘按键而非响应按钮点击,按钮点击仅打印信息,未执行实际急停操作;且错误地重新配置按钮command,导致后续点击失效。 - 移动循环未检查停止标志:
move_kin里的循环未判断stop_flag,即使触发急停,仍会继续执行坐标移动。 - GUI阻塞问题:直接调用
move_kin会阻塞Tkinter主线程,导致界面无响应。
修正后的代码
import tkinter as tk from tkinter import ttk from tkinter import messagebox from Reach_Kinematics import Kinematics import threading class Reach_Sim_GUI_Class: def __init__(self, Reach_Kinematics: Kinematics): self.comport = "COM6" self.flag = False self.coordinates = [] self.kin = Reach_Kinematics # 初始化停止标志 self.kin.stop_flag = False self.root = tk.Tk() self.root.title("Reach Simulation GUI") self.root.geometry("400x400") self.setup_gui() self.root.mainloop() def setup_gui(self): # 创建坐标输入标签 x_label = ttk.Label(self.root, text="X (米):") y_label = ttk.Label(self.root, text="Y (米):") z_label = ttk.Label(self.root, text="Z (米):") # 创建输入框 self.x_entry = ttk.Entry(self.root) self.y_entry = ttk.Entry(self.root) self.z_entry = ttk.Entry(self.root) # 添加坐标按钮 add_button = ttk.Button(self.root, text="添加坐标", command=self.add_coordinate) # 坐标列表标签 coordinates_label = ttk.Label(self.root, text="已添加坐标:") # 坐标列表框 self.coordinates_listbox = tk.Listbox(self.root) # 归位按钮 self.home_button = ttk.Button(self.root, text="归位", command=self.home) # 运行按钮 self.run_button = ttk.Button(self.root, text="运行", command=self.start_move_thread) # 急停按钮 self.stop_button= ttk.Button(self.root, text="急停", command=self.e_stop) # 布局控件 x_label.pack() self.x_entry.pack() y_label.pack() self.y_entry.pack() z_label.pack() self.z_entry.pack() add_button.pack() coordinates_label.pack() self.coordinates_listbox.pack() self.home_button.pack() self.run_button.pack() self.stop_button.pack() def add_coordinate(self): x = self.x_entry.get() y = self.y_entry.get() z = self.z_entry.get() try: self.coordinates.append([float(x), float(y), float(z)]) self.coordinates_listbox.insert(tk.END, f"({x}, {y}, {z})") self.x_entry.delete(0, tk.END) self.y_entry.delete(0, tk.END) self.z_entry.delete(0, tk.END) except ValueError: messagebox.showinfo("无效坐标!", "请重新输入数字类型的坐标") self.x_entry.delete(0, tk.END) self.y_entry.delete(0, tk.END) self.z_entry.delete(0, tk.END) def home(self): # 归位前重置停止标志 self.kin.stop_flag = False self.kin.move_arm_to_pos([0.0, 0.0, 0.0, 1.5207, 0.0]) def move_kin(self): # 重置停止标志 self.kin.stop_flag = False for coord in self.coordinates: # 每次循环前检查停止标志 if self.kin.stop_flag: print("移动已被急停") break coord = [coord] self.kin.CalculateandMove(coord) def start_move_thread(self): # 点击运行按钮时启动移动线程,避免阻塞GUI if not self.coordinates: messagebox.showinfo("提示", "请先添加坐标") return t1 = threading.Thread(target=self.move_kin) t1.daemon = True # 设置为守护线程,关闭GUI时自动退出 t1.start() def e_stop(self): print("执行急停") # 触发停止标志,执行急停指令 self.kin.stop_flag = True self.kin.stop_arm_movement() self.kin.send_disable_comms() def delete_coordinates(self): self.coordinates_listbox.delete(0, tk.END) self.coordinates = [] messagebox.showinfo("完成", "坐标已清空") self.flag = False
关键修正说明
- 线程启动逻辑调整:移除初始化时的
run_thread调用,改为点击Run按钮时启动移动线程start_move_thread,避免提前执行移动逻辑,同时用守护线程保证GUI关闭时线程自动退出。 - 急停逻辑修复:移除
keyboard.is_pressed检测,按钮点击直接触发急停动作,设置stop_flag并调用机械臂停止指令,不再重新配置按钮command。 - 移动循环添加停止检查:
move_kin的循环中每次执行前检查stop_flag,触发急停时立即终止循环。 - 修复线程启动语法:线程启动使用
t1.start()(带括号),确保线程实际运行。 - 增加用户提示:添加坐标为空时的运行提示,提升交互体验。
内容的提问来源于stack exchange,提问作者Minh Le
相关产品推荐
相关产品推荐

