当前位置: 首页 > news >正文

Vision + Robot New Style

简洁风

code

#11:06:57Current_POS_is: X:77Y:471Z:0U:-2   C:\Log\V55.txt
import time
import tkinter as tk  
from tkinter import messagebox  
from PIL import Image, ImageTk  
import socket  
import threading  
from datetime import datetime  
import logging  
import subprocess  # 确保导入 subprocess 库  
import os
import pyautogui
from HslCommunication import MelsecMcNet
import json  
import random
import math
import matplotlib
matplotlib.use('TkAgg')  # 设置matplotlib后端
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
#from sklearn.linear_model import LinearRegression# 修正后的全局变量声明
Response = 0
Offset_X = 0
Offset_Y = 0
Offset_U = 0
Ares_Sensor=None#定义文件夹路径
folder_path = r'c:\Log'  #C:\v5\Public_Release# 检查文件夹是否存在,如果不存在则创建
if not os.path.exists(folder_path):os.makedirs(folder_path)# 设置日志配置  
#logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')  
# 新增格式化器,精确到毫秒
formatter = logging.Formatter(fmt='%(asctime)s,%(msecs)03d - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S'
)# 设置基础日志配置
logging.basicConfig(level=logging.INFO,format='%(asctime)s,%(msecs)03d - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S'
)# 如果已有其他处理器(如 StreamHandler),也应设置相同格式
class TextHandler(logging.Handler):def __init__(self, widget):super().__init__()self.widget = widgetself.formatter = logging.Formatter(fmt='%(asctime)s,%(msecs)03d - %(levelname)s - %(message)s',datefmt='%Y-%m-%d %H:%M:%S')def emit(self, record):# 检查 widget 是否存在且未被销毁if self.widget and self.widget.winfo_exists():msg = self.formatter.format(record)self.widget.insert(tk.END, msg + '\n')self.widget.yview_moveto(1)class MyClass(tk.Frame):def __init__(self, root, parent):super().__init__(parent)  # 初始化父类self.root = rootself.parent = parentclass TCPClientApp:def __init__(self, root, parent=None):  self.root = root  self.vision_client_socket = None  self.robot_client_socket = None  self.connected_to_vision = False  self.connected_to_robot = False  self.vision_ip = "127.0.0.1"  self.vision_port = 8888  self.robot_ip = "192.168.0.1"    #192.168.0.1self.robot_port = 2009           #2004self.is_engineering_mode = True  # 新增模式标志# 新增 CONFIG_PATH 定义self.CONFIG_PATH = r'C:\Log\config.json'  # 配置文件路径# 确保 INDUSTRIAL_COLORS 初始化在 setup_ui 调用之前self.INDUSTRIAL_COLORS = {'bg_main': '#404040',  # 主背景色'fg_main': '#FFFFFF',  # 主前景色'accent': '#FFA500',   # 强调色}self.setup_ui()  self.setup_logging()  self.app3_process = None  # 用于存储子进程的引用self.parent = parent or root  # 自动降级处理self.plc = Noneself.last_y79_state = False  # 新增状态缓存self.last_X2F_state = True  # 新增状态缓存self.setup_plc()self.start_plc_monitoring()self.init_plc_connection()  # PLC运行self.run_button = Noneself.image_label = Noneself.images = []self.image_index = 0  # 确保在类初始化时设置默认值###开启程序后自动启动项目self.connect_to_vision()self.connect_to_robot()###开启程序后自动加载offsetself.load_settings()# 修改窗口关闭事件处理self.root.protocol("WM_DELETE_WINDOW", self.on_exit)# 数据存储  Chartself.history_data = {'X': [],'Y': [],'U': [],'timestamps': []}# 启动定时更新self.update_interval = 888  # 3.888秒self.root.after(self.update_interval, self.update_display)self.update_history_chart()self.home_received = False  # 新增状态变量def update_image(self):# 检查图片列表是否存在且非空if not hasattr(self, 'images') or not self.images:logging.warning("No Pictures")self.root.after(333, self.update_image)  # 使用 after 安排下一次更新return# 检查 image_label 是否初始化if not hasattr(self, 'image_label') or self.image_label is None:logging.error("Picture Ini...")# 使用保存的 right_frame 重新初始化if hasattr(self, 'right_frame'):self.create_right_panel(self.right_frame)else:logging.error("无法找到 right_frame,无法重新初始化 image_label")self.root.after(333, self.update_image)  # 避免直接递归调用returntry:img = self.images[self.image_index]self.image_label.config(image=img)self.image_label.image = imglogging.debug(f"成功更新图片索引 {self.image_index}")except Exception as e:logging.error(f"更新图片失败: {str(e)}")self.root.after(1000, self.update_image)  # 避免直接递归调用return# 更新索引并触发下一次更新self.image_index = (self.image_index + 1) % len(self.images)self.root.after(1000, self.update_image)  # 使用 after 安排下一次更新def toggle_mode(self):self.is_engineering_mode = not self.is_engineering_modeif self.is_engineering_mode:self.mode_button.config(text="切换到运转模式")self.show_engineering_mode()else:self.mode_button.config(text="切换到工程模式")self.show_operation_mode()def start_run(self):# 运行按钮点击事件处理passdef _update_gauge(self, gauge, value):"""单个仪表更新逻辑"""# 更新数值显示gauge['label'].config(text=f"{value:.2f}")# 更新指针角度(-60°到240°范围)angle = 150 * (value / 100) - 60  # 假设值范围-100到100canvas = gauge['canvas']canvas.delete('needle')x = 60 + 40 * math.cos(math.radians(angle))y = 40 - 40 * math.sin(math.radians(angle))canvas.create_line(60, 40, x, y, fill='red', width=2, tags='needle')def update_history_chart(self):"""更新历史趋势图"""if not self.history_data['timestamps']: return # 限制显示8个数据点 keep_points = 8 x_data = self.history_data['timestamps'][-keep_points:] self.line_x.set_data(x_data,  self.history_data['X'][-keep_points:]) self.line_y.set_data(x_data,  self.history_data['Y'][-keep_points:]) self.line_u.set_data(x_data,  self.history_data['U'][-keep_points:]) # 自动调整坐标轴 self.ax.relim() self.ax.autoscale_view() # 显示最新值 - 工业风格 if self.history_data['X']: latest_x = self.history_data['X'][-1] latest_y = self.history_data['Y'][-1] latest_u = self.history_data['U'][-1]  # 清除之前的文本 for text in self.ax.texts: text.remove() # 添加新的值显示 - 工业风格 self.ax.text(0.02,  0.95, f"Last: X={latest_x:.3f}  Y={latest_y:.3f}  U={latest_u:.5f}",transform=self.ax.transAxes, fontsize=12,  # 工业标准字号 color='#FFA500',  # 工业橙色 bbox=dict(facecolor='#404040', alpha=0.69, edgecolor='#333333'))  # 工业灰色背景 # 显示在上还是曲线在上self.chart_canvas.draw() #def toggle_mode(self):self.is_engineering_mode = not self.is_engineering_modeif self.is_engineering_mode:self.mode_button.config(text="切换到运转模式")self.show_engineering_mode()else:self.mode_button.config(text="切换到工程模式")self.show_operation_mode()def start_run(self):# 运行按钮点击事件处理passdef update_display(self):"""定时更新显示"""try:# 更新仪表盘 self.update_gauges() # 更新趋势图 self.update_history_chart()# 确保图表窗口仍然存在if hasattr(self, 'chart_window') and self.chart_window.winfo_exists():# 获取当前数据点限制keep_points = getattr(self, 'point_limit', 8)# 限制显示的数据点数量x_data = self.history_data['timestamps'][-keep_points:] # 更新X轴数据self.line_x.set_data(x_data, self.history_data['X'][-keep_points:]) # 更新Y轴数据self.line_y.set_data(x_data, self.history_data['Y'][-keep_points:]) # 更新U轴数据self.line_u.set_data(x_data, self.history_data['U'][-keep_points:]) # 自动调整坐标轴ax = self.line_x.axesax.relim()ax.autoscale_view()# 更新动态标题 - 工业风格if self.history_data['X']:latest_x = self.history_data['X'][-1]latest_y = self.history_data['Y'][-1]latest_u = self.history_data['U'][-1]# 清除之前的文本for text in ax.texts:text.remove()# 添加新的值显示 - 工业风格ax.text(0.02, 0.95, f"Last: X={latest_x:.3f}  Y={latest_y:.3f}  U={latest_u:.5f}",transform=ax.transAxes, fontsize=12,color='#FFA500',bbox=dict(facecolor='#404040', alpha=0.69, edgecolor='#333333'))# 重新绘制图表ax.figure.canvas.draw()finally:# 确保图表窗口仍然存在时才继续定时器if hasattr(self, 'chart_window') and self.chart_window.winfo_exists():self.root.after(1000, self.update_display)def update_static_chart(self):"""更新静态图表显示"""try:# 获取数据点限制keep_points = 5  # 固定显示最后5个数据点# 如果没有历史数据,直接返回if not self.history_data or not self.history_data['timestamps']:return# 限制显示的数据点数量x_data = self.history_data['timestamps'][-keep_points:] # 更新X轴数据self.line_x.set_data(x_data, self.history_data['X'][-keep_points:]) # 更新Y轴数据self.line_y.set_data(x_data, self.history_data['Y'][-keep_points:]) # 更新U轴数据self.line_u.set_data(x_data, self.history_data['U'][-keep_points:]) # 自动调整坐标轴ax = self.line_x.axesax.relim()ax.autoscale_view()# 更新动态标题 - 工业风格if self.history_data['X']:latest_x = self.history_data['X'][-1]latest_y = self.history_data['Y'][-1]latest_u = self.history_data['U'][-1]# 清除之前的文本for text in ax.texts:text.remove()# 添加新的值显示 - 工业风格ax.text(0.02, 0.95, f"Last: X={latest_x:.3f}  Y={latest_y:.3f}  U={latest_u:.5f}",transform=ax.transAxes, fontsize=12,color='#FFA500',bbox=dict(facecolor='#404040', alpha=0.69, edgecolor='#333333'))# 重新绘制图表ax.figure.canvas.draw()finally:# 静态数据只需更新一次,不需要定时器pass# 确保仪表盘也更新self.update_gauges()def _update_gauge(self, gauge, value):"""单个仪表更新逻辑"""# 更新数值显示gauge['label'].config(text=f"{value:.2f}")# 更新指针角度(-60°到240°范围)angle = 150 * (value / 100) - 60  # 假设值范围-100到100canvas = gauge['canvas']canvas.delete('needle')x = 60 + 40 * math.cos(math.radians(angle))y = 40 - 40 * math.sin(math.radians(angle))canvas.create_line(60, 40, x, y, fill='red', width=2, tags='needle')def update_history_chart(self):"""更新历史趋势图"""if not self.history_data['timestamps']: return # 限制显示8个数据点 keep_points = 8 x_data = self.history_data['timestamps'][-keep_points:] self.line_x.set_data(x_data,  self.history_data['X'][-keep_points:]) self.line_y.set_data(x_data,  self.history_data['Y'][-keep_points:]) self.line_u.set_data(x_data,  self.history_data['U'][-keep_points:]) # 自动调整坐标轴 self.ax.relim() self.ax.autoscale_view() # 显示最新值 - 工业风格 if self.history_data['X']: latest_x = self.history_data['X'][-1] latest_y = self.history_data['Y'][-1] latest_u = self.history_data['U'][-1]  # 清除之前的文本 for text in self.ax.texts: text.remove() # 添加新的值显示 - 工业风格 self.ax.text(0.02,  0.95, f"Last: X={latest_x:.3f}  Y={latest_y:.3f}  U={latest_u:.5f}",transform=self.ax.transAxes, fontsize=12,  # 工业标准字号 color='#FFA500',  # 工业橙色 bbox=dict(facecolor='#404040', alpha=0.69, edgecolor='#333333'))  # 工业灰色背景 # 显示在上还是曲线在上self.chart_canvas.draw() def setup_ui(self):  # 主窗口背景色self.root.configure(bg=self.INDUSTRIAL_COLORS['bg_main'])self.root.title("Design by Tim")  self.root.geometry("1924x968")   #Display  Pix_1024 768 Windows# Grid weights for resizing behavior  self.root.grid_columnconfigure(0, weight=1)  self.root.grid_columnconfigure(1, weight=2)  self.root.grid_columnconfigure(2, weight=1)  self.root.grid_rowconfigure(0, weight=1)  self.root.grid_rowconfigure(1, weight=1)  # Left Frame  left_frame = tk.Frame(self.root)  left_frame.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")  self.create_left_panel(left_frame)  # Right Frame  right_frame = tk.Frame(self.root)  right_frame.grid(row=0, column=2, padx=5, pady=5, sticky="nsew")  self.create_right_panel(right_frame)  # Bottom Frame  bottom_frame = tk.Frame(self.root, bg='lightgray')  bottom_frame.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")  self.create_bottom_panel(bottom_frame)  ##def load_images(self):path = r'C:\Log\Picture'# 新增:检查目录是否存在并记录日志if not os.path.exists(path):logging.error(f"图片文件夹路径不存在: {path}")self.root.after(3000, self.load_images)  # 3秒后重试(替换递归)returnif not os.path.isdir(path):logging.error(f"指定路径不是有效的文件夹: {path}")self.root.after(3000, self.load_images)  # 3秒后重试(替换递归)return# 新增:记录目录下所有文件(排查文件名问题)dir_files = os.listdir(path)logging.debug(f"目录 {path} 下的文件列表: {dir_files}")extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif']self.images = []  # 清空旧数据for ext in extensions:for file in dir_files:  # 使用已获取的文件列表(避免重复调用os.listdir)if file.lower().endswith(ext):img_path = os.path.join(path, file)try:# 新增:记录具体加载的文件logging.info(f"Retry 2 Loading: {img_path}")img = Image.open(img_path)img.thumbnail((456, 456))  # 缩略图适配显示self.images.append(ImageTk.PhotoImage(img))logging.debug(f"Loading : {img_path}")except Exception as e:# 新增:记录具体错误(如文件被占用、格式损坏)logging.error(f"Loading {file}: {str(e)} NG ")# 新增:记录最终加载结果if not self.images:logging.warning(f"未找到有效图片文件(共扫描 {len(dir_files)} 个文件),3秒后重新加载...")self.root.after(3000, self.load_images)  # 用after代替递归,避免栈溢出else:logging.info(f"Loading {len(self.images)} Pictures")##def create_chart_area(self, parent=None):"""显示为独立弹窗的工业级数据显示面板"""# 创建新窗口chart_window = tk.Toplevel(self.root)chart_window.title("Chart")# 设置窗口大小和位置(居中显示)window_width = 1000window_height = 600screen_width = chart_window.winfo_screenwidth()screen_height = chart_window.winfo_screenheight()x = (screen_width - window_width) // 2y = (screen_height - window_height) // 2chart_window.geometry(f'{window_width}x{window_height}+{x}+{y}')# 使用与show_animation相同的框架结构fig = Figure(figsize=(8, 4), dpi=60)ax = fig.add_subplot(111)# 初始化三条曲线 - 使用工业颜色self.line_x, = ax.plot([], [], color='#FF0000', linewidth=2, label='X_Pos')  # 红色self.line_y, = ax.plot([], [], color='#00FF00', linewidth=2, label='Y_Pos')  # 绿色self.line_u, = ax.plot([], [], color='#00B0F0', linewidth=2, label='U_Pos')  # 科技蓝# 配置坐标轴和图例 - 工业风格ax.set_title("Real", fontsize=14, color='#FFFFFF', pad=20)ax.set_xlabel("Time", fontsize=12, color='#CCCCCC')ax.set_ylabel("Value(mm)", fontsize=12, color='#CCCCCC')ax.grid(True, color='#555555', linestyle='--', alpha=0.7)ax.legend(loc='upper right', fontsize=10)# 设置背景色ax.set_facecolor('#333333')fig.patch.set_facecolor('#404040')# 设置刻度颜色ax.tick_params(axis='x', colors='#CCCCCC')ax.tick_params(axis='y', colors='#CCCCCC')# 嵌入到Tkintercanvas = FigureCanvasTkAgg(fig, master=chart_window)canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)# 创建仪表盘框架gauge_frame = tk.Frame(chart_window, bg='#404040')gauge_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10)# X值仪表self.x_gauge = self.create_gauge(gauge_frame, "X Axis")# Y值仪表self.y_gauge = self.create_gauge(gauge_frame, "Y Axis") # U值仪表self.u_gauge = self.create_gauge(gauge_frame, "U Axis")# 创建控制面板control_frame = tk.Frame(chart_window)control_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=5)# 添加重置按钮reset_button = tk.Button(control_frame, text="Reset Data", command=self.reset_chart_data, width=10)reset_button.pack(side=tk.LEFT, padx=5)# 添加数据点数量设置point_frame = tk.Frame(control_frame)point_frame.pack(side=tk.LEFT, padx=5)tk.Label(point_frame, text="Data Points:").pack(side=tk.LEFT)self.point_entry = tk.Entry(point_frame, width=5)self.point_entry.pack(side=tk.LEFT)self.point_entry.insert(0, "5")  # 默认显示5个数据点apply_point_button = tk.Button(point_frame, text="Apply", command=lambda: self.apply_point_limit_change(), width=5)apply_point_button.pack(side=tk.LEFT, padx=2)# 添加关闭按钮close_button = tk.Button(control_frame, text="Close", command=chart_window.destroy, width=10)close_button.pack(side=tk.RIGHT, padx=5)# 初始化历史数据存储self.history_data = {'X': [],'Y': [],'U': [],'timestamps': []}# 读取文件中的最后5条记录file_path = r'C:\Log\log_His.txt'trajectory_data = self.read_last_n_records(file_path, 5)# 如果读取到数据,更新历史数据if trajectory_data:# 计算时间戳(假设每条记录间隔固定为1秒)now = time.time()timestamps = [now + i for i in range(len(trajectory_data))]# 更新历史数据for (x, y, z), t in zip(trajectory_data, timestamps):self.history_data['X'].append(x)self.history_data['Y'].append(y)self.history_data['U'].append(z)self.history_data['timestamps'].append(t)# 初始化图表数据self.setup_history_chart(ax)# 创建并启动静态更新self.update_static_chart()def setup_history_chart(self, parent):"""初始化历史趋势图"""from matplotlib.figure import Figurefrom matplotlib.backends.backend_tkagg import FigureCanvasTkAggdef reset_chart_data(self):"""重置图表数据"""# 清空历史数据self.history_data['X'] = []self.history_data['Y'] = []self.history_data['U'] = []self.history_data['timestamps'] = []# 重新读取文件中的最后5条记录file_path = r'C:\Log\log_His.txt'trajectory_data = self.read_last_n_records(file_path, 5)# 如果读取到数据,更新历史数据if trajectory_data:# 计算时间戳(假设每条记录间隔固定为1秒)now = time.time()timestamps = [now + i for i in range(len(trajectory_data))]# 更新历史数据for (x, y, z), t in zip(trajectory_data, timestamps):self.history_data['X'].append(x)self.history_data['Y'].append(y)self.history_data['U'].append(z)self.history_data['timestamps'].append(t)# 更新静态图表self.update_static_chart()# 日志记录logging.info("图表数据已重置并重新加载")def reset_chart_data(self):"""重置图表数据"""# 初始化历史数据存储self.history_data = {'X': [],'Y': [],'U': [],'timestamps': []}# 读取文件中的最后5条记录file_path = r'C:\Log\log_His.txt'trajectory_data = self.read_last_n_records(file_path, 5)# 如果读取到数据,更新历史数据if trajectory_data:# 计算时间戳(假设每条记录间隔固定为1秒)now = time.time()timestamps = [now + i for i in range(len(trajectory_data))]# 更新历史数据for (x, y, z), t in zip(trajectory_data, timestamps):self.history_data['X'].append(x)self.history_data['Y'].append(y)self.history_data['U'].append(z)self.history_data['timestamps'].append(t)# 更新静态图表self.update_static_chart()# 日志记录logging.info("图表数据已重置并重新加载")def update_chart_style(self):"""更新图表样式设置"""# 设置坐标轴和图例 - 工业风格self.ax.set_title("实时趋势", fontsize=14, color='#FFFFFF', pad=20)self.ax.set_xlabel("Time", fontsize=12, color='#CCCCCC')self.ax.set_ylabel("Value(mm)", fontsize=12, color='#CCCCCC')self.ax.grid(True, color='#555555', linestyle='--', alpha=0.7)self.ax.legend(loc='upper right', fontsize=10)# 设置背景色self.ax.set_facecolor('#333333')self.fig.patch.set_facecolor('#404040')# 设置刻度颜色self.ax.tick_params(axis='x', colors='#CCCCCC')self.ax.tick_params(axis='y', colors='#CCCCCC')# 重新绘制图表self.ax.figure.canvas.draw()# 更新图表样式self.update_chart_style()def create_left_panel(self, parent):# 创建带滚动条的框架left_container = tk.Frame(parent)left_container.pack(fill=tk.BOTH, expand=True)canvas = tk.Canvas(left_container, bg='#FFFFFF')scrollbar = tk.Scrollbar(left_container, orient="vertical", command=canvas.yview)scrollable_frame = tk.Frame(canvas, bg='#FFFFFF')scrollable_frame.bind("<Configure>",lambda e: canvas.configure(scrollregion=canvas.bbox("all")))canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")canvas.configure(yscrollcommand=scrollbar.set)# 设置左面板背景left_frame = tk.Frame(scrollable_frame, bg='#FFFFFF')left_frame.pack(fill=tk.BOTH, expand=True, padx=(5, 0))  # 左移调整并减小宽度# MAIN标题,整体变小main_title = tk.Label(left_frame,text="Main",font=("Arial", 38, "bold"),fg="black",bg="#FAFAD2", anchor='center')  # 标题居中对齐main_title.pack(side=tk.TOP, pady=(53, 30), fill=tk.X)# Launch Vision 按钮launch_button = tk.Button(left_frame, text="Launch Vision", command=self.launch_application,bg="#F0F552",fg="black",width=18,  # 修改按钮宽度为原来的一半font=("Segoe UI", 20))launch_button.pack(pady=(10, 50), anchor='w', padx=30)  # 左对齐并减小间距# Start 按钮start_button = tk.Button(left_frame, text="Start", command=self.start_auto_command,bg="#32CD32",fg="white",width=18,  # 修改按钮宽度为原来的一半font=("Segoe UI", 20))start_button.pack(pady=(0, 30), anchor='w', padx=30)  # 左对齐并减小间距###新增空白区域# 空白区域blank_frame = tk.Frame(left_frame, bg='#FFFFFF', height=10)  # 高度为10像素blank_frame.pack(fill=tk.X, pady=256)  # 填充整个宽度并增加间距# 水平按钮行框架(新增)button_row_frame = tk.Frame(left_frame, bg='#FFFFFF')button_row_frame.pack(pady=10, anchor='w', padx=5)  # 整体间距# 3D 按钮(修改父容器为 button_row_frame)animation_button = tk.Button(button_row_frame, text="3D", command=self.show_animation,bg="#00B0F0",fg="white",width=8,  # 修改按钮宽度为原来的一半font=("Segoe UI", 12))animation_button.pack(side=tk.LEFT, padx=5)  # 水平排列# His Chart 按钮(修改父容器为 button_row_frame)chart_button = tk.Button(button_row_frame, text="His Chart", command=self.create_chart_area,bg="#00B0F0",fg="white",width=8,  # 修改按钮宽度为原来的一半font=("Segoe UI", 12))chart_button.pack(side=tk.LEFT, padx=5)  # 水平排列# Log 按钮(修改父容器为 button_row_frame)new_window_button = tk.Button(button_row_frame, text="Log", command=self.show_new_window,bg="#00B0F0",fg="white",width=8,  # 修改按钮宽度为原来的一半font=("Segoe UI", 12))new_window_button.pack(side=tk.LEFT, padx=5)  # 水平排列# 连接按钮(Vision和Robot)self._create_connection_buttons(left_frame, "Vision", self.connect_to_vision, self.disconnect_from_vision)self._create_connection_buttons(left_frame, "Robot", self.connect_to_robot, self.disconnect_from_robot)# 备用端口按钮(PLC、Falco、Robot)PLC_button = tk.Button(left_frame, text="PLC Port (Backup)", command=self.start_PLC_command,bg="#CDCDCD",fg="gray",font=("Segoe UI", 12))PLC_button.pack(side=tk.BOTTOM, fill=tk.X)Falco_button = tk.Button(left_frame, text="Falco Port (Backup)", command=self.start_Falco_command,bg="#CDCDCD",fg="gray",font=("Segoe UI", 12))Falco_button.pack(side=tk.BOTTOM, fill=tk.X)Robot_button = tk.Button(left_frame, text="Robot Port (Backup)", command=self.start_Robot_command,bg="#CDCDCD",fg="gray",font=("Segoe UI", 12))Robot_button.pack(side=tk.BOTTOM, fill=tk.X)canvas.pack(side="left", fill="both", expand=True)# ---新---区域22blank_frame = tk.Frame(left_frame, bg='#FFFFFF', height=10)  # 高度为10像素blank_frame.pack(fill=tk.X, pady=120)  # 填充整个宽度并增加间距# ---新---区域33blank_frame = tk.Frame(left_frame, bg='#FFFFFF', height=10)  # 高度为10像素blank_frame.pack(fill=tk.X, pady=120)  # 填充整个宽度并增加间距# 修改滚动条初始状态为隐藏,并绑定鼠标事件scrollbar.place(relx=1, rely=0, relheight=1, anchor='ne')scrollbar.lower()  # 初始隐藏left_container.bind("<Enter>", lambda _: scrollbar.lift())  # 鼠标进入时显示left_container.bind("<Leave>", lambda _: scrollbar.lower())  # 鼠标离开时隐藏def on_exit(self):"""处理窗口关闭事件"""# 弹出确认对话框,确保在主线程中执行if messagebox.askokcancel("退出", "确定要退出程序吗?", parent=self.root):logging.info("用户确认退出程序,开始清理资源...")try:# 保存配置self.save_settings()logging.info("配置已自动保存")# 断开与 Vision 的连接if self.connected_to_vision:self.disconnect_from_vision()logging.info("已断开与 Vision 的连接")# 断开与 Robot 的连接if self.connected_to_robot:self.disconnect_from_robot()logging.info("已断开与 Robot 的连接")# 终止子进程if hasattr(self, 'app3_process') and self.app3_process:self.terminate_application3()logging.info("已终止子进程")# 清理日志处理器if hasattr(self, 'new_window_handler'):logger = logging.getLogger()logger.removeHandler(self.new_window_handler)logging.info("已移除日志处理器")except Exception as e:logging.error(f"退出时发生错误: {str(e)}")messagebox.showerror("错误", f"退出时发生错误: {str(e)}")finally:# 安全关闭主窗口self.root.destroy()logging.info("主窗口已关闭")else:logging.info("用户取消退出程序")def show_new_window(self):"""显示一个新的弹窗"""new_window = tk.Toplevel(self.root)new_window.title("Log")# 设置窗口大小和位置(居中显示)window_width = 800window_height = 600screen_width = new_window.winfo_screenwidth()screen_height = new_window.winfo_screenheight()x = (screen_width - window_width) // 2y = (screen_height - window_height) // 2new_window.geometry(f'{window_width}x{window_height}+{x}+{y}')# 创建 Text 组件用于显示日志self.new_window_text = tk.Text(new_window, wrap=tk.WORD, bg='black', fg='white', font=("Helvetica", 18))self.new_window_text.pack(fill=tk.BOTH, expand=True)close_button = tk.Button(new_window, text="Close", command=lambda: self.close_new_window(new_window), width=10)close_button.pack(pady=10)# 获取右侧日志区域的全部内容log_content = self.log_text.get("1.0", tk.END).strip()# 将日志内容插入到新窗口的 Text 组件中if log_content:self.new_window_text.insert(tk.END, log_content)self.new_window_text.yview_moveto(1)  # 滚动到最新位置# 添加日志处理器self.new_window_handler = TextHandler(self.new_window_text)logger = logging.getLogger()logger.addHandler(self.new_window_handler)def close_new_window(self, window):"""关闭新窗口并移除日志处理器"""if hasattr(self, 'new_window_handler'):logger = logging.getLogger()logger.removeHandler(self.new_window_handler)window.destroy()def update_new_window_log(self, record):"""更新新窗口中的日志内容"""if hasattr(self, 'new_window_text') and self.new_window_text.winfo_exists():msg = self.formatter.format(record)self.new_window_text.insert(tk.END, msg + '\n')self.new_window_text.yview_moveto(1)def setup_logging(self):  text_handler = TextHandler(self.log_text)  logger = logging.getLogger()  logger.addHandler(text_handler)  # 添加新的处理程序以支持新窗口日志if hasattr(self, 'new_window_text'):new_window_handler = TextHandler(self.new_window_text)logger.addHandler(new_window_handler)def _create_connection_buttons(self, parent, label_text, connect_cmd, disconnect_cmd):# 创建连接按钮框架button_frame = tk.Frame(parent)button_frame.pack(pady=5)connect_button = tk.Button(button_frame, text=f"Con. {label_text}", command=connect_cmd, width=14, height=1)connect_button.pack(side=tk.LEFT, anchor='center', padx=5)status_indicator = tk.Frame(button_frame, width=20, height=20, bg='red')setattr(self, f"{label_text.lower()}_status_indicator", status_indicator)  # Store as attributestatus_indicator.pack(side=tk.LEFT, anchor='center', padx=(0, 5))disconnect_button = tk.Button(button_frame, text=f"Dis. {label_text}", command=disconnect_cmd, width=14, height=1)disconnect_button.pack(side=tk.LEFT, anchor='center', padx=5)def create_middle_panel(self, parent):# 中间主框架middle_frame = tk.Frame(parent, bg='#FFFFFF')  #OLD #CCCCCCmiddle_frame.pack(fill=tk.BOTH, expand=True)# 修改 create_right_panel 方法中的标题和区域标识def create_right_panel(self, parent):# 保存 right_frame 作为类属性,避免重复初始化self.right_frame = tk.Frame(parent, bg='#FFFFFF')self.right_frame.pack(fill=tk.BOTH, expand=True)# 清除之前的 image_title(如果存在)if hasattr(self, 'image_title') and self.image_title:self.image_title.destroy()# 图片标题self.image_title = tk.Label(self.right_frame,text="Picture",font=("Arial", 38, "bold"),fg="black",bg="#FAFAD2",anchor='center')self.image_title.pack(pady=(15, 30), fill=tk.X)# 创建图片显示区域self.image_label = tk.Label(self.right_frame, bg='white')self.image_label.pack(fill=tk.BOTH, expand=True, padx=328, pady=10)   #PosTimTimTim# 加载图片self.load_images()# 确保 image_index 初始化if not hasattr(self, 'image_index'):logging.warning("image_index 未初始化,正在修复...")self.image_index = 0# 开始更新图片self.root.after(333, self.update_image)  # 使用 after 安排首次更新def update_image(self):# 检查图片列表是否存在且非空if not hasattr(self, 'images') or not self.images:logging.warning("Ini...")self.root.after(333, self.update_image)return# 检查 image_label 是否初始化if not hasattr(self, 'image_label') or self.image_label is None:logging.error("Picture Ini...---")# 使用保存的 right_frame 重新初始化if hasattr(self, 'right_frame'):self.create_right_panel(self.right_frame)else:logging.error("无法找到 right_frame,无法重新初始化 image_label")self.root.after(333, self.update_image)  # 避免直接递归调用returntry:img = self.images[self.image_index]self.image_label.config(image=img)self.image_label.image = imglogging.debug(f"成功更新图片索引 {self.image_index}")except Exception as e:try:logging.error(f"更新图片失败: {str(e)}")except RecursionError:pass  # 避免日志记录引发递归错误self.root.after(333, self.update_image)  # 避免直接递归调用return# 更新索引并触发下一次更新self.image_index = (self.image_index + 1) % len(self.images)self.root.after(333, self.update_image)  # 使用 after 安排下一次更新def load_default_image111(self):"""加载默认图片到右侧显示区域"""image_folder = r'C:\Log\Picture'  # 默认图片文件夹路径if not os.path.exists(image_folder):logging.warning(f"图片文件夹路径不存在: {image_folder}")returnimages = []for file in os.listdir(image_folder):if file.lower().endswith(('.jpg', '.jpeg', '.png', '.bmp', '.gif')):img_path = os.path.join(image_folder, file)try:img = Image.open(img_path)img.thumbnail((800, 600))  # 自适应缩放images.append(ImageTk.PhotoImage(img))except Exception as e:#logging.error(f"无法加载图片 {img_path}: {str(e)}")logging.error(f"Loading Picture NG... {img_path}: {str(e)}")if images:if self.image_label:  # 确保 image_label 存在self.image_label.config(image=images[0])  # 显示第一张图片self.image_label.image = images[0]#logging.info(f"成功加载图片: {len(images)} 张")logging.info(f"Read: {len(images)} Pictures")else:logging.warning("未找到有效图片文件")def create_bottom_panel(self, parent):# 修改后的偏移量输入和写入按钮布局offset_frame = tk.Frame(parent, bg='lightgray')offset_frame.pack(fill=tk.X, pady=5, padx=5)# X输入tk.Label(offset_frame, text="X:", bg='lightgray', font=("Helvetica", 12)).grid(row=0, column=0, padx=2)self.custom_command_entry5 = tk.Entry(offset_frame, width=8, font=("Helvetica", 12))self.custom_command_entry5.grid(row=0, column=1, padx=2)# Y输入tk.Label(offset_frame, text="Y:", bg='lightgray', font=("Helvetica", 12)).grid(row=0, column=2, padx=2)self.custom_command_entry6 = tk.Entry(offset_frame, width=8, font=("Helvetica", 12))self.custom_command_entry6.grid(row=0, column=3, padx=2)# U输入tk.Label(offset_frame, text="U:", bg='lightgray', font=("Helvetica", 12)).grid(row=0, column=4, padx=2)self.custom_command_entry7 = tk.Entry(offset_frame, width=8, font=("Helvetica", 12))self.custom_command_entry7.grid(row=0, column=5, padx=2)# 统一的写入按钮  ###Timwrite_button = tk.Button(offset_frame, text="Offset_Write", command=self.write_all_offsets,bg="#32CD32",fg="white",width=12, font=("Segoe UI", 12)) write_button.grid(row=0, column=6, padx=10)#Enter 1 commandcustom_command_frame = tk.Frame(parent)  custom_command_frame.pack(side=tk.TOP, pady=1, fill=tk.X, expand=True)  custom_command_label = tk.Label(custom_command_frame, text="Enter Vision Command:", font=("Helvetica", 1))  custom_command_label.pack(side=tk.LEFT, padx=5)  self.custom_command_entry1 = tk.Entry(custom_command_frame, font=("Helvetica", 1), fg="purple")  self.custom_command_entry1.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)  send_command_button = tk.Button(custom_command_frame, text="Send", command=self.send_custom_command1, font=("Helvetica", 1))  send_command_button.pack(side=tk.LEFT, padx=5)  # 新增日志显示区域log_frame = tk.Frame(parent, bg='black')log_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)# 调整日志区域高度为原来的一半self.log_text = tk.Text(log_frame, wrap=tk.WORD, bg='black', fg='white', font=("Helvetica", 12), height=10)self.log_text.pack(fill=tk.BOTH, expand=True)
#Enter 2 commandcustom_command_frame2 = tk.Frame(parent)  custom_command_frame2.pack(side=tk.TOP, pady=1, fill=tk.X, expand=True)  custom_command_label = tk.Label(custom_command_frame2, text="Enter Robot Command:", font=("Helvetica", 1))  custom_command_label.pack(side=tk.LEFT, padx=5)  self.custom_command_entry2 = tk.Entry(custom_command_frame2, font=("Helvetica", 1), fg="purple")  self.custom_command_entry2.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)  send_command_button2 = tk.Button(custom_command_frame2, text="Send", command=self.send_custom_command2, font=("Helvetica", 1))  send_command_button2.pack(side=tk.LEFT, padx=5)  
#Enter 3 commandcustom_command_frame3= tk.Frame(parent)  custom_command_frame3.pack(side=tk.TOP, pady=1, fill=tk.X, expand=True)  custom_command_label = tk.Label(custom_command_frame3, text="Enter Send To Vision Command:", font=("Helvetica", 1))  custom_command_label.pack(side=tk.LEFT, padx=5)  self.custom_command_entry3 = tk.Entry(custom_command_frame3, font=("Helvetica", 1), fg="purple")  self.custom_command_entry3.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)  send_command_button3 = tk.Button(custom_command_frame3, text="Send", command=self.send_custom_command3, font=("Helvetica", 1))  send_command_button3.pack(side=tk.LEFT, padx=5)  # 移除发送按钮并绑定 Enter 键事件到输入框   self.custom_command_entry3.bind('<Return>', lambda event: self.send_custom_command3())def _validate_number(self, value):"""数值输入验证"""if value == "" or value == "-":return Truetry:float(value)return Trueexcept ValueError:return Falsedef setup_logging(self):  text_handler = TextHandler(self.log_text)  logger = logging.getLogger()  logger.addHandler(text_handler)  def connect_to_vision(self):  try:  self.vision_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  self.vision_client_socket.settimeout(65536)  self.vision_client_socket.connect((self.vision_ip, self.vision_port))  self.connected_to_vision = True  self.update_status_indicator(self.vision_status_indicator, 'green', "Connected to Vision")  logging.info(f"Connected to Vision at {self.vision_ip}:{self.vision_port}")  threading.Thread(target=self.receive_data, args=(self.vision_client_socket, 'vision'), daemon=True).start()  except Exception as e:  self.connected_to_vision = False  self.update_status_indicator(self.vision_status_indicator, 'red', f"Failed to connect to Vision: {e}")  logging.error(f"Failed to connect to Vision: {e}")  if self.vision_client_socket:  self.vision_client_socket.close()  def disconnect_from_vision(self):  if self.connected_to_vision:  self.vision_client_socket.close()  self.connected_to_vision = False  self.update_status_indicator(self.vision_status_indicator, 'red', "Disconnected from Vision")  logging.info("Disconnected from Vision")  ##OutofRangdef Out_Of_Range_from_vision(self):  self.update_status_indicator2(self.vision_status_indicator, 'red', "Out_Of_Range_±10°")  logging.info("Out_Of_Range_from_vision_±10°")  def Out_Of_Range_from_vision2(self):  self.update_status_indicator2(self.vision_status_indicator, 'red', "Out_Of_Range_±90°")  logging.info("Out_Of_Range_from_vision_±90°")  
##OutofRang##Robot at Homedef Home_POS(self):  self.update_status_indicator2(self.vision_status_indicator, 'red', "Not Match,Pls Check and Put it Again,\n Then Connect Vision Again ")  logging.info("Not Match,Pls Check and Put it Again ...")  
##Robot at Homedef ERROR_(self):  self.update_status_indicator2(self.robot_status_indicator, 'red', "ERROR,PLS Connect Robot\n\n Then, In Robot Software, Press Start to Run...")  logging.info("ERROR,PLS Connect Robot")  def Motor_Off(self):  self.update_status_indicator2(self.robot_status_indicator, 'red', "  Area Semnsor \n\n Area Semnsor \n\nArea Semnsor \n\nThen, In Robot Software, Press Start to Run...")  logging.info("ERROR,Area Semnsor")  def connect_to_robot(self):  try:  self.robot_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  self.robot_client_socket.settimeout(65536)  self.robot_client_socket.connect((self.robot_ip, self.robot_port))  self.connected_to_robot = True  self.update_status_indicator(self.robot_status_indicator, 'green', "Connected to Robot")  logging.info(f"Connected to Robot at {self.robot_ip}:{self.robot_port}")  threading.Thread(target=self.receive_data, args=(self.robot_client_socket, 'robot'), daemon=True).start()  except Exception as e:  self.connected_to_robot = False  self.update_status_indicator(self.robot_status_indicator, 'red', f"Failed to connect to Robot: {e}")  logging.error(f"Failed to connect to Robot: {e}")  if self.robot_client_socket:  self.robot_client_socket.close()  def disconnect_from_robot(self):  if self.connected_to_robot:  self.robot_client_socket.close()  self.connected_to_robot = False  self.update_status_indicator(self.robot_status_indicator, 'red', "Disconnected from Robot")  logging.info("Disconnected from Robot")  def send_custom_command1(self):  command = self.custom_command_entry1.get()  if command:  logging.info(f"Send_Vision_Command2Start: {command}")  self.send_vision_command(command)  # 更新图片逻辑self.load_images()  # 重新加载图片self.update_image()  # 更新图片显示def send_custom_command2(self):  command = self.custom_command_entry2.get()  if command:  logging.info(f"send_robot_command: {command}")  self.send_robot_command(command)  #self.custom_command_entry.delete(0, tk.END)  def send_custom_command3(self):  global Response  # 使用全局变量if Response == 'Camera_not_Match_Picture' :  ##print("666",Response)time.sleep(0.005) else:    #global Response  # 使用全局变量 #command = self.custom_command_entry2.get() command = str(Response)  # 获取全局变量 RES 的值作为命令内容if command:  logging.info(f"Recive_Vision/Robot_Data_is_{command}")  logging.info(f"Then_Auto_send_Vision_Pos2robot")                  self.send_robot_command(command)#self.custom_command_entry.delete(0, tk.END)  ##def send_custom_command6_Offset(self):  command = self.custom_command_entry5.get()  if command:  logging.info(f"send_robot_command_X_Offset: {command}")  self.send_robot_command_Offset(command)  #self.custom_command_entry.delete(0, tk.END)  command = self.custom_command_entry6.get()  if command:  logging.info(f"send_robot_command_Y_Offset: {command}")  self.send_robot_command_Offset(command)  #self.custom_command_entry.delete(0, tk.END)  command = self.custom_command_entry7.get()  if command:  logging.info(f"send_robot_command_Z_Offset: {command}")  self.send_robot_command_Offset(command)  #self.custom_command_entry.delete(0, tk.END)  def send_x_offset(self):self._send_offset("X", self.custom_command_entry5.get())def send_y_offset(self):self._send_offset("Y", self.custom_command_entry6.get())def send_u_offset(self):self._send_offset("U", self.custom_command_entry7.get())def _send_offset(self, axis_type, value):if not value:returntry:# 数值有效性验证float(value)except ValueError:messagebox.showerror("Error", "Pls Inpout Number")#messagebox.showerror("输入错误", "请输入有效的数字")returnif self.connected_to_robot:try:cmd_template = {"X": "Tim{}Tim0Tim0TimOKTim666666\r\n","Y": "Tim0Tim{}Tim0TimOKTim666666\r\n","U": "Tim0Tim0Tim{}TimOKTim666666\r\n"}command = cmd_template[axis_type].format(value)self.robot_client_socket.sendall(command.encode('utf-8'))logging.info(f"Sent {axis_type}_Offset: {command.strip()}")except Exception as e:#logging.error(f"发送{axis_type}偏移失败: {str(e)}")#self.update_status_indicator2(self.robot_statuslogging.error(f"Sent {axis_type}Fail,Message is: {str(e)}")self.update_status_indicator2(self.robot_status_indicator, 'red', f"Sent Fail: {str(e)}")else:messagebox.showwarning("Connect Error", "Can not Connected Robot")def receive_data(self, client_socket, source):  global Response  # 使用全局变量 while client_socket and client_socket.fileno() >= 0:  try:  data = client_socket.recv(1024).decode('utf-8')  Response=data  ##print (Response)if not data:  break  # 加载图片#    self.load_images()# 启动图片更新定时器#    self.update_image()current_time = datetime.now().strftime("%H:%M:%S")  ##print(current_time)log_entry = f"[{current_time}]  {data}\n"  # Append to log file  with open(r"c:\Log\log_His.txt", "a") as log_file:  log_file.write(log_entry)  # Append to log file  with open(r"c:\Log\log_His_BK.txt", "a") as log_file:  log_file.write(log_entry)  # Update the appropriate text widget  if source == 'vision':  data66=data#print(data66)if data66 == 'Out_Of_Range_CW10_CCW10Out_Of_Range_CW90_CCW90' or  data66 == 'Out_Of_Range_CW10_CCW10' :  #Out_Of_Range_CW10_CCW10#self.disconnect_from_vision() #print("111") self.Out_Of_Range_from_vision() #print("---111") if data66 == 'Out_Of_Range_CW90_CCW90':  #self.disconnect_from_vision() self.Out_Of_Range_from_vision2() if data66 == 'Camera_not_Match_Picture' :  #self.disconnect_from_vision() ##print("666",data66)#self.Home_POS() self.root.after(200, lambda: self.Home_POS())#print("11111111111")# 解析数据并记录需格式调整 Chart   17:11:35  Tim-692.003Tim233.098Tim-177.533TimOKTim88888888x_val = float(data66.split('Tim')[1].split('Tim')[0])#print("22222222222")y_val = float(data.split('Tim')[2])#print("333")u_val = float(data.split('Tim')[3])#print("555")#print(x_val)#print(x_val,y_val,u_val)self.history_data['X'].append(x_val)self.history_data['Y'].append(y_val)self.history_data['U'].append(u_val)self.history_data['timestamps'].append(time.time())                       ##    self.vision_data_text.insert(tk.END, f"\n«Vision»  -Raw data1- \n\n{current_time}  {data}\n")  #Response=data  #print (Response)time.sleep(0.01)##    self.vision_data_text.yview_moveto(1)data2=data                             #data = "-801.226XX218.608YY-13.962YY"x_value = data2.split('X')[0].strip()       #将字符串按 X 分割,取第一个部分,即 -801.226,并去除可能的前后空白字符。start_y = data2.rfind('-') y_valueLS = data2[start_y:] y_value =   y_valueLS[:-2]##   self.vision_char_text.insert(tk.END, f"\n«Vision»  -Split data2- \n\n{current_time}  Received: {x_val}  {y_val}  {u_val}  \n")  #self.vision_char_text.insert(tk.END, f"\n«Vision»  -Split data- \n\n{current_time}  x:{x_value}  y:{y_value} \n")  ##    self.vision_char_text.yview_moveto(1)  parts = data.split('Tim') if len(parts) >= 4:  # Ensure we have X, Y, U values x_val = float(parts[1])y_val = float(parts[2])u_val = float(parts[3])self.history_data['X'].append(x_val) self.history_data['Y'].append(y_val) self.history_data['U'].append(u_val) self.history_data['timestamps'].append(time.time()) elif source == 'robot':  data666666 = str(Response).strip()  # 去除前后空白Real_Data=repr(Response)##print("111 repr Real Data:", repr(Response))  # 显示原始字符串#data666666=data#data666666 = str(Response) #print("111",Response)#print("222",data666666)if data666666 == 'Shot' or data666666 == 'Shot2':  #self.disconnect_from_vision() #print("333",data666666)#self.Home_POS() self.root.after(200, lambda: self.Ali_Comand())if data666666 == 'ERROR_' :  #self.disconnect_from_vision() #print("333",data666666)#self.Home_POS() self.root.after(200, lambda: self.ERROR_())if data666666 == 'Motor_Off' :  self.root.after(200, lambda: self.Motor_Off())# 在接收数据时检查Home信号if 'Home1' in data:self.home_received = Trueself.start_button.config(state=tk.NORMAL)logging.info("Home position received - Start enabled")elif 'NotHome' in data:self.home_received = Falseself.start_button.config(state=tk.DISABLED)logging.info("Not in Home position - Start disabled")##    self.robot_data_text.insert(tk.END, f"\n«Robot_data1»\n{current_time}  {data}  Real_Data is {Real_Data}\n")  ##    self.robot_data_text.yview_moveto(1)  ##    self.robot_char_text.insert(tk.END, f"\n«Robot_data2»\n{current_time}  {data}  Data is {data666666}\n")  ##    self.robot_char_text.yview_moveto(1)  # Log the data to the log area  ##    self.log_text.insert(tk.END, log_entry)  ##   self.log_text.yview_moveto(1)  # 自动发送接收到的数据作为命令   self.send_custom_command3()except Exception as e:  logging.error(f"Error receiving data: {e}")  logging.error(f"Data parsing error: {str(e)}")break  if client_socket == self.vision_client_socket:  self.disconnect_from_vision()  elif client_socket == self.robot_client_socket:  self.disconnect_from_robot()  def send_custom_command(self, command=None):  global RES # 使用全局变量# 如果没有提供命令,则使用全局变量 RES 的值if command is None:command = Responseif command:  logging.info(f"Auto_Custom command entered: {command}")  self.send_robot_command3(command)  self.custom_command_entry3.delete(0, tk.END)  def send_vision_command(self, command):    #visionif self.connect_to_vision and self.vision_client_socket:  try:  self.vision_client_socket.sendall(command.encode('utf-8'))  ## logging.info(f"Command vision sent to vision: {command}")  except Exception as e:  logging.error(f"Failed to send command to vision: {e}")  def send_robot_command_Area_Sensor(self, command):   if self.connected_to_robot and self.robot_client_socket:  command345="Motor_Off"try:  self.robot_client_socket.sendall(command345.encode('utf-8'))#  logging.info(f"Command sent to Robot: {command345.strip()}")print("55555555555")except Exception as e:  logging.error(f"Failed to send command to Robot: {e}")  def send_robot_command(self, command):global Offset_X, Offset_Y, Offset_UABCDEFG=0if self.connected_to_robot and self.robot_client_socket:try:# 解析原始命令并应用偏移量parts = command.split('Tim')if len(parts) >= 4:x = float(parts[1]) + (Offset_X if Offset_X else 0)y = float(parts[2]) + (Offset_Y if Offset_Y else 0)u = float(parts[3]) + (Offset_U if Offset_U else 0)command = f"Tim{x}Tim{y}Tim{u}TimOKTim666666\r\n"# 分开记录日志logging.info(f"Applied offsets - X: {Offset_X}, Y: {Offset_Y}, U: {Offset_U}")self.robot_client_socket.sendall(command.encode('utf-8'))logging.info(f"1、Send_Vision_Pos2robot  2、Robot_X_Y_U_Move_Data  3、 From_robot_command: {command.strip()}")except Exception as e:logging.error(f"Failed to send command to Robot: {e}")##Offsetdef send_robot_command_Offset(self, command):  if self.connect_to_vision and self.robot_client_socket:  try:    #Tim-495.047Tim86.1133Tim-0.284364TimOKTim88888888  "Tim"(command)TimcommandTimcommandTimOKTim88888888"send_robot_command_Offset=("Tim"+(command)+"Tim"+(command)+"Tim"+(command)+"Tim"+"OK"+"Tim"+"88888888"+"\r\n")##print(send_robot_command_Offset)send_robot_command_Offset66=((command)+"\r\n")self.robot_client_socket.sendall(send_robot_command_Offset66.encode('utf-8'))  logging.info(f"Command robot sent to Robot66: {command}")  except Exception as e:  logging.error(f"Failed to send command to Robot: {e}")  
##Offset                def launch_application(self):  #Demo app_path = r"C:\Users\ShineTek\Desktop\V1\Public_Release\v1.exe"  app_path = r"C:\Log\V5\Public_Release\V5.exe"#app_path = r"C:\Study\Case\V5\Public_Release\V5.exe"try:  subprocess.Popen(app_path)  logging.info("Launched application successfully.")  except Exception as e:  messagebox.showerror("Error", f"Failed to launch application: {e}")  logging.error(f"Failed to launch application: {e}")  def launch_application3(self):app_path = r"C:\Users\ShineTek\AppData\Local\Programs\Python\Python37\Python.exe E:\Tim_Study\Python_Code\Ali_Show_Picture666.py"#app_path = r"C:\Users\ShineTek\Desktop\大视野\V1_Big_OK_250219_AddCode\Ali_Show_Picture666.exe"#app_path = r"C:\Users\ShineTek\AppData\Local\Programs\Python\Python37\Python.exe C:\Log\Ali_Show_Picture666.py"###   app_path = r"C:\Users\ShineTek\AppData\Local\Programs\Python\Python37\Python.exe E:\EpsonRC70\Projects\V999_1Cycle_\Show_Picture222.py"try:# 启动新进程并保存引用self.app3_process = subprocess.Popen(app_path)logging.info("Launched application successfully3.")except Exception as e:messagebox.showerror("Error", f"Failed to launch application3: {e}")logging.error(f"Failed to launch application3: {e}")def terminate_application3(self):if self.app3_process and self.app3_process.poll() is None:# 尝试终止进程try:self.app3_process.terminate()self.app3_process.wait()logging.info("Terminated application3 successfully.")except Exception as e:logging.error(f"Failed to terminate application3: {e}")self.app3_process = None  # 重置进程引用def update_status_indicator(self, indicator, color, message):  indicator.config(bg=color)  self.root.update_idletasks()  messagebox.showinfo("Status", message)  def update_status_indicator2(self, indicator, color, message):  indicator.config(bg=color)  self.root.update_idletasks()  messagebox.showinfo("Waring", message)  ##Timdef update_status_indicator6(self, indicator, color, message):  indicator.config(bg=color)  self.root.update_idletasks()  messagebox.showinfo("ERROR", message)  self.update_status_indicator(self._status_indicator6, 'green', "Center") self.update_status_indicator(self._status_indicator6, 'red', f"not Center") def Auto_send(self):     # 等待3秒,以便用户将焦点切换到目标输入框 time.sleep(3) # 在指定位置输入XXX x1, y1 = map(int, input("请输入要输入XXX的位置坐标(以空格分隔,例如:100 200):").split()) pyautogui.click(x1, y1) pyautogui.typewrite('XXX') # 在指定位置输入YYY x2, y2 = map(int, input("请输入要输入YYY的位置坐标(以空格分隔,例如:300 400):").split()) pyautogui.click(x2, y2) pyautogui.typewrite('YYY') # 找到send按钮的位置(这里假设已经知道send按钮的位置,假设为x_send, y_send) x_send, y_send = map(int, input("请输入send按钮的位置坐标(以空格分隔,例如:500 600):").split()) # 点击send按钮 pyautogui.click(x_send, y_send) time.sleep(0.5) pyautogui.click(x_send, y_send)       def start_auto_command(self):if self.connect_to_vision and self.vision_client_socket:  #self.connect_to_vision()#self.connect_to_robot()#self.root.after(200, lambda: self.connect_to_vision())print("1111111111111")#time.sleep(100)self.custom_command_entry1.delete(0, tk.END)self.custom_command_entry1.insert(0, "1st_Camera")self.send_custom_command1()# 先终止可能正在运行的进程self.terminate_application3()# 再启动新进程self.root.after(200, lambda: self.launch_application3())def Recive_PLC_start_command(self):  #PC Start yeshi zouzheli##print(Response)data_Tim = str(Response).strip()  # 去除前后空白if data_Tim=="1NO_Home_Pos":#if not data_Tim=="Home_Pos":time.sleep(0.005) self.root.after(200, lambda: self.Home_POS())else: if self.connect_to_vision and self.vision_client_socket:  #self.connect_to_vision()#self.connect_to_robot()#self.root.after(200, lambda: self.connect_to_vision())#print("2222222222")#time.sleep(100)self.custom_command_entry1.delete(0, tk.END)self.custom_command_entry1.insert(0, "1st_Camera")self.send_custom_command1()# 先终止可能正在运行的进程self.terminate_application3()# 再启动新进程##self.root.after(200, lambda: self.launch_application3())# 更新图片逻辑self.root.after(5000, lambda: self.load_images())self.root.after(500, lambda: self.update_image())self.load_images()  # 重新加载图片self.update_image()  # 更新图片显示#self.root.after(200, lambda: self.Ali_Comand())def Ali_Comand(self):self.custom_command_entry1.delete(0, tk.END)self.custom_command_entry1.insert(0, "2nd_Camera")self.send_custom_command1()# 先终止可能正在运行的进程#self.terminate_application3()# 再启动新进程###self.root.after(200, lambda: self.launch_application3())def continue_auto_command(self): self.custom_command_entry1.delete(0, tk.END) self.custom_command_entry1.insert(0, "YYY")self.send_custom_command1() self.root.after(200, lambda: self.continue_auto_command_U())def continue_auto_command_U(self): self.custom_command_entry1.delete(0, tk.END) self.custom_command_entry1.insert(0, "UUU")self.send_custom_command1() def init_plc_connection(self):"""增强型工业连接协议"""try:self.plc = MelsecMcNet("192.168.0.11", 1028)conn = self.plc.ConnectServer()if conn.IsSuccess:#self.status_bar.config(text="PLC已连接 | 协议版本6.2", fg="green")logging.info(f"Connected to PLC at IP:192.168.0.11  Port:1028 ") else:#self.status_bar.config(text=f"连接失败: {conn.Message}", fg="red")logging.info(f"PLC Connect NG at [{datetime.now().strftime('%H:%M:%S')}]")self.plc = Noneexcept Exception as e:#self.status_bar.config(text=f"初始化异常: {str(e)}", fg="orange")logging.info(f"PLC Connect NG at [{datetime.now().strftime('%H:%M:%S')}]")def setup_plc(self):# PLC连接配置self.plc = MelsecMcNet("192.168.0.11", 1028)connect_result = self.plc.ConnectServer()if not connect_result.IsSuccess:print("PLC Connect NG:", connect_result.Message)self.plc = Nonedef start_plc_monitoring(self):"""智能重连监控系统"""if self.plc and self._check_connection():self._monitor_y79()else:self.parent.after(2000, self.start_plc_monitoring)def _monitor_y79(self):"""修正地址并增强监测"""try:# 使用八进制地址Y117(十进制79)#read_result = self.plc.ReadBool("Y79")read_result = self.plc.ReadBool("L801")read_result3 = self.plc.ReadBool("X2F")#self._log(f"Y79读取结果: 成功={read_result.IsSuccess} 状态={read_result.Content}")#logging.info(f"Y79读取结果: 成功={read_result.IsSuccess} 状态={read_result.Content}")#logging.info(f"成功读取到Y79状态:{read_result.Content}")#logging.info(f"[{datetime.now().strftime('%H:%M:%S')}],Recive PLC Y79 Status is:{read_result.IsSuccess}")Time_Tim=datetime.now().strftime('%H:%M:%S')if read_result.Content is False:print("Content is False")    #logging.info(f"[{datetime.now().strftime('%H:%M:%S')}],PLC No Command")if read_result.Content is True:time.sleep(0.005)#print("Content is True")#logging.info(f"[{Time_Tim}] Content is True")#log_entry = f"[{Time_Tim}] Content is True\n"#logging.info(f"[{datetime.now().strftime('%H:%M:%S')}],Recive PLC Start Command")                if read_result.IsSuccess:current_state = read_result.Content# 精确的上升沿检测if current_state and not self.last_y79_state:#self._log("检测到Y79上升沿,触发自动命令")logging.info(f"Check PLC Start Command,UI Start")#self.start_auto_command#self.Recive_PLC_start_commandself.start_auto_command()  ###Tim Modifyself.last_y79_state = current_stateif read_result3.Content is False:time.sleep(0.00001)# print("Content3 is False,Area Sensor On")    # global Ares_Sensor  # 使用全局变量# Ares_Sensor = 1# print(Ares_Sensor)if read_result3.Content is True:time.sleep(0.005) #print("222Content3 is False,Area Sensor On")      #     if read_result3.IsSuccess:#         print("333Content3 is False,Area Sensor On") #         current_state3 = read_result.Content3#         # 精确的上升沿检测#         if current_state3 and not self.last_X2F_state:#             #self._log("检测到Y79上升沿,触发自动命令")#             logging.info(f"Check PLC Area Sensor  Command,UI Start")#             print("444Content3 is False,Area Sensor On") #             self.send_robot_command_Area_Sensor()  #########         self.last_X2F_state = current_state3else:#self._log(f"通信失败: {read_result.Message}")#  logging.info(f"Recived PLC Area Sensor ...")#  print("Content PLC OK ,Area Sensor is On")    #  SERVER_IP = "192.168.0.150"   #192.168.0.1#  SERVER_PORT = 5670  # 创建TCP服务器#  server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#  server.bind((SERVER_IP, SERVER_PORT))#  server.listen(1)#  print(f"Server OK,Waiting Robot Connect...")# 接受EPSON控制器连接#  conn, addr = server.accept()#  print(f"Robot Connected: {addr}")global Ares_Sensor  # 使用全局变量Ares_Sensor = 0                          ##3Area Sensor On  1   off  0if Ares_Sensor == 1:#print(Ares_Sensor)try: # 创建TCP服务器 server = socket.socket(socket.AF_INET,  socket.SOCK_STREAM) # 绑定IP和端口 server.bind((SERVER_IP,  SERVER_PORT)) # 开始监听,最大连接数为1 server.listen(1)  print(f"Server OK,Waiting Robot Connect...") # 接受客户端连接 conn, addr = server.accept()  print(f"Robot Connected: {addr}") # 使用全局变量 Ares_Sensor = 1 if Ares_Sensor == 1: print(Ares_Sensor) # 定义命令列表 commands222 = [ "STOP",    # 紧急停止  "PAUSE",   # 暂停运行 "RESUME",  # 恢复运行 "STATUS",  # 请求状态反馈 "RESET"    # 复位错误 ] commands3333 = [ "STOP" ,1  # 紧急停止  ] # 要发送的命令列表 #commands = ["STOP", "PAUSE", "RESUME"] commands = ["PAUSE"] index = 0 #while True: for aaaa in range(1):    # 获取当前要发送的命令 cmd = commands[index % len(commands)] + "\n" try: # 发送命令 conn.sendall(cmd.encode('utf-8'))   #  t66=((cmd)+"\r\n")#conn.sendall((cmd)+"\n".encode())  #conn.sendall((cmd)+"\r\n".encode('utf-8'))  print(f"[{time.strftime('%H:%M:%S')}]  Send OK。。。。。。 {cmd}") except socket.error  as e: print(f"Send error: {e}") break index += 1 aaaa+=1print(aaaa)# 暂停一段时间 time.sleep(0.0001)  # 修复括号未关闭的问题except socket.error  as e: print(f"Socket error: {e}") finally: # 关闭服务器和连接 if 'server' in locals(): server.close()  if 'conn' in locals(): conn.close()  time.sleep(0.0001)                  except Exception as e:#self._log(f"监测异常: {str(e)}")logging.info(f"Error to PLC,Message is : {str(e)}")finally:self.parent.after(333, self._monitor_y79)def _check_connection(self):"""工业级连接状态验证"""try:return self.plc.ConnectServer().IsSuccessexcept:return Falsedef start_auto_command(self):"""修正后的自动控制流程,确保仅运行一次"""logging.info("Start button triggered, running command sequence...")time.sleep(0.00006)# 确保仅执行一次流程if not hasattr(self, '_is_running') or not self._is_running:self._is_running = Truetry:self.Recive_PLC_start_command()  # 执行主流程finally:self._is_running = Falsedef _safe_write(self, address, value, data_type):"""通用安全写入模板"""try:if data_type == 'float':result = self.plc.WriteFloat(address, value)elif data_type == 'int32':result = self.plc.WriteInt32(address, value)elif data_type == 'bool':result = self.plc.Write(address, [value])if not result.IsSuccess:print(f"Write {address} NG: {result.Message}")except Exception as e:print(f"Write NG,Message is : {str(e)}")def check_y79_status(self):try:if self.plc:# 读取Y79状态(注意地址格式需要根据实际PLC配置调整)read_result = self.plc.ReadBool("Y79")if read_result.IsSuccess and read_result.Content:self.start_auto_command()finally:# 持续监控self.parent.after(500, self.check_y79_status)def start_Robot_command(self):"""2025版自动控制流程"""  #StartTim1Tim000Tim111Tim222Tim888Tim##print("Running Command ...")time.sleep (0.00006)app_path = r"C:\Users\ShineTek\AppData\Local\Programs\Python\Python37\Python.exe E:\Tim_Study\Python_Code\V5_20250312_Robot_Client_UI_Control.py"try:# 启动新进程并保存引用self.app3_process = subprocess.Popen(app_path)logging.info("Launched start_Robot_command application successfully.")except Exception as e:messagebox.showerror("Error", f"Failed to launch start_Robot_command application: {e}")logging.error(f"Failed to launch start_Robot_command application: {e}")  def start_Falco_command(self):"""2025版自动控制流程"""##print("Running Command ...")time.sleep (0.00006)#self.Recive_PLC_start_command()  ###Tim Modify# 保持原有写入逻辑#self._safe_write("D390", 7777.888, 'float')#self._safe_write("D397", 55, 'int32')#self._safe_write("M260", True, 'bool')def start_PLC_command(self):"""2025版自动控制流程"""##print("Running PLC Command ...")app_path = r"C:\Users\ShineTek\AppData\Local\Programs\Python\Python37\Python.exe E:\Tim_Study\Python_Code\V6_PLC_BaseOn_Ali_Show_Picture666.py"try:# 启动新进程并保存引用self.app3_process = subprocess.Popen(app_path)logging.info("Launched start_PLC_command application successfully.")except Exception as e:messagebox.showerror("Error", f"Failed to launch start_PLC_command application: {e}")logging.error(f"Failed to launch start_PLC_command application: {e}")  def save_settings(self):"""增强型配置保存方法"""config = {'version': 1.0,'offsets': {'x': self.custom_command_entry5.get(),'y': self.custom_command_entry6.get(),'u': self.custom_command_entry7.get()}}try:# 确保目录存在os.makedirs(os.path.dirname(self.CONFIG_PATH), exist_ok=True)with open(self.CONFIG_PATH, 'w') as f:json.dump(config, f, indent=2)#logging.info("配置保存成功")logging.info("Config Save")except Exception as e:logging.error(f"Save Config FAil,Message is: {str(e)}")messagebox.showerror("Error", f"Can not Save Config:\n{str(e)}")#logging.error(f"保存配置失败: {str(e)}")#messagebox.showerror("错误", f"无法保存配置:\n{str(e)}")def load_settings(self):"""增强型配置加载方法"""try:if os.path.exists(self.CONFIG_PATH):with open(self.CONFIG_PATH, 'r') as f:config = json.load(f)# 处理旧版本配置文件if 'offsets' in config:  # 新版本结构offsets = config['offsets']else:  # 兼容旧版本offsets = config# 设置输入框值(带空值保护)self.custom_command_entry5.delete(0, tk.END)self.custom_command_entry5.insert(0, offsets.get('x', ''))self.custom_command_entry6.delete(0, tk.END)self.custom_command_entry6.insert(0, offsets.get('y', ''))self.custom_command_entry7.delete(0, tk.END)self.custom_command_entry7.insert(0, offsets.get('u', ''))except json.JSONDecodeError:#logging.warning("配置文件格式错误,已重置")logging.warning("Config Format Error,Loading Def Config File")self._create_default_config()except Exception as e:#logging.error(f"加载配置失败: {str(e)}")#messagebox.showwarning("警告", "配置加载失败,已恢复默认值")    logging.error(f"Loading Config Fail,Message is: {str(e)}")messagebox.showwarning("Waring", "Loading Config Fail,Loading Def Config File")    def _create_default_config(self):"""创建默认配置文件"""default_config = {'version': 1.0,'offsets': {'x': "0.0",'y': "0.0",'u': "0.0"}}try:with open(self.CONFIG_PATH, 'w') as f:json.dump(default_config, f, indent=2)except Exception as e:logging.error(f"Great Def Config Fail,Message is: {str(e)}")def update_gauges(self):# 从实际数据源获取值speed = random.randint(0,100)temp = random.randint(0,100)#self.speed_gauge.update_value(speed)#self.temp_gauge.update_value(temp)self.root.after(1000, self.update_gauges)def apply_point_limit_change(self):"""应用数据点数量限制的变更"""try:new_limit = int(self.point_entry.get())if new_limit > 0:self.point_limit = new_limit# 立即更新显示self.update_display()else:messagebox.showwarning("输入无效", "数据点数量必须大于0")except ValueError:messagebox.showerror("输入错误", "请输入有效的整数")def write_all_offsets(self):global Offset_X, Offset_Y, Offset_U# 获取输入值并验证try:Offset_X = float(self.custom_command_entry5.get()) if self.custom_command_entry5.get() else NoneOffset_Y = float(self.custom_command_entry6.get()) if self.custom_command_entry6.get() else NoneOffset_U = float(self.custom_command_entry7.get()) if self.custom_command_entry7.get() else Noneexcept ValueError:messagebox.showerror("错误", "请输入有效的数字")return# 写入日志log_msg = f"Offset updated - X: {Offset_X}, Y: {Offset_Y}, U: {Offset_U}"logging.info(log_msg)# 更新界面##    self.robot_data_text.yview_moveto(1)##    self.robot_char_text.insert(tk.END, f"{datetime.now().strftime('%H:%M:%S')} {log_msg}\n")##    self.robot_char_text.yview_moveto(1)def read_last_n_records(self, file_path, n=5):"""读取文件中最后n条有效数据记录"""data = []try:with open(file_path, 'r') as f:# 读取所有行lines = f.readlines()# 倒序查找有效数据,最多检查最后20行for line in reversed(lines[-20:]) :if "Tim" in line:try:# 使用正则表达式提取数值import repos_match = re.search(r'Tim([-\d.]+)Tim([-\d.]+)Tim([-\d.]+)Tim', line)if pos_match:x, y, z = map(float, pos_match.groups())data.append((x, y, z))if len(data) >= n:break  # 达到所需数据量后停止搜索except Exception as e:logging.error(f"解析行失败: {str(e)}")# 返回按时间顺序排列的数据return data[::-1]except FileNotFoundError:logging.error("轨迹文件未找到,请确认路径是否正确")return []except Exception as e:logging.error(f"读取文件时发生错误: {str(e)}")return []def read_trajectory_data(self, file_path):"""使用正则表达式增强版轨迹读取"""data = []try:with open(file_path, 'r') as f:for line in f:if "Current_POS_is:" in line:try:import repos_match = re.search(r'X:([\-0-9.]+)Y:([\-0-9.]+)Z:([\-0-9.]+)U:([\-0-9.]+)', line)if pos_match:x, y, z, u = map(float, pos_match.groups())data.append((x, y, z, u))except Exception as e:logging.error(f"解析行失败: {str(e)}")return dataexcept FileNotFoundError:logging.error("轨迹文件未找到,请确认路径是否正确")return []def show_animation(self):"""显示高科技风格的3D轨迹动画"""file_path = r'C:\Log\v555.txt'# 验证文件路径if not os.path.exists(file_path):messagebox.showerror("文件错误", f"轨迹文件未找到\n路径: {file_path}")logging.error(f"轨迹文件不存在: {file_path}")returntrajectory_data = self.read_trajectory_data(file_path)if not trajectory_data:logging.warning("没有读取到有效轨迹数据")return# 创建新窗口用于显示动画animation_window = tk.Toplevel(self.root)animation_window.title("Robot Trajectory Animation")fig = Figure(figsize=(6, 4), dpi=100)# 设置中文字体和负号显示from matplotlib import rcParamsrcParams['font.sans-serif'] = ['SimHei']  # 使用黑体以支持中文rcParams['axes.unicode_minus'] = False  # 正常显示负号ax = fig.add_subplot(111, projection='3d')  # 启用3D绘图ax.set_title("3D")ax.set_xlabel("X Position")ax.set_ylabel("Y Position")ax.set_zlabel("Z Position")  # 添加Z轴标签ax.grid(True)ax.set_facecolor('#f0f0f0')# 修正后的坐标轴背景颜色设置ax.xaxis.pane.fill = Trueax.xaxis.pane.set_alpha(0.94)ax.yaxis.pane.fill = Trueax.yaxis.pane.set_alpha(0.90)ax.zaxis.pane.fill = Trueax.zaxis.pane.set_alpha(0.85)# 设置坐标轴面板颜色渐变ax.xaxis.pane.set_facecolor((0.94, 0.94, 0.94))ax.yaxis.pane.set_facecolor((0.90, 0.90, 0.90))ax.zaxis.pane.set_facecolor((0.85, 0.85, 0.85))canvas = FigureCanvasTkAgg(fig, master=animation_window)canvas.draw()canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)# 使用颜色映射来表示时间进程from matplotlib import cmcolors = [cm.viridis(i / len(trajectory_data)) for i in range(len(trajectory_data))]# 创建轨迹线对象line, = ax.plot([], [], [], lw=2, label='')  # 初始化3D线条  实时轨迹yellow_line, = ax.plot([], [], [], c='gold', lw=2, label='His')  # 历史路径标签# 创建当前点标记current_point, = ax.plot([], [], [], 'ro', markersize=10, label='Cur')  # 当前位置标签# 创建轨迹尾迹trail, = ax.plot([], [], [], c='blue', alpha=0.3, lw=2, label='...')  # 轨迹尾迹标签# 添加图例说明ax.legend(loc='upper left', fontsize=12, bbox_to_anchor=(0.0, 0.9))def init():xs = [d[0] for d in trajectory_data]ys = [d[1] for d in trajectory_data]zs = [d[2] for d in trajectory_data]min_range = 20  # 最小显示范围ax.set_xlim(min(xs) - 5, max(xs) + 5 if max(xs)-min(xs) > min_range else min(xs) + min_range)ax.set_ylim(min(ys) - 5, max(ys) + 5 if max(ys)-min(ys) > min_range else min(ys) + min_range)ax.set_zlim(min(zs) - 5, max(zs) + 5 if max(zs)-min(zs) > min_range else min(zs) + min_range)ax.view_init(elev=20, azim=200)  # 默认视角return line, yellow_line, current_point, traildef update(frame):# 提取当前帧前的所有X、Y、Z值x_values = [d[0] for d in trajectory_data[:frame+1]]y_values = [d[1] for d in trajectory_data[:frame+1]]z_values = [d[2] for d in trajectory_data[:frame+1]]  # 提取Z值# 更新轨迹线line.set_data(x_values, y_values)line.set_3d_properties(z_values)line.set_color(colors[frame])  # 设置当前线段的颜色# 更新黄色轨迹线(现为历史路径)yellow_x = x_values[:max(0, frame-10)]yellow_y = y_values[:max(0, frame-10)]yellow_z = z_values[:max(0, frame-10)]yellow_line.set_data(yellow_x, yellow_y)yellow_line.set_3d_properties(yellow_z)# 更新当前点标记current_point.set_data([x_values[-1]], [y_values[-1]])current_point.set_3d_properties([z_values[-1]])# 更新轨迹尾迹(仅显示最近的20个点)trail_start = max(0, frame-5)trail.set_data(x_values[trail_start:], y_values[trail_start:])trail.set_3d_properties(z_values[trail_start:])trail.set_alpha(np.linspace(0.2, 0.8, frame - trail_start + 1)[-1])# 动态更新标题显示当前帧信息#ax.set_title(f"智能制造演示 | 当前帧: {frame} | X:{x_values[-1]:.2f}, Y:{y_values[-1]:.2f}, Z:{z_values[-1]:.2f} (mm)")ax.set_title(f"3D")# 每50帧自动调整视角if frame % 50 == 0:ax.view_init(elev=20, azim=35 + frame//10)return line, yellow_line, current_point, trailfrom matplotlib.animation import FuncAnimationani = FuncAnimation(fig, update, frames=len(trajectory_data), init_func=init,blit=True, interval=250, repeat=False)  # 运行速度降为原始速度的 1/5  运行速度ani._start()  # 使用TkAgg推荐的启动方式# 添加动画控制面板control_frame = tk.Frame(animation_window)control_frame.pack(side=tk.BOTTOM, fill=tk.X)# 添加动画控制按钮btn_frame = tk.Frame(control_frame)btn_frame.pack(pady=10)def toggle_animation():if ani.event_source is None:returnif ani.event_source.is_running():ani.event_source.stop()toggle_btn.config(text="Play")else:ani.event_source.start()toggle_btn.config(text="Pause")toggle_btn.config(command=toggle_animation)def reset_animation():ani.event_source.stop()init()toggle_btn.config(text="Play")reset_btn = tk.Button(btn_frame, text="Reset", command=reset_animation,bg="#FFA500", fg="white", width=6, font=("Segoe UI", 10))reset_btn.pack(side=tk.LEFT, padx=5)close_btn = tk.Button(btn_frame, text="Close", command=animation_window.destroy,bg="#C0C0C0", fg="black", width=6, font=("Segoe UI", 10))close_btn.pack(side=tk.RIGHT, padx=5)#C:\Users\SKD\AppData\Local\Programs\Python\Python311\Scripts\pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pyautoguiif __name__ == "__main__":  root = tk.Tk()  app = TCPClientApp(root)  root.mainloop()

