Vi~sion + Robot New Style

3rd Update

Vi~sion + Robot New Style_第1张图片

简洁风

Vi~sion + Robot New Style_第2张图片

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 = widget
        self.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 = root
        self.parent = parent

class 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.1
        self.robot_port = 2009           #2004
        self.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 = None
        self.last_y79_state = False  # 新增状态缓存
        self.last_X2F_state = True  # 新增状态缓存
        self.setup_plc()
        self.start_plc_monitoring()

        self.init_plc_connection()  # PLC运行

        self.run_button = None
        self.image_label = None
        self.images = []
        self.image_index = 0  # 确保在类初始化时设置默认值

        ###开启程序后自动启动项目
        self.connect_to_vision()
        self.connect_to_robot()

        ###开启程序后自动加载offset
        self.load_settings()

        # 修改窗口关闭事件处理
        self.root.protocol("WM_DELETE_WINDOW", self.on_exit)

        # 数据存储  Chart
        self.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)  # 避免直接递归调用
            return

        try:
            img = self.images[self.image_index]
            self.image_label.config(image=img)
            self.image_label.image = img
            logging.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_mode
        if 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):
        # 运行按钮点击事件处理
        pass



    def _update_gauge(self, gauge, value):
        """单个仪表更新逻辑"""
        # 更新数值显示
        gauge['label'].config(text=f"{value:.2f}")
        
        # 更新指针角度(-60°到240°范围)
        angle = 150 * (value / 100) - 60  # 假设值范围-100到100
        canvas = 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_mode
        if 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):
        # 运行按钮点击事件处理
        pass

    def 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.axes
                ax.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.axes
            ax.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到100
        canvas = 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秒后重试(替换递归)
            return

        if 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 = 1000
        window_height = 600
        screen_width = chart_window.winfo_screenwidth()
        screen_height = chart_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        chart_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')
        
        # 嵌入到Tkinter
        canvas = 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 Figure
        from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    def 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(
            "",
            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)



        # ---新---区域22
        blank_frame = tk.Frame(left_frame, bg='#FFFFFF', height=10)  # 高度为10像素
        blank_frame.pack(fill=tk.X, pady=120)  # 填充整个宽度并增加间距
 



 
        # ---新---区域33
        blank_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("", lambda _: scrollbar.lift())  # 鼠标进入时显示
        left_container.bind("", 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 = 800
        window_height = 600
        screen_width = new_window.winfo_screenwidth()
        screen_height = new_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        new_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 attribute
        status_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 #CCCCCC
        middle_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)  # 避免直接递归调用
            return

        try:
            img = self.images[self.image_index]
            self.image_label.config(image=img)
            self.image_label.image = img
            logging.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}")
            return

        images = []
        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)

        # 统一的写入按钮  ###Tim
        write_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 command
        custom_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 command
        custom_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 command
        custom_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('', lambda event: self.send_custom_command3())


    def _validate_number(self, value):
        """数值输入验证"""
        if value == "" or value == "-":
            return True
        try:
            float(value)
            return True
        except ValueError:
            return False



    def 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")  

##OutofRang
    def 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 Home
    def 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 Home


    def 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:
            return
            
        try:
            # 数值有效性验证
            float(value)
        except ValueError:
            messagebox.showerror("Error", "Pls Inpout Number")
            #messagebox.showerror("输入错误", "请输入有效的数字")
            return

        if 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_status
                logging.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.533TimOKTim88888888
                    x_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 = True
                        self.start_button.config(state=tk.NORMAL)
                        logging.info("Home position received - Start enabled")
                    elif 'NotHome' in data:
                        self.home_received = False
                        self.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 = Response

        if 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):    #vision
        if 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_U
        ABCDEFG=0
        if 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}")



##Offset
    def 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)  

