You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键修正说明

  1. 线程启动逻辑调整:移除初始化时的run_thread调用,改为点击Run按钮时启动移动线程start_move_thread,避免提前执行移动逻辑,同时用守护线程保证GUI关闭时线程自动退出。
  2. 急停逻辑修复:移除keyboard.is_pressed检测,按钮点击直接触发急停动作,设置stop_flag并调用机械臂停止指令,不再重新配置按钮command。
  3. 移动循环添加停止检查:move_kin的循环中每次执行前检查stop_flag,触发急停时立即终止循环。
  4. 修复线程启动语法:线程启动使用t1.start()(带括号),确保线程实际运行。
  5. 增加用户提示:添加坐标为空时的运行提示,提升交互体验。

内容的提问来源于stack exchange,提问作者Minh Le

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:30:23