Robot

 


------------
Process.prg
------------Function Alignment_TCP_212GoTo lblOpenPort
lblOpenPort:CloseNet #212Print "Waiting Servers Open ", Time$SetNet #212, "192.168.0.150", 7777, CRLF, NONE, 0OpenNet #212 As ClientWaitNet #212Print "IP:192.168.0.150 Port:7777 Open at ", Time$MemOff 18  'Clean''14:28:13  Tim-682.789Tim289.271Tim89.7095TimOKTim888888'Recive data  DOWNTimNoneAUOTim11.999Tim1061.1652Tim1612.829Tim90.005055TimDo'MemOn 18If MemSw(18) = Off ThenWait 0.6Status_212 = ChkNet(212)Print "Recive data Len/Status is ", Status_212If Status_212 > 0 And Status_212 < 62 ThenRead #212, Data_212$, Status_212Print "Recive data1 ", Status_212, "Recive data2 ", Data_212$, "Recive data3 ", Data_212_Read'ParseStr Data_212$, PData_212$(), "Tim"  '锟街革拷锟街凤拷'Print "Recive data sp is ", PData_212$(0), PData_212$(1), PData_212$(2)MemOn 18ElseIf Status_212 > 62 ThenPrint "Recive len is so long"String msg2$, title2$Integer mFlag2s, answer2msg2$ = "Recive len is so long" + CRLFmsg2$ = msg2$ + "Press Y or N to Exit..." + CRLFmsg2$ = msg2$ + "Press N or Y to Exit..." + CRLFtitle2$ = "Recive Title"mFlag2s = MB_YESNO + MB_ICONQUESTIONMsgBox msg2$, mFlag2s, title2$, answer2If answer2 = IDNO Or answer2 = IDYES ThenQuit AllEndIfExit DoElseIf Status_212 = -3 ThenMemOff 2 'Ethernet Connect StatusPrint "Ethernet is Close,Pls Check it...", Time$GoTo lblOpenPortEndIfEndIfIf MemSw(18) = On ThenWait 0.022ParseStr Data_212$, PData_212$(), "Tim"  '锟街革拷锟街凤拷'Print "Recive data sp is ", PData_212$(0), PData_212$(1), PData_212$(2), PData_212$(3), PData_212$(4), PData_212$(5)''Order:1=Ref_A1 2=Ref_A2 3=Ref_A3 4=Ref_A4 5=Start Index:888888	Order = Val(PData_212$(1))'Index = Val(PData_212$(5))Pitch = Val(PData_212$(2))''RIGHTTim2Tim11.999Tim1061.1652Tim1612.829Tim90.005055Tim  ''if Pdate 0 1 2 = None, No Action  ''Data_212_Start$ = PData_212$(0)=LEFRUPDOWNSAVE   ''Data_212_Start$ = PData_212$(1)=Order    ''Data_212_Start$ = PData_212$(2)=PitchIf Order = 0 ThenPrint "Home Pos Send", P986Print #212, "Home Pos Send", P986Go P986 'Home_RefElseIf Order = 1 ThenPrint "Go Ref_A1"Wait 0.3P987 = RealPosPrint #212, "Go Ref_A1", P987Go P985 'A1_RefElseIf Order = 2 ThenPrint "Go Ref_A2"Wait 0.3P987 = RealPosPrint #212, "Go Ref_A2", P987Go P984 'A2_Ref		EndIfWait 0.88
'CX_Here = CX(Here)CY_Here = CY(Here)CZ_Here = CZ(Here)CU_Here = CU(Here)Print "Now pos is :", HereData_212_Start$ = PData_212$(0)If Data_212_Start$ = "UP" ThenPrint "Recive UP = ", Data_212_Start$Go XY(CX(Here) + Pitch, CY(Here), CZ(Here), CU(Here))Print "Now pos is :", HereElseIf Data_212_Start$ = "LEF" ThenPrint "Recive Left = ", Data_212_Start$Go XY(CX(Here), CY(Here) + Pitch, CZ(Here), CU(Here))Print "Now pos is :", HereElseIf Data_212_Start$ = "RIGH" ThenPrint "Recive Right = ", Data_212_Start$Go XY(CX(Here), CY(Here) - Pitch, CZ(Here), CU(Here))Print "Now pos is :", HereElseIf Data_212_Start$ = "DOWN" ThenPrint "Recive Down = ", Data_212_Start$Go XY(CX(Here) - Pitch, CY(Here), CZ(Here), CU(Here))Print "Now pos is :", HereElseIf Data_212_Start$ = "CW" ThenPrint "Recive CW = ", Data_212_Start$Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) - Pitch)Print "Now pos is :", HereElseIf Data_212_Start$ = "CCW" ThenPrint "Recive CCW = ", Data_212_Start$Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) + Pitch)Print "Now pos is :", HereElseIf Data_212_Start$ = "SAVE" ThenPrint "Saving Aligment OK Pos ", HereString msg$, title$Integer mFlags, answermsg$ = "Save Pos" + CRLFmsg$ = msg$ + "Are U Sure?"title$ = "Setting 2 Save"mFlags = MB_YESNO + MB_ICONQUESTIONMsgBox msg$, mFlags, title$, answerIf answer = IDNO ThenQuit AllElseIf answer = IDYES ThenPLabel 988, "Aligment"Here P988Print "Save Pos ", CRLF, HerePrint #212, "Save Pos ", CRLF, HereEndIfEndIfSavePoints "rbtPoints_212.pts"Print "Eecive data OK...Start 2 Waiting Order..."MemOff 18  'CleanEndIfPrint #212, "---", Time$Print "---", Time$MemOff 18  'CleanLoopErrorHandle:'errnum = ErrPrint "ERROR", errnumQuit All
FendFunction WelcomeDoIf MemSw(2) = Off ThenPrint "Welcome 2 Use"String msg$, title$Integer mFlags, answermsg$ = "Welcome 2 Use" + CRLFmsg$ = msg$ + "Do not Press Or Press Y to Continue..." + CRLFmsg$ = msg$ + "Press N to Exit..." + CRLFtitle$ = "Robot Control Tool"mFlags = MB_YESNO + MB_ICONQUESTIONMsgBox msg$, mFlags, title$, answerIf answer = IDNO ThenQuit AllEndIfEndIf'CloseNet #212Exit DoLoop
Fend
Function Recive_lendayu62DoIf Status_212 > 62 ThenPrint "Recive len is so long"String msg$, title$Integer mFlags, answermsg$ = "Recive len is so long" + CRLFmsg$ = msg$ + "Press Y to Continue..." + CRLFmsg$ = msg$ + "Press N to Exit..." + CRLFtitle$ = "Recive Title"mFlags = MB_YESNO + MB_ICONQUESTIONMsgBox msg$, mFlags, title$, answerIf answer = IDNO Or answer = IDYES ThenQuit AllEndIfEndIfExit DoLoop
FendFunction TCP_209_AreaSensor_As_Client' 锟截憋拷锟斤拷锟斤拷锟斤拷锟紼S THENCloseNet #209Print "#209 Config Waiting Servers Open ", Time$' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟絆pen ", Time$SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷, 0OpenNet #209 As Client' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0WaitNet #209Print "#209 Config IP:192.168.0.150 Port:5678 Open at ", Time$' 锟饺达拷1锟斤拷 Wait 1Do' 锟截憋拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0CloseNet #209Print "#209  Waiting Servers Open ", Time$' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟?, TIME$SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷E, 0OpenNet #209 As Client' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟?29Tim90.005055Tim  WaitNet #209Print "#209  IP:192.168.0.150 Port:5678 Open at ", Time$' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟捷筹拷锟絠me$Area_Sensor___ = ChkNet(209)Print "#209 Recived Lens: ", Area_Sensor___' 锟斤拷锟斤拷锟斤拷锟斤拷萁锟斤拷锟?If ChkNet(209) > 0 Then' 锟斤拷取一锟斤拷锟斤拷锟斤拷 ''Line Input #209, Area_Sensor_$Read #209, Area_Sensor_$, Area_Sensor___Print "data is : ", Area_Sensor_$' 锟斤拷锟斤拷锟斤拷盏锟斤拷锟斤拷锟斤拷锟?Select Case UCase$(Trim$(Area_Sensor_$))Case "PAUSE"Print "Pause"Pause ' 锟斤拷停 Case "RESET"Print "RESUME"Reset ' 锟斤拷锟斤拷锟斤拷锟阶刺?锟斤拷位锟斤拷锟斤拷 Case "STOP"Print "Motor_Off"Motor Off ' 锟截闭碉拷锟?Case "ESTOPON"Print "ESTOPON"'SafeguardOn ' 锟截闭碉拷锟?             'EStopOnCase "1"Print "Other command: ", Area_Sensor_$Motor OffSendEndIfIf Area_Sensor___ = -3 ThenPause ' 锟斤拷停'Motor OffString msg6_$, title_6$Integer mFlags_6, answer_6msg6_$ = "Waring" + CRLFmsg6_$ = msg6_$ + "Area Sensor !!!" + CRLFmsg6_$ = msg6_$ + "Area Sensor !!!" + CRLFmsg6_$ = msg6_$ + "Area Sensor !!!" + CRLFmsg6_$ = msg6_$ + " " + CRLFmsg6_$ = msg6_$ + "Press N to STOP !!!" + CRLFmsg6_$ = msg6_$ + "Press Y to Continue" + CRLFtitle_6$ = "Robot Control Tool"mFlags_6 = MB_YESNO + MB_ICONQUESTIONMsgBox msg6_$, mFlags_6, title_6$, answer_6If answer_6 = IDNO ThenQuit AllEndIfIf answer_6 = IDYES ThenWait 0.0001EndIfEndIfLoopFendFunction Big_TCP_212_RunmodeCloseNet #210SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0OpenNet #210 As ServerWaitNet #210Print "#210 Open at ", Time$MemOff RecvData  'CleanJump P988 LimZ (0) 'NG_Port	'Jump P988Off 9Off 8Wait 0.8Jump P999 LimZ (0) 'home_StandbyDoOff 9Off 8Wait 0.05  '<1 3 CycleIf MemSw(RecvData) = Off Thenstate211 = ChkNet(210)Print "Recived Lens: ", state211Print "For_Index:", For_LS_timIf state211 > 0 ThenIf For_LS_tim = 3 Then'cLANE 	 'Input #211, Data211$Print #210, Clean_Tim$Clean_Tim$ = ""Wait 2Input #210, Data210$Print Time$, " Recive data:  ", Data210$   'recive data				state211 = ChkNet(210)'Input #211, Data211$'Print Time$, " Recive data:  ", Data211$   'recive data'cLANE  okInput #210, Data211$Print Time$, " Recive data_Clean:  ", Data211$   'recive dataParseStr Data211$, Pdata211$(), "Tim"  'spilt dataMemOn RecvDataStart_String_211$ = Data211$'Start_Real_211 = Val(Start_String_211$) Start_Real_211 = Val(Right$(Start_String_211$, 6))Print "Start index:  ", Start_Real_211ElseIf For_LS_tim = 1 Or For_LS_tim = 2 ThenInput #210, Data211$Print Time$, " Recive data_Clean:  ", Data211$   'recive dataParseStr Data211$, Pdata211$(), "Tim"  'spilt dataMemOn RecvDataStart_String_211$ = Data211$'Start_Real_211 = Val(Start_String_211$) Start_Real_211 = Val(Right$(Start_String_211$, 6))Print "Start index:  ", Start_Real_211ElseIf For_LS_tim = 0 ThenInput #210, Data211$Print Time$, " Recive data:  ", Data211$   'recive dataParseStr Data211$, Pdata211$(), "Tim"  'spilt dataMemOn RecvDataStart_String_211$ = Data211$'Start_Real_211 = Val(Start_String_211$) Start_Real_211 = Val(Right$(Start_String_211$, 6))Print "Start index:  ", Start_Real_211EndIfElseIf state211 = -3 ThenPrint Time$, "Ethernet NG ,Pls Connect it."Print Time$, "Ethernet NG ,Pls Connect it.."Print Time$, "Ethernet NG ,Pls Connect it..."''	DoCloseNet #210SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0OpenNet #210 As ServerWaitNet #210Print "#210 Open at ", Time$If state211 <> -3 ThenQuit AllEndIfExit DoLoop''	EndIfEndIfIf MemSw(RecvData) = On And For_LS_tim = 0 Or Start_Real_211 = 888888 Or Start_Real_211 = 666666 ThenHome_POS_Index = 0'Print "x:", Pdata211$(0), "y:", Pdata211$(1), "u:", Pdata211$(2)X_String_211$ = Pdata211$(0)X_Real_211 = Val(X_String_211$)Y_String_211$ = Pdata211$(1)Y_Real_211 = Val(Y_String_211$)U_String_211$ = Pdata211$(2)U_Real_211 = Val(U_String_211$)If U_Real_211 > 0 ThenU_Real_211_Angle = -U_Real_211ElseIf U_Real_211 < 0 ThenU_Real_211_Angle = -U_Real_211EndIf''	Off_String_211$ = Pdata211$(3)''	Print "Off_String_211$", (Off_String_211$)''	If Off_String_211$ = "Motor_off" Then''		Print #210, "Motor_Off"''		Print "Off"''   	Motor Off''	EndIf'Print U_Real_211_AnglePrint "Spilt data:  ", "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211_AnglePrint #210, "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211_Angle
''		
'			X_Max = 542.666  -386 -372       -355
'			X_Min = -990.222 -915            -805
'			Y_Max = 836.666  217  206  286   310
'			Y_Min = -122.222  -400  -400     -124 If X_Real_211 >= -805 And X_Real_211 <= -355 And Y_Real_211 >= -124 And Y_Real_211 <= 310 ThenP993 = XY(X_Real_211, Y_Real_211, -6.6666, U_Real_211_Angle)Jump P993  'Vision_Pre''Go XY(X_Real_211 + 20, Y_Real_211, -1.666, U_Real_211_Angle)ElsePrint "Error 4007, Target position out of range"String msg$, title$Integer mFlags, answermsg$ = "There has An Error" + CRLFmsg$ = msg$ + "Press Y to Close and Call Tim"title$ = "Error Message From Robot"mFlags = MB_YESNO + MB_ICONQUESTIONMsgBox msg$, mFlags, title$, answerIf answer = IDNO ThenQuit AllEndIfCloseNet #210Exit DoEndIfIf U_Real_211_Angle >= 0 ThenX_Real_211 = X_Real_211 + 0Y_Real_211 = Y_Real_211 + 0U_Real_211_Angle = U_Real_211_Angle + 0
''			ElseIf U_Real_211_Angle >= -16 And U_Real_211_Angle <= 45 Then
''				X_Real_211 = X_Real_211 + 21.237
''				Y_Real_211 = Y_Real_211 + -6.463
''				U_Real_211_Angle = U_Real_211_Angle + -3.065
''			ElseIf U_Real_211_Angle >= -46 And U_Real_211_Angle <= 75 Then
''				X_Real_211 = X_Real_211 + 24.166
''				Y_Real_211 = Y_Real_211 + -10.672
''				U_Real_211_Angle = U_Real_211_Angle + -2.829
''			ElseIf U_Real_211_Angle >= -76 And U_Real_211_Angle <= 105 Then
''				X_Real_211 = X_Real_211 + 25.630
''				Y_Real_211 = Y_Real_211 + -14.882
''				U_Real_211_Angle = U_Real_211_Angle + -2.592
''			ElseIf U_Real_211_Angle >= -106 And U_Real_211_Angle <= 135 Then
''				X_Real_211 = X_Real_211 + 20.834
''				Y_Real_211 = Y_Real_211 + -13.221
''				U_Real_211_Angle = U_Real_211_Angle + -2.728
''			ElseIf U_Real_211_Angle >= -136 And U_Real_211_Angle <= 165 Then
''				X_Real_211 = X_Real_211 + 16.037
''				Y_Real_211 = Y_Real_211 + -11.559
''				U_Real_211_Angle = U_Real_211_Angle + -2.864
''			ElseIf U_Real_211_Angle >= -166 And U_Real_211_Angle <= 195 Then
''				X_Real_211 = X_Real_211 + 11.241
''				Y_Real_211 = Y_Real_211 + -10.063
''				U_Real_211_Angle = U_Real_211_Angle + -2.728
''			ElseIf U_Real_211_Angle >= -196 And U_Real_211_Angle <= 225 Then
''				X_Real_211 = X_Real_211 + 12.060
''				Y_Real_211 = Y_Real_211 + -7.852
''				U_Real_211_Angle = U_Real_211_Angle + -2.852
''			ElseIf U_Real_211_Angle >= -226 And U_Real_211_Angle <= 255 Then
''				X_Real_211 = X_Real_211 + 12.880
''				Y_Real_211 = Y_Real_211 + -5.641
''				U_Real_211_Angle = U_Real_211_Angle + -2.976
''			ElseIf U_Real_211_Angle >= -256 And U_Real_211_Angle <= 285 Then
''				X_Real_211 = X_Real_211 + 13.699
''				Y_Real_211 = Y_Real_211 + 2.791
''				U_Real_211_Angle = U_Real_211_Angle + -2.976
''			ElseIf U_Real_211_Angle >= -286 And U_Real_211_Angle <= 315 Then
''				X_Real_211 = X_Real_211 + 16.212
''				Y_Real_211 = Y_Real_211 + -0.529
''				U_Real_211_Angle = U_Real_211_Angle + -3.102
''			ElseIf U_Real_211_Angle >= -316 And U_Real_211_Angle <= 345 Then
''				X_Real_211 = X_Real_211 + 18.724
''				Y_Real_211 = Y_Real_211 + -3.849
''				U_Real_211_Angle = U_Real_211_Angle + -3.228
''			ElseIf U_Real_211_Angle >= -346 And U_Real_211_Angle <= -15 Then
''				X_Real_211 = X_Real_211 + +20.082
''				Y_Real_211 = Y_Real_211 + 0.812
''				U_Real_211_Angle = U_Real_211_Angle + -3.302EndIf'ADD	Go XY(X_Real_211, Y_Real_211, -247.387, U_Real_211_Angle) 'Down   -247.387On 8												  'VacuumWait 3.8''锟斤拷Go XY(X_Real_211, Y_Real_211, -116, U_Real_211_Angle) 'Up'Jump S_put'Go Put'Wait 1.8''Jump Put2Jump P983 'PlaceWait 3.8Off 8On 9Wait 0.6Off 9'ADDJump P999 'home_StandbyPrint "home_Pos"Print #210, "Home_Pos", "Tim", "OK", "Tim"Home_POS_Index = 1For_LS_tim = 1 + For_LS_timEndIfIf For_LS_tim = 3 ThenFor_LS_tim = 1EndIfMemOff RecvDataIf Home_POS_Index = 1 ThenWait 0.00001''Print #210, "Home"EndIfLoopFendFunction Rbt_PC216CloseNet #216OpenNet #216 As ServerWaitNet #216Print "Open #216 at ", Time$For_LS = 1Print For_LSDo'Print #216, "Send data from robot "Wait 3Print For_LSstate216 = ChkNet(216)Print "ChkNet= data", state216If state216 > 0 And For_LS = 2 Then'If state216 = 23 Or state216 = 25 ThenWait 0.01'Print "Send data XXX"'send_Data$ = "XXXYYUUU"'Print #216, send_Data$'Print #216, "ABCC"'Input #216, Response$'Print "ChkNet(216) Line Input: "'Print Response$Print "Has data"Read #216, Data$, state216DataLS$ = Data$Print #216, Data$Print "ChkNet(216) Read: "Print Data$Print state216Integer fileNum2, i, jfileNum2 = FreeFileAOpen "D:\V80.txt" As #fileNum2Line Input #fileNum2, Read_file$Y_Tim_Real = Val(Read_file$)Print "Y:", Y_Tim_RealPrint "---"Close #fileNum2'Input #216, Data$'Print "Receive data: ", Data$, Time$'ParseStr Data$, Pdata_x$(), "XX"'X_Tim_Real = Val(Pdata_x$)'Print "X:", X_Tim_RealX_Tim_Real = Val(Left$(Data$, 8))Print "X:", X_Tim_Real,ParseStr DataLS$, Pdata_x$(), "YYY"Y_Tim_Real = Val(Pdata_x$)Print "Y:", Y_Tim_Real,U_Tim_Real = Val(Right$(DataLS$, 13))Print "U:", U_Tim_Real'Vision_Process			'Wait start_Awitch = TruePrint "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"'Call Rbt_PC216Print "Process_Going 2 St_Pick Pos"'Speed 100, 100, 100Go P993'Go P992'Speed 100, 100, 5Print "Process_St_Pick Pos"'Print Here'Go XY(X_Tim_Real, Y_Tim_Real, -246.628, 5)Print HereWait 0.1On 8'Wait Sw(8) = 1'Wait 1'Go P990    'OK POS_LSGo P992   'OK POSOff 8'Wait 1Go P993'Go pick'Print "Process_Pick Pos"			
'Vision_Process					'Read #216, Data$, numOfChars'numOfChars = ChkNet(216)'Print numOfCharsElseIf state216 = -3 ThenPrint "#216 Close ,Pls open #216 "ElseIf state216 = 0 ThenPrint "#216 Net no data ,Pls check it "' 锟斤拷止锟斤拷锟斤拷65536		ElseIf state216 > 0 And For_LS = 6 ThenFor_LS = 10ElseIf state216 > 0 And For_LS = 12 ThenFor_LS = 5
' 锟斤拷止锟斤拷锟斤拷65536	EndIfstate216 = 25
'		If Data$ = 3.15 Then
'			Select Pdata$(5)
'				Case "10000"
'					Print #216, "SHAKEHAND 10000"
'				Case "31"
'					Print #216, "SHAKEHAND 31"
'					Go P999
'			Send
'		EndIfFor_LS = 1 + For_LSLoopFendFunction Vision_ProcessDo'Wait start_Awitch = TruePrint "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"'Call Rbt_PC216Print "Process_Going 2 St_Pick Pos"'Speed 100, 100, 100Go S_pick'Speed 100, 100, 5Print "Process_St_Pick Pos"Print HereGo XY(X_Tim_Real, Y_Tim_Real, -216, 5)Print Here'Go pick'Print "Process_Pick Pos"Loop
Fend
Function FileDoPrint "File"Wait 2Integer fileNu, i, j'	fileNum = FreeFile'	WOpen "timTEST.DAT " As #fileNum'	For i = 0 To 100'Print #fileNum, i'Next I'Close #fileNum'........fileNu = FreeFileROpen "timTEST88.DAT" As #fileNuFor j = 4 To 8Input #fileNu, jPrint jNext jClose #fileNuLoopFend
Function tcpip_211_1CycleCloseNet #210SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0OpenNet #210 As ServerWaitNet #210Print "  #210 Open at ", Time$MemOff RecvData  'CleanFor_LS = 0DoWait 2If MemSw(RecvData) = Off Thenstate211 = ChkNet(210)Print "state211: ", state211Print "For_LS_tim", For_LS_timIf state211 > 0 And For_LS_tim = 0 ThenInput #210, Data211$Print Time$, " Recive data:  ", Data211$   'recive dataParseStr Data211$, Pdata211$(), "Tim"  'spilt dataMemOn RecvDataElseIf state211 = -3 ThenPrint "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟铰达拷"EndIfEndIfIf MemSw(RecvData) = On And For_LS_tim = 0 Then'Print "x:", Pdata211$(0), "y:", Pdata211$(1), "u:", Pdata211$(2)X_String_211$ = Pdata211$(0)X_Real_211 = Val(X_String_211$)Y_String_211$ = Pdata211$(1)Y_Real_211 = Val(Y_String_211$)U_String_211$ = Pdata211$(2)U_Real_211 = Val(U_String_211$)Print " Spilt data:  ", "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211Print #210, "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211Go XY(X_Real_211, Y_Real_211, -216, U_Real_211)Wait 3Go P993' 锟斤拷止锟斤拷锟斤拷65536		
'			If state211 > 0 And For_LS = 6 Then
'				For_LS_tim = 10
'			ElseIf state211 > 0 And For_LS = 12 Then
'				For_LS_tim = 5
'			EndIfFor_LS_tim = 2 + For_LS_timPrint "For_LS_tim222", For_LS_tim
' 锟斤拷止锟斤拷锟斤拷65536'			Select Pdata211$(0)
'				Case "Tim"
'					Print "SHAKEHAND 10000"
'				Case "31"
'					Print "SHAKEHAND 31"
'			SendEndIfMemOff RecvDataLoopFendFunction To_RobotPrint "To_Robot_锟斤拷始锟斤拷锟斤拷Robot 锟斤拷 PC 通讯锟斤拷锟斤拷"SetNet #205, "192.168.0.1", 2004, CRLF, NONE, 0OpenNet #205 As ServerPrint "To_Robot_锟皆凤拷锟斤拷锟斤拷锟斤拷式锟斤拷205锟剿匡拷"Print "To_Robot_锟饺达拷锟斤拷锟斤拷"WaitNet #205Print "To_Robot_锟斤拷锟接★拷锟斤拷锟斤拷"DoPrint "To_Robot_Robot 锟斤拷 PC 通讯锟斤拷锟斤拷锟斤拷锟叫★拷锟斤拷锟斤拷"Wait 1Print #205, "Robot used: ", h'Print #205, ""Print "Robot used: ", hATCLRWait 1'Print #205, "Axis Runing Status not 0 is OK : ", "X=", ATRQ(1), "/", "Y=", ATRQ(2), "/", "Z=", ATRQ(3), "/", "U=", ATRQ(4)   'Send Tor data2	Real statustimstatustim = ChkNet(205)If statustim > 0 ThenPrint "#205 锟斤拷锟斤拷锟斤拷"Print #205, "Robot used: ", hPrint #205, ""Print "From #205 Recive data  "Print #205, "send data From Robot 192.168.0.1:205"Wait .5Input #205, datattt$ElseIf statustim = -3 ThenPrint "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟斤拷锟铰打开斤拷锟斤拷头'Input #205, datatt$EndIfLoop
FendFunction ProcessDoPrint "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"Print "Process_Standby Pos"Go P999Print "Process_Pick_Standby Pos"Go S_pickPrint "Process_Pick Pos"Go pickOff 8Wait 1On 8Print "Vacuum"Print "Process_Pick_Standby Pos"Go S_pickPrint "Process_Put_Standby Pos"Go S_putPrint "Process_Put"Go PutOff 8Wait 1Print "Process_Put_Standby Pos"Go S_putWait .6On 9Off 9Print "blow"Loop
FendFunction Running_timeDoh = Time(0) '锟斤拷小时锟斤拷锟斤拷通锟斤拷时锟斤拷Print "Running_time_Robot 锟窖撅拷使锟斤拷: ", h, "小时 ", ",", " 1锟斤拷锟接回憋拷一锟斤拷"Wait 60Loop
Fend
Function Current_POSCloseNet #215Print "#215 Config Waiting Servers Open ", Time$SetNet #215, "192.168.0.150", 1122, CRLF, NONE, 0OpenNet #215 As ClientWaitNet #215Print "#215 Config IP:192.168.0.150 Port:1122 Open at ", Time$Wait 1Do'	CloseNet #215'	Print "#215  Waiting Servers Open ", Time$'	SetNet #215, "192.168.0.150", 1122, CRLF, NONE, 0'    OpenNet #215 As Client'    WaitNet #215'    Print "#215  IP:192.168.0.150 Port:1122 Open at ", Time$Check_215 = ChkNet(215)'    Print "#215  Recived Lens: ", Check_215' If ChkNet(215) > 0 Then'Print Time$, " Current_POS_is: ", "X:", CX_Here, " ,", "Y:", CY_Here, " ,", "Z:", CZ_Here, " ,", "U:", CU_HereWait 0.0003P982 = CurPos''Print CX(P982), CY(P982), CY(P982), CY(P982)Print #215, Time$, " Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)Print Time$, " Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)Integer fileNum6, XXX, YYY, ZZZ, UUUString ZZZ$, UUU$, XXX$, YYY$fileNum6 = FreeFileXXX = CX(P982)XXX$ = Str$(XXX)YYY = CY(P982)YYY$ = Str$(YYY)ZZZ = CZ(P982)ZZZ$ = Str$(ZZZ)UUU = CU(P982)UUU$ = Str$(UUU)AOpen "C:\log\V555.txt" As #fileNum6Write #fileNum6, Time$ + "Current_POS_is: " + "X:" + "" + XXX$ + "Y:" + "" + YYY$ + "Z:" + "" + ZZZ$ + "U:" + "" + UUU$ + CRLFPrint Time$, "--- Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)Close #fileNum6'	EndIfLoopFend
Function Move_Current_POSDoJump A2_Alignmnet_RefBMove XY(100, 0, -58.888, -45) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)Go A1_Alignmnet_RefBGo XY(-80.88, 0, -18.888, -180) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)Print "Running_"Wait 0.5Loop
Fend------------
Main.prg
------------' 
'Design By Tim
' 
Global Integer h, InData, OutData, start_Awitch, Long_Tim, For_LS, fileNum, RecvData, For_LS_tim
Global Real CX_Here, X_Tim_Real, Y_Tim_Real, U_Tim_Real
Global Real CY_Here
Global Real CZ_Here
Global Real CU_Here
Global String datattt$, Data$, DataLS$, Response$, X_Tim_string$, Y_Tim_String$, Data_Client$, send_Data$, Read_file$, Data211$, X_String_211$, Y_String_211$, U_String_211$, Start_String_211$, Clean_Tim$, Data210$
Global String Pdata_x$(100), Pdata_y$(100), Pdata$(100), Pdata211$(100)
Global Real state216, state21666, numOfChars, state_client, state211, X_Real_211, Y_Real_211, U_Real_211, U_Real_211_Angle, Start_Real_211
Global Real state212, Pitch, Area_Sensor___, III, Check_215
Global String Data_212$, PData_212$(100), Data_212_Start$, Off_String_211$, Area_Sensor_$, Area_Sensor___$
Global Integer errnum, Data_212_Read, Status_212, Index, Order, Home_POS_IndexFunction mainMotor OnPower HighSpeed 100  'Go Speed Tim on High ,Off Low	SpeedS 2000 'MAX 2000Print "Program Runing at: ", Time$Print "The current control device is:", CtrlDev, "  Remark锟斤拷21 PC锟斤拷22 Remote I/O锟斤拷26 Remote Ethernet锟斤拷29 Remote RS232C"Print "Waiting... "''Xqt Big_TCP_212_Runmode, Normal 'Big_Vison
''	Xqt Current_POS, Normal  'NoPause	Xqt Welcome, Normal  'NoPauseWelcomeXqt Recive_lendayu62, Normal  'Recive data Lens>62 Alarm'Xqt TCP_209_AreaSensor_As_Client, Normal 'Big_AreaSensor'Xqt To_Robot, Normal	'Xqt tcpip_208_Jog, Normal'Xqt tcpip_211_1Cycle, Normal'Xqt Rbt_PC216, Normal'Xqt Vision_Process, Normal'Xqt Process, Normal'Xqt Running_time, NoPause'Xqt Current_POS, Normal  'NoPause'Xqt Move_Current_POS, Normal  'NoPause	'Xqt Alignment_TCP_212, Normal  'Aligenmnet'Xqt Welcome, Normal'Xqt Recive_lendayu62, Normal'Xqt File, Normal	Fend