##Tim
    def 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 = None
        except 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 = None

    def 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_command
                    self.start_auto_command()  ###Tim Modify
                self.last_y79_state = current_state


            if 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_state3


            else:
                #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  0
                if 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+=1
                                print(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().IsSuccess
        except:
            return False

    def 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 = True
            try:
                self.Recive_PLC_start_command()  # 执行主流程
            finally:
                self._is_running = False

    def _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 None
            Offset_Y = float(self.custom_command_entry6.get()) if self.custom_command_entry6.get() else None
            Offset_U = float(self.custom_command_entry7.get()) if self.custom_command_entry7.get() else None
        except 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 re
                            pos_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 re
                            pos_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 data
        except 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}")
            return

        trajectory_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 rcParams
        rcParams['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 = True
        ax.xaxis.pane.set_alpha(0.94)
        ax.yaxis.pane.fill = True
        ax.yaxis.pane.set_alpha(0.90)
        ax.zaxis.pane.fill = True
        ax.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 cm
        colors = [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, trail

        def 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, trail

        from matplotlib.animation import FuncAnimation
        ani = 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:
                return
            if 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/ pyautogui

if __name__ == "__main__":  
    root = tk.Tk()  
    app = TCPClientApp(root)  
    root.mainloop()


Robot

 


------------
Process.prg
------------


Function Alignment_TCP_212
	GoTo lblOpenPort
lblOpenPort:
	CloseNet #212
	Print "Waiting Servers Open ", Time$
	SetNet #212, "192.168.0.150", 7777, CRLF, NONE, 0
	OpenNet #212 As Client
	WaitNet #212
	Print "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.005055Tim
	Do
		'MemOn 18
        If MemSw(18) = Off Then
        	Wait 0.6
			Status_212 = ChkNet(212)
			Print "Recive data Len/Status is ", Status_212
			If Status_212 > 0 And Status_212 < 62 Then
				Read #212, Data_212$, Status_212
				Print "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 18
			
			ElseIf Status_212 > 62 Then
				Print "Recive len is so long"

				String msg2$, title2$
				Integer mFlag2s, answer2
				msg2$ = "Recive len is so long" + CRLF
				msg2$ = msg2$ + "Press Y or N to Exit..." + CRLF
				msg2$ = msg2$ + "Press N or Y to Exit..." + CRLF
				title2$ = "Recive Title"
				mFlag2s = MB_YESNO + MB_ICONQUESTION
				MsgBox msg2$, mFlag2s, title2$, answer2
				If answer2 = IDNO Or answer2 = IDYES Then
					Quit All
				EndIf
				Exit Do
			ElseIf Status_212 = -3 Then
				MemOff 2 'Ethernet Connect Status
				Print "Ethernet is Close,Pls Check it...", Time$
				GoTo lblOpenPort
			EndIf
		EndIf
		
		If MemSw(18) = On Then
			Wait 0.022

			ParseStr 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)=Pitch
			
			If Order = 0 Then
				Print "Home Pos Send", P986
				Print #212, "Home Pos Send", P986
				Go P986 'Home_Ref
			ElseIf Order = 1 Then
				Print "Go Ref_A1"
				Wait 0.3
				P987 = RealPos
				Print #212, "Go Ref_A1", P987
				Go P985 'A1_Ref
			ElseIf Order = 2 Then
				Print "Go Ref_A2"
				Wait 0.3
				P987 = RealPos
				Print #212, "Go Ref_A2", P987
				Go P984 'A2_Ref		
			EndIf
			Wait 0.88
'
			CX_Here = CX(Here)
			CY_Here = CY(Here)
			CZ_Here = CZ(Here)
			CU_Here = CU(Here)
			Print "Now pos is :", Here
			Data_212_Start$ = PData_212$(0)
			If Data_212_Start$ = "UP" Then
				Print "Recive UP = ", Data_212_Start$
				Go XY(CX(Here) + Pitch, CY(Here), CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "LEF" Then
				Print "Recive Left = ", Data_212_Start$
				Go XY(CX(Here), CY(Here) + Pitch, CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "RIGH" Then
				Print "Recive Right = ", Data_212_Start$
				Go XY(CX(Here), CY(Here) - Pitch, CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "DOWN" Then
				Print "Recive Down = ", Data_212_Start$
				Go XY(CX(Here) - Pitch, CY(Here), CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "CW" Then
				Print "Recive CW = ", Data_212_Start$
				Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) - Pitch)
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "CCW" Then
				Print "Recive CCW = ", Data_212_Start$
				Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) + Pitch)
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "SAVE" Then
				Print "Saving Aligment OK Pos ", Here
				String msg$, title$
				Integer mFlags, answer
				msg$ = "Save Pos" + CRLF
				msg$ = msg$ + "Are U Sure?"
				title$ = "Setting 2 Save"
				mFlags = MB_YESNO + MB_ICONQUESTION
				MsgBox msg$, mFlags, title$, answer
				If answer = IDNO Then
					Quit All
				ElseIf answer = IDYES Then
					
					PLabel 988, "Aligment"
					Here P988
                    Print "Save Pos ", CRLF, Here
                    Print #212, "Save Pos ", CRLF, Here
				EndIf

			EndIf
			SavePoints "rbtPoints_212.pts"
			Print "Eecive data OK...Start 2 Waiting Order..."
			MemOff 18  'Clean
		EndIf
		
		Print #212, "---", Time$
		Print "---", Time$
		MemOff 18  'Clean

	Loop

	ErrorHandle:
	'errnum = Err
	Print "ERROR", errnum
	Quit All
Fend

Function Welcome
	Do
		If MemSw(2) = Off Then
			Print "Welcome 2 Use"

			String msg$, title$
			Integer mFlags, answer
			msg$ = "Welcome 2 Use" + CRLF
			msg$ = msg$ + "Do not Press Or Press Y to Continue..." + CRLF
			msg$ = msg$ + "Press N to Exit..." + CRLF
			title$ = "Robot Control Tool"
			mFlags = MB_YESNO + MB_ICONQUESTION
			MsgBox msg$, mFlags, title$, answer
			If answer = IDNO Then
				Quit All
			EndIf
		EndIf
				
		'CloseNet #212
		Exit Do


	Loop
Fend
Function Recive_lendayu62
	Do
		If Status_212 > 62 Then
			Print "Recive len is so long"

			String msg$, title$
			Integer mFlags, answer
			msg$ = "Recive len is so long" + CRLF
			msg$ = msg$ + "Press Y to Continue..." + CRLF
			msg$ = msg$ + "Press N to Exit..." + CRLF
			title$ = "Recive Title"
			mFlags = MB_YESNO + MB_ICONQUESTION
			MsgBox msg$, mFlags, title$, answer
			If answer = IDNO Or answer = IDYES Then
				Quit All
			EndIf
		EndIf
		Exit Do


	Loop
Fend

Function TCP_209_AreaSensor_As_Client

    ' 锟截憋拷锟斤拷锟斤拷锟斤拷锟紼S THEN
    CloseNet #209
    Print "#209 Config Waiting Servers Open ", Time$
 
    ' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟絆pen ", Time$
    SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0
 
    ' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷, 0
    OpenNet #209 As Client
 
    ' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0
    WaitNet #209
    Print "#209 Config IP:192.168.0.150 Port:5678 Open at ", Time$
 
    ' 锟饺达拷1锟斤拷 
    Wait 1
 
    Do
    ' 锟截憋拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0
    	CloseNet #209
    	Print "#209  Waiting Servers Open ", Time$
 
    ' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟?, TIME$
   		SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0
 
    ' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷E, 0
  	  OpenNet #209 As Client
 
    ' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟?29Tim90.005055Tim  
  	  WaitNet #209
  	  Print "#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 ' 锟截闭碉拷锟?             
                    'EStopOn
                Case "1"
                    Print "Other command: ", Area_Sensor_$
                    Motor Off
			Send

		EndIf
		
		

		If Area_Sensor___ = -3 Then
			Pause ' 锟斤拷停
			'Motor Off
			String msg6_$, title_6$
			Integer mFlags_6, answer_6
			msg6_$ = "Waring" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + " " + CRLF
			msg6_$ = msg6_$ + "Press N to STOP !!!" + CRLF
			msg6_$ = msg6_$ + "Press Y to Continue" + CRLF
			title_6$ = "Robot Control Tool"
			mFlags_6 = MB_YESNO + MB_ICONQUESTION
			MsgBox msg6_$, mFlags_6, title_6$, answer_6
			If answer_6 = IDNO Then
				Quit All
			EndIf
			If answer_6 = IDYES Then
				Wait 0.0001
			EndIf
			
		EndIf
        
	Loop

Fend


Function Big_TCP_212_Runmode

	CloseNet #210
	SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
	OpenNet #210 As Server
	WaitNet #210
	Print "#210 Open at ", Time$
	MemOff RecvData  'Clean
	
	Jump P988 LimZ (0) 'NG_Port	
	'Jump P988
	Off 9
	Off 8
	Wait 0.8
	Jump P999 LimZ (0) 'home_Standby
	
	Do

		Off 9
		Off 8
		Wait 0.05  '<1 3 Cycle
        If MemSw(RecvData) = Off Then
			state211 = ChkNet(210)
			Print "Recived Lens: ", state211
			
			Print "For_Index:", For_LS_tim
			If state211 > 0 Then
				If For_LS_tim = 3 Then
	   				'cLANE 	 
					'Input #211, Data211$
					Print #210, Clean_Tim$
					Clean_Tim$ = ""
					Wait 2
					Input #210, Data210$
					Print Time$, " Recive data:  ", Data210$   'recive data				
					state211 = ChkNet(210)
					'Input #211, Data211$
					'Print Time$, " Recive data:  ", Data211$   'recive data
				    'cLANE  ok
				    
					Input #210, Data211$
					Print Time$, " Recive data_Clean:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
					Print "Start index:  ", Start_Real_211
				ElseIf For_LS_tim = 1 Or For_LS_tim = 2 Then
					Input #210, Data211$
					Print Time$, " Recive data_Clean:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
					Print "Start index:  ", Start_Real_211
				ElseIf For_LS_tim = 0 Then
					Input #210, Data211$
					Print Time$, " Recive data:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
				
					Print "Start index:  ", Start_Real_211

				EndIf
				
				
			ElseIf state211 = -3 Then

				Print Time$, "Ethernet NG ,Pls Connect it."
				Print Time$, "Ethernet NG ,Pls Connect it.."
				Print Time$, "Ethernet NG ,Pls Connect it..."
				
			''	
				Do
					CloseNet #210
					SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
					OpenNet #210 As Server
					WaitNet #210
					Print "#210 Open at ", Time$
					If state211 <> -3 Then
						Quit All
					EndIf
					Exit Do
				Loop

			''	
			EndIf
		EndIf
		If MemSw(RecvData) = On And For_LS_tim = 0 Or Start_Real_211 = 888888 Or Start_Real_211 = 666666 Then

			Home_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 Then
				U_Real_211_Angle = -U_Real_211
			ElseIf U_Real_211 < 0 Then
				U_Real_211_Angle = -U_Real_211
			EndIf
			
		''	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_Angle
			Print "Spilt data:  ", "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211_Angle
			Print #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 Then
				P993 = 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)
			Else
             Print "Error 4007, Target position out of range"

				String msg$, title$
				Integer mFlags, answer
				msg$ = "There has An Error" + CRLF
				msg$ = msg$ + "Press Y to Close and Call Tim"
				title$ = "Error Message From Robot"
				mFlags = MB_YESNO + MB_ICONQUESTION
				MsgBox msg$, mFlags, title$, answer
				If answer = IDNO Then
					Quit All
				EndIf
				
				CloseNet #210
				Exit Do
			EndIf
			
			
			If U_Real_211_Angle >= 0 Then
				X_Real_211 = X_Real_211 + 0
				Y_Real_211 = Y_Real_211 + 0
				U_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.302
			EndIf
		'ADD	
			Go XY(X_Real_211, Y_Real_211, -247.387, U_Real_211_Angle) 'Down   -247.387
			On 8												  'Vacuum
			Wait 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 Put2
			Jump P983 'Place
			Wait 3.8
			Off 8
			On 9
			Wait 0.6
			Off 9
		'ADD
		
			
			Jump P999 'home_Standby
			Print "home_Pos"
			Print #210, "Home_Pos", "Tim", "OK", "Tim"
			Home_POS_Index = 1
			
		For_LS_tim = 1 + For_LS_tim
		EndIf
		If For_LS_tim = 3 Then
			For_LS_tim = 1
		EndIf

		MemOff RecvData
		
		If Home_POS_Index = 1 Then
			Wait 0.00001
			''Print #210, "Home"
		EndIf
	Loop