1.05m  


<?xml version="1.0" encoding="UTF-8"?>
<CalibInfo><CalibInputParam><CalibParam ParamName="CreateCalibTime" DataType="string"><ParamValue>2025-05-28 15:15:50</ParamValue></CalibParam><CalibParam ParamName="CalibType" DataType="string"><ParamValue>NPointCalib</ParamValue></CalibParam><CalibParam ParamName="TransNum" DataType="int"><ParamValue>9</ParamValue></CalibParam><CalibParam ParamName="RotNum" DataType="int"><ParamValue>0</ParamValue></CalibParam><CalibParam ParamName="CalibErrStatus" DataType="int"><ParamValue>0</ParamValue></CalibParam><CalibParam ParamName="TransError" DataType="float"><ParamValue>0.63482422</ParamValue></CalibParam><CalibParam ParamName="RotError" DataType="float"><ParamValue>-999</ParamValue></CalibParam><CalibParam ParamName="TransWorldError" DataType="float"><ParamValue>0.14751892</ParamValue></CalibParam><CalibParam ParamName="RotWorldError" DataType="float"><ParamValue>-999</ParamValue></CalibParam><CalibParam ParamName="PixelPrecisionX" DataType="float"><ParamValue>0.23190695</ParamValue></CalibParam><CalibParam ParamName="PixelPrecisionY" DataType="float"><ParamValue>0.2328483</ParamValue></CalibParam><CalibParam ParamName="PixelPrecision" DataType="float"><ParamValue>0.23237759</ParamValue></CalibParam><CalibPointFListParam ParamName="ImagePointLst" DataType="CalibPointList"><PointF><X>1327.212</X><Y>1867.099</Y><R>0</R></PointF><PointF><X>1499.212</X><Y>1867.099</Y><R>0</R></PointF><PointF><X>1671.212</X><Y>1867.099</Y><R>0</R></PointF><PointF><X>1671.212</X><Y>2039.99</Y><R>0</R></PointF><PointF><X>1499.212</X><Y>2039.99</Y><R>0</R></PointF><PointF><X>1327.212</X><Y>2039.99</Y><R>0</R></PointF><PointF><X>1327.212</X><Y>2212.1089</Y><R>0</R></PointF><PointF><X>1499.212</X><Y>2212.1089</Y><R>0</R></PointF><PointF><X>1671.212</X><Y>2212.1089</Y><R>0</R></PointF></CalibPointFListParam><CalibPointFListParam ParamName="WorldPointLst" DataType="CalibPointList"><PointF><X>-617.96002</X><Y>210.513</Y><R>-0.0572</R></PointF><PointF><X>-617.96002</X><Y>171.04201</Y><R>-0.0502</R></PointF><PointF><X>-617.96002</X><Y>130.737</Y><R>0.36719999</R></PointF><PointF><X>-658.18103</X><Y>130.737</Y><R>-0.033399999</R></PointF><PointF><X>-658.18103</X><Y>171.04201</Y><R>0.62330002</R></PointF><PointF><X>-658.18103</X><Y>210.513</Y><R>-0.0502</R></PointF><PointF><X>-698.29498</X><Y>210.513</Y><R>-0.044100001</R></PointF><PointF><X>-698.29498</X><Y>171.04201</Y><R>-0.0502</R></PointF><PointF><X>-698.29498</X><Y>130.737</Y><R>-0.050299998</R></PointF></CalibPointFListParam></CalibInputParam><CalibOutputParam><CalibParam ParamName="RotDirectionState" DataType="int"><ParamValue>-999</ParamValue></CalibParam><CalibParam ParamName="IsRightCoorA" DataType="int"><ParamValue>1</ParamValue></CalibParam><PointF ParamName="RotCenterImagePoint" DataType="CalibPointF"><RotCenterImagePointX>0</RotCenterImagePointX><RotCenterImagePointY>0</RotCenterImagePointY><RotCenterImageR>-999</RotCenterImageR></PointF><PointF ParamName="RotCenterWorldPoint" DataType="CalibPointF"><RotCenterWorldPointX>0</RotCenterWorldPointX><RotCenterWorldPointY>0</RotCenterWorldPointY><RotCenterWorldR>-999</RotCenterWorldR></PointF><CalibFloatListParam ParamName="CalibMatrix" DataType="FloatList"><ParamValue>1.0378213e-008</ParamValue><ParamValue>-0.2328483</ParamValue><ParamValue>-183.20914</ParamValue><ParamValue>-0.23190695</ParamValue><ParamValue>1.3837616e-008</ParamValue><ParamValue>518.30267</ParamValue><ParamValue>0</ParamValue><ParamValue>0</ParamValue><ParamValue>1</ParamValue></CalibFloatListParam></CalibOutputParam>
</CalibInfo>