Fend



































Function Rbt_PC216
	
	CloseNet #216
	OpenNet #216 As Server
	WaitNet #216
	Print "Open #216 at ", Time$
	For_LS = 1
	Print For_LS


	Do

		'Print #216, "Send data from robot "
		Wait 3
		Print For_LS
		

		state216 = ChkNet(216)
		Print "ChkNet= data", state216
		If state216 > 0 And For_LS = 2 Then
		'If state216 = 23 Or state216 = 25 Then
	
			Wait 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$, state216
			DataLS$ = Data$
			Print #216, Data$
			Print "ChkNet(216) Read: "
			Print Data$
			Print state216

			Integer fileNum2, i, j
			fileNum2 = FreeFile
			AOpen "D:\V80.txt" As #fileNum2
			Line Input #fileNum2, Read_file$
			Y_Tim_Real = Val(Read_file$)
			Print "Y:", Y_Tim_Real
			Print "---"
			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_Real
			
			X_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 = True
			Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		'Call Rbt_PC216
			Print "Process_Going 2 St_Pick Pos"
		'Speed 100, 100, 100
			Go P993
			'Go P992
		'Speed 100, 100, 5
			Print "Process_St_Pick Pos"

		'Print Here
			'Go XY(X_Tim_Real, Y_Tim_Real, -246.628, 5)
			
			Print Here
			Wait 0.1
			On 8
			'Wait Sw(8) = 1
			'Wait 1
			'Go P990    'OK POS_LS
			Go P992   'OK POS
			Off 8
			'Wait 1
			Go P993
			

		'Go pick
		'Print "Process_Pick Pos"			
'Vision_Process					

			'Read #216, Data$, numOfChars
			'numOfChars = ChkNet(216)
			'Print numOfChars
			
		ElseIf state216 = -3 Then
			Print "#216 Close ,Pls open #216 "
			
		ElseIf state216 = 0 Then
			Print "#216 Net no data ,Pls check it "
			
' 锟斤拷止锟斤拷锟斤拷65536		
		ElseIf state216 > 0 And For_LS = 6 Then
			For_LS = 10
		ElseIf state216 > 0 And For_LS = 12 Then
			For_LS = 5
' 锟斤拷止锟斤拷锟斤拷65536	

		EndIf
		state216 = 25
'		If Data$ = 3.15 Then
'			Select Pdata$(5)
'				Case "10000"
'					Print #216, "SHAKEHAND 10000"
'				Case "31"
'					Print #216, "SHAKEHAND 31"
'					Go P999
'			Send
'		EndIf
		
		
		For_LS = 1 + For_LS
		
	Loop

Fend

Function Vision_Process
	Do
		'Wait start_Awitch = True
		Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		'Call Rbt_PC216
		Print "Process_Going 2 St_Pick Pos"
		'Speed 100, 100, 100
		Go S_pick
		'Speed 100, 100, 5
		Print "Process_St_Pick Pos"

		Print Here
		Go XY(X_Tim_Real, Y_Tim_Real, -216, 5)
		Print Here
		
		'Go pick
		'Print "Process_Pick Pos"

	Loop
Fend
Function File
 	
	Do
		Print "File"
		Wait 2
		Integer fileNu, i, j
	'	fileNum = FreeFile
	'	WOpen "timTEST.DAT " As #fileNum
	'	For i = 0 To 100
			'Print #fileNum, i
		'Next I
		'Close #fileNum
		'........
		fileNu = FreeFile
		ROpen "timTEST88.DAT" As #fileNu
		For j = 4 To 8
			Input #fileNu, j
		Print j
		Next j
		Close #fileNu
		
		
	Loop

Fend
Function tcpip_211_1Cycle

	CloseNet #210
	SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
	OpenNet #210 As Server
	WaitNet #210
	Print "  #210 Open at ", Time$
	MemOff RecvData  'Clean
	For_LS = 0
	
	Do
		Wait 2
        If MemSw(RecvData) = Off Then
			state211 = ChkNet(210)
			Print "state211: ", state211
			Print "For_LS_tim", For_LS_tim
			If state211 > 0 And For_LS_tim = 0 Then
				Input #210, Data211$
				Print Time$, " Recive data:  ", Data211$   'recive data
				ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
				MemOn RecvData
			ElseIf state211 = -3 Then

				Print "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟铰达拷"

			EndIf
		EndIf
		

		If 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_211
			Print #210, "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211
			Go XY(X_Real_211, Y_Real_211, -216, U_Real_211)
			Wait 3
			Go 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
'			EndIf
		For_LS_tim = 2 + For_LS_tim
		Print "For_LS_tim222", For_LS_tim