http://www.xdnf.cn/news/694765.html

相关文章:

  • 民意调查员
  • 将 AI 解答转换为 Word 文档
  • [网页五子棋][匹配模块]前后端交互接口(消息推送机制)、客户端开发(匹配页面、匹配功能)
  • Nginx的反向代理
  • 【HW系列】—Log4j2、Fastjson漏洞流量特征
  • Android 16系统源码_无障碍辅助(一)认识无障碍服务
  • 2025.05.28【Choropleth】群体进化学专用图:区域数据可视化
  • WifiEspNow库函数详解
  • 【时时三省】(C语言基础)函数的递归调用例题
  • Flask集成pyotp生成动态口令
  • DeepSeek实战:打造智能数据分析与可视化系统
  • 用 Python 实现了哪些办公自动化
  • canal高可用配置
  • Java开发之定时器学习
  • LVS -DR
  • 每日算法 -【Swift 算法】正则表达式匹配:支持 `.` 和 `*`
  • 如何设计高效的数据湖架构:存储策略、Schema 演进与数据生命周期管理
  • 基于51单片机的音乐盒汽车喇叭调音量proteus仿真
  • 基于Doc2Vec的Markdown文档分类实战:从预处理到模型评估
  • 部署swagger接口文档到云服务器
  • ZooKeeper 命令操作
  • Gin项目脚手架与标配组件
  • 网络协议DHCP
  • YOLO 系列算法的参数量
  • Java大师成长计划之第33天:应用监控与日志管理
  • 顺序表与链表专项训练:在 LeetCode 实战中深化数据结构理解
  • 力扣 秋招 打卡第一天 2025年5月28日 Java
  • Vim 中设置插入模式下输入中文
  • 考研系列-操作系统:第一章、计算机系统概述
  • freecad TechDraw工作台中虚线(隐藏线)的实现方式