' 锟斤拷止锟斤拷锟斤拷65536













'			Select Pdata211$(0)
'				Case "Tim"
'					Print "SHAKEHAND 10000"
'				Case "31"
'					Print "SHAKEHAND 31"
'			Send
			
		EndIf

		MemOff RecvData
	Loop

Fend

Function To_Robot
	Print "To_Robot_锟斤拷始锟斤拷锟斤拷Robot 锟斤拷 PC 通讯锟斤拷锟斤拷"
	SetNet #205, "192.168.0.1", 2004, CRLF, NONE, 0
	OpenNet #205 As Server
	Print "To_Robot_锟皆凤拷锟斤拷锟斤拷锟斤拷式锟斤拷205锟剿匡拷"
	Print "To_Robot_锟饺达拷锟斤拷锟斤拷"
	WaitNet #205
	Print "To_Robot_锟斤拷锟接★拷锟斤拷锟斤拷"
	Do
		Print "To_Robot_Robot 锟斤拷 PC 通讯锟斤拷锟斤拷锟斤拷锟叫★拷锟斤拷锟斤拷"
		Wait 1

		Print #205, "Robot used: ", h
		'Print #205, ""
		Print "Robot used: ", h
		ATCLR
		Wait 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 statustim
		statustim = ChkNet(205)
		
		If statustim > 0 Then
			Print "#205 锟斤拷锟斤拷锟斤拷"
			Print #205, "Robot used: ", h
			Print #205, ""
			Print "From #205 Recive data  "
			Print #205, "send data From Robot 192.168.0.1:205"
			Wait .5
			Input #205, datattt$
		ElseIf statustim = -3 Then
			Print "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟斤拷锟铰打开斤拷锟斤拷头
			'Input #205, datatt$
		EndIf
		

	Loop
Fend


Function Process
	Do
		Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		Print "Process_Standby Pos"
		Go P999
		Print "Process_Pick_Standby Pos"
		Go S_pick
		Print "Process_Pick Pos"
		Go pick
		Off 8
		Wait 1
		On 8
		Print "Vacuum"
		Print "Process_Pick_Standby Pos"
		Go S_pick
		Print "Process_Put_Standby Pos"
		Go S_put
		Print "Process_Put"
		Go Put
		Off 8
		Wait 1
		Print "Process_Put_Standby Pos"
		Go S_put
		Wait .6
		On 9
		Off 9
		Print "blow"
	Loop
Fend

Function Running_time
	Do
		h = Time(0) '锟斤拷小时锟斤拷锟斤拷通锟斤拷时锟斤拷
		Print "Running_time_Robot 锟窖撅拷使锟斤拷: ", h, "小时 ", ",", " 1锟斤拷锟接回憋拷一锟斤拷"
		Wait 60

	Loop
Fend
Function Current_POS

	CloseNet #215
	Print "#215 Config Waiting Servers Open ", Time$
	SetNet #215, "192.168.0.150", 1122, CRLF, NONE, 0
	OpenNet #215 As Client
	WaitNet #215
	Print "#215 Config IP:192.168.0.150 Port:1122 Open at ", Time$
	Wait 1
	Do
    	
    '	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_Here
			Wait 0.0003
			P982 = 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, UUU
			String ZZZ$, UUU$, XXX$, YYY$
			fileNum6 = FreeFile
			XXX = 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 #fileNum6
			Write #fileNum6, Time$ + "Current_POS_is: " + "X:" + "" + XXX$ + "Y:" + "" + YYY$ + "Z:" + "" + ZZZ$ + "U:" + "" + UUU$ + CRLF
			Print Time$, "--- Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)
			Close #fileNum6
		
	'	EndIf
	Loop
	
Fend
Function Move_Current_POS
	Do
			
		Jump A2_Alignmnet_Ref
		BMove XY(100, 0, -58.888, -45) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)
		Go A1_Alignmnet_Ref
		BGo XY(-80.88, 0, -18.888, -180) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)
		
		
		Print "Running_"
		Wait 0.5

	Loop
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_Index

Function main
	Motor On
	Power High
	Speed 100  'Go Speed Tim on High ,Off Low	
	SpeedS 2000 'MAX 2000
	Print "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  'NoPauseWelcome
	Xqt 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  




    
        
            2025-05-28 15:15:50
        
        
            NPointCalib
        
        
            9
        
        
            0
        
        
            0
        
        
            0.63482422
        
        
            -999
        
        
            0.14751892
        
        
            -999
        
        
            0.23190695
        
        
            0.2328483
        
        
            0.23237759
        
        
            
                1327.212
                1867.099
                0
            
            
                1499.212
                1867.099
                0
            
            
                1671.212
                1867.099
                0
            
            
                1671.212
                2039.99
                0
            
            
                1499.212
                2039.99
                0
            
            
                1327.212
                2039.99
                0
            
            
                1327.212
                2212.1089
                0
            
            
                1499.212
                2212.1089
                0
            
            
                1671.212
                2212.1089
                0
            
        
        
            
                -617.96002
                210.513
                -0.0572
            
            
                -617.96002
                171.04201
                -0.0502
            
            
                -617.96002
                130.737
                0.36719999
            
            
                -658.18103
                130.737
                -0.033399999
            
            
                -658.18103
                171.04201
                0.62330002
            
            
                -658.18103
                210.513
                -0.0502
            
            
                -698.29498
                210.513
                -0.044100001
            
            
                -698.29498
                171.04201
                -0.0502
            
            
                -698.29498
                130.737
                -0.050299998
            
        
    
    
        
            -999
        
        
            1
        
        
            0
            0
            -999
        
        
            0
            0
            -999
        
        
            1.0378213e-008
            -0.2328483
            -183.20914
            -0.23190695
            1.3837616e-008
            518.30267
            0
            0
            1
        
    


迭代 V3

 

#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 = widget
        self.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 = root
        self.parent = parent

class 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.1
        self.robot_port = 2009           #2004
        self.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 = None
        self.last_y79_state = False  # 新增状态缓存
        self.last_X2F_state = True  # 新增状态缓存
        self.setup_plc()
        self.start_plc_monitoring()

        self.init_plc_connection()  # PLC运行

        self.run_button = None
        self.image_label = None
        self.images = []
        self.image_index = 0  # 确保在类初始化时设置默认值

        ###开启程序后自动启动项目
        self.connect_to_vision()
        self.connect_to_robot()

        ###开启程序后自动加载offset
        self.load_settings()

        # 修改窗口关闭事件处理
        self.root.protocol("WM_DELETE_WINDOW", self.on_exit)

        # 数据存储  Chart
        self.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)  # 避免直接递归调用
            return

        try:
            img = self.images[self.image_index]
            self.image_label.config(image=img)
            self.image_label.image = img
            logging.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_mode
        if 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):
        # 运行按钮点击事件处理
        pass





    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_mode
        if 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):
        # 运行按钮点击事件处理
        pass

    def 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.axes
                ax.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.axes
            ax.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 setup_history_chart(self, ax):
        """初始化历史趋势图"""
        self.line_x, = ax.plot([], [], color='#FF0000', linewidth=2, label='X_Pos', marker='o', markersize=3)
        self.line_y, = ax.plot([], [], color='#00FF00', linewidth=2, label='Y_Pos', marker='o', markersize=3)
        self.line_u, = ax.plot([], [], color='#00B0F0', linewidth=2, label='U_Pos', marker='o', markersize=3)

        # 配置坐标轴和图例 - 工业风格
        ax.set_title("XYU_Chart", 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')
        ax.figure.patch.set_facecolor('#404040')
        
        # 设置刻度颜色
        ax.tick_params(axis='x', colors='#CCCCCC')
        ax.tick_params(axis='y', colors='#CCCCCC')

    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秒后重试(替换递归)
            return

        if 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 = 1000
        window_height = 600
        screen_width = chart_window.winfo_screenwidth()
        screen_height = chart_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        chart_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')
        
        # 嵌入到Tkinter
        canvas = 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'
        file_path = r'C:\Log\Vision_Data_Log6_11.txt'   ##Vision_Data_Log6_11.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()
        
        # 在此处调用 draw()
        self.chart_canvas.draw()

    def setup_history_chart(self, parent):
        """初始化历史趋势图"""
        from matplotlib.figure import Figure
        from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    def 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("Real", 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(
            "",
            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=15)  # 水平排列

        # 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=15)  # 水平排列

        # 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=15)  # 水平排列

        # 连接按钮(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)



        # ---新---区域22
        blank_frame = tk.Frame(left_frame, bg='#FFFFFF', height=10)  # 高度为10像素
        blank_frame.pack(fill=tk.X, pady=120)  # 填充整个宽度并增加间距
 



 
        # ---新---区域33
        blank_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("", lambda _: scrollbar.lift())  # 鼠标进入时显示
        left_container.bind("", 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 = 800
        window_height = 600
        screen_width = new_window.winfo_screenwidth()
        screen_height = new_window.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        new_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 attribute
        status_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 #CCCCCC
        middle_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)  # 避免直接递归调用
            return

        try:
            img = self.images[self.image_index]
            self.image_label.config(image=img)
            self.image_label.image = img
            logging.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}")
            return

        images = []
        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)

        # 统一的写入按钮  ###Tim
        write_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 command
        custom_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 command
        custom_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 command
        custom_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('', lambda event: self.send_custom_command3())


    def _validate_number(self, value):
        """数值输入验证"""
        if value == "" or value == "-":
            return True
        try:
            float(value)
            return True
        except ValueError:
            return False



    def 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")  

##OutofRang
    def 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 Home
    def 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 Home


    def 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:
            return
            
        try:
            # 数值有效性验证
            float(value)
        except ValueError:
            messagebox.showerror("Error", "Pls Inpout Number")
            #messagebox.showerror("输入错误", "请输入有效的数字")
            return

        if 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_status
                logging.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.533TimOKTim88888888
                    x_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 = True
                        self.start_button.config(state=tk.NORMAL)
                        logging.info("Home position received - Start enabled")
                    elif 'NotHome' in data:
                        self.home_received = False
                        self.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 = Response

        if 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):    #vision
        if 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_U
        ABCDEFG=0
        if 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}")



##Offset
    def 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)  

##Tim
    def 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 = None
        except 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 = None

    def 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_command
                    self.start_auto_command()  ###Tim Modify
                self.last_y79_state = current_state


            if 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_state3


            else:
                #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  0
                if 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+=1
                                print(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().IsSuccess
        except:
            return False

    def 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 = True
            try:
                self.Recive_PLC_start_command()  # 执行主流程
            finally:
                self._is_running = False

    def _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 None
            Offset_Y = float(self.custom_command_entry6.get()) if self.custom_command_entry6.get() else None
            Offset_U = float(self.custom_command_entry7.get()) if self.custom_command_entry7.get() else None
        except 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 re
                            pos_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 re
                            pos_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 data
        except FileNotFoundError:
            logging.error("轨迹文件未找到,请确认路径是否正确")
            return []

    def show_animation(self):
        """显示高科技风格的3D轨迹动画"""
        file_path = r'C:\Log\Robot_POS.txt'
        
        # 验证文件路径
        if not os.path.exists(file_path):
            messagebox.showerror("文件错误", f"轨迹文件未找到\n路径: {file_path}")
            logging.error(f"轨迹文件不存在: {file_path}")
            return

        trajectory_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 rcParams
        rcParams['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 = True
        ax.xaxis.pane.set_alpha(0.94)
        ax.yaxis.pane.fill = True
        ax.yaxis.pane.set_alpha(0.90)
        ax.zaxis.pane.fill = True
        ax.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 cm
        colors = [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, trail

        def 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, trail

        from matplotlib.animation import FuncAnimation
        ani = 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:
                return
            if 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/ pyautogui

if __name__ == "__main__":  
    root = tk.Tk()  
    app = TCPClientApp(root)  
    root.mainloop()





--------------------------------------------


' 
'Design By Tim  Process.prg
' 

Function Alignment_TCP_212
	GoTo lblOpenPort
lblOpenPort:
	CloseNet #212
	Print "Waiting Servers Open ", Time$
	SetNet #212, "192.168.0.150", 7777, CRLF, NONE, 0
	OpenNet #212 As Client
	WaitNet #212
	Print "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.005055Tim
	Do
		'MemOn 18
        If MemSw(18) = Off Then
        	Wait 0.6
			Status_212 = ChkNet(212)
			Print "Recive data Len/Status is ", Status_212
			If Status_212 > 0 And Status_212 < 62 Then
				Read #212, Data_212$, Status_212
				Print "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 18
			
			ElseIf Status_212 > 62 Then
				Print "Recive len is so long"

				String msg2$, title2$
				Integer mFlag2s, answer2
				msg2$ = "Recive len is so long" + CRLF
				msg2$ = msg2$ + "Press Y or N to Exit..." + CRLF
				msg2$ = msg2$ + "Press N or Y to Exit..." + CRLF
				title2$ = "Recive Title"
				mFlag2s = MB_YESNO + MB_ICONQUESTION
				MsgBox msg2$, mFlag2s, title2$, answer2
				If answer2 = IDNO Or answer2 = IDYES Then
					Quit All
				EndIf
				Exit Do
			ElseIf Status_212 = -3 Then
				MemOff 2 'Ethernet Connect Status
				Print "Ethernet is Close,Pls Check it...", Time$
				GoTo lblOpenPort
			EndIf
		EndIf
		
		If MemSw(18) = On Then
			Wait 0.022

			ParseStr 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)=Pitch
			
			If Order = 0 Then
				Print "Home Pos Send", P986
				Print #212, "Home Pos Send", P986
				Go P986 'Home_Ref
			ElseIf Order = 1 Then
				Print "Go Ref_A1"
				Wait 0.3
				P987 = RealPos
				Print #212, "Go Ref_A1", P987
				Go P985 'A1_Ref
			ElseIf Order = 2 Then
				Print "Go Ref_A2"
				Wait 0.3
				P987 = RealPos
				Print #212, "Go Ref_A2", P987
				Go P984 'A2_Ref		
			EndIf
			Wait 0.88
'
			CX_Here = CX(Here)
			CY_Here = CY(Here)
			CZ_Here = CZ(Here)
			CU_Here = CU(Here)
			Print "Now pos is :", Here
			Data_212_Start$ = PData_212$(0)
			If Data_212_Start$ = "UP" Then
				Print "Recive UP = ", Data_212_Start$
				Go XY(CX(Here) + Pitch, CY(Here), CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "LEF" Then
				Print "Recive Left = ", Data_212_Start$
				Go XY(CX(Here), CY(Here) + Pitch, CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "RIGH" Then
				Print "Recive Right = ", Data_212_Start$
				Go XY(CX(Here), CY(Here) - Pitch, CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "DOWN" Then
				Print "Recive Down = ", Data_212_Start$
				Go XY(CX(Here) - Pitch, CY(Here), CZ(Here), CU(Here))
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "CW" Then
				Print "Recive CW = ", Data_212_Start$
				Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) - Pitch)
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "CCW" Then
				Print "Recive CCW = ", Data_212_Start$
				Go XY(CX(Here), CY(Here), CZ(Here), CU(Here) + Pitch)
				Print "Now pos is :", Here
			ElseIf Data_212_Start$ = "SAVE" Then
				Print "Saving Aligment OK Pos ", Here
				String msg$, title$
				Integer mFlags, answer
				msg$ = "Save Pos" + CRLF
				msg$ = msg$ + "Are U Sure?"
				title$ = "Setting 2 Save"
				mFlags = MB_YESNO + MB_ICONQUESTION
				MsgBox msg$, mFlags, title$, answer
				If answer = IDNO Then
					Quit All
				ElseIf answer = IDYES Then
					
					PLabel 988, "Aligment"
					Here P988
                    Print "Save Pos ", CRLF, Here
                    Print #212, "Save Pos ", CRLF, Here
				EndIf

			EndIf
			SavePoints "rbtPoints_212.pts"
			Print "Eecive data OK...Start 2 Waiting Order..."
			MemOff 18  'Clean
		EndIf
		
		Print #212, "---", Time$
		Print "---", Time$
		MemOff 18  'Clean

	Loop

	ErrorHandle:
	'errnum = Err
	Print "ERROR", errnum
	Quit All
Fend

Function Welcome
	Do
		If MemSw(2) = Off Then
			Print "Welcome 2 Use"

			String msg$, title$
			Integer mFlags, answer
			msg$ = "Welcome 2 Use" + CRLF
			msg$ = msg$ + "Do not Press Or Press Y to Continue..." + CRLF
			msg$ = msg$ + "Press N to Exit..." + CRLF
			title$ = "Robot Control Tool"
			mFlags = MB_YESNO + MB_ICONQUESTION
			MsgBox msg$, mFlags, title$, answer
			If answer = IDNO Then
				Quit All
			EndIf
		EndIf
				
		'CloseNet #212
		Exit Do


	Loop
Fend
Function Recive_lendayu62
	Do
		If Status_212 > 62 Then
			Print "Recive len is so long"

			String msg$, title$
			Integer mFlags, answer
			msg$ = "Recive len is so long" + CRLF
			msg$ = msg$ + "Press Y to Continue..." + CRLF
			msg$ = msg$ + "Press N to Exit..." + CRLF
			title$ = "Recive Title"
			mFlags = MB_YESNO + MB_ICONQUESTION
			MsgBox msg$, mFlags, title$, answer
			If answer = IDNO Or answer = IDYES Then
				Quit All
			EndIf
		EndIf
		Exit Do


	Loop
Fend

Function TCP_209_AreaSensor_As_Client

    ' 锟截憋拷锟斤拷锟斤拷锟斤拷锟紼S THEN
    CloseNet #209
    Print "#209 Config Waiting Servers Open ", Time$
 
    ' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟絆pen ", Time$
    SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0
 
    ' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷, 0
    OpenNet #209 As Client
 
    ' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0
    WaitNet #209
    Print "#209 Config IP:192.168.0.150 Port:5678 Open at ", Time$
 
    ' 锟饺达拷1锟斤拷 
    Wait 1
 
    Do
    ' 锟截憋拷锟斤拷锟斤拷锟斤拷锟接斤拷锟斤拷锟浇, 0
    	CloseNet #209
    	Print "#209  Waiting Servers Open ", Time$
 
    ' 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟?, TIME$
   		SetNet #209, "192.168.0.150", 5670, CRLF, NONE, 0
 
    ' 锟皆客伙拷锟斤拷模式锟斤拷锟斤拷锟斤拷锟斤拷E, 0
  	  OpenNet #209 As Client
 
    ' 锟饺达拷锟斤拷锟斤拷锟斤拷锟接斤拷锟?29Tim90.005055Tim  
  	  WaitNet #209
  	  Print "#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 ' 锟截闭碉拷锟?             
                    'EStopOn
                Case "1"
                    Print "Other command: ", Area_Sensor_$
                    Motor Off
			Send

		EndIf
		
		

		If Area_Sensor___ = -3 Then
			Pause ' 锟斤拷停
			'Motor Off
			String msg6_$, title_6$
			Integer mFlags_6, answer_6
			msg6_$ = "Waring" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + "Area Sensor !!!" + CRLF
			msg6_$ = msg6_$ + " " + CRLF
			msg6_$ = msg6_$ + "Press N to STOP !!!" + CRLF
			msg6_$ = msg6_$ + "Press Y to Continue" + CRLF
			title_6$ = "Robot Control Tool"
			mFlags_6 = MB_YESNO + MB_ICONQUESTION
			MsgBox msg6_$, mFlags_6, title_6$, answer_6
			If answer_6 = IDNO Then
				Quit All
			EndIf
			If answer_6 = IDYES Then
				Wait 0.0001
			EndIf
			
		EndIf
        
	Loop

Fend


Function Big_TCP_212_Runmode

	CloseNet #210
	SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
	OpenNet #210 As Server
	WaitNet #210
	Print "#210 Open at ", Time$
	MemOff RecvData  'Clean
	
	Jump P988 LimZ (0) 'NG_Port	
	'Jump P988
	Off 9
	Off 8
	Wait 0.8
	Jump P999 LimZ (0) 'home_Standby
	
	Do

		Off 9
		Off 8
		Wait 0.05  '<1 3 Cycle
        If MemSw(RecvData) = Off Then
			state211 = ChkNet(210)
			Print "Recived Lens: ", state211
			
			Print "For_Index:", For_LS_tim
			If state211 > 0 Then
				If For_LS_tim = 3 Then
	   				'cLANE 	 
					'Input #211, Data211$
					Print #210, Clean_Tim$
					Clean_Tim$ = ""
					Wait 2
					Input #210, Data210$
					Print Time$, " Recive data:  ", Data210$   'recive data				
					state211 = ChkNet(210)
					'Input #211, Data211$
					'Print Time$, " Recive data:  ", Data211$   'recive data
				    'cLANE  ok
				    
					Input #210, Data211$
					Print Time$, " Recive data_Clean:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
					Print "Start index:  ", Start_Real_211
				ElseIf For_LS_tim = 1 Or For_LS_tim = 2 Then
					Input #210, Data211$
					Print Time$, " Recive data_Clean:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
					Print "Start index:  ", Start_Real_211
				ElseIf For_LS_tim = 0 Then
					Input #210, Data211$
					Print Time$, " Recive data:  ", Data211$   'recive data
					ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
					MemOn RecvData
				
					Start_String_211$ = Data211$
					'Start_Real_211 = Val(Start_String_211$) 
					Start_Real_211 = Val(Right$(Start_String_211$, 6))
				
					Print "Start index:  ", Start_Real_211

				EndIf
				
				
			ElseIf state211 = -3 Then

				Print Time$, "Ethernet NG ,Pls Connect it."
				Print Time$, "Ethernet NG ,Pls Connect it.."
				Print Time$, "Ethernet NG ,Pls Connect it..."
				
			''	
				Do
					CloseNet #210
					SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
					OpenNet #210 As Server
					WaitNet #210
					Print "#210 Open at ", Time$
					If state211 <> -3 Then
						Quit All
					EndIf
					Exit Do
				Loop

			''	
			EndIf
		EndIf
		If MemSw(RecvData) = On And For_LS_tim = 0 Or Start_Real_211 = 888888 Or Start_Real_211 = 666666 Then

			Home_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 Then
				U_Real_211_Angle = -U_Real_211
			ElseIf U_Real_211 < 0 Then
				U_Real_211_Angle = -U_Real_211
			EndIf
			
		''	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_Angle
			Print "Spilt data:  ", "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211_Angle
			Print #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 Then
				P993 = 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)
			Else
             Print "Error 4007, Target position out of range"

				String msg$, title$
				Integer mFlags, answer
				msg$ = "There has An Error" + CRLF
				msg$ = msg$ + "Press Y to Close and Call Tim"
				title$ = "Error Message From Robot"
				mFlags = MB_YESNO + MB_ICONQUESTION
				MsgBox msg$, mFlags, title$, answer
				If answer = IDNO Then
					Quit All
				EndIf
				
				CloseNet #210
				Exit Do
			EndIf
			
			
			If U_Real_211_Angle >= 0 Then
				X_Real_211 = X_Real_211 + 0
				Y_Real_211 = Y_Real_211 + 0
				U_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.302
			EndIf
		'ADD	
			Go XY(X_Real_211, Y_Real_211, -247.387, U_Real_211_Angle) 'Down   -247.387
			On 8												  'Vacuum
			Wait 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 Put2
			Jump P983 'Place
			Wait 3.8
			Off 8
			On 9
			Wait 0.6
			Off 9
		'ADD
		
			
			Jump P999 'home_Standby
			Print "home_Pos"
			Print #210, "Home_Pos", "Tim", "OK", "Tim"
			Home_POS_Index = 1
			
		For_LS_tim = 1 + For_LS_tim
		EndIf
		If For_LS_tim = 3 Then
			For_LS_tim = 1
		EndIf

		MemOff RecvData
		
		If Home_POS_Index = 1 Then
			Wait 0.00001
			''Print #210, "Home"
		EndIf
	Loop

Fend



































Function Rbt_PC216
	
	CloseNet #216
	OpenNet #216 As Server
	WaitNet #216
	Print "Open #216 at ", Time$
	For_LS = 1
	Print For_LS


	Do

		'Print #216, "Send data from robot "
		Wait 3
		Print For_LS
		

		state216 = ChkNet(216)
		Print "ChkNet= data", state216
		If state216 > 0 And For_LS = 2 Then
		'If state216 = 23 Or state216 = 25 Then
	
			Wait 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$, state216
			DataLS$ = Data$
			Print #216, Data$
			Print "ChkNet(216) Read: "
			Print Data$
			Print state216

			Integer fileNum2, i, j
			fileNum2 = FreeFile
			AOpen "D:\V80.txt" As #fileNum2
			Line Input #fileNum2, Read_file$
			Y_Tim_Real = Val(Read_file$)
			Print "Y:", Y_Tim_Real
			Print "---"
			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_Real
			
			X_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 = True
			Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		'Call Rbt_PC216
			Print "Process_Going 2 St_Pick Pos"
		'Speed 100, 100, 100
			Go P993
			'Go P992
		'Speed 100, 100, 5
			Print "Process_St_Pick Pos"

		'Print Here
			'Go XY(X_Tim_Real, Y_Tim_Real, -246.628, 5)
			
			Print Here
			Wait 0.1
			On 8
			'Wait Sw(8) = 1
			'Wait 1
			'Go P990    'OK POS_LS
			Go P992   'OK POS
			Off 8
			'Wait 1
			Go P993
			

		'Go pick
		'Print "Process_Pick Pos"			
'Vision_Process					

			'Read #216, Data$, numOfChars
			'numOfChars = ChkNet(216)
			'Print numOfChars
			
		ElseIf state216 = -3 Then
			Print "#216 Close ,Pls open #216 "
			
		ElseIf state216 = 0 Then
			Print "#216 Net no data ,Pls check it "
			
' 锟斤拷止锟斤拷锟斤拷65536		
		ElseIf state216 > 0 And For_LS = 6 Then
			For_LS = 10
		ElseIf state216 > 0 And For_LS = 12 Then
			For_LS = 5
' 锟斤拷止锟斤拷锟斤拷65536	

		EndIf
		state216 = 25
'		If Data$ = 3.15 Then
'			Select Pdata$(5)
'				Case "10000"
'					Print #216, "SHAKEHAND 10000"
'				Case "31"
'					Print #216, "SHAKEHAND 31"
'					Go P999
'			Send
'		EndIf
		
		
		For_LS = 1 + For_LS
		
	Loop

Fend

Function Vision_Process
	Do
		'Wait start_Awitch = True
		Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		'Call Rbt_PC216
		Print "Process_Going 2 St_Pick Pos"
		'Speed 100, 100, 100
		Go S_pick
		'Speed 100, 100, 5
		Print "Process_St_Pick Pos"

		Print Here
		Go XY(X_Tim_Real, Y_Tim_Real, -216, 5)
		Print Here
		
		'Go pick
		'Print "Process_Pick Pos"

	Loop
Fend
Function File
 	
	Do
		Print "File"
		Wait 2
		Integer fileNu, i, j
	'	fileNum = FreeFile
	'	WOpen "timTEST.DAT " As #fileNum
	'	For i = 0 To 100
			'Print #fileNum, i
		'Next I
		'Close #fileNum
		'........
		fileNu = FreeFile
		ROpen "timTEST88.DAT" As #fileNu
		For j = 4 To 8
			Input #fileNu, j
		Print j
		Next j
		Close #fileNu
		
		
	Loop

Fend
Function tcpip_211_1Cycle

	CloseNet #210
	SetNet #210, "192.168.0.1", 2009, CRLF, NONE, 0
	OpenNet #210 As Server
	WaitNet #210
	Print "  #210 Open at ", Time$
	MemOff RecvData  'Clean
	For_LS = 0
	
	Do
		Wait 2
        If MemSw(RecvData) = Off Then
			state211 = ChkNet(210)
			Print "state211: ", state211
			Print "For_LS_tim", For_LS_tim
			If state211 > 0 And For_LS_tim = 0 Then
				Input #210, Data211$
				Print Time$, " Recive data:  ", Data211$   'recive data
				ParseStr Data211$, Pdata211$(), "Tim"  'spilt data
				MemOn RecvData
			ElseIf state211 = -3 Then

				Print "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟铰达拷"

			EndIf
		EndIf
		

		If 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_211
			Print #210, "x_Real:", X_Real_211, "y_Real:", Y_Real_211, "u_Real:", U_Real_211
			Go XY(X_Real_211, Y_Real_211, -216, U_Real_211)
			Wait 3
			Go 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
'			EndIf
		For_LS_tim = 2 + For_LS_tim
		Print "For_LS_tim222", For_LS_tim
' 锟斤拷止锟斤拷锟斤拷65536













'			Select Pdata211$(0)
'				Case "Tim"
'					Print "SHAKEHAND 10000"
'				Case "31"
'					Print "SHAKEHAND 31"
'			Send
			
		EndIf

		MemOff RecvData
	Loop

Fend

Function To_Robot
	Print "To_Robot_锟斤拷始锟斤拷锟斤拷Robot 锟斤拷 PC 通讯锟斤拷锟斤拷"
	SetNet #205, "192.168.0.1", 2004, CRLF, NONE, 0
	OpenNet #205 As Server
	Print "To_Robot_锟皆凤拷锟斤拷锟斤拷锟斤拷式锟斤拷205锟剿匡拷"
	Print "To_Robot_锟饺达拷锟斤拷锟斤拷"
	WaitNet #205
	Print "To_Robot_锟斤拷锟接★拷锟斤拷锟斤拷"
	Do
		Print "To_Robot_Robot 锟斤拷 PC 通讯锟斤拷锟斤拷锟斤拷锟叫★拷锟斤拷锟斤拷"
		Wait 1

		Print #205, "Robot used: ", h
		'Print #205, ""
		Print "Robot used: ", h
		ATCLR
		Wait 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 statustim
		statustim = ChkNet(205)
		
		If statustim > 0 Then
			Print "#205 锟斤拷锟斤拷锟斤拷"
			Print #205, "Robot used: ", h
			Print #205, ""
			Print "From #205 Recive data  "
			Print #205, "send data From Robot 192.168.0.1:205"
			Wait .5
			Input #205, datattt$
		ElseIf statustim = -3 Then
			Print "锟斤拷太锟斤拷通讯锟较匡拷锟斤拷锟斤拷锟斤拷锟铰打开斤拷锟斤拷头
			'Input #205, datatt$
		EndIf
		

	Loop
Fend


Function Process
	Do
		Print "Process_锟竭讹拷锟斤拷锟斤拷锟教筹拷锟斤拷执锟斤拷锟叫★拷锟斤拷锟斤拷"
		Print "Process_Standby Pos"
		Go P999
		Print "Process_Pick_Standby Pos"
		Go S_pick
		Print "Process_Pick Pos"
		Go pick
		Off 8
		Wait 1
		On 8
		Print "Vacuum"
		Print "Process_Pick_Standby Pos"
		Go S_pick
		Print "Process_Put_Standby Pos"
		Go S_put
		Print "Process_Put"
		Go Put
		Off 8
		Wait 1
		Print "Process_Put_Standby Pos"
		Go S_put
		Wait .6
		On 9
		Off 9
		Print "blow"
	Loop
Fend

Function Running_time
	Do
		h = Time(0) '锟斤拷小时锟斤拷锟斤拷通锟斤拷时锟斤拷
		Print "Running_time_Robot 锟窖撅拷使锟斤拷: ", h, "小时 ", ",", " 1锟斤拷锟接回憋拷一锟斤拷"
		Wait 60

	Loop
Fend
Function Current_POS

	CloseNet #215
	Print "#215 Config Waiting Servers Open ", Time$
	SetNet #215, "192.168.0.150", 1122, CRLF, NONE, 0
	OpenNet #215 As Client
	WaitNet #215
	Print "#215 Config IP:192.168.0.150 Port:1122 Open at ", Time$
	Wait 1
	Do
    	
    '	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_Here
			Wait 0.0003
			P982 = 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, UUU
			String ZZZ$, UUU$, XXX$, YYY$
			fileNum6 = FreeFile
			XXX = 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\Robot_POS.txt" As #fileNum6
			Write #fileNum6, Time$ + "Current_POS_is: " + "X:" + "" + XXX$ + "Y:" + "" + YYY$ + "Z:" + "" + ZZZ$ + "U:" + "" + UUU$ + CRLF
			Print Time$, "--- Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)
			Close #fileNum6
		
	'	EndIf
	Loop
	
Fend


Function Current_POS_2
	Do
		Wait 0.25
		P982 = CurPos
		Integer fileNum6
		Real XXX, YYY, ZZZ, UUU, LS_Z, LS_U
		String ZZZ$, UUU$, XXX$, YYY$
		fileNum6 = FreeFile
		XXX = 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\Robot_POS.txt" As #fileNum6
		LS_U = Val(Left$(Str$(CU(P982)), 6))
		LS_Z = Val(Left$(Str$(CZ(P982)), 6))
		
		If LS_U <> CU(P999) And LS_Z <> CZ(P999) Then  ''ZU			
			Print Time$, "Save POS Data", LS_U, LS_Z, "VS", CU(P999), CZ(P999)
			Write #fileNum6, Time$ + "Current_POS_is: " + "X:" + "" + XXX$ + "Y:" + "" + YYY$ + "Z:" + "" + ZZZ$ + "U:" + "" + UUU$ + CRLF
			Print Time$, "--- Current_POS_is: ", "X:", CX(P982), " ,", "Y:", CY(P982), " ,", "Z:", CZ(P982), " ,", "U:", CU(P982)
		EndIf

		Close #fileNum6
		
			
	Loop
	
Fend
Function Move_Current_POS
	Do
			
		Jump A2_Alignmnet_Ref
		BMove XY(100, 0, -58.888, -45) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)
		Go A1_Alignmnet_Ref
		BGo XY(-80.88, 0, -18.888, -180) '锛堝湪鏈湴鍧愭爣绯讳腑锛夊悜 X 鏂瑰悜绉诲姩 100mm)
		
		
		Print "Running_"
		Wait 0.5

	Loop
Fend

--------------------------------------------

' 
'Design By Tim  main.prg
' 
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_Index

Function main
	Motor On
	Power High
	Speed 100  'Go Speed Tim on High ,Off Low	
	SpeedS 2000 'MAX 2000
	Print "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_2, Normal  'NoPause	
	Xqt Welcome, Normal  'NoPauseWelcome
	Xqt 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


3rd

 

NEW Page  to bigger

Vi~sion + Robot New Style_第3张图片

你可能感兴趣的:(python,RC+,Python)