From b0a4c47dd74bc41c5df3bab6ddd8de7bcc6a52b0 Mon Sep 17 00:00:00 2001
From: patrick <patrick.xu@broconcentric.com>
Date: 星期五, 06 十二月 2019 18:35:42 +0800
Subject: [PATCH] 1. 重新整理项目,按照A034模式,将设备异步操作修改为类同步操作。使用任务队列来存储和分配任务。

---
 src/Bro.Device.SeerAGV/SeerAGVConfig.cs            |   51 
 src/A032.Process/ProcessConfig.cs                  |   89 
 src/A032.Process/ProcessControl_Calibration.cs     |  180 --
 src/Bro.Common.Model/Model/MonitorSet.cs           |   20 
 src/Bro.Common.Model/Interface/IDeviceConfig.cs    |   11 
 src/Bro.Common.Model/Model/CustomizedPoint.cs      |   60 
 src/Bro.Device.AuboRobot/AuboRobotConfig.cs        |  205 +
 src/A032.Process/AGVPath.cs                        |   17 
 src/Bro.Device.AuboRobot/AuboRobotDriver.cs        |  362 +++-
 src/Bro.Device.Common/Base/DeviceBase.cs           |   42 
 src/A032.Process/AGVBindUnit.cs                    |  336 +--
 src/A032.Process/Calibration/FrmCalib9PDynamic.cs  |    4 
 src/A032.Process/ProcessControl_Task.cs            |  759 +++++++++
 src/Bro.Common.Model/Helper/ExceptionHelper.cs     |   40 
 src/A032.Process/Calibration/CtrlCalib9PDynamic.cs |   14 
 src/A032.Process/Calibration/CalibrationConfig.cs  |   16 
 src/A032.Process/ProcessControl_AGV.cs             |  102 +
 src/A032.Process/ProcessControl_Robot.cs           |   24 
 src/A032.Process/A032.Process.csproj               |    3 
 src/Bro.Device.Common/Helper/AspectHelper.cs       |    2 
 src/Bro.Device.SeerAGV/SeerAGVDriver.cs            |  189 ++
 src/A032.Process/ProcessControl.cs                 |  182 -
 src/Bro.Common.Model/Bro.Common.Model.csproj       |    1 
 src/Bro.Common.Model/Helper/ListHelper.cs          |   58 
 src/Bro.Common.Model/Model/IODefinition.cs         |   43 
 src/Bro.Device.OmronFins/FinsFrame.cs              |    6 
 src/A032.Process/ProcessControl_Method.cs          | 1787 ++++++++-------------
 src/Bro.Device.Common/DeviceBase/HDevEngineTool.cs |   23 
 src/Bro.Common.Model/Helper/EnumHelper.cs          |    9 
 src/Bro.Common.Model/Interface/IMonitor.cs         |    2 
 src/Bro.Device.Common/Base/DeviceConfigBase.cs     |   18 
 src/Bro.Device.OmronFins/OmronFinsDriver.cs        |  145 
 src/Bro.Device.Common/DeviceBase/PLCBase.cs        |   16 
 src/Bro.Device.SeerAGV/Bro.Device.SeerAGV.csproj   |    1 
 34 files changed, 2,866 insertions(+), 1,951 deletions(-)

diff --git a/src/A032.Process/A032.Process.csproj b/src/A032.Process/A032.Process.csproj
index 2a1c97b..73afc99 100644
--- a/src/A032.Process/A032.Process.csproj
+++ b/src/A032.Process/A032.Process.csproj
@@ -90,9 +90,12 @@
     </Compile>
     <Compile Include="Helper\PropertyConvertHelper.cs" />
     <Compile Include="ProcessConfig.cs" />
+    <Compile Include="ProcessControl_AGV.cs" />
     <Compile Include="ProcessControl_Calibration.cs" />
     <Compile Include="ProcessControl_Method.cs" />
     <Compile Include="ProcessControl.cs" />
+    <Compile Include="ProcessControl_Robot.cs" />
+    <Compile Include="ProcessControl_Task.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
diff --git a/src/A032.Process/AGVBindUnit.cs b/src/A032.Process/AGVBindUnit.cs
index 5d843f3..f4e06cc 100644
--- a/src/A032.Process/AGVBindUnit.cs
+++ b/src/A032.Process/AGVBindUnit.cs
@@ -15,42 +15,84 @@
 
 namespace A032.Process
 {
-    public enum TaskStatus
+    public enum TaskState
     {
-        Available = 1,
+        /// <summary>
+        /// 鏂颁换鍔�
+        /// </summary>
+        New = 0,
+        /// <summary>
+        /// 浠诲姟瀹屾垚
+        /// </summary>
+        Done = 1,
+        /// <summary>
+        /// 浠诲姟澶辫触
+        /// </summary>
+        Failed = 2,
+        /// <summary>
+        /// 浠诲姟宸叉坊鍔犻槦鍒楋紝绛夊緟鎵ц
+        /// </summary>
+        Queueing = 3,
+        /// <summary>
+        /// 浠诲姟宸叉寚娲�
+        /// </summary>
+        Assigned = 4,
+        /// <summary>
+        /// 浠诲姟鏈寚娲撅紝宸插彇娑�
+        /// </summary>
+        Cancelled = 5,
+    }
+
+    public enum AGVState
+    {
+        /// <summary>
+        /// AGV鐘舵�佷笉鍙煡
+        /// </summary>
+        Unknown = 0,
+        /// <summary>
+        /// 绌洪棽鐘舵�侊紝鍙帴鏀朵换鍔�
+        /// </summary>
+        Idle = 1,
+        /// <summary>
+        /// 浠诲姟鎵ц涓�
+        /// </summary>
         Running = 2,
+        /// <summary>
+        /// 鎶ヨ涓紝涓嶅彲鎵ц浠诲姟
+        /// </summary>
         Warning = 3,
+        /// <summary>
+        /// 鍏呯數涓紝涓嶅彲鎵ц浠诲姟
+        /// </summary>
+        InCharge = 4,
+        /// <summary>
+        /// 绌洪棽鍏呯數鐘舵�侊紝鍙帴鏀朵换鍔�
+        /// </summary>
+        IdleCharge = 5,
     }
 
-    public enum TaskAvailableLevel
-    {
-        Robot = 1,
-        AGV = 2,
-        Both = 3,
-    }
+    //public class AGVTaskModel
+    //{
+    //    public TaskAvailableLevel Level { get; set; } = TaskAvailableLevel.Robot;
 
-    public class AGVTaskModel
-    {
-        public TaskAvailableLevel Level { get; set; } = TaskAvailableLevel.Robot;
+    //    public string MethodName { get; set; }
 
-        public string MethodName { get; set; }
+    //    public IOperationConfig OpConfig { get; set; }
 
-        public IOperationConfig OpConfig { get; set; }
+    //    public IDevice Device { get; set; }
 
-        public IDevice Device { get; set; }
+    //    //public int Priority { get; set; } = 10;
 
-        //public int Priority { get; set; } = 10;
+    //    public AGVTaskModel() { }
 
-        public AGVTaskModel() { }
-
-        public AGVTaskModel(TaskAvailableLevel level, string methodName, IOperationConfig opConfig = null, IDevice device = null)
-        {
-            Level = level;
-            MethodName = methodName;
-            OpConfig = opConfig ?? new OperationConfigBase();
-            Device = device;
-        }
-    }
+    //    public AGVTaskModel(TaskAvailableLevel level, string methodName, IOperationConfig opConfig = null, IDevice device = null)
+    //    {
+    //        Level = level;
+    //        MethodName = methodName;
+    //        OpConfig = opConfig ?? new OperationConfigBase();
+    //        Device = device;
+    //    }
+    //}
 
     public class AGVBindUnit : IComplexDisplay
     {
@@ -90,60 +132,32 @@
         }
         #endregion
 
+        #region 鍚庡彴灞炴��
+        #region 鐘舵��
+        private AGVState unitState = AGVState.Idle;
         [Browsable(false)]
         [JsonIgnore]
-        public Action<AGVTaskModel> OnMethodInvoke { get; set; }
-
-        public string AGVDest { get; set; } = "";
-
-        private TaskStatus agvStatus = TaskStatus.Available;
-        [Browsable(false)]
-        [JsonIgnore]
-        public TaskStatus AGVStatus
+        public AGVState UnitState
         {
-            get => agvStatus;
+            get => unitState;
             set
             {
-                agvStatus = value;
-                //InvokeTaskCheck();
-            }
-        }
+                if (value != unitState)
+                {
+                    var preState = unitState;
+                    unitState = value;
 
-        private TaskStatus robotStatus = TaskStatus.Available;
-        [Browsable(false)]
-        [JsonIgnore]
-        public TaskStatus RobotStatus
-        {
-            get => robotStatus;
-            set
-            {
-                robotStatus = value;
-                //InvokeTaskCheck();
+                    OnUnitStateChanged?.Invoke(this.Id, preState, unitState);
+                }
             }
         }
 
         [Browsable(false)]
         [JsonIgnore]
-        public TaskStatus UnitStatus
-        {
-            get
-            {
-                if (AGVStatus == TaskStatus.Warning || RobotStatus == TaskStatus.Warning)
-                {
-                    return TaskStatus.Warning;
-                }
-                else
-                {
-                    if (AGVStatus == TaskStatus.Available && RobotStatus == TaskStatus.Available)
-                    {
-                        return TaskStatus.Available;
-                    }
-                }
+        public string WarningMsg { get; set; } = "";
+        #endregion
 
-                return TaskStatus.Running;
-            }
-        }
-
+        #region 璁惧
         [Browsable(false)]
         [JsonIgnore]
         public SeerAGVDriver AGV { get; set; } = null;
@@ -153,150 +167,42 @@
         [Browsable(false)]
         [JsonIgnore]
         public CameraBase Camera { get; set; } = null;
+        #endregion
 
-        //[Browsable(false)]
-        //[JsonIgnore]
-        //public ObservableCollection<AGVTaskModel> TaskList { get; set; } = new ObservableCollection<AGVTaskModel>();
+        #region 浠诲姟淇℃伅
+        [JsonIgnore]
+        [Browsable(false)]
+        public string CurrentTaskId { get; set; }
 
-        [Browsable(false)]
         [JsonIgnore]
-        public int CurrentEmptyTray { get; set; }
         [Browsable(false)]
-        [JsonIgnore]
-        public int CurrentFullTray { get; set; }
-        [Browsable(false)]
-        [JsonIgnore]
-        public bool IsFullTrayFull { get; set; }
-        [Browsable(false)]
-        [JsonIgnore]
-        public bool IsFullTrayEmpty { get; set; }
-        [Browsable(false)]
-        [JsonIgnore]
-        public bool IsEmptyTrayEmpty { get; set; }
+        public bool IsTaskCancelled { get; set; } = false;
 
-        [Browsable(false)]
         [JsonIgnore]
-        public bool IsFullTrayTaskAssigned { get; set; }
-
         [Browsable(false)]
+        public bool IsTaskCancelling { get; set; } = false;
+        #endregion
+
+        #region 浜嬩欢
         [JsonIgnore]
-        public bool IsEmptyTrayTaskAssigned { get; set; }
+        [Browsable(false)]
+        public Action<string, AGVState, AGVState> OnUnitStateChanged { get; set; }
+        #endregion
 
-        //[Browsable(false)]
-        //[JsonIgnore]
-        //public ManualResetEvent FullTrayFullHandle { get; set; } = new ManualResetEvent(false);
+        #region 鎵樼洏淇℃伅
+        [JsonIgnore]
+        [Browsable(false)]
+        public int FullTrayNum { get; set; }
 
-        //[Browsable(false)]
-        //[JsonIgnore]
-        //public ManualResetEvent FullTrayEmptyHandle { get; set; } = new ManualResetEvent(false);
-
-        public ManualResetEvent RobotIOHandle { get; set; } = new ManualResetEvent(false);
+        [JsonIgnore]
+        [Browsable(false)]
+        public int EmptyTrayNum { get; set; }
+        #endregion
+        #endregion
 
         public AGVBindUnit()
         {
-            //TaskList.CollectionChanged += TaskList_CollectionChanged;
         }
-
-        object agvStatusLock = new object();
-        public bool SetAGVStatus(TaskStatus status)
-        {
-            lock (agvStatusLock)
-            {
-                switch (status)
-                {
-                    case TaskStatus.Available:
-                        break;
-                    case TaskStatus.Running:
-                        if (AGVStatus == TaskStatus.Available)
-                        {
-                            AGVStatus = status;
-                            return true;
-                        }
-                        else
-                        {
-                            return false;
-                        }
-                    case TaskStatus.Warning:
-                        break;
-                    default:
-                        break;
-                }
-
-                AGVStatus = status;
-                return true;
-            }
-        }
-        //private void TaskList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
-        //{
-        //    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
-        //    {
-        //        InvokeTaskCheck();
-        //    }
-        //}
-
-        //private void InvokeTaskCheck()
-        //{
-        //    lock (taskLock)
-        //    {
-        //        for (int i = 0; i < TaskList.Count; i++)
-        //        {
-        //            var task = TaskList[i];
-
-        //            bool isAgvOK = false;
-        //            bool isRobotOK = false;
-
-        //            if ((task.Level & TaskAvailableLevel.AGV) == TaskAvailableLevel.AGV)
-        //            {
-        //                isAgvOK = AGVStatus == TaskStatus.Available;
-        //            }
-        //            else
-        //            {
-        //                isAgvOK = true;
-        //            }
-
-        //            if ((task.Level & TaskAvailableLevel.Robot) == TaskAvailableLevel.Robot)
-        //            {
-        //                isRobotOK = RobotStatus == TaskStatus.Available;
-        //            }
-        //            else
-        //            {
-        //                isRobotOK = true;
-        //            }
-
-        //            if (isRobotOK && isAgvOK)
-        //            {
-        //                OnMethodInvoke?.Invoke(TaskList[i]);
-        //                TaskList.RemoveAt(i);
-        //                break;
-        //            }
-        //        }
-        //    }
-        //}
-
-        //object taskLock = new object();
-        //public void AddTask(AGVTaskModel task)
-        //{
-        //    lock (taskLock)
-        //    {
-        //        TaskList.Add(task);
-        //    }
-        //}
-
-        //public void ClearTask()
-        //{
-        //    lock (taskLock)
-        //    {
-        //        TaskList.Clear();
-        //    }
-        //}
-
-        //public AGVTaskModel GetTask(int index)
-        //{
-        //    lock (taskLock)
-        //    {
-        //        return TaskList[index];
-        //    }
-        //}
     }
 
     public class AGVDeviceConverter : ComboBoxItemTypeConvert
@@ -364,4 +270,40 @@
             }
         }
     }
+
+    public class AllDeviceIdConverter : ComboBoxItemTypeConvert
+    {
+        public override void GetConvertHash()
+        {
+            using (var scope = GlobalVar.Container.BeginLifetimeScope())
+            {
+                _hash[""] = "鏈寚瀹�";
+
+                List<IDevice> deviceList = scope.Resolve<List<IDevice>>();
+
+                deviceList.ForEach(d =>
+                {
+                    _hash[d.Id] = d.Name;
+                });
+            }
+        }
+    }
+
+    public class AllDeviceNameConverter : ComboBoxItemTypeConvert
+    {
+        public override void GetConvertHash()
+        {
+            using (var scope = GlobalVar.Container.BeginLifetimeScope())
+            {
+                _hash[""] = "鏈寚瀹�";
+
+                List<IDevice> deviceList = scope.Resolve<List<IDevice>>();
+
+                deviceList.ForEach(d =>
+                {
+                    _hash[d.Name] = d.Name;
+                });
+            }
+        }
+    }
 }
diff --git a/src/A032.Process/AGVPath.cs b/src/A032.Process/AGVPath.cs
index 2e19e32..426a620 100644
--- a/src/A032.Process/AGVPath.cs
+++ b/src/A032.Process/AGVPath.cs
@@ -3,6 +3,7 @@
 using Bro.Common.Model;
 using Bro.Common.Model.Interface;
 using Bro.Device.HikCamera;
+using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -48,6 +49,10 @@
         [TypeConverter(typeof(PLCDeviceConverter))]
         public string DeviceOwner { get; set; }
 
+        [Browsable(false)]
+        [JsonIgnore]
+        public bool IsOccupied { get; set; } = false;
+
         public string GetDisplayText()
         {
             return $"{PositionCode}-{Description}";
@@ -83,6 +88,18 @@
         [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
         public HikCameraOperationConfig CameraOpConfig { get; set; } = new HikCameraOperationConfig();
 
+        [Category("绀烘暀閰嶇疆")]
+        [Description("鏈哄櫒浜烘媿鐓т綅缃�")]
+        [TypeConverter(typeof(ComplexObjectConvert))]
+        [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
+        public RobotPoint RobotSnapshotPoint { get; set; } = new RobotPoint();
+
+        [Category("绀烘暀閰嶇疆")]
+        [Description("鏈哄櫒浜虹ず鏁欎綅缃埌瀹為檯鎶撳彇浣嶇疆鐨勫亸绉�")]
+        [TypeConverter(typeof(ComplexObjectConvert))]
+        [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
+        public RobotPoint RobotShift { get; set; } = new RobotPoint();
+
         public string GetDisplayText()
         {
             return $"{PositionCode}:鏇濆厜锛歿CameraOpConfig.Exposure};鏍囧畾鐭╅樀锛歿string.Join(",", Matrix)}";
diff --git a/src/A032.Process/Calibration/CalibrationConfig.cs b/src/A032.Process/Calibration/CalibrationConfig.cs
index 1b8f099..1c02514 100644
--- a/src/A032.Process/Calibration/CalibrationConfig.cs
+++ b/src/A032.Process/Calibration/CalibrationConfig.cs
@@ -19,8 +19,8 @@
     {
         [Category("鍏宠仈閰嶇疆")]
         [Description("浣嶇疆搴忓彿")]
-        [TypeConverter(typeof(PositionNoConverter))]
-        public int PositionNo { get; set; }
+        [TypeConverter(typeof(PositionCodeConverter))]
+        public string PositionCode { get; set; }
 
         [Category("鍏宠仈閰嶇疆")]
         [Description("閫傜敤鐩告満缂栧彿")]
@@ -39,7 +39,7 @@
 
         public string GetDisplayText()
         {
-            return $"PositionNo:{PositionNo}; Configs:{Configs.Count}";
+            return $"PositionNo:{PositionCode}; Configs:{Configs.Count}";
         }
 
         public List<string> GetHalconToolPathList()
@@ -86,11 +86,17 @@
         [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
         public HalconRelatedCameraOprerationConfigBase CameraOpConfig { get; set; } = new HalconRelatedCameraOprerationConfigBase();
 
+        //[Category("杩愬姩骞冲彴璁剧疆")]
+        //[Description("骞冲彴褰撳墠鍧愭爣")]
+        //[TypeConverter(typeof(ComplexObjectConvert))]
+        //[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
+        //public CustomizedPoint CurrentPlatPoint { get; set; } = new CustomizedPoint();
+
         [Category("杩愬姩骞冲彴璁剧疆")]
-        [Description("骞冲彴褰撳墠鍧愭爣")]
+        [Description("鏈哄櫒浜鸿繍鍔ㄥ潗鏍�")]
         [TypeConverter(typeof(ComplexObjectConvert))]
         [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
-        public CustomizedPoint CurrentPlatPoint { get; set; } = new CustomizedPoint();
+        public RobotPoint PlatPoint { get; set; } = new RobotPoint();
 
         public event PropertyChangedEventHandler PropertyChanged;
 
diff --git a/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs b/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
index 1cce895..3edee32 100644
--- a/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
+++ b/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
@@ -30,7 +30,7 @@
             InitializeComponent();
         }
 
-        public CtrlCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<AGVBindUnit, int, int> commuAction, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation)
+        public CtrlCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation)
         {
             InitializeComponent();
 
@@ -42,7 +42,6 @@
 
             Bind = bind;
             Position = position;
-            CommuAction = commuAction;
             FinalCalculation = finalCalculation;
         }
 
@@ -161,7 +160,8 @@
 
             _canvas.LoadImage(Config.Configs[index].Image);
             _canvas.Elements.Clear();
-            CrossHair ch = new CrossHair(new CalibrationPoint(Config.Configs[index].ImageMarkPoint, Config.Configs[index].CurrentPlatPoint));
+            var config = Config.Configs[index];
+            CrossHair ch = new CrossHair(new CalibrationPoint(new CustomizedPoint(config.ImageMarkPoint.X, config.ImageMarkPoint.Y), new CustomizedPoint(config.PlatPoint.X, config.PlatPoint.Y)));
             _canvas.Elements.Add(ch);
 
             tsslInfo.Text = $"姝ラ{index + 1}瀹屾垚";
@@ -191,7 +191,9 @@
             {
                 _canvas.LoadImage(stepConfig.Image);
                 _canvas.Elements.Clear();
-                _canvas.Elements.Add(new CrossHair(new CalibrationPoint(stepConfig.ImageMarkPoint, stepConfig.CurrentPlatPoint)));
+
+                CrossHair ch = new CrossHair(new CalibrationPoint(new CustomizedPoint(stepConfig.ImageMarkPoint.X, stepConfig.ImageMarkPoint.Y), new CustomizedPoint(stepConfig.PlatPoint.X, stepConfig.PlatPoint.Y)));
+                _canvas.Elements.Add(ch);
             }
         }
 
@@ -206,7 +208,7 @@
             //    //ProcessControl.SendCalibStartSignal(Config.TriggerAddress);
             //}
 
-            ProcessControl.MultipleStepsProcess(Config, Bind, CommuAction);
+            ProcessControl.MultipleStepsProcess(Config, Bind);
         }
 
         private void btnLoadOfflineImages_Click(object sender, EventArgs e)
@@ -236,7 +238,7 @@
 
             //tsslInfo.Text = $"鍗曟杩愮畻瀹屾垚銆傛爣璁扮偣鍧愭爣锛歿config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}";
 
-            ProcessControl.SingleStepProcess(config, CommuAction, Bind, Position.PositionNo, _selectedStepIndex);
+            ProcessControl.SingleStepProcess(config, Bind, _selectedStepIndex);
             tsslInfo.Text = $"鍗曟杩愮畻瀹屾垚銆傛爣璁扮偣鍧愭爣锛歿config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}";
         }
 
diff --git a/src/A032.Process/Calibration/FrmCalib9PDynamic.cs b/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
index 5fe5c52..efbb287 100644
--- a/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
+++ b/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
@@ -37,7 +37,7 @@
         //    CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, device, config, finalCalculation);
         //}
 
-        public FrmCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<AGVBindUnit, int, int> commuAction, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation)
+        public FrmCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation)
         {
             InitializeComponent();
 
@@ -48,7 +48,7 @@
             //CommuAction = commuAction;
             //FinalCalculation = finalCalculation;
 
-            CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, calibConfig, bind, position, commuAction, finalCalculation);
+            CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, calibConfig, bind, position, finalCalculation);
         }
 
         //AGVBindUnit Bind { get; set; }
diff --git a/src/A032.Process/ProcessConfig.cs b/src/A032.Process/ProcessConfig.cs
index c7cbb46..f71d683 100644
--- a/src/A032.Process/ProcessConfig.cs
+++ b/src/A032.Process/ProcessConfig.cs
@@ -3,6 +3,7 @@
 using Bro.Common.Helper;
 using Bro.Common.Interface;
 using Bro.Common.Model;
+using Bro.Common.Model.Interface;
 using Bro.Device.AuboRobot;
 using Bro.Device.HikCamera;
 using Bro.Device.OmronFins;
@@ -20,7 +21,7 @@
 
 namespace A032.Process
 {
-    public class ProcessConfig : IStationConfig
+    public class ProcessConfig : IStationConfig, IHalconToolPath
     {
         #region 璁惧閰嶇疆
         [Category("璁惧閰嶇疆")]
@@ -70,6 +71,10 @@
         [TypeConverter(typeof(CollectionCountConvert))]
         [Editor(typeof(OperationConfigBindEditor), typeof(UITypeEditor))]
         public Dictionary<string, IOperationConfig> ProcessOpConfigDict { get; set; } = new Dictionary<string, IOperationConfig>();
+
+        [Category("鎿嶄綔閰嶇疆")]
+        [Description("鎿嶄綔瓒呮椂璁剧疆锛屽崟浣峬in")]
+        public int OperationTimeout { get; set; } = 10;
 
         //[Category("鐩戝惉鍜屾搷浣滈厤缃�")]
         //[Description("鐩戝惉鎿嶄綔閰嶇疆闆嗗悎")]
@@ -139,6 +144,7 @@
         //[Description("鏄惁閲囩敤澶栭儴绠楀瓙銆倀rue锛氶噰鐢ㄥ閮ㄧ畻瀛愶紝false锛氫娇鐢ㄥ唴閮ㄧ畻娉�")]
         //public bool IsUsingExternalAlgorithem { get; set; } = true;
 
+        #region A032
         [Category("璺緞鐩稿叧")]
         [Description("璺緞鑺傜偣閰嶇疆")]
         [TypeConverter(typeof(CollectionCountConvert))]
@@ -155,19 +161,21 @@
         [Description("鏄惁鍚敤瑙嗚寮曞")]
         public bool IsEnableVisionGuide { get; set; } = false;
 
-        /// <summary>
-        /// 绌篢ray涓婃枡闃堝�硷紝AGV涓婄殑绌簍ray鏁伴噺涓嶅ぇ浜庤鏁板�兼椂锛孉GV鍙互鎵ц绌篢ray涓婃枡浠诲姟
-        /// </summary>
-        [Category("闃堝�艰缃�")]
-        [Description("绌篢ray涓婃枡闃堝�硷紝AGV涓婄殑绌簍ray鏁伴噺涓嶅ぇ浜庤鏁板�兼椂锛孉GV鍙互鎵ц绌篢ray涓婃枡浠诲姟")]
-        public int AGV_EmptyTrayThreshold { get; set; } = 0;
+        [Category("瑙嗚閰嶇疆")]
+        [Description("瑙嗚寮曞娆℃暟")]
+        public int VisionGuideTimes { get; set; } = 2;
 
-        /// <summary>
-        /// 婊ray涓嬫枡闃堝�硷紝AGV涓婄殑婊ray鏁伴噺涓嶅皬浜庤鏁板�兼椂锛孉GV鍙互鎵ц婊ray涓嬫枡浠诲姟
-        /// </summary>
-        [Category("闃堝�艰缃�")]
-        [Description("婊ray涓嬫枡闃堝�硷紝AGV涓婄殑婊ray鏁伴噺涓嶅皬浜庤鏁板�兼椂锛孉GV鍙互鎵ц婊ray涓嬫枡浠诲姟")]
-        public int AGV_FullTrayThreshold { get; set; } = 10;
+        [Category("璁惧鍙傛暟閰嶇疆")]
+        [Description("鍏夋簮寮�鍏崇储寮曢厤缃�")]
+        public int LightOutputIndex { get; set; }
+
+        [Category("璁惧鍙傛暟閰嶇疆")]
+        [Description("AGV婊¤浇婊ray/绌篢ray鏁伴噺")]
+        public int AGVAvailableTrayNums { get; set; } = 6;
+
+        [Category("璁惧鍙傛暟閰嶇疆")]
+        [Description("榛樿绛夊緟浠诲姟杞暟銆傚綋鏌愪簺鏉′欢涓嶆弧瓒冲綋鍓嶄换鍔℃墽琛屽墠鎻愶紝褰撳墠浠诲姟浼氱瓑寰呰嫢骞蹭换鍔℃暟鍚庢墽琛�")]
+        public int DefaultWaitShift { get; set; } = 3;
 
         /// <summary>
         /// 浜х嚎蹇欐椂鎷嶇収纭绛夊緟闂撮殧锛屼互绉掍负鍗曚綅
@@ -185,11 +193,43 @@
 
         [Category("闃堝�艰缃�")]
         [Description("鏈哄彴鍘嬫満婊ray鏁伴噺")]
-        public int Machine_FullTrayNum { get; set; }
+        public int Machine_FullTrayNum { get; set; } = 6;
 
         [Category("闃堝�艰缃�")]
         [Description("鏈哄彴鍘嬫満绌篢ray鏁伴噺")]
-        public int Machine_EmptyTrayNum { get; set; }
+        public int Machine_EmptyTrayNum { get; set; } = 6;
+        #endregion
+
+        #region IHalconToolPath
+        public List<string> GetHalconToolPathList()
+        {
+            List<string> list = new List<string>();
+
+            ProcessOpConfigDict.Values.ToList().ForEach(c =>
+            {
+                if (c is IHalconToolPath)
+                {
+                    list.AddRange((c as IHalconToolPath).GetHalconToolPathList());
+                }
+            });
+
+            this.GetType().GetProperties().ToList().ForEach(p =>
+            {
+                var pValue = p.GetValue(this);
+
+                if (pValue is IHalconToolPath)
+                {
+                    list.AddRange((pValue as IHalconToolPath).GetHalconToolPathList());
+                }
+                else if (pValue is IEnumerable<IHalconToolPath>)
+                {
+                    list.AddRange((pValue as IEnumerable<IHalconToolPath>).SelectMany(u => u.GetHalconToolPathList()));
+                }
+            });
+
+            return list.Distinct().ToList();
+        }
+        #endregion
 
         #region Ignore
         [Browsable(false)]
@@ -239,4 +279,23 @@
         public virtual bool IsDBSave { get; set; } = false;
         #endregion
     }
+
+    [Device("OperationTest", "娴嬭瘯鏂规硶閰嶇疆", DeviceAttributeType.OperationConfig)]
+    public class OperationTestConfig : OperationConfigBase
+    {
+        //[Category("娴嬭瘯閰嶇疆")]
+        //[Description("鏂规硶绫诲瀷")]
+        //public TaskType TaskType { get; set; } = TaskType.LoadEmptyTrayToAGV;
+
+        [Category("娴嬭瘯閰嶇疆")]
+        [Description("鏂规硶淇℃伅")]
+        [TypeConverter(typeof(ComplexObjectConvert))]
+        [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
+        public TrayTask TaskInfo { get; set; } = new TrayTask();
+
+        [Category("娴嬭瘯閰嶇疆")]
+        [Description("鎵цAGV璁惧")]
+        [TypeConverter(typeof(AGVDeviceConverter))]
+        public string AGVId { get; set; }
+    }
 }
diff --git a/src/A032.Process/ProcessControl.cs b/src/A032.Process/ProcessControl.cs
index 08cba1d..1c21d00 100644
--- a/src/A032.Process/ProcessControl.cs
+++ b/src/A032.Process/ProcessControl.cs
@@ -5,7 +5,6 @@
 using Bro.Common.Model;
 using Bro.Common.Model.Interface;
 using Bro.Common.PubSub;
-using Bro.Common.UI;
 using Bro.Device.AuboRobot;
 using Bro.Device.OmronFins;
 using Bro.Device.SeerAGV;
@@ -14,18 +13,14 @@
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 using System;
-using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
-using System.Configuration;
 using System.Diagnostics;
 using System.Drawing;
-using System.Drawing.Imaging;
 using System.IO;
 using System.Linq;
 using System.Reflection;
-using System.Runtime.ExceptionServices;
 using System.Threading;
 using System.Threading.Tasks;
 using static Bro.Common.Helper.EnumHelper;
@@ -152,6 +147,11 @@
             if (ProcessState == DeviceState.DSClose)
                 return;
 
+            List<string> currentTaskIds = Config.AGVBindCollection.Select(u => u.CurrentTaskId).Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
+            TrayTaskCollection.RemoveAll(t => !currentTaskIds.Contains(t.TaskId));
+
+            _bindTaskDoneHandleDict.Values.ToList().ForEach(h => h.WaitOne());
+
             CloseDevice(PLCDict.Values.ToList());
             CloseDevice(RobotDict.Values.ToList());
             CloseDevice(AGVDict.Values.ToList());
@@ -168,6 +168,7 @@
                 return;
 
             InitialProcessMethods();
+            TrayTaskCollection.OnItemChangedWithItemInfo = OnTaskListChanged;
 
             OpenDevices(RobotDict.Values.ToList());
             OpenDevices(AGVDict.Values.ToList());
@@ -177,14 +178,15 @@
 
             OpenDevices(PLCDict.Values.ToList());
 
+            //鍔犺浇AGVUnit鐘舵�佷簨浠�
+            Config.AGVBindCollection.ForEach(b =>
+            {
+                b.OnUnitStateChanged = OnUnitStateChanged;
+
+                _bindTaskDoneHandleDict[b.Id] = new AutoResetEvent(true);
+            });
+
             ProcessState = DeviceState.DSOpen;
-
-            //QueryRobotIO();
-
-            //Task.Run(() =>
-            //{
-            //    //PLCMonitor();
-            //});
 
             LogAsync(DateTime.Now, "Process Opened", "");
         }
@@ -291,27 +293,27 @@
             #region 涓埆閰嶇疆鐨勭壒鍒鐞�
             #endregion
 
-            _warningRemains.CollectionChanged -= _warningRemains_CollectionChanged;
-            _warningRemains.CollectionChanged += _warningRemains_CollectionChanged;
+            WarningRemains.CollectionChanged -= _warningRemains_CollectionChanged;
+            WarningRemains.CollectionChanged += _warningRemains_CollectionChanged;
 
             InitialPLCs();
             InitialAGVs();
             InitialRobots();
             InitialCameras();
             InitialAGVBindUnit();
-            InitialMachineTrayNums();
+            //InitialMachineTrayNums();
 
             AutoFacRegister();
 
             LogAsync(DateTime.Now, "Process Initialized", "");
         }
 
-        private void InitialMachineTrayNums()
-        {
-            machineEmptyTrayDict = Config.PositionCollection.Where(u => u.Description == PathPositionDefinition.UnloadEmptyTray).ToDictionary(p => p.PositionNo, p => 0);
+        //private void InitialMachineTrayNums()
+        //{
+        //    machineEmptyTrayDict = Config.PositionCollection.Where(u => u.Description == PathPositionDefinition.UnloadEmptyTray).ToDictionary(p => p.PositionNo, p => 0);
 
-            machineFullTrayDict = Config.PositionCollection.Where(u => u.Description == PathPositionDefinition.LoadFullTray).ToDictionary(p => p.PositionNo, p => 0);
-        }
+        //    machineFullTrayDict = Config.PositionCollection.Where(u => u.Description == PathPositionDefinition.LoadFullTray).ToDictionary(p => p.PositionNo, p => 0);
+        //}
 
         private void InitialAGVBindUnit()
         {
@@ -390,6 +392,9 @@
                 agv.InitialConfig = c;
                 AGVDict[agv.InitialConfig.ID] = agv;
 
+                agv.OnMonitorAlarm -= OnMonitorAlarm;
+                agv.OnMonitorInvoke -= OnMonitorInvoke;
+
                 agv.OnLog = OnDeviceLog;
                 agv.OnAGVPositoinChanged = OnAGVPositionChanged;
                 agv.OnAGVTaskStatusChanged = OnAGVTaskStatusChanged;
@@ -448,7 +453,7 @@
 
             ProcessConfig pConfig = config as ProcessConfig;
             if (pConfig == null)
-                throw new ProcessException("鐩墠鍙敮鎸丳rocessConfig绫诲瀷鐨勯潪绌哄唴瀹逛繚瀛�", null);
+                throw new ProcessException("鐩墠鍙敮鎸丳rocessConfig绫诲瀷鐨勯潪绌哄唴瀹逛繚瀛�");
 
             string newConfig = JsonConvert.SerializeObject(pConfig, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
             using (StreamWriter writer = new StreamWriter(CONFIG_PATH, false, System.Text.Encoding.UTF8))
@@ -505,71 +510,36 @@
                 if (attr != null)
                 {
                     _processMethodDict[attr.MethodCode] = m;
-
-                    #region 鍒濆鍖朒alconTool 鏍规嵁processMethod鐨勭壒鎬ф潵閰嶇疆
-                    //if (attr.DeviceType.EndsWith("Camera"))
-                    //{
-                    //    if (StationConfig.ProcessOpConfigDict.Keys.Contains(attr.MethodCode))
-                    //    {
-                    //        var opConfig = StationConfig.ProcessOpConfigDict[attr.MethodCode] as HalconRelatedCameraOprerationConfigBase;
-
-                    //        if (opConfig != null)
-                    //        {
-                    //            if (!string.IsNullOrWhiteSpace(opConfig.AlgorithemPath))
-                    //            {
-                    //                string directoryPath = Path.GetDirectoryName(opConfig.AlgorithemPath);
-                    //                string fileName = Path.GetFileNameWithoutExtension(opConfig.AlgorithemPath);
-
-                    //                HDevEngineTool tool = new HDevEngineTool(directoryPath);
-                    //                tool.LoadProcedure(fileName);
-
-                    //                _halconToolDict[attr.MethodCode] = tool;
-                    //            }
-                    //        }
-                    //    }
-                    //}
-                    #endregion
                 }
             });
 
             #region 鍒濆鍖朒alconTool 鏍规嵁閰嶇疆鐨勬帴鍙g被鍨嬫潵閰嶇疆
-            _halconToolDict = new Dictionary<string, HDevEngineTool>();
-            Config.PLCConfigCollection.SelectMany(plcConfig => plcConfig.MonitorSetCollection).Select(ms => ms.OpConfig).ToList().ForEach(c =>
-            {
-                InitialHalconTool(c as IHalconToolPath);
-            });
-
-            Config.VisionConfigCollection.ForEach(c =>
-            {
-                InitialHalconTool(c as IHalconToolPath);
-            });
-
-            Config.ProcessOpConfigDict.Values.ToList().ForEach(c =>
-            {
-                InitialHalconTool(c as IHalconToolPath);
-            });
+            InitialHalconTool();
             #endregion
         }
 
-        private void InitialHalconTool(IHalconToolPath toolPath)
+        private void InitialHalconTool()
         {
-            //IHalconToolPath toolPath = c as IHalconToolPath;
-            if (toolPath != null)
+            foreach (HDevEngineTool tool in _halconToolDict.Values)
             {
-                toolPath.GetHalconToolPathList().ForEach(path =>
-                {
-                    if (!string.IsNullOrWhiteSpace(path) && !_halconToolDict.ContainsKey(path))
-                    {
-                        string directoryPath = Path.GetDirectoryName(path);
-                        string fileName = Path.GetFileNameWithoutExtension(path);
-
-                        HDevEngineTool tool = new HDevEngineTool(directoryPath);
-                        tool.LoadProcedure(fileName);
-
-                        _halconToolDict[path] = tool;
-                    }
-                });
+                tool?.Dispose();
             }
+
+            _halconToolDict = new Dictionary<string, HDevEngineTool>();
+
+            Config.GetHalconToolPathList().ForEach(path =>
+            {
+                if (!string.IsNullOrWhiteSpace(path) && !_halconToolDict.ContainsKey(path))
+                {
+                    string directoryPath = Path.GetDirectoryName(path);
+                    string fileName = Path.GetFileNameWithoutExtension(path);
+
+                    HDevEngineTool tool = new HDevEngineTool(directoryPath);
+                    tool.LoadProcedure(fileName);
+
+                    _halconToolDict[path] = tool;
+                }
+            });
         }
 
         public List<IDevice> GetDeviceList()
@@ -621,7 +591,7 @@
                                     res = new ProcessResponse((int)ReturnValue.EXCEPTIONVALUE);
                                 }
 
-                                var newEx = new ProcessException("鍑芥暟" + methodCode + "鎵ц寮傚父", ex);
+                                var newEx = new ProcessException("鍑芥暟" + methodCode + "鎵ц寮傚父", ExceptionLevel.Warning, ex);
                             }
                             else
                             {
@@ -658,60 +628,6 @@
             {
                 monitorSet.Response.ResultValue = (int)ReturnValue.OKVALUE;
             }
-            #endregion
-
-            //sw.Stop();
-            //LogAsync(DateTime.Now, methodCode + " 璋冪敤鑰楁椂: " + sw.ElapsedMilliseconds.ToString() + "ms", "");
-            //TimeRecordCSV(DateTime.Now, methodCode + "璋冪敤", (int)sw.ElapsedMilliseconds);
-            //sw.Start();
-
-            #region 鍘熸湁PLC鍐欏叆缁撴灉鎿嶄綔锛岀幇杞埌寮傛璋冪敤鍚庡洖璋冨幓鎵ц
-            //ProcessResponse resValues = res as ProcessResponse;
-
-            //if (resValues.ResultValue == (int)PLCReplyValue.IGNORE)
-            //{
-            //    return;
-            //}
-
-            //if (monitorSet.ReplyDataAddress != -1 && resValues.DataList.Count > 0)
-            //{
-            //    PLC_ITEM item = new PLC_ITEM();
-            //    item.OP_TYPE = 2;
-            //    item.ITEM_LENGTH = resValues.DataList.Count;
-            //    item.ADDRESS = monitorSet.ReplyDataAddress.ToString();
-            //    item.ITEM_VALUE = String.Join(",", resValues.DataList);
-            //    PLC.WriteItem(item, false);
-            //}
-
-            //if (monitorSet.NoticeAddress != -1)
-            //{
-            //    //娴嬭瘯妯″紡涓嬪缁堝弽棣圤K淇″彿
-            //    if (StationConfig.IsDemoMode && resValues.ResultValue <= 0)
-            //    {
-            //        resValues.ResultValue = (int)ReturnValue.OKVALUE;
-            //    }
-
-            //    int repeatTime = 5;
-
-            //    //LogAsync(DateTime.Now, methodCode + "寮�濮嬪弽棣�", "");
-            //    do
-            //    {
-            //        try
-            //        {
-            //            PLC.WriteSingleAddress(set.NoticeAddress, resValues.ResultValue, false);
-            //            repeatTime = 0;
-            //        }
-            //        catch (Exception ex)
-            //        {
-            //            repeatTime--;
-
-            //            if (repeatTime <= 0)
-            //            {
-            //                new ProcessException("PLC鍙嶉鍐欏叆寮傚父", ex);
-            //            }
-            //        }
-            //    } while (repeatTime > 0);
-            //}
             #endregion
         }
 
@@ -1176,7 +1092,7 @@
                     else
                     {
                         //MessageBox.Show("鏈兘鑾峰彇绂荤嚎鍥剧墖锛�");
-                        throw new ProcessException("鏈兘鑾峰彇绂荤嚎鍥剧墖锛�", null);
+                        throw new ProcessException("鏈兘鑾峰彇绂荤嚎鍥剧墖锛�");
                     }
                 }
             }
@@ -1440,7 +1356,7 @@
         #endregion
 
         #region 鎶ヨ鍜孌ownTime
-        public ObservableCollection<string> _warningRemains = new ObservableCollection<string>();
+        public ObservableCollection<string> WarningRemains { get; set; } = new ObservableCollection<string>();
 
         bool warningRemainFlag = false;
         bool WarningRemainFlag
diff --git a/src/A032.Process/ProcessControl_AGV.cs b/src/A032.Process/ProcessControl_AGV.cs
new file mode 100644
index 0000000..dcfacac
--- /dev/null
+++ b/src/A032.Process/ProcessControl_AGV.cs
@@ -0,0 +1,102 @@
+锘縰sing Bro.Common.Helper;
+using Bro.Device.SeerAGV;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace A032.Process
+{
+    public partial class ProcessControl
+    {
+        private async void OnAGVBatteryLvlChanged(SeerAGVDriver agv, float preBatteryLvl, float batteryLvl)
+        {
+            await Task.Run(() =>
+            {
+                var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
+                SeerAGVInitialConfig iConfig = bind.AGV.InitialConfig as SeerAGVInitialConfig;
+
+                if (bind.UnitState == AGVState.Idle)
+                {
+                    if (batteryLvl <= iConfig.BatteryLvlToCharge)
+                    {
+                        bind.CurrentTaskId = "InCharge";
+                        bind.UnitState = AGVState.InCharge;
+
+                        var chargePosition = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.Charge);
+
+                        if (chargePosition == null)
+                        {
+                            bind.WarningMsg = $"{bind.AGV.Name}鐩墠鏃犲彲鐢ㄥ厖鐢靛湴鍧�";
+                            new ProcessException(bind.WarningMsg);
+                            bind.UnitState = AGVState.Warning;
+                        }
+                        else
+                        {
+                            bind.AGV.TaskOrder(chargePosition.PositionCode, true);
+                        }
+                    }
+                    else if (batteryLvl <= iConfig.BatteryLvlToCharge_Recommand)
+                    {
+                        ChargeWhenIdle(bind);
+                    }
+                }
+                else if (bind.UnitState == AGVState.InCharge)
+                {
+                    if (batteryLvl >= iConfig.BatteryLvlChargeDone)
+                    {
+                        bind.UnitState = AGVState.Idle;
+                    }
+                    else if (batteryLvl >= iConfig.BatteryLvlToCharge_Recommand)
+                    {
+                        bind.UnitState = AGVState.IdleCharge;
+                    }
+                }
+            });
+        }
+
+        private async void OnAGVTaskStatusChanged(SeerAGVDriver agv, AGVTaskStatus taskStatus)
+        {
+            await Task.Run(() =>
+            {
+                //濡傛灉鎴愬姛鍒拌揪鍏呯數鍦扮偣锛屽紑濮嬪厖鐢�
+                if (taskStatus == AGVTaskStatus.Completed && Config.PositionCollection.Any(u => u.Description == PathPositionDefinition.Charge && u.PositionCode == agv.CurrentPosition))
+                {
+                    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
+                    if (bind != null)
+                    {
+                        //琛ㄧず鍏呯數鍔ㄤ綔浠诲姟瀹屾垚
+                        bind.CurrentTaskId = "";
+                    }
+                }
+            });
+        }
+
+        private async void OnAGVPositionChanged(SeerAGVDriver agv, string positionCode)
+        {
+            await Task.Run(() =>
+            {
+
+            });
+        }
+
+        private void ChargeWhenIdle(AGVBindUnit bind)
+        {
+            bind.CurrentTaskId = "IdleCharge";
+            bind.UnitState = AGVState.IdleCharge;
+
+            //璁剧疆涓烘棤闇�绛夊緟鏄负浜嗘柟渚挎墽琛岃繃绋嬩腑鍙互鍙栨秷褰撳墠鎿嶄綔锛屾墽琛屼换鍔�
+            var chargePosition = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.Charge);
+
+            if (chargePosition != null)
+            {
+                bind.AGV.TaskOrder(chargePosition.PositionCode, true);
+            }
+            else
+            {
+                new ProcessException($"{bind.AGV.Name}鏈兘鑾峰彇鍏呯數鍦板潃");
+            }
+        }
+    }
+}
diff --git a/src/A032.Process/ProcessControl_Calibration.cs b/src/A032.Process/ProcessControl_Calibration.cs
index 44a19ea..7dad539 100644
--- a/src/A032.Process/ProcessControl_Calibration.cs
+++ b/src/A032.Process/ProcessControl_Calibration.cs
@@ -3,6 +3,7 @@
 using Bro.Common.Helper;
 using Bro.Common.Interface;
 using Bro.Common.Model;
+using Bro.Device.AuboRobot;
 using HalconDotNet;
 using System;
 using System.Collections.Generic;
@@ -16,8 +17,6 @@
 {
     public partial class ProcessControl
     {
-        CalibReplyMsg _calibReply = new CalibReplyMsg();
-
         [ProcessMethod("CalibrationCollection", "RobotCalibration", "鏈哄櫒浜�9鐐规爣瀹�", true)]
         public ProcessResponse RobotCalibration(IOperationConfig config, IDevice device)
         {
@@ -29,7 +28,7 @@
                 throw new ProcessException("鏈兘鑾峰彇缁戝畾璁惧淇℃伅");
             }
 
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo);
+            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionCode == calibConfig.PositionCode);
             if (position == null)
             {
                 throw new ProcessException("鏈兘鑾峰彇姝g‘浣嶇疆淇℃伅");
@@ -42,64 +41,15 @@
 
             if (calibConfig.IsStartedFromUI)
             {
-                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Calibration, CalculateMatrix);
+                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, CalculateMatrix);
                 frm.ShowDialog();
             }
             else
             {
-                MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Calibration);
+                MultipleStepsProcess(calibConfig, bind);
 
                 CalculateMatrix(calibConfig, bind, position);
             }
-
-            //for (int i = 0; i < calibConfig.Configs.Count; i++)
-            //{
-            //    bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, calibConfig.PositionNo, new List<float>() { i + 1 });
-
-            //    _calibReply.CalibHandle.WaitOne();
-
-            //    if (_calibReply.CalibIndex != (i + 1) || _calibReply.CalibPositionNo != calibConfig.PositionNo)
-            //    {
-            //        throw new ProcessException("鏍囧畾鍙嶉鐨勭储寮曟垨浣嶇疆淇℃伅涓嶄竴鑷�");
-            //    }
-
-            //    calibConfig.Configs[i].CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y);
-
-            //    using (HObject hImage = CollectHImage(bind.Camera, calibConfig.Configs[i].CameraOpConfig, "RobotCalibration"))
-            //    {
-            //        var tool = _halconToolDict[calibConfig.Configs[i].CameraOpConfig.AlgorithemPath];
-
-            //        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-            //        tool.RunProcedure();
-
-            //        float x = (float)tool.GetResultTuple("OUTPUT_X").D;
-            //        float y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-            //        float angel = (float)tool.GetResultTuple("OUTPUT_Angle").D;
-            //        if (x < 0 || y < 0)
-            //        {
-            //            throw new ProcessException("鑾峰彇鐐逛綅淇℃伅涓嶆纭�");
-            //        }
-
-            //        calibConfig.Configs[i].ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel);
-            //    }
-            //}
-
-            //HOperatorSet.VectorToHomMat2d(new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.Y).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.Y).ToArray()), out HTuple matrix);
-
-            //var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode);
-            //if (visionConfig != null)
-            //{
-            //    visionConfig.Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 };
-            //}
-            //else
-            //{
-            //    Config.VisionConfigCollection.Add(new PositionVisionConfig()
-            //    {
-            //        CameraId = bind.CameraId,
-            //        PositionCode = position.PositionCode,
-            //        Matrix = new List<double>() { matrix[0], matrix[1], 0, matrix[3], matrix[4], 0 },
-            //    });
-            //}
 
             return new ProcessResponse(true);
         }
@@ -115,7 +65,7 @@
                 throw new ProcessException("鏈兘鑾峰彇缁戝畾璁惧淇℃伅");
             }
 
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo);
+            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionCode == calibConfig.PositionCode);
             if (position == null)
             {
                 throw new ProcessException("鏈兘鑾峰彇姝g‘浣嶇疆淇℃伅");
@@ -128,72 +78,22 @@
 
             if (calibConfig.IsStartedFromUI)
             {
-                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Standard, CalculateStandardPoint);
+                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, CalculateStandardPoint);
                 frm.ShowDialog();
             }
             else
             {
-                MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Standard);
+                MultipleStepsProcess(calibConfig, bind);
 
                 CalculateStandardPoint(calibConfig, bind, position);
             }
-
-            //for (int i = 0; i < calibConfig.Configs.Count; i++)
-            //{
-            //    bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, calibConfig.PositionNo, new List<float>() { i + 1 });
-
-            //    _calibReply.CalibHandle.WaitOne();
-
-            //    if (_calibReply.CalibPositionNo != calibConfig.PositionNo)
-            //    {
-            //        throw new ProcessException("鏍囧畾鍙嶉鐨勪綅缃俊鎭笉涓�鑷�");
-            //    }
-
-            //    calibConfig.Configs[i].CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y);
-
-            //    using (HObject hImage = CollectHImage(bind.Camera, calibConfig.Configs[i].CameraOpConfig, "RobotCalibration"))
-            //    {
-            //        var tool = _halconToolDict[calibConfig.Configs[i].CameraOpConfig.AlgorithemPath];
-
-            //        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-            //        tool.RunProcedure();
-
-            //        float x = (float)tool.GetResultTuple("OUTPUT_X").D;
-            //        float y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-            //        float angel = (float)tool.GetResultTuple("OUTPUT_Angle").D;
-            //        if (x < 0 || y < 0)
-            //        {
-            //            throw new ProcessException("鑾峰彇鐐逛綅淇℃伅涓嶆纭�");
-            //        }
-
-            //        calibConfig.Configs[i].ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel);
-            //    }
-            //}
-
-            //CustomizedPointWithAngle markPoint = calibConfig.Configs[0].ImageMarkPoint;
-            //var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode);
-            //if (visionConfig != null)
-            //{
-            //    visionConfig.StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle);
-            //}
-            //else
-            //{
-            //    Config.VisionConfigCollection.Add(new PositionVisionConfig()
-            //    {
-            //        CameraId = bind.CameraId,
-            //        PositionCode = position.PositionCode,
-            //        StandardPoint = new CustomizedPointWithAngle(markPoint.X, markPoint.Y, markPoint.Angle),
-            //    });
-            //}
 
             return new ProcessResponse(true);
         }
 
         public void CalculateMatrix(CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position)
         {
-            //HOperatorSet.VectorToHomMat2d(new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.ImageMarkPoint.Y).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.X).ToArray()), new HTuple(calibConfig.Configs.Select(u => u.CurrentPlatPoint.Y).ToArray()), out HTuple matrix);
-
-            List<double> matrix = GetMovementMatrix(calibConfig.Configs.Select(u => u.ImageMarkPoint as CustomizedPoint).ToList(), calibConfig.Configs.Select(u => u.CurrentPlatPoint).ToList(), out string msg);
+            List<double> matrix = GetMovementMatrix(calibConfig.Configs.Select(u => u.ImageMarkPoint as CustomizedPoint).ToList(), calibConfig.Configs.Select(u => new CustomizedPoint(u.PlatPoint.X, u.PlatPoint.Y)).ToList(), out string msg);
 
             var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode);
             if (visionConfig != null)
@@ -235,7 +135,6 @@
                 sum += Math.Sqrt((Math.Pow((m.D - platPoints[i].X), 2) + Math.Pow((n.D - platPoints[i].Y), 2)));
             }
 
-            //sum = ((sum / (double)Config.LengthPulseRatio) * 100.0) / ((double)imagePoints.Count);
             sum = sum / (double)imagePoints.Count;
 
             msg = $"鏍囧畾鐐规暟閲�:{imagePoints.Count};鍗曠偣璇樊:{sum.ToString()}鑴夊啿";
@@ -251,18 +150,6 @@
 
         public void CalculateStandardPoint(CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position)
         {
-            //var bind = Config.AGVBindCollection.FirstOrDefault(u => u.CameraId == calibConfig.CameraId);
-            //if (bind == null)
-            //{
-            //    throw new ProcessException("鏈兘鑾峰彇缁戝畾璁惧淇℃伅");
-            //}
-
-            //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == calibConfig.PositionNo);
-            //if (position == null)
-            //{
-            //    throw new ProcessException("鏈兘鑾峰彇姝g‘浣嶇疆淇℃伅");
-            //}
-
             CustomizedPointWithAngle markPoint = calibConfig.Configs[0].ImageMarkPoint;
             var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == position.PositionCode);
             if (visionConfig != null)
@@ -282,51 +169,25 @@
             PubSubCenter.Publish(PubTag.CalibAllDone.ToString(), "", $"鏍囧畾瀹屾垚锛屾爣鍑嗙偣:{markPoint.GetDisplayText()}", true);
         }
 
-        public void MultipleStepsProcess(CalibrationConfigCollection calibConfig, AGVBindUnit bind, Action<AGVBindUnit, int, int> sendMessageToRobot)
+        public void MultipleStepsProcess(CalibrationConfigCollection calibConfig, AGVBindUnit bind)
         {
             for (int i = 0; i < calibConfig.Configs.Count; i++)
             {
-                SingleStepProcess(calibConfig.Configs[i], sendMessageToRobot, bind, calibConfig.PositionNo, i);
+                SingleStepProcess(calibConfig.Configs[i], bind, i);
             }
         }
 
-        public void SendMessageToRobot_Calibration(AGVBindUnit bind, int positionNo, int index)
+        public void SingleStepProcess(CalibrationConfig config, AGVBindUnit bind, int index)
         {
-            bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, positionNo, new List<float>() { index + 1 });
-
-            _calibReply.CalibHandle.WaitOne();
-
-            if (_calibReply.CalibIndex != (index + 1) || _calibReply.CalibPositionNo != positionNo)
-            {
-                throw new ProcessException("鏍囧畾鍙嶉鐨勭储寮曟垨浣嶇疆淇℃伅涓嶄竴鑷�");
-            }
-        }
-
-        public void SendMessageToRobot_Standard(AGVBindUnit bind, int positionNo, int index)
-        {
-            bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.StandardPoint, Bro.Device.AuboRobot.RobotMsgParas.None, positionNo);
-
-            _calibReply.CalibHandle.WaitOne();
-
-            if (_calibReply.CalibPositionNo != positionNo)
-            {
-                throw new ProcessException("鏍囧畾鍙嶉鐨勪綅缃俊鎭笉涓�鑷�");
-            }
-        }
-
-        //PubSubCenter.Subscribe(PubTag.CalibStepDone.ToString(), CalibStepDone);
-        //PubSubCenter.Subscribe(PubTag.CalibAllDone.ToString(), CalibAllDone);
-        public void SingleStepProcess(CalibrationConfig config, Action<AGVBindUnit, int, int> sendMessageToRobot, AGVBindUnit bind, int positionNo, int index)
-        {
-            sendMessageToRobot.Invoke(bind, positionNo, index);
-
-            config.CurrentPlatPoint = new CustomizedPoint(_calibReply.RobotPosition.X, _calibReply.RobotPosition.Y);
+            bind.Robot.Move(config.PlatPoint, MoveType.AbsoluteMove, true);
 
             using (HObject hImage = CollectHImage(bind.Camera, config.CameraOpConfig, "RobotCalibration"))
             {
                 var tool = _halconToolDict[config.CameraOpConfig.AlgorithemPath];
 
-                tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+                tool.InputImageDic.Clear();
+                tool.InputImageDic["INPUT_Image"] = hImage;
+
                 tool.RunProcedure();
 
                 float x = (float)tool.GetResultTuple("OUTPUT_X").D;
@@ -342,16 +203,5 @@
 
             PubSubCenter.Publish(PubTag.CalibStepDone.ToString(), index, "", true);
         }
-    }
-
-    public class CalibReplyMsg
-    {
-        public AutoResetEvent CalibHandle { get; set; } = new AutoResetEvent(false);
-
-        public int CalibIndex { get; set; } = 0;
-
-        public int CalibPositionNo { get; set; }
-
-        public CustomizedPoint RobotPosition { get; set; } = new CustomizedPoint();
     }
 }
diff --git a/src/A032.Process/ProcessControl_Method.cs b/src/A032.Process/ProcessControl_Method.cs
index dc0d8c8..00c656d 100644
--- a/src/A032.Process/ProcessControl_Method.cs
+++ b/src/A032.Process/ProcessControl_Method.cs
@@ -8,6 +8,7 @@
 using HalconDotNet;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Drawing;
 using System.IO;
@@ -20,331 +21,7 @@
 {
     public partial class ProcessControl
     {
-        const int WAITTIME = 5000;
-
-        Dictionary<int, int> machineFullTrayDict = new Dictionary<int, int>();
-        Dictionary<int, int> machineEmptyTrayDict = new Dictionary<int, int>();
-        List<TaskAssignInfo> taskAssignedList = new List<TaskAssignInfo>();
-
-        #region AGV浜嬩欢
-        private void OnAGVBatteryLvlChanged(SeerAGVDriver agv, float preBatteryLvl, float batteryLvl)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
-            SeerAGVInitialConfig iConfig = agv.InitialConfig as SeerAGVInitialConfig;
-            if (batteryLvl <= iConfig.BatteryLvlToCharge && preBatteryLvl > iConfig.BatteryLvlToCharge)
-            {
-                Task.Run(() =>
-                {
-                    var position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.Charge);
-
-                    if (position == null)
-                    {
-                        throw new ProcessException("鏈壘鍒板厖鐢靛湴鐐�");
-                    }
-
-                    while (bind.UnitStatus != TaskStatus.Available)
-                    {
-                        if (bind.SetAGVStatus(TaskStatus.Running))
-                        {
-                            bind.AGV.TaskOrder(position.PositionCode);
-                            break;
-                        }
-
-                        Thread.Sleep(WAITTIME);
-                    }
-                });
-
-                return;
-            }
-
-            if (batteryLvl >= iConfig.BatteryLvlChargeDone && preBatteryLvl < iConfig.BatteryLvlChargeDone)
-            {
-                var position = Config.PositionCollection.FirstOrDefault(u => u.PositionCode == agv.CurrentPosition);
-
-                if (position != null && position.Description == PathPositionDefinition.Charge)
-                {
-                    bind.SetAGVStatus(TaskStatus.Available);
-                }
-                return;
-            }
-        }
-
-        private void OnAGVTaskStatusChanged(SeerAGVDriver agv, AGVTaskStatus taskStatus)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
-
-            if (bind == null)
-            {
-                throw new ProcessException("鏈兘鏍规嵁AGV淇℃伅鑾峰彇缁戝畾璁惧淇℃伅", null);
-            }
-
-            if (bind.AGVDest == agv.CurrentPosition && taskStatus == AGVTaskStatus.Completed)
-            {
-                //PathPosition loadEmptyTrayPosition = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
-
-                //if (bind.AGVDest == loadEmptyTrayPosition.PositionCode)
-                //{
-                //    bind.RobotStatus = TaskStatus.Running;
-                //}
-
-                bind.SetAGVStatus(TaskStatus.Available);
-            }
-        }
-
-        private void OnAGVPositionChanged(SeerAGVDriver agv, string positionCode)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
-
-            if (bind == null)
-            {
-                throw new ProcessException("鏈兘鏍规嵁AGV淇℃伅鑾峰彇缁戝畾璁惧淇℃伅", null);
-            }
-
-            if (bind.AGVDest == positionCode && agv.TaskStatus == AGVTaskStatus.Completed)
-            {
-                //PathPosition loadEmptyTrayPosition = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
-
-                //if (bind.AGVDest == loadEmptyTrayPosition.PositionCode)
-                //{
-                //    bind.RobotStatus = TaskStatus.Running;
-                //}
-
-                bind.SetAGVStatus(TaskStatus.Available);
-                LogAsync(DateTime.Now, $"AGV鍒颁綅{positionCode}", "");
-
-                PathPosition position = Config.PositionCollection.FirstOrDefault(p => p.PositionCode == bind.AGVDest);
-                switch (position.Description)
-                {
-                    case PathPositionDefinition.LoadEmptyTray:
-                        LogAsync(DateTime.Now, $"AGV瀹屾垚锛屽噯澶囦笂绌篢ray", "");
-                        Robot_LoadEmptyTray(bind.Id, position);
-                        break;
-                    case PathPositionDefinition.LoadFullTray:
-                        LogAsync(DateTime.Now, $"AGV瀹屾垚锛屽噯澶囦笂婊ray", "");
-                        Robot_LoadFullTraySnap(bind.Id, position);
-                        break;
-                    case PathPositionDefinition.UnloadEmptyTray:
-                        LogAsync(DateTime.Now, $"AGV瀹屾垚锛屽噯澶囦笅绌篢ray", "");
-                        Robot_UnloadEmptyTraySnap(bind.Id, position);
-                        break;
-                    case PathPositionDefinition.UnloadFullTray:
-                        LogAsync(DateTime.Now, $"AGV瀹屾垚锛屽噯澶囦笅婊ray", "");
-                        Robot_UnloadFullTraySnap(bind.Id, position);
-                        break;
-                    default:
-                        break;
-                }
-            }
-        }
-        #endregion
-
-        private void OnRobotMsgReceived(DateTime dt, AuboRobotDriver robot, RobotMsg msg)
-        {
-            LogAsync(dt, robot.Name + "鎺ユ敹淇℃伅", msg.GetDisplayText());
-
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robot.Id);
-
-            if (bind == null)
-            {
-                throw new ProcessException("鏈兘鏍规嵁鏈哄櫒浜轰俊鎭幏鍙栫粦瀹氳澶囦俊鎭�", null);
-            }
-
-            //List<AGVTaskModel> models = new List<AGVTaskModel>();
-
-            switch (msg.Action)
-            {
-                case RobotMsgAction.Load:
-                    {
-                        switch (msg.Para1)
-                        {
-                            case RobotMsgParas.EmptyTray:
-                                {
-                                    bind.RobotStatus = bind.AGVStatus = TaskStatus.Available;
-                                }
-                                break;
-                            case RobotMsgParas.FullTray:
-                                {
-                                    machineFullTrayDict[msg.Para2]--;
-                                    bind.CurrentFullTray = int.Parse(msg.Datas[1]);
-
-                                    if (machineFullTrayDict[msg.Para2] > 0 && !bind.IsFullTrayFull)
-                                    {
-                                        RobotMsg_UnloadEmptyTray.Para2 = msg.Para2;
-                                        robot.SendMsg(RobotMsg_UnloadEmptyTray, true);
-                                    }
-                                    else
-                                    {
-                                        bind.RobotStatus = TaskStatus.Available;
-                                    }
-                                }
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    break;
-                case RobotMsgAction.Unload:
-                    {
-                        switch (msg.Para1)
-                        {
-                            case RobotMsgParas.EmptyTray:
-                                {
-                                    machineEmptyTrayDict[msg.Para2]++;
-                                    bind.CurrentEmptyTray = int.Parse(msg.Datas[0]);
-
-                                    if (machineEmptyTrayDict[msg.Para2] < Config.Machine_EmptyTrayNum)
-                                    {
-                                        //bind.RobotIOHandle.Reset();
-                                        //bind.RobotIOHandle.WaitOne();
-                                        bind.Robot.MonitorHandle.WaitOne();
-                                        //bind.Robot.IOChangedHandle.WaitOne();
-                                        Thread.Sleep((bind.Robot.InitialConfig as AuboRobotInitialConfig).ScanInterval);
-
-                                        if (!bind.IsFullTrayFull)
-                                        {
-                                            RobotMsg_UnloadEmptyTray.Para2 = msg.Para2;
-                                            robot.SendMsg(RobotMsg_UnloadEmptyTray, true);
-                                        }
-                                        else
-                                        {
-                                            bind.RobotStatus = TaskStatus.Available;
-                                        }
-                                    }
-                                    else
-                                    {
-                                        bind.RobotStatus = TaskStatus.Available;
-                                    }
-                                }
-                                break;
-                            case RobotMsgParas.FullTray:
-                                {
-                                    bind.CurrentFullTray = int.Parse(msg.Datas[1]);
-
-                                    //bind.RobotIOHandle.Reset();
-                                    //bind.RobotIOHandle.WaitOne();
-                                    bind.Robot.MonitorHandle.WaitOne();
-                                    //bind.Robot.IOChangedHandle.WaitOne();
-                                    Thread.Sleep((bind.Robot.InitialConfig as AuboRobotInitialConfig).ScanInterval);
-
-                                    if (!bind.IsFullTrayEmpty)
-                                    {
-                                        Camera_UnloadFullTray(robot.Id, msg.Para2);
-                                    }
-                                    else
-                                    {
-                                        bind.RobotStatus = TaskStatus.Available;
-                                    }
-                                }
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    break;
-                case RobotMsgAction.Move:
-                    {
-                        switch (msg.Para1)
-                        {
-                            case RobotMsgParas.LineSnap:
-                                {
-                                    Camera_UnloadFullTray(robot.Id, msg.Para2);
-                                }
-                                break;
-                            case RobotMsgParas.LoadFullTraySnap:
-                                {
-                                    Camera_LoadFullTray(robot.Id, msg.Para2);
-                                }
-                                break;
-                            case RobotMsgParas.UnloadEmptyTraySnap:
-                                {
-                                    Camera_UnloadEmptyTray(robot.Id, msg.Para2);
-                                }
-                                break;
-                            case RobotMsgParas.Home:
-                                {
-                                    bind.RobotStatus = TaskStatus.Available;
-                                }
-                                break;
-                            default:
-                                break;
-                        }
-                    }
-                    break;
-                case RobotMsgAction.Calibration:
-                    {
-                        _calibReply.CalibIndex = int.Parse(msg.Datas[4]);
-                        _calibReply.CalibPositionNo = msg.Para2;
-                        _calibReply.RobotPosition = new CustomizedPoint(float.Parse(msg.Datas[0]), float.Parse(msg.Datas[1]));
-
-                        _calibReply.CalibHandle.Set();
-                    }
-                    break;
-                case RobotMsgAction.StandardPoint:
-                    {
-                        _calibReply.CalibPositionNo = msg.Para2;
-                        _calibReply.CalibHandle.Set();
-                    }
-                    break;
-                default:
-                    break;
-            }
-
-            //if (models.Count > 0)
-            //{
-            //    models.ForEach(model =>
-            //    {
-            //        if (!bind.TaskList.Any(t => t.MethodName == model.MethodName))
-            //        {
-            //            model.OpConfig = new AGVBindOpConfig(bind.Id);
-            //            bind.AddTask(model);
-            //        }
-            //    });
-            //}
-        }
-
-        public void QueryRobotIO()
-        {
-            RobotDict.Values.ToList().ForEach(r =>
-            {
-                r.SendMsg(RobotMsgAction.IO, RobotMsgParas.Query, 0);
-            });
-        }
-
-        //private void OnBindUnitTaskInvoke(AGVTaskModel task)
-        //{
-        //    InvokeMethodDict[task.MethodName].Invoke(this, new object[] { task.OpConfig, task.Device });
-
-        //    //var response = task.MethodFunc.Invoke(task.OpConfig, task.Device);
-        //}
-
         #region Robot鐩戝惉浜嬩欢
-        //private void AddNewTaskToBind(string robotId, List<AGVTaskModel> models)
-        //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
-
-        //    if (bind == null)
-        //    {
-        //        throw new ProcessException("鏈兘鏍规嵁鏈哄櫒浜轰俊鎭幏鍙栫粦瀹氳澶囦俊鎭�", null);
-        //    }
-
-        //    AddNewTaskToBind(bind, models);
-        //}
-
-        //private void AddNewTaskToBind(AGVBindUnit bind, List<AGVTaskModel> models)
-        //{
-        //    if (models.Count > 0)
-        //    {
-        //        models.ForEach(model =>
-        //        {
-        //            if (!bind.TaskList.Any(t => t.MethodName == model.MethodName))
-        //            {
-        //                model.OpConfig = new AGVBindOpConfig(bind.Id);
-        //                bind.AddTask(model);
-        //            }
-        //        });
-        //    }
-        //}
-
         [ProcessMethod("", "Robot_Monitor_Alarm", "鏈哄櫒浜虹洃鍚簨浠�-鎶ヨ", true)]
         public ProcessResponse Robot_Monitor_Alarm(IOperationConfig config, IDevice device)
         {
@@ -352,11 +29,11 @@
 
             if (bind == null)
             {
-                throw new ProcessException("鏈兘鏍规嵁鏈哄櫒浜轰俊鎭幏鍙栫粦瀹氳澶囦俊鎭�", null);
+                throw new ProcessException($"鏈兘鑾峰彇{device.Name}鐨勭粦瀹氳澶囦俊鎭�");
             }
 
-            bind.AGV.PauseTask();
-            bind.RobotStatus = TaskStatus.Warning;
+            bind.AGV.CancelTask();
+            bind.UnitState = AGVState.Warning;
 
             return new ProcessResponse(true);
         }
@@ -364,92 +41,58 @@
         [ProcessMethod("", "Robot_Monitor_EmptyTrayEmpty", "鏈哄櫒浜虹洃鍚簨浠�-绌篢ray鍖哄煙娓呯┖", true)]
         public ProcessResponse Robot_Monitor_EmptyTrayEmpty(IOperationConfig config, IDevice device)
         {
-            bool isEmptyTrayEmpty = config.InputPara[0] == 0;
             var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == device.Id);
-            if (isEmptyTrayEmpty)
+
+            if (bind == null)
             {
-                bind.IsEmptyTrayEmpty = true;
-
-                Task.Run(() =>
-                {
-                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadEmptyTray;
-                    while (bind.IsEmptyTrayEmpty && !bind.IsEmptyTrayTaskAssigned)
-                    {
-                        //if (bind.TaskList.Count == 0)
-                        if (bind.UnitStatus == TaskStatus.Available)
-                        {
-                            //List<AGVTaskModel> models = new List<AGVTaskModel>();
-                            //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_LoadEmptyTray"));
-                            //models.Add(new AGVTaskModel(TaskAvailableLevel.AGV, "AfterEmptyTrayPositionArrived"));
-
-                            //AddNewTaskToBind(device.Id, models);
-
-                            if (AGV_LoadEmptyTray(bind.Id))
-                            {
-                                bind.IsEmptyTrayTaskAssigned = true;
-                            }
-                        }
-                        else
-                        {
-                            Thread.Sleep(WAITTIME);
-                        }
-                    }
-                });
+                throw new ProcessException($"鏈兘鑾峰彇{device.Name}鐨勭粦瀹氳澶囦俊鎭�");
             }
-            else
-            {
-                bind.IsEmptyTrayEmpty = false;
-                bind.IsEmptyTrayTaskAssigned = false;
-            }
+
+            bind.EmptyTrayNum = 0;
+
+            TrayTask task = new TrayTask();
+            task.TaskType = TaskType.LoadEmptyTrayToAGV;
+            //task.Priority = 10;
+            task.SourceDeviceId = device.Id;
+            //task.SourceDeviceName = device.Name;
+
+            //濡傛灉鐩墠鍦板潃琚崰鐢紝鍦板潃鏈夊彲鑳戒负绌猴紝闇�瑕佸湪浠诲姟鎸囨淳鏃跺啀娆$‘璁�
+            task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.LoadEmptyTray);
+
+            InsertTask(task);
 
             return new ProcessResponse(true);
         }
 
+        /// <summary>
+        /// 淇″彿瑕佹眰闀夸俊鍙疯Е鍙戯紝閬垮厤璇Е鍙�
+        /// </summary>
+        /// <param name="config"></param>
+        /// <param name="device"></param>
+        /// <returns></returns>
         [ProcessMethod("", "Robot_Monitor_FullTrayFull", "鏈哄櫒浜虹洃鍚簨浠�-婊ray鍖哄煙鏀炬弧", true)]
         public ProcessResponse Robot_Monitor_FullTrayFull(IOperationConfig config, IDevice device)
         {
-            //(device as AuboRobotDriver).IOChangedHandle.Reset();
-            bool isFullTrayFull = config.InputPara[0] == 1;
             var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == device.Id);
-            if (isFullTrayFull)
+
+            if (bind == null)
             {
-                bind.IsFullTrayFull = true;
-
-                Task.Run(() =>
-                {
-                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadFullTray;
-                    while (bind.IsFullTrayFull && !bind.IsFullTrayTaskAssigned)
-                    {
-                        //if (bind.TaskList.Count == 0)
-                        if (bind.UnitStatus == TaskStatus.Available)
-                        {
-                            //List<AGVTaskModel> models = new List<AGVTaskModel>();
-                            //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_UnloadFullTray"));
-                            //models.Add(new AGVTaskModel(TaskAvailableLevel.AGV, "Robot_UnloadFullTray"));
-
-                            //AddNewTaskToBind(device.Id, models);
-
-                            if (AGV_UnloadFullTray(bind.Id))
-                            {
-                                bind.IsFullTrayTaskAssigned = true;
-                            }
-                        }
-                        else
-                        {
-                            Thread.Sleep(WAITTIME);
-                        }
-                    }
-                });
-            }
-            else
-            {
-                bind.IsFullTrayFull = false;
-                bind.IsFullTrayTaskAssigned = false;
+                throw new ProcessException($"鏈兘鑾峰彇{device.Name}鐨勭粦瀹氳澶囦俊鎭�");
             }
 
-            //(device as AuboRobotDriver).IOChangedHandle.Set();
+            //if (bind.FullTrayNum >= Config.AGVAvailableTrayNums)
+            {
+                bind.FullTrayNum = Config.AGVAvailableTrayNums;
 
-            //bind.RobotIOHandle.Set();
+                TrayTask task = new TrayTask();
+                task.TaskType = TaskType.UnloadFullTrayToLine;
+                task.SourceDeviceId = device.Id;
+
+                //濡傛灉鐩墠鍦板潃琚崰鐢紝鍦板潃鏈夊彲鑳戒负绌猴紝闇�瑕佸湪浠诲姟鎸囨淳鏃跺啀娆$‘璁�
+                task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.UnloadFullTray);
+
+                InsertTask(task);
+            }
 
             return new ProcessResponse(true);
         }
@@ -457,13 +100,14 @@
         [ProcessMethod("", "Robot_Monitor_FullTrayEmpty", "鏈哄櫒浜虹洃鍚簨浠�-婊ray鍖哄煙娓呯┖", true)]
         public ProcessResponse Robot_Monitor_FullTrayEmpty(IOperationConfig config, IDevice device)
         {
-            //(device as AuboRobotDriver).IOChangedHandle.Reset();
-            bool isFullTrayEmpty = config.InputPara[0] == 0;
             var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == device.Id);
-            bind.IsFullTrayEmpty = isFullTrayEmpty;
 
-            //(device as AuboRobotDriver).IOChangedHandle.Set();
-            //bind.RobotIOHandle.Set();
+            if (bind == null)
+            {
+                throw new ProcessException($"鏈兘鑾峰彇{device.Name}鐨勭粦瀹氳澶囦俊鎭�");
+            }
+
+            bind.FullTrayNum = 0;
 
             return new ProcessResponse(true);
         }
@@ -499,27 +143,103 @@
 
             if (bind == null)
             {
-                throw new ProcessException("鏈兘鏍规嵁鏈哄櫒浜轰俊鎭幏鍙栫粦瀹氳澶囦俊鎭�", null);
+                throw new ProcessException($"鏈兘鑾峰彇{device.Name}鐨勭粦瀹氳澶囦俊鎭�");
             }
             bind.AGV.CancelTask();
 
-            //isEmptyTrayTaskAssigned = false;
-            //isFullTrayTaskAssigned = false;
-
-            taskAssignedList.RemoveAll(u => u.AgvId == device.Id);
-
-            //bind.ClearTask();
-            bind.RobotStatus = bind.AGVStatus = TaskStatus.Available;
+            Reset(bind.Id);
 
             return new ProcessResponse(true);
         }
         #endregion
 
-        #region 绌篢ray涓婃枡
-        //[ProcessMethod("", "AGV_LoadEmptyTray", "AGV鍘诲線绌篢ray涓婃枡", true)]
-        //public ProcessResponse AGV_LoadEmptyTray(IOperationConfig config, IDevice device)
+        #region PLC鐩戝惉浜嬩欢
+        [ProcessMethod("", "PLC_NoticeEmptyTray", "PLC閫氱煡闇�瑕佷笂绌篢ray", true)]
+        public ProcessResponse PLC_NoticeEmptyTray(IOperationConfig config, IDevice device)
+        {
+            TrayTask task = new TrayTask();
+            task.TaskType = TaskType.UnloadEmptyTrayToMachine;
+            task.SourceDeviceId = device.Id;
+            //task.SourceDeviceName = device.Name;
+            task.Location = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray && u.DeviceOwner == device.Id);
+
+            InsertTask(task);
+
+            return new ProcessResponse(true);
+        }
+
+        [ProcessMethod("", "PLC_NoticeFullTray", "PLC閫氱煡婊ray闇�瑕佸彇璧�", true)]
+        public ProcessResponse PLC_NoticeFullTray(IOperationConfig config, IDevice device)
+        {
+            TrayTask task = new TrayTask();
+            task.TaskType = TaskType.LoadFullTrayFromMachine;
+            task.SourceDeviceId = device.Id;
+            //task.SourceDeviceName = device.Name;
+            task.Location = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.DeviceOwner == device.Id);
+
+            InsertTask(task);
+
+            return new ProcessResponse(true);
+        }
+        #endregion
+
+        [ProcessMethod("OperationTest", "OperationDemo", "鍗曟娴嬭瘯鏂规硶", true)]
+        public ProcessResponse OperationDemo(IOperationConfig config, IDevice device)
+        {
+            string s = (-1).ToString("D2");
+            string a = (1).ToString("D2");
+
+            OperationTestConfig opConfig = config as OperationTestConfig;
+
+            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == opConfig.AGVId);
+            if (bind == null)
+                throw new ProcessException("鏈兘鑾峰彇鎸囧畾AGV淇℃伅鎴朅GV缁戝畾鐨勮澶囦俊鎭�");
+
+            switch (opConfig.TaskInfo.TaskType)
+            {
+                case TaskType.LoadEmptyTrayToAGV:
+                    LoadEmptyTrayToAGV(opConfig.TaskInfo, bind);
+                    break;
+                case TaskType.LoadFullTrayFromMachine:
+                    LoadFullTrayFromMachine(opConfig.TaskInfo, bind);
+                    break;
+                case TaskType.UnloadEmptyTrayToMachine:
+                    UnloadEmptyTrayToMachine(opConfig.TaskInfo, bind);
+                    break;
+                case TaskType.UnloadFullTrayToLine:
+                    UnloadFullTrayToLine(opConfig.TaskInfo, bind);
+                    break;
+                default:
+                    throw new ProcessException($"鏈兘鎸囧畾{opConfig.TaskInfo.TaskType.ToString()}鐨勫搴旀柟娉�");
+            }
+
+            return new ProcessResponse(true);
+        }
+
+        #region old
+        //#region 绌篢ray涓婃枡
+        ////[ProcessMethod("", "AGV_LoadEmptyTray", "AGV鍘诲線绌篢ray涓婃枡", true)]
+        ////public ProcessResponse AGV_LoadEmptyTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
+
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓婃枡鐐�");
+        ////    }
+
+        ////    bind.AGVDest = position.PositionCode;
+        ////    bind.AGV.TaskOrder(position.PositionCode);
+
+        ////    bind.AGVStatus = TaskStatus.Running;
+
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public bool AGV_LoadEmptyTray(string bindId)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
         //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
 
         //    if (position == null)
@@ -527,42 +247,45 @@
         //        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓婃枡鐐�");
         //    }
 
-        //    bind.AGVDest = position.PositionCode;
-        //    bind.AGV.TaskOrder(position.PositionCode);
+        //    if (bind.SetAGVStatus(TaskStatus.Running))
+        //    {
+        //        bind.AGVDest = position.PositionCode;
+        //        bind.AGV.TaskOrder(position.PositionCode);
 
-        //    bind.AGVStatus = TaskStatus.Running;
-
-        //    return new ProcessResponse(true);
+        //        return true;
+        //    }
+        //    else
+        //    {
+        //        return false;
+        //    }
         //}
 
-        public bool AGV_LoadEmptyTray(string bindId)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
+        ////[ProcessMethod("", "AfterEmptyTrayPositionArrived", "鍒拌揪绌篢ray涓婃枡鐐�", true)]
+        ////public ProcessResponse AfterEmptyTrayPositionArrived(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
 
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓婃枡鐐�");
-            }
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓婃枡鐐�", null);
+        ////    }
 
-            if (bind.SetAGVStatus(TaskStatus.Running))
-            {
-                bind.AGVDest = position.PositionCode;
-                bind.AGV.TaskOrder(position.PositionCode);
+        ////    if (bind.AGV.CurrentPosition != position.PositionCode)
+        ////    {
+        ////        throw new ProcessException("AGV灏氭湭鍒拌揪绌篢ray涓婃枡鐐�", null);
+        ////    }
 
-                return true;
-            }
-            else
-            {
-                return false;
-            }
-        }
+        ////    bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.EmptyTray, 0);
+        ////    bind.RobotStatus = TaskStatus.Running;
 
-        //[ProcessMethod("", "AfterEmptyTrayPositionArrived", "鍒拌揪绌篢ray涓婃枡鐐�", true)]
-        //public ProcessResponse AfterEmptyTrayPositionArrived(IOperationConfig config, IDevice device)
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public void Robot_LoadEmptyTray(string bindId, PathPosition position)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
-        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+        //    //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
 
         //    if (position == null)
         //    {
@@ -576,160 +299,166 @@
 
         //    bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.EmptyTray, 0);
         //    bind.RobotStatus = TaskStatus.Running;
-
-        //    return new ProcessResponse(true);
         //}
 
-        public void Robot_LoadEmptyTray(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadEmptyTray);
+        ////[ProcessMethod("", "EmptyTrayReady", "绌篢ray涓婃枡瀹屾垚", true)]
+        ////public ProcessResponse EmptyTrayReady(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    bind.RobotStatus = bind.AGVStatus = TaskStatus.Available;
 
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓婃枡鐐�", null);
-            }
+        ////    return new ProcessResponse(true);
+        ////}
+        //#endregion
 
-            if (bind.AGV.CurrentPosition != position.PositionCode)
-            {
-                throw new ProcessException("AGV灏氭湭鍒拌揪绌篢ray涓婃枡鐐�", null);
-            }
+        //#region 绌篢ray寰�鏈哄彴涓嬫枡
+        ////bool isEmptyTrayNeed = false;
+        ////bool isEmptyTrayTaskAssigned = false;
+        //RobotMsg RobotMsg_UnloadEmptyTray = new RobotMsg();
 
-            bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.EmptyTray, 0);
-            bind.RobotStatus = TaskStatus.Running;
-        }
-
-        //[ProcessMethod("", "EmptyTrayReady", "绌篢ray涓婃枡瀹屾垚", true)]
-        //public ProcessResponse EmptyTrayReady(IOperationConfig config, IDevice device)
+        //private async void CheckUnloadEmptyTrayTask(int positionNo)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
-        //    bind.RobotStatus = bind.AGVStatus = TaskStatus.Available;
+        //    await Task.Run(() =>
+        //    {
+        //        var taskStatus = taskAssignedList.FirstOrDefault(u => u.PositionNo == positionNo);
 
-        //    return new ProcessResponse(true);
+        //        if (taskStatus == null)
+        //            return;
+
+        //        while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
+        //        {
+        //            //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadEmptyTray;
+
+        //            //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodName == "AGV_UnloadEmptyTray")))
+        //            {
+        //                var bind = Config.AGVBindCollection.FirstOrDefault(u => u.UnitStatus == TaskStatus.Available);
+        //                if (bind != null)
+        //                {
+        //                    var position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNo);
+        //                    //AGVTaskModel model_AGV = new AGVTaskModel(TaskAvailableLevel.Both, "AGV_UnloadEmptyTray", new AGVBindOpConfig(bind.Id, position));
+        //                    //AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, "Robot_UnloadEmptyTray", new AGVBindOpConfig(bind.Id));
+
+        //                    //bind.AddTask(model_AGV);
+        //                    //bind.AddTask(model_Robot);
+
+        //                    if (AGV_UnloadEmptyTray(bind.Id, position))
+        //                    {
+        //                        taskStatus.IsTaskAssgined = true;
+        //                        taskStatus.AgvId = bind.AGVId;
+        //                    }
+        //                }
+        //            }
+
+        //            Thread.Sleep(WAITTIME);
+        //        }
+        //    });
         //}
-        #endregion
 
-        #region 绌篢ray寰�鏈哄彴涓嬫枡
-        //bool isEmptyTrayNeed = false;
-        //bool isEmptyTrayTaskAssigned = false;
-        RobotMsg RobotMsg_UnloadEmptyTray = new RobotMsg();
-
-        [ProcessMethod("", "PLC_NoticeEmptyTray", "PLC閫氱煡闇�瑕佷笂绌篢ray", true)]
-        public ProcessResponse PLC_NoticeEmptyTray(IOperationConfig config, IDevice device)
-        {
-            if (config.InputPara == null || config.InputPara.Count == 0)
-            {
-                throw new ProcessException("涓婄┖Tray鏂规硶鏈厤缃緭鍏ュ弬鏁�", null);
-            }
-
-            bool isEmptyTrayNeed = config.InputPara[0] == 1;
-
-            if (isEmptyTrayNeed)
-            {
-                var position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray && u.DeviceOwner == device.Id);
-
-                machineEmptyTrayDict[position.PositionNo] = 0;
-
-                if (!taskAssignedList.Any(u => u.PositionNo == position.PositionNo))
-                {
-                    taskAssignedList.Add(new TaskAssignInfo()
-                    {
-                        IsTaskNeed = true,
-                        IsTaskAssgined = false,
-                        PositionNo = position.PositionNo,
-                    });
-                }
-
-                CheckUnloadEmptyTrayTask(position.PositionNo);
-            }
-
-            return new ProcessResponse(true);
-        }
-
-        private async void CheckUnloadEmptyTrayTask(int positionNo)
-        {
-            await Task.Run(() =>
-            {
-                var taskStatus = taskAssignedList.FirstOrDefault(u => u.PositionNo == positionNo);
-
-                if (taskStatus == null)
-                    return;
-
-                while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
-                {
-                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadEmptyTray;
-
-                    //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodName == "AGV_UnloadEmptyTray")))
-                    {
-                        var bind = Config.AGVBindCollection.FirstOrDefault(u => u.UnitStatus == TaskStatus.Available);
-                        if (bind != null)
-                        {
-                            var position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNo);
-                            //AGVTaskModel model_AGV = new AGVTaskModel(TaskAvailableLevel.Both, "AGV_UnloadEmptyTray", new AGVBindOpConfig(bind.Id, position));
-                            //AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, "Robot_UnloadEmptyTray", new AGVBindOpConfig(bind.Id));
-
-                            //bind.AddTask(model_AGV);
-                            //bind.AddTask(model_Robot);
-
-                            if (AGV_UnloadEmptyTray(bind.Id, position))
-                            {
-                                taskStatus.IsTaskAssgined = true;
-                                taskStatus.AgvId = bind.AGVId;
-                            }
-                        }
-                    }
-
-                    Thread.Sleep(WAITTIME);
-                }
-            });
-        }
-
-        //[ProcessMethod("", "AGV_UnloadEmptyTray", "AGV鍘诲線鍗歌浇绌篢ray鏂欎綅缃�", true)]
-        public bool AGV_UnloadEmptyTray(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
-            }
-
-            if (bind.SetAGVStatus(TaskStatus.Running))
-            {
-                bind.AGVDest = position.PositionCode;
-                bind.AGV.TaskOrder(position.PositionCode);
-
-                return true;
-            }
-            else
-            {
-                return false;
-            }
-        }
-
-        //[ProcessMethod("", "Robot_UnloadEmptyTray", "鏈哄櫒浜鸿繍鍔ㄨ嚦绌篢ray鎷嶇収浣嶇疆", true)]
-        public void Robot_UnloadEmptyTraySnap(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray && u.PositionCode == bind.AGV.CurrentPosition);
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
-            }
-
-            taskAssignedList.RemoveAll(u => u.AgvId == bind.AGVId && u.PositionNo == position.PositionNo);
-
-            bind.RobotStatus = TaskStatus.Running;
-            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.UnloadEmptyTraySnap, position.PositionNo);
-        }
-
-        //[ProcessMethod("", "Camera_UnloadEmptyTray", "鐩告満纭绌篢ray鍗歌浇鏈哄櫒浜轰綅缃皟鏁�", true)]
-        //public ProcessResponse Camera_UnloadEmptyTray(IOperationConfig config, IDevice device)
+        ////[ProcessMethod("", "AGV_UnloadEmptyTray", "AGV鍘诲線鍗歌浇绌篢ray鏂欎綅缃�", true)]
+        //public bool AGV_UnloadEmptyTray(string bindId, PathPosition position)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
 
-        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray);
+        //    if (position == null)
+        //    {
+        //        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
+        //    }
+
+        //    if (bind.SetAGVStatus(TaskStatus.Running))
+        //    {
+        //        bind.AGVDest = position.PositionCode;
+        //        bind.AGV.TaskOrder(position.PositionCode);
+
+        //        return true;
+        //    }
+        //    else
+        //    {
+        //        return false;
+        //    }
+        //}
+
+        ////[ProcessMethod("", "Robot_UnloadEmptyTray", "鏈哄櫒浜鸿繍鍔ㄨ嚦绌篢ray鎷嶇収浣嶇疆", true)]
+        //public void Robot_UnloadEmptyTraySnap(string bindId, PathPosition position)
+        //{
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+        //    //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray && u.PositionCode == bind.AGV.CurrentPosition);
+
+        //    if (position == null)
+        //    {
+        //        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
+        //    }
+
+        //    taskAssignedList.RemoveAll(u => u.AgvId == bind.AGVId && u.PositionNo == position.PositionNo);
+
+        //    bind.RobotStatus = TaskStatus.Running;
+        //    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.UnloadEmptyTraySnap, position.PositionNo);
+        //}
+
+        ////[ProcessMethod("", "Camera_UnloadEmptyTray", "鐩告満纭绌篢ray鍗歌浇鏈哄櫒浜轰綅缃皟鏁�", true)]
+        ////public ProcessResponse Camera_UnloadEmptyTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadEmptyTray);
+
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
+        ////    }
+
+        ////    if (bind.AGV.CurrentPosition != position.PositionCode)
+        ////    {
+        ////        throw new ProcessException("AGV褰撳墠鏈浜庣┖Tray涓嬫枡鐐�");
+        ////    }
+
+        ////    PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
+
+        ////    if (visionConfig == null)
+        ////    {
+        ////        throw new ProcessException("鏈厤缃鐩告満鐨勭┖Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
+        ////    }
+
+        ////    float x = 0;
+        ////    float y = 0;
+        ////    float angle = 0;
+
+        ////    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadEmptyTray"))
+        ////    {
+        ////        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
+        ////        if (!_halconToolDict.ContainsKey(toolPath))
+        ////        {
+        ////            throw new ProcessException($"鏈厤缃瓹amera_UnloadEmptyTray鐨勮瑙夌畻娉曡矾寰�");
+        ////        }
+
+        ////        var tool = _halconToolDict[toolPath];
+        ////        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+        ////        tool.RunProcedure();
+
+        ////        x = (float)tool.GetResultTuple("OUTPUT_X").D;
+        ////        y = (float)tool.GetResultTuple("OUTPUT_Y").D;
+        ////        angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        ////    }
+
+        ////    if (x <= 0 || y <= 0)
+        ////    {
+        ////        throw new ProcessException("Camera_UnloadEmptyTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
+        ////    }
+
+        ////    float dx = visionConfig.StandardPoint.X - x;
+        ////    float dy = visionConfig.StandardPoint.Y - y;
+
+        ////    HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
+
+        ////    bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.EmptyTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public ProcessResponse Camera_UnloadEmptyTray(string robotId, int positionNum)
+        //{
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
+
+        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNum);
 
         //    if (position == null)
         //    {
@@ -741,231 +470,162 @@
         //        throw new ProcessException("AGV褰撳墠鏈浜庣┖Tray涓嬫枡鐐�");
         //    }
 
-        //    PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
+        //    float adjust_X = 0.0f;
+        //    float adjust_Y = 0.0f;
+        //    float adjust_Angle = 0.0f;
 
-        //    if (visionConfig == null)
+        //    if (Config.IsEnableVisionGuide)
         //    {
-        //        throw new ProcessException("鏈厤缃鐩告満鐨勭┖Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
-        //    }
+        //        PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
 
-        //    float x = 0;
-        //    float y = 0;
-        //    float angle = 0;
-
-        //    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadEmptyTray"))
-        //    {
-        //        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
-        //        if (!_halconToolDict.ContainsKey(toolPath))
+        //        if (visionConfig == null)
         //        {
-        //            throw new ProcessException($"鏈厤缃瓹amera_UnloadEmptyTray鐨勮瑙夌畻娉曡矾寰�");
+        //            throw new ProcessException("鏈厤缃鐩告満鐨勭┖Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
         //        }
 
-        //        var tool = _halconToolDict[toolPath];
-        //        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-        //        tool.RunProcedure();
+        //        float x = 0;
+        //        float y = 0;
+        //        float angle = 0;
 
-        //        x = (float)tool.GetResultTuple("OUTPUT_X").D;
-        //        y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-        //        angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        //        using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadEmptyTray"))
+        //        {
+        //            string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
+        //            if (!_halconToolDict.ContainsKey(toolPath))
+        //            {
+        //                throw new ProcessException($"鏈厤缃瓹amera_UnloadEmptyTray鐨勮瑙夌畻娉曡矾寰�");
+        //            }
+
+        //            var tool = _halconToolDict[toolPath];
+        //            tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+        //            tool.RunProcedure();
+
+        //            x = (float)tool.GetResultTuple("OUTPUT_X").D;
+        //            y = (float)tool.GetResultTuple("OUTPUT_Y").D;
+        //            angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        //        }
+
+        //        if (x <= 0 || y <= 0)
+        //        {
+        //            throw new ProcessException("Camera_UnloadEmptyTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
+        //        }
+
+        //        float dx = visionConfig.StandardPoint.X - x;
+        //        float dy = visionConfig.StandardPoint.Y - y;
+
+        //        HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
+
+        //        adjust_X = (float)dx_Robot.D;
+        //        adjust_Y = (float)dy_Robot.D;
+        //        adjust_Angle = visionConfig.StandardPoint.Angle - angle;
         //    }
 
-        //    if (x <= 0 || y <= 0)
-        //    {
-        //        throw new ProcessException("Camera_UnloadEmptyTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
-        //    }
-
-        //    float dx = visionConfig.StandardPoint.X - x;
-        //    float dy = visionConfig.StandardPoint.Y - y;
-
-        //    HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
-
-        //    bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.EmptyTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+        //    //bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.EmptyTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+        //    RobotMsg_UnloadEmptyTray.Action = RobotMsgAction.Unload;
+        //    RobotMsg_UnloadEmptyTray.Para1 = RobotMsgParas.EmptyTray;
+        //    RobotMsg_UnloadEmptyTray.Para2 = position.PositionNo;
+        //    RobotMsg_UnloadEmptyTray.Datas = new List<float>() { adjust_X, adjust_Y, 0, adjust_Angle }.ConvertAll(s => s.ToString()).ToList();
+        //    bind.Robot.SendMsg(RobotMsg_UnloadEmptyTray, true);
 
         //    return new ProcessResponse(true);
         //}
+        //#endregion
 
-        public ProcessResponse Camera_UnloadEmptyTray(string robotId, int positionNum)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
+        //#region 浠庢満鍙颁笂婊ray
+        ////bool isFullTrayNeed = false;
+        ////bool isFullTrayTaskAssigned = false;
+        //RobotMsg RobotMsg_LoadFullTray = new RobotMsg();
 
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNum);
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃┖Tray涓嬫枡鐐�");
-            }
-
-            if (bind.AGV.CurrentPosition != position.PositionCode)
-            {
-                throw new ProcessException("AGV褰撳墠鏈浜庣┖Tray涓嬫枡鐐�");
-            }
-
-            float adjust_X = 0.0f;
-            float adjust_Y = 0.0f;
-            float adjust_Angle = 0.0f;
-
-            if (Config.IsEnableVisionGuide)
-            {
-                PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
-
-                if (visionConfig == null)
-                {
-                    throw new ProcessException("鏈厤缃鐩告満鐨勭┖Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
-                }
-
-                float x = 0;
-                float y = 0;
-                float angle = 0;
-
-                using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadEmptyTray"))
-                {
-                    string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
-                    if (!_halconToolDict.ContainsKey(toolPath))
-                    {
-                        throw new ProcessException($"鏈厤缃瓹amera_UnloadEmptyTray鐨勮瑙夌畻娉曡矾寰�");
-                    }
-
-                    var tool = _halconToolDict[toolPath];
-                    tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-                    tool.RunProcedure();
-
-                    x = (float)tool.GetResultTuple("OUTPUT_X").D;
-                    y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-                    angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
-                }
-
-                if (x <= 0 || y <= 0)
-                {
-                    throw new ProcessException("Camera_UnloadEmptyTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
-                }
-
-                float dx = visionConfig.StandardPoint.X - x;
-                float dy = visionConfig.StandardPoint.Y - y;
-
-                HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
-
-                adjust_X = (float)dx_Robot.D;
-                adjust_Y = (float)dy_Robot.D;
-                adjust_Angle = visionConfig.StandardPoint.Angle - angle;
-            }
-
-            //bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.EmptyTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
-            RobotMsg_UnloadEmptyTray.Action = RobotMsgAction.Unload;
-            RobotMsg_UnloadEmptyTray.Para1 = RobotMsgParas.EmptyTray;
-            RobotMsg_UnloadEmptyTray.Para2 = position.PositionNo;
-            RobotMsg_UnloadEmptyTray.Datas = new List<float>() { adjust_X, adjust_Y, 0, adjust_Angle }.ConvertAll(s => s.ToString()).ToList();
-            bind.Robot.SendMsg(RobotMsg_UnloadEmptyTray, true);
-
-            return new ProcessResponse(true);
-        }
-        #endregion
-
-        #region 浠庢満鍙颁笂婊ray
-        //bool isFullTrayNeed = false;
-        //bool isFullTrayTaskAssigned = false;
-        RobotMsg RobotMsg_LoadFullTray = new RobotMsg();
-
-        [ProcessMethod("", "PLC_NoticeFullTray", "PLC閫氱煡婊ray闇�瑕佸彇璧�", true)]
-        public ProcessResponse PLC_NoticeFullTray(IOperationConfig config, IDevice device)
-        {
-            if (config.InputPara == null || config.InputPara.Count == 0)
-            {
-                throw new ProcessException("涓婄┖Tray鏂规硶鏈厤缃緭鍏ュ弬鏁�", null);
-            }
-
-            bool isFullTrayNeed = config.InputPara[0] == 1;
-            if (isFullTrayNeed)
-            {
-                var position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.DeviceOwner == device.Id);
-
-                machineFullTrayDict[position.PositionNo] = Config.Machine_FullTrayNum;
-
-                if (!taskAssignedList.Any(u => u.PositionNo == position.PositionNo))
-                {
-                    taskAssignedList.Add(new TaskAssignInfo()
-                    {
-                        IsTaskNeed = true,
-                        IsTaskAssgined = false,
-                        PositionNo = position.PositionNo,
-                    });
-                }
-
-                CheckFullTrayTask(position.PositionNo);
-            }
-
-            return new ProcessResponse(true);
-        }
-
-        private async void CheckFullTrayTask(int positionNo)
-        {
-            await Task.Run(() =>
-            {
-                var taskStatus = taskAssignedList.FirstOrDefault(u => u.PositionNo == positionNo);
-
-                if (taskStatus == null)
-                    return;
-
-                while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
-                {
-                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadFullTray;
-
-                    //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodFunc.Method.Name == action.Method.Name)))
-                    {
-                        var bind = Config.AGVBindCollection.FirstOrDefault(u => u.UnitStatus == TaskStatus.Available);
-                        if (bind != null)
-                        {
-                            var position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNo);
-                            //AGVTaskModel model_AGV = new AGVTaskModel(TaskAvailableLevel.Both, "AGV_LoadFullTray", new AGVBindOpConfig(bind.Id, position));
-                            //AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, "Robot_LoadFullTray", new AGVBindOpConfig(bind.Id));
-
-                            //bind.AddTask(model_AGV);
-                            //bind.AddTask(model_Robot);
-
-                            if (AGV_LoadFullTray(bind.Id, position))
-                            {
-                                taskStatus.IsTaskAssgined = true;
-                                taskStatus.AgvId = bind.AGVId;
-                            }
-                        }
-                    }
-
-                    Thread.Sleep(300);
-                }
-            });
-        }
-
-        //[ProcessMethod("", "AGV_LoadFullTray", "AGV鍘诲線婊ray涓婃枡浣嶇疆", true)]
-        public bool AGV_LoadFullTray(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-
-            //PathPosition position = (config as AGVBindOpConfig).Position;
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
-            }
-
-            if (bind.SetAGVStatus(TaskStatus.Running))
-            {
-                bind.AGVDest = position.PositionCode;
-                bind.AGV.TaskOrder(position.PositionCode);
-
-                return true;
-            }
-            else
-            {
-                return false;
-            }
-
-            //return new ProcessResponse(true);
-        }
-
-        //[ProcessMethod("", "Robot_LoadFullTray", "鏈哄櫒浜鸿繍鍔ㄨ嚦婊ray鎷嶇収浣嶇疆", true)]
-        //public ProcessResponse Robot_LoadFullTray(IOperationConfig config, IDevice device)
+        //private async void CheckFullTrayTask(int positionNo)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
-        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.PositionCode == bind.AGV.CurrentPosition);
+        //    await Task.Run(() =>
+        //    {
+        //        var taskStatus = taskAssignedList.FirstOrDefault(u => u.PositionNo == positionNo);
+
+        //        if (taskStatus == null)
+        //            return;
+
+        //        while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
+        //        {
+        //            //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadFullTray;
+
+        //            //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodFunc.Method.Name == action.Method.Name)))
+        //            {
+        //                var bind = Config.AGVBindCollection.FirstOrDefault(u => u.UnitStatus == TaskStatus.Available);
+        //                if (bind != null)
+        //                {
+        //                    var position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNo);
+        //                    //AGVTaskModel model_AGV = new AGVTaskModel(TaskAvailableLevel.Both, "AGV_LoadFullTray", new AGVBindOpConfig(bind.Id, position));
+        //                    //AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, "Robot_LoadFullTray", new AGVBindOpConfig(bind.Id));
+
+        //                    //bind.AddTask(model_AGV);
+        //                    //bind.AddTask(model_Robot);
+
+        //                    if (AGV_LoadFullTray(bind.Id, position))
+        //                    {
+        //                        taskStatus.IsTaskAssgined = true;
+        //                        taskStatus.AgvId = bind.AGVId;
+        //                    }
+        //                }
+        //            }
+
+        //            Thread.Sleep(300);
+        //        }
+        //    });
+        //}
+
+        ////[ProcessMethod("", "AGV_LoadFullTray", "AGV鍘诲線婊ray涓婃枡浣嶇疆", true)]
+        //public bool AGV_LoadFullTray(string bindId, PathPosition position)
+        //{
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+
+        //    //PathPosition position = (config as AGVBindOpConfig).Position;
+
+        //    if (position == null)
+        //    {
+        //        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
+        //    }
+
+        //    if (bind.SetAGVStatus(TaskStatus.Running))
+        //    {
+        //        bind.AGVDest = position.PositionCode;
+        //        bind.AGV.TaskOrder(position.PositionCode);
+
+        //        return true;
+        //    }
+        //    else
+        //    {
+        //        return false;
+        //    }
+
+        //    //return new ProcessResponse(true);
+        //}
+
+        ////[ProcessMethod("", "Robot_LoadFullTray", "鏈哄櫒浜鸿繍鍔ㄨ嚦婊ray鎷嶇収浣嶇疆", true)]
+        ////public ProcessResponse Robot_LoadFullTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.PositionCode == bind.AGV.CurrentPosition);
+
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
+        ////    }
+
+        ////    //if (bind.AGV.CurrentPosition != position.PositionCode)
+        ////    //{
+        ////    //    throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓婃枡鐐�");
+        ////    //}
+
+        ////    bind.RobotStatus = TaskStatus.Running;
+        ////    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LoadFullTraySnap, position.PositionNo);
+
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public void Robot_LoadFullTraySnap(string bindId, PathPosition position)
+        //{
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+        //    //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.PositionCode == bind.AGV.CurrentPosition);
 
         //    if (position == null)
         //    {
@@ -979,35 +639,73 @@
 
         //    bind.RobotStatus = TaskStatus.Running;
         //    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LoadFullTraySnap, position.PositionNo);
-
-        //    return new ProcessResponse(true);
         //}
 
-        public void Robot_LoadFullTraySnap(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.PositionCode == bind.AGV.CurrentPosition);
+        ////[ProcessMethod("", "Camera_LoadFullTray", "鐩告満纭婊ray涓婃枡鏈哄櫒浜轰綅缃皟鏁�", true)]
+        ////public ProcessResponse Camera_LoadFullTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
 
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
-            }
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray);
 
-            //if (bind.AGV.CurrentPosition != position.PositionCode)
-            //{
-            //    throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓婃枡鐐�");
-            //}
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
+        ////    }
 
-            bind.RobotStatus = TaskStatus.Running;
-            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LoadFullTraySnap, position.PositionNo);
-        }
+        ////    if (bind.AGV.CurrentPosition != position.PositionCode)
+        ////    {
+        ////        throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓婃枡鐐�");
+        ////    }
 
-        //[ProcessMethod("", "Camera_LoadFullTray", "鐩告満纭婊ray涓婃枡鏈哄櫒浜轰綅缃皟鏁�", true)]
-        //public ProcessResponse Camera_LoadFullTray(IOperationConfig config, IDevice device)
+        ////    PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
+
+        ////    if (visionConfig == null)
+        ////    {
+        ////        throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓婃枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
+        ////    }
+
+        ////    float x = 0;
+        ////    float y = 0;
+        ////    float angle = 0;
+
+        ////    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_LoadFullTray"))
+        ////    {
+        ////        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
+        ////        if (!_halconToolDict.ContainsKey(toolPath))
+        ////        {
+        ////            throw new ProcessException($"鏈厤缃瓹amera_LoadFullTray鐨勮瑙夌畻娉曡矾寰�");
+        ////        }
+
+        ////        var tool = _halconToolDict[toolPath];
+        ////        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+        ////        tool.RunProcedure();
+
+        ////        x = (float)tool.GetResultTuple("OUTPUT_X").D;
+        ////        y = (float)tool.GetResultTuple("OUTPUT_Y").D;
+        ////        angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        ////    }
+
+        ////    if (x <= 0 || y <= 0)
+        ////    {
+        ////        throw new ProcessException("Camera_LoadFullTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
+        ////    }
+
+        ////    float dx = visionConfig.StandardPoint.X - x;
+        ////    float dy = visionConfig.StandardPoint.Y - y;
+
+        ////    HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
+
+        ////    bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.FullTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public ProcessResponse Camera_LoadFullTray(string robotId, int positionNum)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
 
-        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray);
+        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNum);
 
         //    if (position == null)
         //    {
@@ -1019,130 +717,89 @@
         //        throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓婃枡鐐�");
         //    }
 
-        //    PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
+        //    float adjust_X = 0.0f;
+        //    float adjust_Y = 0.0f;
+        //    float adjust_Angle = 0.0f;
 
-        //    if (visionConfig == null)
+        //    if (Config.IsEnableVisionGuide)
         //    {
-        //        throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓婃枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
-        //    }
+        //        PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
 
-        //    float x = 0;
-        //    float y = 0;
-        //    float angle = 0;
-
-        //    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_LoadFullTray"))
-        //    {
-        //        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
-        //        if (!_halconToolDict.ContainsKey(toolPath))
+        //        if (visionConfig == null)
         //        {
-        //            throw new ProcessException($"鏈厤缃瓹amera_LoadFullTray鐨勮瑙夌畻娉曡矾寰�");
+        //            throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓婃枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
         //        }
 
-        //        var tool = _halconToolDict[toolPath];
-        //        tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-        //        tool.RunProcedure();
+        //        float x = 0;
+        //        float y = 0;
+        //        float angle = 0;
 
-        //        x = (float)tool.GetResultTuple("OUTPUT_X").D;
-        //        y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-        //        angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        //        using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_LoadFullTray"))
+        //        {
+        //            string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
+        //            if (!_halconToolDict.ContainsKey(toolPath))
+        //            {
+        //                throw new ProcessException($"鏈厤缃瓹amera_LoadFullTray鐨勮瑙夌畻娉曡矾寰�");
+        //            }
+
+        //            var tool = _halconToolDict[toolPath];
+        //            tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+        //            tool.RunProcedure();
+
+        //            x = (float)tool.GetResultTuple("OUTPUT_X").D;
+        //            y = (float)tool.GetResultTuple("OUTPUT_Y").D;
+        //            angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+        //        }
+
+        //        if (x <= 0 || y <= 0)
+        //        {
+        //            throw new ProcessException("Camera_LoadFullTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
+        //        }
+
+        //        float dx = visionConfig.StandardPoint.X - x;
+        //        float dy = visionConfig.StandardPoint.Y - y;
+
+        //        HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
+
+        //        adjust_X = (float)dx_Robot.D;
+        //        adjust_Y = (float)dy_Robot.D;
+        //        adjust_Angle = visionConfig.StandardPoint.Angle - angle;
         //    }
 
-        //    if (x <= 0 || y <= 0)
-        //    {
-        //        throw new ProcessException("Camera_LoadFullTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
-        //    }
-
-        //    float dx = visionConfig.StandardPoint.X - x;
-        //    float dy = visionConfig.StandardPoint.Y - y;
-
-        //    HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
-
-        //    bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.FullTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+        //    //bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.FullTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
+        //    RobotMsg_LoadFullTray.Action = RobotMsgAction.Load;
+        //    RobotMsg_LoadFullTray.Para1 = RobotMsgParas.FullTray;
+        //    RobotMsg_LoadFullTray.Para2 = position.PositionNo;
+        //    RobotMsg_LoadFullTray.Datas = new List<float>() { adjust_X, adjust_Y, 0, adjust_Angle }.ConvertAll(s => s.ToString()).ToList();
+        //    bind.Robot.SendMsg(RobotMsg_LoadFullTray, true);
 
         //    return new ProcessResponse(true);
         //}
+        //#endregion
 
-        public ProcessResponse Camera_LoadFullTray(string robotId, int positionNum)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
+        //#region 婊ray浜х嚎涓嬫枡
+        ////[ProcessMethod("", "AGV_UnloadFullTray", "AGV鍘诲線鍗歌浇婊ray鏂�", true)]
+        ////public ProcessResponse AGV_UnloadFullTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
 
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNum);
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
+        ////    }
 
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓婃枡鐐�");
-            }
+        ////    bind.AGVDest = position.PositionCode;
+        ////    bind.AGV.TaskOrder(position.PositionCode);
 
-            if (bind.AGV.CurrentPosition != position.PositionCode)
-            {
-                throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓婃枡鐐�");
-            }
+        ////    bind.AGVStatus = TaskStatus.Running;
 
-            float adjust_X = 0.0f;
-            float adjust_Y = 0.0f;
-            float adjust_Angle = 0.0f;
+        ////    return new ProcessResponse(true);
+        ////}
 
-            if (Config.IsEnableVisionGuide)
-            {
-                PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
-
-                if (visionConfig == null)
-                {
-                    throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓婃枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
-                }
-
-                float x = 0;
-                float y = 0;
-                float angle = 0;
-
-                using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_LoadFullTray"))
-                {
-                    string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
-                    if (!_halconToolDict.ContainsKey(toolPath))
-                    {
-                        throw new ProcessException($"鏈厤缃瓹amera_LoadFullTray鐨勮瑙夌畻娉曡矾寰�");
-                    }
-
-                    var tool = _halconToolDict[toolPath];
-                    tool.SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_X", new HTuple() }, { "OUTPUT_Y", new HTuple() }, { "OUTPUT_Angle", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-                    tool.RunProcedure();
-
-                    x = (float)tool.GetResultTuple("OUTPUT_X").D;
-                    y = (float)tool.GetResultTuple("OUTPUT_Y").D;
-                    angle = (float)tool.GetResultTuple("OUTPUT_Angle").D;
-                }
-
-                if (x <= 0 || y <= 0)
-                {
-                    throw new ProcessException("Camera_LoadFullTray瑙嗚璁$畻鑾峰彇鐐逛綅涓嶅彲灏忎簬0");
-                }
-
-                float dx = visionConfig.StandardPoint.X - x;
-                float dy = visionConfig.StandardPoint.Y - y;
-
-                HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix[0], visionConfig.Matrix[1], 0, visionConfig.Matrix[3], visionConfig.Matrix[4], 0), dx, dy, out HTuple dx_Robot, out HTuple dy_Robot);
-
-                adjust_X = (float)dx_Robot.D;
-                adjust_Y = (float)dy_Robot.D;
-                adjust_Angle = visionConfig.StandardPoint.Angle - angle;
-            }
-
-            //bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.FullTray, position.PositionNo, new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle });
-            RobotMsg_LoadFullTray.Action = RobotMsgAction.Load;
-            RobotMsg_LoadFullTray.Para1 = RobotMsgParas.FullTray;
-            RobotMsg_LoadFullTray.Para2 = position.PositionNo;
-            RobotMsg_LoadFullTray.Datas = new List<float>() { adjust_X, adjust_Y, 0, adjust_Angle }.ConvertAll(s => s.ToString()).ToList();
-            bind.Robot.SendMsg(RobotMsg_LoadFullTray, true);
-
-            return new ProcessResponse(true);
-        }
-        #endregion
-
-        #region 婊ray浜х嚎涓嬫枡
-        //[ProcessMethod("", "AGV_UnloadFullTray", "AGV鍘诲線鍗歌浇婊ray鏂�", true)]
-        //public ProcessResponse AGV_UnloadFullTray(IOperationConfig config, IDevice device)
+        //public bool AGV_UnloadFullTray(string bindId)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
         //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
 
         //    if (position == null)
@@ -1150,42 +807,45 @@
         //        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
         //    }
 
-        //    bind.AGVDest = position.PositionCode;
-        //    bind.AGV.TaskOrder(position.PositionCode);
+        //    if (bind.SetAGVStatus(TaskStatus.Running))
+        //    {
+        //        bind.AGVDest = position.PositionCode;
+        //        bind.AGV.TaskOrder(position.PositionCode);
 
-        //    bind.AGVStatus = TaskStatus.Running;
-
-        //    return new ProcessResponse(true);
+        //        return true;
+        //    }
+        //    else
+        //    {
+        //        return false;
+        //    }
         //}
 
-        public bool AGV_UnloadFullTray(string bindId)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
+        ////[ProcessMethod("", "Robot_UnloadFullTray", "鏈哄櫒浜哄嵏杞芥弧Tray", true)]
+        ////public ProcessResponse Robot_UnloadFullTray(IOperationConfig config, IDevice device)
+        ////{
+        ////    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
+        ////    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
 
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
-            }
+        ////    if (position == null)
+        ////    {
+        ////        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
+        ////    }
 
-            if (bind.SetAGVStatus(TaskStatus.Running))
-            {
-                bind.AGVDest = position.PositionCode;
-                bind.AGV.TaskOrder(position.PositionCode);
+        ////    if (bind.AGV.CurrentPosition != position.PositionCode)
+        ////    {
+        ////        throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓嬫枡鐐�");
+        ////    }
 
-                return true;
-            }
-            else
-            {
-                return false;
-            }
-        }
+        ////    bind.RobotStatus = TaskStatus.Running;
+        ////    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LineSnap, position.PositionNo);
 
-        //[ProcessMethod("", "Robot_UnloadFullTray", "鏈哄櫒浜哄嵏杞芥弧Tray", true)]
-        //public ProcessResponse Robot_UnloadFullTray(IOperationConfig config, IDevice device)
+        ////    return new ProcessResponse(true);
+        ////}
+
+        //public void Robot_UnloadFullTraySnap(string bindId, PathPosition position)
         //{
-        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
-        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+        //    //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
 
         //    if (position == null)
         //    {
@@ -1199,148 +859,97 @@
 
         //    bind.RobotStatus = TaskStatus.Running;
         //    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LineSnap, position.PositionNo);
+        //    //LogAsync(DateTime.Now, "Robot杩愬姩鑷充笅婊ray鎷嶇収", "");
+        //}
+
+        ////[ProcessMethod("", "Camera_UnloadFullTray", "鐩告満鎿嶄綔鍗歌浇婊ray", true)]
+        ////public ProcessResponse Camera_UnloadFullTray(IOperationConfig config, IDevice device)
+        //public ProcessResponse Camera_UnloadFullTray(string robotId, int positionNum)
+        //{
+        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
+        //    PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray && u.PositionNo == positionNum);
+
+        //    if (position == null)
+        //    {
+        //        throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
+        //    }
+
+        //    if (bind.AGV.CurrentPosition != position.PositionCode)
+        //    {
+        //        throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓嬫枡鐐�");
+        //    }
+
+        //    //float adjust_X = 0.0f;
+        //    //float adjust_Y = 0.0f;
+        //    //float adjust_Angle = 0.0f;
+        //    bool isLineReady = false;
+
+        //    if (Config.IsEnableVisionGuide)
+        //    {
+        //        PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
+
+        //        if (visionConfig == null)
+        //        {
+        //            throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
+        //        }
+
+
+        //        int reTryTime = Config.LineBusyRetryTimes;
+
+        //        do
+        //        {
+        //            using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadFullTray"))
+        //            {
+        //                string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
+        //                if (!_halconToolDict.ContainsKey(toolPath))
+        //                {
+        //                    throw new ProcessException($"鏈厤缃瓹amera_UnloadFullTray鐨勮瑙夌畻娉曡矾寰�");
+        //                }
+
+        //                _halconToolDict[toolPath].SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_Result", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
+        //                _halconToolDict[toolPath].RunProcedure();
+
+        //                isLineReady = _halconToolDict[toolPath].GetResultTuple("OUTPUT_Result").I == 1;
+        //            }
+
+        //            if (!isLineReady)
+        //            {
+        //                Thread.Sleep(Config.LineBusyWaitInterval * 1000);
+        //                reTryTime--;
+        //            }
+        //            else
+        //            {
+        //                reTryTime = 0;
+        //            }
+        //        } while (reTryTime > 0);
+
+        //        //if (!isLineReady)
+        //        //{
+        //        //    bind.Robot.SendMsg(RobotMsgType.Send, -1, true, RobotMsgAction.State, RobotMsgParas.LineSnap, new List<string>() { "-1" });
+        //        //    throw new ProcessException("浜х嚎蹇欙紝绛夊緟瓒呮椂");
+        //        //}
+        //        //else
+        //        //{
+        //        //    bind.Robot.SendMsg(RobotMsgType.Send, -1, true, RobotMsgAction.State, RobotMsgParas.LineSnap, new List<string>() { "1" });
+        //        //}
+        //    }
+        //    else
+        //    {
+        //        isLineReady = true;
+        //    }
+
+        //    if (isLineReady)
+        //    {
+        //        bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.FullTray, position.PositionNo);
+        //    }
+        //    else
+        //    {
+        //        bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.Home, position.PositionNo);
+        //    }
 
         //    return new ProcessResponse(true);
         //}
-
-        public void Robot_UnloadFullTraySnap(string bindId, PathPosition position)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
-            //PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray);
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
-            }
-
-            if (bind.AGV.CurrentPosition != position.PositionCode)
-            {
-                throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓嬫枡鐐�");
-            }
-
-            bind.RobotStatus = TaskStatus.Running;
-            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LineSnap, position.PositionNo);
-            //LogAsync(DateTime.Now, "Robot杩愬姩鑷充笅婊ray鎷嶇収", "");
-        }
-
-        //[ProcessMethod("", "Camera_UnloadFullTray", "鐩告満鎿嶄綔鍗歌浇婊ray", true)]
-        //public ProcessResponse Camera_UnloadFullTray(IOperationConfig config, IDevice device)
-        public ProcessResponse Camera_UnloadFullTray(string robotId, int positionNum)
-        {
-            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
-            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.UnloadFullTray && u.PositionNo == positionNum);
-
-            if (position == null)
-            {
-                throw new ProcessException("璺緞閰嶇疆鏈缃弧Tray涓嬫枡鐐�");
-            }
-
-            if (bind.AGV.CurrentPosition != position.PositionCode)
-            {
-                throw new ProcessException("AGV褰撳墠鏈浜庢弧Tray涓嬫枡鐐�");
-            }
-
-            //float adjust_X = 0.0f;
-            //float adjust_Y = 0.0f;
-            //float adjust_Angle = 0.0f;
-            bool isLineReady = false;
-
-            if (Config.IsEnableVisionGuide)
-            {
-                PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
-
-                if (visionConfig == null)
-                {
-                    throw new ProcessException("鏈厤缃鐩告満鐨勬弧Tray涓嬫枡鐐圭殑瑙嗚鎿嶄綔閰嶇疆");
-                }
-
-
-                int reTryTime = Config.LineBusyRetryTimes;
-
-                do
-                {
-                    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadFullTray"))
-                    {
-                        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
-                        if (!_halconToolDict.ContainsKey(toolPath))
-                        {
-                            throw new ProcessException($"鏈厤缃瓹amera_UnloadFullTray鐨勮瑙夌畻娉曡矾寰�");
-                        }
-
-                        _halconToolDict[toolPath].SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_Result", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
-                        _halconToolDict[toolPath].RunProcedure();
-
-                        isLineReady = _halconToolDict[toolPath].GetResultTuple("OUTPUT_Result").I == 1;
-                    }
-
-                    if (!isLineReady)
-                    {
-                        Thread.Sleep(Config.LineBusyWaitInterval * 1000);
-                        reTryTime--;
-                    }
-                    else
-                    {
-                        reTryTime = 0;
-                    }
-                } while (reTryTime > 0);
-
-                //if (!isLineReady)
-                //{
-                //    bind.Robot.SendMsg(RobotMsgType.Send, -1, true, RobotMsgAction.State, RobotMsgParas.LineSnap, new List<string>() { "-1" });
-                //    throw new ProcessException("浜х嚎蹇欙紝绛夊緟瓒呮椂");
-                //}
-                //else
-                //{
-                //    bind.Robot.SendMsg(RobotMsgType.Send, -1, true, RobotMsgAction.State, RobotMsgParas.LineSnap, new List<string>() { "1" });
-                //}
-            }
-            else
-            {
-                isLineReady = true;
-            }
-
-            if (isLineReady)
-            {
-                bind.Robot.SendMsg(RobotMsgAction.Unload, RobotMsgParas.FullTray, position.PositionNo);
-            }
-            else
-            {
-                bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.Home, position.PositionNo);
-            }
-
-            return new ProcessResponse(true);
-        }
+        //#endregion
         #endregion
-    }
-
-    //[Device("AGVBind", "AGVBind", EnumHelper.DeviceAttributeType.OperationConfig)]
-    public class AGVBindOpConfig : OperationConfigBase
-    {
-        [Category("璁惧淇℃伅")]
-        [Description("鎿嶄綔鐩稿叧鐨勮澶囩紪鍙�")]
-        public string BindId { get; set; }
-
-        [Category("浣嶇疆淇℃伅")]
-        [Description("鎿嶄綔鐩稿叧鐨勪綅缃�")]
-        public PathPosition Position { get; set; }
-
-        public AGVBindOpConfig() { }
-
-        public AGVBindOpConfig(string bindId, PathPosition position = null)
-        {
-            BindId = bindId;
-            Position = position;
-        }
-    }
-
-    public class TaskAssignInfo
-    {
-        public int PositionNo { get; set; }
-
-        public bool IsTaskNeed { get; set; } = false;
-
-        public bool IsTaskAssgined { get; set; } = false;
-
-        public string AgvId { get; set; }
     }
 }
diff --git a/src/A032.Process/ProcessControl_Robot.cs b/src/A032.Process/ProcessControl_Robot.cs
new file mode 100644
index 0000000..ef57b2e
--- /dev/null
+++ b/src/A032.Process/ProcessControl_Robot.cs
@@ -0,0 +1,24 @@
+锘縰sing Bro.Device.AuboRobot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace A032.Process
+{
+    public partial class ProcessControl
+    {
+        private void OnRobotMsgReceived(DateTime dt, AuboRobotDriver robot, RobotMsg msg)
+        {
+        }
+
+        private void SwitchLight(AuboRobotDriver robot, bool isOn)
+        {
+            if (Config.LightOutputIndex > 0)
+            {
+                robot.SetIO(Config.LightOutputIndex, isOn);
+            }
+        }
+    }
+}
diff --git a/src/A032.Process/ProcessControl_Task.cs b/src/A032.Process/ProcessControl_Task.cs
new file mode 100644
index 0000000..4bf24ed
--- /dev/null
+++ b/src/A032.Process/ProcessControl_Task.cs
@@ -0,0 +1,759 @@
+锘縰sing Autofac;
+using Bro.Common.Base;
+using Bro.Common.Helper;
+using Bro.Common.Interface;
+using Bro.Common.Model;
+using Bro.Device.AuboRobot;
+using Bro.Device.SeerAGV;
+using HalconDotNet;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Drawing.Design;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace A032.Process
+{
+    public class TrayTask : IComplexDisplay
+    {
+        [Browsable(false)]
+        public string TaskId { get; set; } = Guid.NewGuid().ToString();
+
+        /// <summary>
+        /// 浼樺厛绾ц秺楂橈紝瓒婂揩鎵ц
+        /// </summary>
+        [Category("浠诲姟閰嶇疆")]
+        [Description("浼樺厛绾с�備紭鍏堢骇瓒婇珮锛岃秺蹇墽琛�")]
+        public int Priority { get; set; }
+
+        private string locationCode = "";
+
+        [Category("浠诲姟閰嶇疆")]
+        [Description("浠诲姟鎵ц鍦板潃浠g爜")]
+        [TypeConverter(typeof(PositionCodeConverter))]
+        public string LocationCode
+        {
+            get => locationCode;
+            set
+            {
+                if (locationCode != value)
+                {
+                    locationCode = value;
+
+                    using (var scope = GlobalVar.Container.BeginLifetimeScope())
+                    {
+                        ProcessConfig config = scope.Resolve<ProcessConfig>();
+
+                        Location = config.PositionCollection.FirstOrDefault(u => u.PositionCode == locationCode);
+                    }
+                }
+            }
+        }
+
+        [Browsable(false)]
+        public PathPosition Location { get; set; } = new PathPosition();
+
+        private TaskType taskType = TaskType.LoadEmptyTrayToAGV;
+        [Category("浠诲姟閰嶇疆")]
+        [Description("浠诲姟绫诲瀷")]
+        public TaskType TaskType
+        {
+            get => taskType;
+            set
+            {
+                taskType = value;
+
+                var attr = taskType.GetEnumAttribute<PriorityAttribute>();
+                if (attr != null)
+                {
+                    Priority = attr.Priority;
+                }
+            }
+        }
+
+        private string sourceDeviceId = "";
+        [Category("浠诲姟閰嶇疆")]
+        [Description("浠诲姟鏉ユ簮璁惧")]
+        [TypeConverter(typeof(AllDeviceIdConverter))]
+        public string SourceDeviceId
+        {
+            get => sourceDeviceId;
+            set
+            {
+                if (sourceDeviceId != value)
+                {
+                    sourceDeviceId = value;
+
+                    using (var scope = GlobalVar.Container.BeginLifetimeScope())
+                    {
+                        List<IDevice> deviceList = scope.Resolve<List<IDevice>>();
+
+                        var device = deviceList.FirstOrDefault(u => u.Id == value);
+                        SourceDeviceName = device.Name;
+                    }
+                }
+            }
+        }
+
+        [Browsable(false)]
+        [JsonIgnore]
+        public string SourceDeviceName { get; set; } = "";
+
+        [Browsable(false)]
+        [JsonIgnore]
+        public string BindId { get; set; } = "";
+
+        [Browsable(false)]
+        [JsonIgnore]
+        public int WaitShift { get; set; } = 0;
+
+        public string GetDisplayText()
+        {
+            return $"{SourceDeviceName}鍙戣捣鐨剓TaskType.ToString()}浠诲姟";
+        }
+    }
+
+    public enum TaskType
+    {
+        [Priority(30)]
+        UnloadEmptyTrayToMachine,
+
+        [Priority(20)]
+        LoadEmptyTrayToAGV,
+
+        [Priority(30)]
+        LoadFullTrayFromMachine,
+
+        [Priority(20)]
+        UnloadFullTrayToLine,
+
+        [Priority(50)]
+        Charge,
+
+        [Priority(10)]
+        IdleCharge,
+    }
+
+    public class PriorityAttribute : Attribute
+    {
+        public int Priority { get; set; }
+
+        public PriorityAttribute(int priority)
+        {
+            Priority = priority;
+        }
+    }
+
+    public partial class ProcessControl
+    {
+        private bool isEnableExecuteTask = true;
+        public bool IsEnableExecuteTask
+        {
+            get => isEnableExecuteTask;
+            set
+            {
+                isEnableExecuteTask = value;
+
+                LogAsync(DateTime.Now, $"Set IsEnableExecuteTask {value.ToString()}", $"{(value ? "鎵撳紑" : "鍏抽棴")}浠诲姟鎵ц");
+            }
+        }
+        List<AGVState> _disableStates = new List<AGVState>() { AGVState.InCharge, AGVState.Warning, AGVState.Unknown };
+
+        private void Reset(string bindId = "")
+        {
+            WarningRemains.Clear();
+            IsEnableExecuteTask = true;
+
+            if (string.IsNullOrWhiteSpace(bindId))
+            {
+                Config.AGVBindCollection.ForEach(bind =>
+                {
+                    if (bind.UnitState == AGVState.Warning)
+                    {
+                        bind.WarningMsg = "";
+                        bind.UnitState = AGVState.Idle;
+                    }
+                });
+
+                LogAsync(DateTime.Now, "Reset", "鎵ц鍏ㄤ綋澶嶄綅鎿嶄綔");
+            }
+            else
+            {
+                var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
+
+                if (bind != null && bind.UnitState == AGVState.Warning)
+                {
+                    bind.WarningMsg = "";
+                    bind.UnitState = AGVState.Idle;
+
+                    LogAsync(DateTime.Now, "Reset", $"鎵ц{bind.AGV.Name}澶嶄綅鎿嶄綔");
+                }
+            }
+        }
+
+        static object _taskLock = new object();
+        NoticedList<TrayTask> TrayTaskCollection = new NoticedList<TrayTask>();
+
+        private void InsertTask(TrayTask task)
+        {
+            lock (_taskLock)
+            {
+                if (TrayTaskCollection.Any(u => u.TaskType == task.TaskType && u.SourceDeviceId == task.SourceDeviceId))
+                {
+                    LogAsync(DateTime.Now, "閲嶅浠诲姟", $"{task.SourceDeviceName}鍙戣捣鐨剓task.TaskType.ToString()}浠诲姟宸插瓨鍦ㄤ换鍔″垪琛ㄤ腑");
+                    return;
+                }
+
+                int insertIndex = TrayTaskCollection.Count;
+                var nextTask = TrayTaskCollection.FirstOrDefault(u => u.Priority < task.Priority && u.WaitShift == 0);
+                if (nextTask != null)
+                {
+                    insertIndex = TrayTaskCollection.IndexOf(nextTask);
+                }
+
+                TrayTaskCollection.Insert(insertIndex, task);
+            }
+        }
+
+        #region 浠诲姟瑙﹀彂
+        private async void OnTaskListChanged(NotifyCollectionChangedAction action, List<TrayTask> task)
+        {
+            await Task.Run(() =>
+            {
+                if (action == NotifyCollectionChangedAction.Add)
+                {
+                    ExecuteTask();
+                }
+            });
+        }
+
+        private async void OnUnitStateChanged(string unitId, AGVState preState, AGVState currentState)
+        {
+            await Task.Run(() =>
+            {
+                if (currentState == AGVState.Idle || currentState == AGVState.IdleCharge)
+                {
+                    ExecuteTask(unitId);
+                }
+            });
+        }
+
+        private void ExecuteTask(string unitId = "")
+        {
+            TrayTask task = null;
+
+            lock (_taskLock)
+            {
+                if (TrayTaskCollection.Count <= 0)
+                {
+                    return;
+                }
+
+                task = TrayTaskCollection.FirstOrDefault(u => string.IsNullOrWhiteSpace(u.BindId));
+            }
+
+            //浠诲姟鏄惁宸插湪鎵ц涓�
+            if (Config.AGVBindCollection.Any(u => u.CurrentTaskId == task.TaskId))
+            {
+                LogAsync(DateTime.Now, "浠诲姟鎵ц涓�", $"{task.GetDisplayText()}姝e湪鎵ц涓�");
+                return;
+            }
+
+            AGVBindUnit bind = null;
+
+            if (string.IsNullOrWhiteSpace(unitId))
+            {
+                var available = Config.AGVBindCollection.Where(u => u.UnitState == AGVState.Idle || u.UnitState == AGVState.IdleCharge);
+
+                switch (task.TaskType)
+                {
+                    case TaskType.LoadFullTrayFromMachine:
+                        available = available.Where(u => u.FullTrayNum < Config.AGVAvailableTrayNums);
+                        break;
+                    case TaskType.UnloadEmptyTrayToMachine:
+                        available = available.Where(u => u.EmptyTrayNum > 0);
+                        break;
+                    default:
+                        break;
+                }
+
+                bind = available.FirstOrDefault();
+            }
+            else
+            {
+                bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == unitId);
+            }
+
+            if (bind == null)
+            {
+                LogAsync(DateTime.Now, $"鏆傛椂娌℃湁鍙墽琛屼换鍔$殑鍗曞厓", "");
+                ReArrangeTask(task);
+                return;
+            }
+
+            if (task.Location == null)
+            {
+                switch (task.TaskType)
+                {
+                    case TaskType.LoadEmptyTrayToAGV:
+                        task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.LoadEmptyTray);
+                        break;
+                    case TaskType.LoadFullTrayFromMachine:
+                        task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.LoadFullTray && u.DeviceOwner == task.SourceDeviceId);
+                        break;
+                    case TaskType.UnloadEmptyTrayToMachine:
+                        task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.UnloadEmptyTray && u.DeviceOwner == task.SourceDeviceId);
+                        break;
+                    case TaskType.UnloadFullTrayToLine:
+                        task.Location = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.UnloadFullTray && u.DeviceOwner == task.SourceDeviceId);
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+            if (task.Location == null)
+            {
+                ReArrangeTask(task);
+                return;
+            }
+            else
+            {
+                task.Location.IsOccupied = true;
+            }
+
+            task.BindId = bind.Id;
+
+            if (!string.IsNullOrWhiteSpace(bind.CurrentTaskId))
+            {
+                bind.AGV.CancelTask();
+            }
+
+            LogAsync(DateTime.Now, $"寮�濮嬫墽琛屼换鍔�", task.GetDisplayText());
+
+            bind.IsTaskCancelled = false;
+            bind.IsTaskCancelling = false;
+
+            bind.UnitState = AGVState.Running;
+            bind.CurrentTaskId = task.TaskId;
+
+            try
+            {
+                switch (task.TaskType)
+                {
+                    case TaskType.LoadEmptyTrayToAGV:
+                        LoadEmptyTrayToAGV(task, bind);
+                        break;
+                    case TaskType.LoadFullTrayFromMachine:
+                        LoadFullTrayFromMachine(task, bind);
+                        break;
+                    case TaskType.UnloadEmptyTrayToMachine:
+                        UnloadEmptyTrayToMachine(task, bind);
+                        break;
+                    case TaskType.UnloadFullTrayToLine:
+                        UnloadFullTrayToLine(task, bind);
+                        break;
+                    default:
+                        break;
+                }
+
+                ////浠诲姟瀹屾垚鍚庢鏌ョ數閲�
+                //bind.AGV.BatteryHandle.Reset();
+                //bool isNotTimeout = bind.AGV.BatteryHandle.WaitOne((bind.AGV.InitialConfig as SeerAGVInitialConfig).ScanInterval * 10);
+
+                //if (!isNotTimeout)
+                //{
+                //    throw new ProcessException($"{bind.AGV.Name}鑾峰彇鐢垫睜鐘舵�佽秴鏃�");
+                //}
+            }
+            catch (TaskCanceledException ex)
+            {
+                try
+                {
+                    CancelTask(bind);
+                }
+                catch (Exception)
+                {
+                    ExceptionHandle(task, bind, ex, $"浠诲姟{task.TaskId}鍙栨秷澶辫触锛�");
+                    return;
+                }
+                finally
+                {
+                    bind.IsTaskCancelled = false;
+                    bind.IsTaskCancelling = false;
+                }
+            }
+            catch (Exception ex)
+            {
+                ExceptionHandle(task, bind, ex);
+                return;
+            }
+            finally
+            {
+                //lock (_taskListLock)
+                //{
+                //    _taskList.RemoveAt(0);
+                //}
+            }
+
+            LogAsync(DateTime.Now, $"浠诲姟{task.TaskId}娴佺▼缁撴潫", "");
+
+            AfterTaskHandle(task, bind);
+        }
+
+        private void ReArrangeTask(TrayTask task)
+        {
+            task.WaitShift++;
+
+            TrayTaskCollection.Remove(task);
+
+            if (task.WaitShift > Config.DefaultWaitShift)
+            {
+                LogAsync(DateTime.Now, "浠诲姟鏃犳硶鎵ц", $"{task.GetDisplayText()}绛夊緟{task.WaitShift}娆℃棤娉曟墽琛岋紝宸茬Щ鍑轰换鍔¢槦鍒�");
+            }
+            else
+            {
+                InsertTask(task);
+            }
+        }
+
+        //AutoResetEvent _taskDoneHandle = new AutoResetEvent(true);
+        Dictionary<string, AutoResetEvent> _bindTaskDoneHandleDict = new Dictionary<string, AutoResetEvent>();
+        private void AfterTaskHandle(TrayTask task, AGVBindUnit bind, string warningMsg = "", bool isWarningRaised = false)
+        {
+            lock (_taskLock)
+            {
+                task.Location.IsOccupied = false;
+                TrayTaskCollection.Remove(task);
+            }
+
+            bind.CurrentTaskId = "";
+            if (isWarningRaised)
+            {
+                bind.WarningMsg = warningMsg;
+                bind.UnitState = AGVState.Warning;
+            }
+            else
+            {
+                //浠诲姟瀹屾垚鍚庢鏌ョ數閲�
+                bind.AGV.BatteryHandle.Reset();
+                bool isNotTimeout = bind.AGV.BatteryHandle.WaitOne((bind.AGV.InitialConfig as SeerAGVInitialConfig).ScanInterval * 10);
+
+                if (!isNotTimeout)
+                {
+                    bind.WarningMsg = $"{bind.AGV.Name}鑾峰彇鐢垫睜鐘舵�佽秴鏃�";
+                    new ProcessException(bind.WarningMsg);
+                    bind.UnitState = AGVState.Warning;
+                }
+                else
+                {
+                    SeerAGVInitialConfig iConfig = bind.AGV.InitialConfig as SeerAGVInitialConfig;
+                    if (bind.AGV.BatteryLvl <= iConfig.BatteryLvlToCharge)
+                    {
+                        bind.UnitState = AGVState.InCharge;
+
+                        var chargePosition = Config.PositionCollection.FirstOrDefault(u => !u.IsOccupied && u.Description == PathPositionDefinition.Charge);
+
+                        if (chargePosition == null)
+                        {
+                            bind.WarningMsg = $"{bind.AGV.Name}鐩墠鏃犲彲鐢ㄥ厖鐢靛湴鍧�";
+                            new ProcessException(bind.WarningMsg);
+                            bind.UnitState = AGVState.Warning;
+                        }
+                        else
+                        {
+                            bind.AGV.TaskOrder(chargePosition.PositionCode, true);
+                        }
+                    }
+                    else
+                    {
+                        bind.UnitState = AGVState.Idle;
+                    }
+                }
+            }
+
+            _bindTaskDoneHandleDict[bind.Id].Set();
+        }
+
+        /// <summary>
+        /// 鍙栨秷褰撳墠浠诲姟锛屽鏋滃凡鍙栧嵎瀹楋紝褰掕繕鍒板師澶�
+        /// </summary>
+        /// <param name="bind"></param>
+        private void CancelTask(AGVBindUnit bind)
+        {
+            bind.IsTaskCancelling = true;
+
+            bind.AGV.CancelTask();
+            bind.Robot.Move(new RobotPoint(), MoveType.Origin, true);
+        }
+
+        /// <summary>
+        /// 杩囩▼寮傚父澶勭悊锛屽弽棣堝紓甯告秷鎭埌RabbitMQ
+        /// </summary>
+        /// <param name="task"></param>
+        /// <param name="bind"></param>
+        /// <param name="ex"></param>
+        /// <param name="errorMsg"></param>
+        private void ExceptionHandle(TrayTask task, AGVBindUnit bind, Exception ex, string errorMsg = "")
+        {
+            bool isWarningEx = false;
+            if (ex is ProcessException)
+            {
+                isWarningEx = (ex as ProcessException).Level > 0;
+                errorMsg += (ex as ProcessException).ErrorCode;
+            }
+            else
+            {
+                isWarningEx = true;
+                errorMsg += ex.Message;
+                LogAsync(DateTime.Now, $"{task.TaskId}寮傚父", ex.GetExceptionMessage());
+            }
+
+            try
+            {
+                SwitchLight(bind.Robot, false);
+                bind.Robot.Move(new RobotPoint(), MoveType.Origin, true);
+            }
+            catch (Exception)
+            {
+            }
+
+            LogAsync(DateTime.Now, $"浠诲姟{task.GetDisplayText()}寮傚父鍙嶉", errorMsg);
+
+            AfterTaskHandle(task, bind, errorMsg, isWarningEx);
+        }
+        #endregion
+
+        #region 浠诲姟鎵ц
+        /// <summary>
+        /// 灏嗘弧Tray鏀剧疆鍒颁骇绾夸笂
+        /// </summary>
+        /// <param name="task"></param>
+        /// <param name="bind"></param>
+        private void UnloadFullTrayToLine(TrayTask task, AGVBindUnit bind)
+        {
+            string methodName = "UnloadFullTrayToLine";
+
+            bind.AGV.TaskOrder(task.Location.PositionCode, true);
+
+            var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == task.Location.PositionCode);
+
+            if (visionConfig == null)
+                throw new ProcessException($"鏈兘鑾峰彇{bind.Camera.Name}鍦▄task.Location.PositionCode}鐨勮瑙夐厤缃�");
+
+            while (bind.FullTrayNum > 0)
+            {
+                bind.Robot.Move(visionConfig.RobotSnapshotPoint, MoveType.AbsoluteMove, true);
+
+                bool isLineReady = false;
+                if (Config.IsEnableVisionGuide)
+                {
+                    int reTryTime = Config.LineBusyRetryTimes;
+
+                    HDevEngineTool tool = null;
+                    if (!_halconToolDict.ContainsKey(visionConfig.CameraOpConfig.AlgorithemPath))
+                    {
+                        throw new ProcessException($"鏈厤缃畕methodName}鐨勭畻娉曞伐鍏�");
+                    }
+
+                    tool = _halconToolDict[visionConfig.CameraOpConfig.AlgorithemPath];
+
+                    SwitchLight(bind.Robot, true);
+                    Thread.Sleep(500);//绛夊緟鐏紑
+
+                    do
+                    {
+                        RobotPoint point = new RobotPoint();
+                        using (var hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, methodName))
+                        {
+                            tool.InputImageDic.Clear();
+                            tool.InputImageDic["INPUT_Image"] = hImage;
+
+                            tool.RunProcedure();
+
+                            if (!tool.IsSuccessful)
+                            {
+                                throw new ProcessException($"{visionConfig.CameraOpConfig.AlgorithemPath}绠楁硶杩愯澶辫触");
+                            }
+
+                            isLineReady = tool.GetResultTuple("OUTPUT_Result").I == 1;
+                        }
+
+                        if (!isLineReady)
+                        {
+                            LogAsync(DateTime.Now, $"{task.Location.PositionCode}浣嶇疆绾夸綋绻佸繖", "");
+                            Thread.Sleep(Config.LineBusyWaitInterval * 1000);
+                            reTryTime--;
+                        }
+                        else
+                        {
+                            reTryTime = 0;
+                        }
+                    } while (reTryTime > 0);
+
+                    SwitchLight(bind.Robot, false);
+                }
+                else
+                {
+                    isLineReady = true;
+                }
+
+                if (isLineReady)
+                {
+                    bind.Robot.UnLoad(bind.Robot.CurrentPoint, TrayType.FullTray, true);
+                }
+                else
+                {
+                    bind.Robot.Move(new RobotPoint(), MoveType.Origin, true);
+                    break;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 灏嗙┖Tray鏀剧疆鍒板帇鏈轰笂
+        /// </summary>
+        /// <param name="task"></param>
+        /// <param name="bind"></param>
+        private void UnloadEmptyTrayToMachine(TrayTask task, AGVBindUnit bind)
+        {
+            string methodName = "UnloadEmptyTrayToMachine";
+
+            MachineRelatedOperation(task, bind, methodName);
+
+            RobotPoint point = bind.Robot.CurrentPoint.DeepSerializeClone();
+
+            int emptyTrayNum = 0;
+            do
+            {
+                bind.Robot.UnLoad(point, TrayType.EmptyTray, true);
+                emptyTrayNum++;
+
+                bind.Robot.MonitorHandle.Reset();
+                var isNotTimeout = bind.Robot.MonitorHandle.WaitOne((bind.Robot.InitialConfig as AuboRobotInitialConfig).ReplyTimeout * 3);
+                if (!isNotTimeout)
+                    throw new ProcessException($"{bind.Robot.Name}鐩戝惉鎿嶄綔瓒呮椂");
+
+            } while (emptyTrayNum < Config.Machine_EmptyTrayNum && bind.EmptyTrayNum > 0);
+        }
+
+        /// <summary>
+        /// 浠庡帇鏈轰笂鍙栨弧Tray鍒癆GV
+        /// </summary>
+        /// <param name="task"></param>
+        /// <param name="bind"></param>
+        private void LoadFullTrayFromMachine(TrayTask task, AGVBindUnit bind)
+        {
+            string methodName = "LoadFullTrayFromMachine";
+
+            MachineRelatedOperation(task, bind, methodName);
+
+            RobotPoint point = bind.Robot.CurrentPoint.DeepSerializeClone();
+
+            int fullTrayNum = Config.Machine_FullTrayNum;
+            do
+            {
+                bind.Robot.Load(point, TrayType.FullTray, true);
+                fullTrayNum--;
+                bind.FullTrayNum++;
+
+                bind.Robot.MonitorHandle.Reset();
+                var isNotTimeout = bind.Robot.MonitorHandle.WaitOne((bind.Robot.InitialConfig as AuboRobotInitialConfig).ReplyTimeout * 3);
+                if (!isNotTimeout)
+                    throw new ProcessException($"{bind.Robot.Name}鐩戝惉鎿嶄綔瓒呮椂");
+
+            } while (fullTrayNum > 0 && bind.FullTrayNum < Config.AGVAvailableTrayNums);
+        }
+
+        private void MachineRelatedOperation(TrayTask task, AGVBindUnit bind, string methodName)
+        {
+            bind.AGV.TaskOrder(task.Location.PositionCode, true);
+
+            var visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.CameraId == bind.CameraId && u.PositionCode == task.Location.PositionCode);
+
+            if (visionConfig == null)
+                throw new ProcessException($"鏈兘鑾峰彇{bind.Camera.Name}鍦▄task.Location.PositionCode}鐨勮瑙夐厤缃�");
+
+            bind.Robot.Move(visionConfig.RobotSnapshotPoint, MoveType.AbsoluteMove, true);
+
+            if (Config.IsEnableVisionGuide)
+            {
+                int repeatTime = Config.VisionGuideTimes;
+
+                HDevEngineTool tool = null;
+                if (!_halconToolDict.ContainsKey(visionConfig.CameraOpConfig.AlgorithemPath))
+                {
+                    throw new ProcessException($"鏈厤缃畕methodName}鐨勭畻娉曞伐鍏�");
+                }
+
+                tool = _halconToolDict[visionConfig.CameraOpConfig.AlgorithemPath];
+
+                SwitchLight(bind.Robot, true);
+                Thread.Sleep(500);//绛夊緟鐏紑
+
+                do
+                {
+                    RobotPoint point = new RobotPoint();
+                    using (var hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, methodName))
+                    {
+                        tool.InputImageDic.Clear();
+                        tool.InputImageDic["INPUT_Image"] = hImage;
+
+                        tool.RunProcedure();
+
+                        if (!tool.IsSuccessful)
+                        {
+                            throw new ProcessException($"{visionConfig.CameraOpConfig.AlgorithemPath}绠楁硶杩愯澶辫触");
+                        }
+
+                        double du = tool.GetResultTuple("OUTPUT_X").D;
+                        double dv = tool.GetResultTuple("OUTPUT_Y").D;
+
+                        if (du < 0 || dv < 0)
+                        {
+                            throw new ProcessException($"{visionConfig.CameraOpConfig.AlgorithemPath}绠楁硶缁撴灉寮傚父锛岀偣浣嶄俊鎭幏鍙栧け璐�");
+                        }
+
+                        du -= visionConfig.StandardPoint.X;
+                        dv -= visionConfig.StandardPoint.Y;
+
+                        HOperatorSet.AffineTransPoint2d(new HTuple(visionConfig.Matrix), du, dv, out HTuple dx, out HTuple dy);
+
+                        point.X = (float)dx.D;
+                        point.Y = (float)dy.D;
+                        point.A = (float)tool.GetResultTuple("OUTPUT_Angle").D;
+                    }
+
+                    LogAsync(DateTime.Now, $"{methodName}寮曞鍧愭爣", point.GetDisplayText());
+
+                    bind.Robot.Move(point, MoveType.RobotRelativeMove, true);
+
+                    repeatTime--;
+                } while (repeatTime > 0);
+
+                SwitchLight(bind.Robot, false);
+
+                //瑙嗚瀵煎紩鍚庡啀鍋氬浐瀹氬亸绉�
+                bind.Robot.Move(visionConfig.RobotShift, MoveType.RobotRelativeMove, true);
+            }
+        }
+
+        /// <summary>
+        /// 浜哄伐瑁呯┖Tray鍒癆GV
+        /// </summary>
+        /// <param name="task"></param>
+        /// <param name="bind"></param>
+        private void LoadEmptyTrayToAGV(TrayTask task, AGVBindUnit bind)
+        {
+            bind.AGV.TaskOrder(task.Location.PositionCode, true);
+            bind.Robot.Load(new RobotPoint(), TrayType.EmptyTray, true);
+        }
+        #endregion
+    }
+}
diff --git a/src/Bro.Common.Model/Bro.Common.Model.csproj b/src/Bro.Common.Model/Bro.Common.Model.csproj
index 2a3bf1d..fa82c2b 100644
--- a/src/Bro.Common.Model/Bro.Common.Model.csproj
+++ b/src/Bro.Common.Model/Bro.Common.Model.csproj
@@ -89,6 +89,7 @@
     <Compile Include="Interface\IStationProcess.cs" />
     <Compile Include="Model\CustomizedPoint.cs" />
     <Compile Include="Model\DeviceCmmd.cs" />
+    <Compile Include="Model\IODefinition.cs" />
     <Compile Include="Model\ModbusFrame.cs" />
     <Compile Include="Model\MonitorSet.cs" />
     <Compile Include="Model\NGDesc.cs" />
diff --git a/src/Bro.Common.Model/Helper/EnumHelper.cs b/src/Bro.Common.Model/Helper/EnumHelper.cs
index 21a319e..d50b5d9 100644
--- a/src/Bro.Common.Model/Helper/EnumHelper.cs
+++ b/src/Bro.Common.Model/Helper/EnumHelper.cs
@@ -73,6 +73,15 @@
             }
         }
 
+        public static T GetEnumAttribute<T>(this Enum enumObj) where T : Attribute
+        {
+            Type t = enumObj.GetType();
+            FieldInfo f = t.GetField(enumObj.ToString());
+
+            T attr = f.GetCustomAttribute<T>();
+            return attr;
+        }
+
         public static string GetPartSFCName(this PartType partType)
         {
             Type t = partType.GetType();
diff --git a/src/Bro.Common.Model/Helper/ExceptionHelper.cs b/src/Bro.Common.Model/Helper/ExceptionHelper.cs
index db85703..87763af 100644
--- a/src/Bro.Common.Model/Helper/ExceptionHelper.cs
+++ b/src/Bro.Common.Model/Helper/ExceptionHelper.cs
@@ -8,8 +8,17 @@
 
 namespace Bro.Common.Helper
 {
+    public enum ExceptionLevel
+    {
+        Info = 0,
+        Warning = 1,
+        Fatal = 2,
+    }
+
     public class ProcessException : Exception
     {
+        public ExceptionLevel Level { get; set; } = ExceptionLevel.Warning;
+
         public static Action<DateTime, string, string> OnExceptionNotice;
 
         //PubSubCenter pubSub = PubSubCenter.GetInstance();
@@ -38,9 +47,11 @@
         {
         }
 
-        public ProcessException(Exception ex)
+        public ProcessException(Exception ex, ExceptionLevel lvl = ExceptionLevel.Warning)
         {
             OriginalException = ex;
+            Level = lvl;
+
             ExceptionNotice();
         }
 
@@ -50,9 +61,10 @@
         //    PositionIndex = positionIndex;
         //}
 
-        public ProcessException(string error, Exception ex = null) : base(error, ex)
+        public ProcessException(string error, ExceptionLevel lvl = ExceptionLevel.Warning, Exception ex = null) : base(error, ex)
         {
             ErrorCode = error;
+            Level = lvl;
             OriginalException = ex;
 
             ExceptionNotice();
@@ -74,29 +86,5 @@
             //pubSub.Publish(PubTag.ExceptionUpdate.ToString(), ErrorCode, OriginalException, true);
             OnExceptionNotice?.Invoke(DateTime.Now, ErrorCode, OriginalException?.GetExceptionMessage());
         }
-    }
-
-    public class Level3Exception : ProcessException
-    {
-        public Level3Exception() : base() { }
-
-        public Level3Exception(string error, Exception ex) : base(error, ex) { }
-    }
-
-    /// <summary>
-    /// 鏉ユ枡妫�娴嬪紓甯�
-    /// </summary>
-    public class IncomingMaterialException : ProcessException
-    {
-        public IncomingMaterialException() : base() { }
-
-        public IncomingMaterialException(string error, Exception ex) : base(error, ex) { }
-    }
-
-    public class BarcodeScanFailureException : ProcessException
-    {
-        public BarcodeScanFailureException() : base() { }
-
-        public BarcodeScanFailureException(string msg, Exception ex) : base(msg, ex) { }
     }
 }
diff --git a/src/Bro.Common.Model/Helper/ListHelper.cs b/src/Bro.Common.Model/Helper/ListHelper.cs
index ad17def..1331583 100644
--- a/src/Bro.Common.Model/Helper/ListHelper.cs
+++ b/src/Bro.Common.Model/Helper/ListHelper.cs
@@ -1,18 +1,17 @@
 锘縰sing System;
 using System.Collections.Generic;
+using System.Collections.Specialized;
 using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace Bro.Common.Helper
 {
     public class NoticedList<T> : List<T> where T : class
     {
-        public Action OnItemChanged;
+        public Action<NotifyCollectionChangedAction> OnItemChanged;
 
-        public Action<List<T>> OnItemChangedWithItemInfo;
+        public Action<NotifyCollectionChangedAction, List<T>> OnItemChangedWithItemInfo;
 
-        public Action<NoticedList<T>> OnItemChangedWithSelf;
+        //public Action<NotifyCollectionChangedAction, NoticedList<T>> OnItemChangedWithSelf;
 
         public new T this[int index]
         {
@@ -33,9 +32,8 @@
                 if (base[index] != value)
                 {
                     base[index] = value;
-                    OnItemChanged?.Invoke();
-                    OnItemChangedWithItemInfo?.Invoke(new List<T>() { value });
-                    OnItemChangedWithSelf?.Invoke(this);
+                    OnItemChanged?.Invoke(NotifyCollectionChangedAction.Replace);
+                    OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Replace, new List<T>() { value });
                 }
             }
         }
@@ -43,40 +41,36 @@
         public new void Add(T item)
         {
             base.Add(item);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithItemInfo?.Invoke(new List<T>() { item });
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, new List<T>() { item });
         }
 
         public new void AddRange(IEnumerable<T> collection)
         {
             base.AddRange(collection);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithItemInfo?.Invoke(collection.ToList());
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, collection.ToList());
         }
 
         public new void Clear()
         {
             base.Clear();
-            OnItemChanged?.Invoke();
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Reset);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Reset, this);
         }
 
         public new void Insert(int index, T item)
         {
             base.Insert(index, item);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithItemInfo?.Invoke(new List<T>() { item });
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, new List<T>() { item });
         }
 
         public new void InsertRange(int index, IEnumerable<T> collection)
         {
             base.InsertRange(index, collection);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithItemInfo?.Invoke(collection.ToList());
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Add);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Add, collection.ToList());
         }
 
         public new bool Remove(T item)
@@ -85,9 +79,8 @@
 
             if (flag)
             {
-                OnItemChanged?.Invoke();
-                OnItemChangedWithItemInfo?.Invoke(new List<T>() { item });
-                OnItemChangedWithSelf?.Invoke(this);
+                OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
+                OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, new List<T>() { item });
             }
 
             return flag;
@@ -95,11 +88,12 @@
 
         public new int RemoveAll(Predicate<T> match)
         {
+            List<T> temp = this.Where(u => match.Invoke(u)).ToList();
             int i = base.RemoveAll(match);
             if (i > 0)
             {
-                OnItemChanged?.Invoke();
-                OnItemChangedWithSelf?.Invoke(this);
+                OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
+                OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, temp);
             }
 
             return i;
@@ -107,16 +101,18 @@
 
         public new void RemoveAt(int index)
         {
+            var item = this[index];
             base.RemoveAt(index);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, new List<T>() { item });
         }
 
         public new void RemoveRange(int index, int count)
         {
+            List<T> temp = this.Skip(index).Take(count).ToList();
             base.RemoveRange(index, count);
-            OnItemChanged?.Invoke();
-            OnItemChangedWithSelf?.Invoke(this);
+            OnItemChanged?.Invoke(NotifyCollectionChangedAction.Remove);
+            OnItemChangedWithItemInfo?.Invoke(NotifyCollectionChangedAction.Remove, temp);
         }
     }
 }
diff --git a/src/Bro.Common.Model/Interface/IDeviceConfig.cs b/src/Bro.Common.Model/Interface/IDeviceConfig.cs
index 40ee6d1..ec8236f 100644
--- a/src/Bro.Common.Model/Interface/IDeviceConfig.cs
+++ b/src/Bro.Common.Model/Interface/IDeviceConfig.cs
@@ -20,7 +20,7 @@
     /// <summary>
     /// 璁惧鍒濆閰嶇疆
     /// </summary>
-    public interface IInitialConfig
+    public interface IInitialConfig : ILog
     {
         /// <summary>
         /// 璁惧搴忓彿 GUID
@@ -31,5 +31,14 @@
         string Name { get; set; }
 
         bool IsEnabled { get; set; }
+
+        string DriverType { get; set; }
+    }
+
+    public interface ILog
+    {
+        string LogPath { get; set; }
+
+        bool IsEnableLog { get; set; }
     }
 }
diff --git a/src/Bro.Common.Model/Interface/IMonitor.cs b/src/Bro.Common.Model/Interface/IMonitor.cs
index 2d9e1b3..be201fb 100644
--- a/src/Bro.Common.Model/Interface/IMonitor.cs
+++ b/src/Bro.Common.Model/Interface/IMonitor.cs
@@ -11,7 +11,7 @@
     public delegate void OnMonitorAlarmDelegate(DateTime dt, IDevice device, WarningSet warning, bool isAlarmRaised);
     public interface IMonitor
     {
-        List<int> GetMonitorValues(int startAddress, int length);
+        //List<int> GetMonitorValues(int startAddress, int length);
         void Monitor();
 
         event OnMonitorInvokeDelegate OnMonitorInvoke;
diff --git a/src/Bro.Common.Model/Model/CustomizedPoint.cs b/src/Bro.Common.Model/Model/CustomizedPoint.cs
index 942c76b..00bf7cd 100644
--- a/src/Bro.Common.Model/Model/CustomizedPoint.cs
+++ b/src/Bro.Common.Model/Model/CustomizedPoint.cs
@@ -599,4 +599,64 @@
             return data.TrimEnd(new char[] { ',' });
         }
     }
+
+    public class RobotPoint : IComplexDisplay
+    {
+        [Category("鐐逛綅淇℃伅")]
+        [Description("鍧愭爣X")]
+        public float X { get; set; }
+
+        [Category("鐐逛綅淇℃伅")]
+        [Description("鍧愭爣Y")]
+        public float Y { get; set; }
+
+        [Category("鐐逛綅淇℃伅")]
+        [Description("鍧愭爣Z")]
+        public float Z { get; set; }
+
+        [Category("鐐逛綅淇℃伅")]
+        [Description("瑙掑害A")]
+        public float A { get; set; }
+
+        [Category("鐐逛綅淇℃伅")]
+        [Description("瑙掑害B")]
+        public float B { get; set; }
+
+        [Category("鐐逛綅淇℃伅")]
+        [Description("瑙掑害C")]
+        public float C { get; set; }
+
+        public string GetDisplayText()
+        {
+            return $"X:{X.ToString()} Y:{Y.ToString()} Z:{Z.ToString()} A:{A.ToString()} B:{B.ToString()} C:{C.ToString()}";
+        }
+
+        public double[] GetArray()
+        {
+            return new double[] { X, Y, Z, A, B, C };
+        }
+
+        public static RobotPoint GetRobotPointByArray(double[] array)
+        {
+            if (array.Length != 6)
+            {
+                return null;
+            }
+
+            RobotPoint point = new RobotPoint();
+            point.X = (float)array[0];
+            point.Y = (float)array[1];
+            point.Z = (float)array[2];
+            point.A = (float)array[3];
+            point.B = (float)array[4];
+            point.C = (float)array[5];
+
+            return point;
+        }
+
+        public static float GetDistance(RobotPoint pointA, RobotPoint pointB)
+        {
+            return (float)Math.Sqrt(Math.Pow(pointA.X - pointB.X, 2) + Math.Pow(pointA.Y - pointB.Y, 2) + Math.Pow(pointA.Z - pointB.Z, 2));
+        }
+    }
 }
diff --git a/src/Bro.Common.Model/Model/IODefinition.cs b/src/Bro.Common.Model/Model/IODefinition.cs
new file mode 100644
index 0000000..6ff8d25
--- /dev/null
+++ b/src/Bro.Common.Model/Model/IODefinition.cs
@@ -0,0 +1,43 @@
+锘縰sing Bro.Common.Helper;
+using Newtonsoft.Json;
+using System;
+using System.ComponentModel;
+
+namespace Bro.Common.Model
+{
+    public class IODefinition : IComplexDisplay
+    {
+        [Category("IO閰嶇疆")]
+        [Description("IO绱㈠紩锛屼粠0寮�濮�")]
+        public int IOIndex { get; set; }
+
+        [Category("IO閰嶇疆")]
+        [Description("IO鎻忚堪")]
+        public string IODesc { get; set; } = "";
+
+        [Category("IO閰嶇疆")]
+        [Description("true锛氭帴閫氳Е鍙�  false锛氭柇寮�瑙﹀彂")]
+        public bool TriggerValue { get; set; } = true;
+
+        [Browsable(false)]
+        [JsonIgnore]
+        public bool CurrentValue { get; set; } = true;
+
+        [Category("IO閰嶇疆")]
+        [Description("IO瀹氫箟绫诲瀷")]
+        public IODefinitionType IOType { get; set; } = IODefinitionType.Warning;
+
+        public string GetDisplayText()
+        {
+            return $"{IOIndex}{(string.IsNullOrWhiteSpace(IODesc) ? "" : (":" + IODesc))}:{IOType.ToString()}";
+        }
+    }
+
+    public enum IODefinitionType
+    {
+        Start,
+        Stop,
+        Reset,
+        Warning,
+    }
+}
diff --git a/src/Bro.Common.Model/Model/MonitorSet.cs b/src/Bro.Common.Model/Model/MonitorSet.cs
index 6a29c6f..fe435a2 100644
--- a/src/Bro.Common.Model/Model/MonitorSet.cs
+++ b/src/Bro.Common.Model/Model/MonitorSet.cs
@@ -47,6 +47,10 @@
         [Description("瑙﹀彂鍊硷紝璁剧疆涓�-999鏃跺彉鍖栧嵆瑙﹀彂")]
         public int TriggerValue { get; set; } = -1;
 
+        [Browsable(false)]
+        [JsonIgnore]
+        public int CurrentValue { get; set; }
+
         /// <summary>
         /// 浼犲叆鏁版嵁鍦板潃鐨勭储寮� 鎸夌収PLC鐩戝惉鍦板潃浠�0寮�濮嬬殑绱㈠紩闆嗗悎
         /// </summary>
@@ -68,32 +72,18 @@
         [Category("鍥炰紶璁剧疆")]
         [Description("閫氱煡鍦板潃 瀹為檯PLC瀵勫瓨鍣ㄧ殑鍦板潃,10杩涘埗锛屼緥濡� 40012")]
         public int NoticeAddress { get; set; } = -1;
-
-        //[Browsable(false)]
-        //[JsonIgnore]
-        //public List<int> InputDatas { get; set; } = new List<int>();
-
+        
         [Browsable(false)]
         [JsonIgnore]
         public ProcessResponse Response { get; set; } = new ProcessResponse();
 
         public MonitorSet() { }
 
-        //public MonitorSet(int triggerIndex, int triggerValue, List<int> inputDataIndex, int dataIndex, int noticeIndex)
-        //{
-        //    TriggerIndex = triggerIndex;
-        //    TriggerValue = triggerValue;
-        //    InputDataIndex = inputDataIndex;
-        //    ReplyDataAddress = dataIndex;
-        //    NoticeAddress = noticeIndex;
-        //}
-
         public string GetDisplayText()
         {
             using (var scope = GlobalVar.Container.BeginLifetimeScope())
             {
                 List<ProcessMethodAttribute> methodList = scope.Resolve<List<ProcessMethodAttribute>>();
-                //List<IDevice> deviceList = scope.Resolve<List<IDevice>>();
 
                 string desc = "";
 
diff --git a/src/Bro.Device.AuboRobot/AuboRobotConfig.cs b/src/Bro.Device.AuboRobot/AuboRobotConfig.cs
index 8c70b49..043faec 100644
--- a/src/Bro.Device.AuboRobot/AuboRobotConfig.cs
+++ b/src/Bro.Device.AuboRobot/AuboRobotConfig.cs
@@ -1,7 +1,6 @@
 锘縰sing Bro.Common.Base;
 using Bro.Common.Helper;
 using Bro.Common.Model;
-using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing.Design;
@@ -25,12 +24,20 @@
         public int ReplyTimeout { get; set; } = 1000;
 
         [Category("閫氫俊璁剧疆")]
+        [Description("鍙嶉瓒呮椂閲嶈瘯娆℃暟")]
+        public int TimeoutRetryTimes { get; set; } = 5;
+
+        [Category("閫氫俊璁剧疆")]
         [Description("鍗忚鏂囨湰缁撴潫瀛楃")]
         public string EndChar { get; set; } = "#";
 
         [Category("閫氫俊璁剧疆")]
         [Description("鍗忚鍐呭鍒嗛殧瀛楃")]
         public string Seperator { get; set; } = ",";
+
+        [Category("鍔ㄤ綔璁剧疆")]
+        [Description("鍔ㄤ綔瓒呮椂璁剧疆锛屽崟浣峬in")]
+        public float OperationTimeout { get; set; } = 1;
 
         [Category("IO鐩戝惉璁剧疆")]
         [Description("IO鐩戝惉鎿嶄綔閰嶇疆闆嗗悎")]
@@ -40,12 +47,54 @@
 
         [Category("IO鐩戝惉璁剧疆")]
         [Description("IO鐩戝惉闂撮殧锛屼互ms涓哄崟浣�")]
-        public int ScanInterval { get; set; } = 100;
+        public int ScanInterval { get; set; } = 9999;
+
+        [Category("IO鐩戝惉璁剧疆")]
+        [Description("鏄惁鍚敤IO鐩戝惉,true锛氱洃鍚� false锛氫笉鐩戝惉")]
+        public bool IsEnableMonitor { get; set; } = false;
+
+        [Category("鎶ヨ閰嶇疆")]
+        [Description("鎶ヨ浠g爜閰嶇疆")]
+        [TypeConverter(typeof(CollectionCountConvert))]
+        [Editor(typeof(ComplexCollectionEditor<RobotWarningCode>), typeof(UITypeEditor))]
+        public List<RobotWarningCode> RobotWarnings { get; set; } = new List<RobotWarningCode>();
+    }
+
+    public class RobotWarningCode
+    {
+        [Category("鎶ヨ閰嶇疆")]
+        [Description("鎶ヨ浠g爜")]
+        public int WarningCode { get; set; }
+
+        [Category("鎶ヨ閰嶇疆")]
+        [Description("鎶ヨ浠g爜鎻忚堪")]
+        public string WarningDescription { get; set; }
     }
 
     [Device("AuboRobot", "濂ュ崥鏈哄櫒浜�", EnumHelper.DeviceAttributeType.OperationConfig)]
     public class AuboRobotOperationConfig : OperationConfigBase
     {
+        [Category("鍔ㄤ綔鎸囦护")]
+        [Description("鍔ㄤ綔鎸囦护")]
+        public RobotMsgAction Action { get; set; } = RobotMsgAction.Move;
+
+        [Category("鍙傛暟")]
+        [Description("鍙傛暟1")]
+        public int Para1 { get; set; } = 0;
+
+        [Category("鍙傛暟")]
+        [Description("鍙傛暟2")]
+        public int Para2 { get; set; } = 0;
+
+        [Category("杩愬姩閰嶇疆")]
+        [Description("鏈哄櫒浜鸿繍鍔ㄧ偣浣�")]
+        [TypeConverter(typeof(ComplexObjectConvert))]
+        [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
+        public RobotPoint Point { get; set; } = new RobotPoint();
+
+        [Category("鎿嶄綔閰嶇疆")]
+        [Description("鏄惁绛夊緟瀹屾垚淇″彿")]
+        public bool IsWaitFinished { get; set; } = true;
     }
 
     public class RobotMsg : IComplexDisplay
@@ -56,16 +105,13 @@
 
         public RobotMsgAction Action { get; set; } = RobotMsgAction.Move;
 
-        public RobotMsgParas Para1 { get; set; } = RobotMsgParas.None;
+        public int Para1 { get; set; }
 
         public int Para2 { get; set; } = 0;
 
-        /// <summary>
-        /// Paras涓嶅寘鍚玃ara1,Para2鍐呭
-        /// </summary>
-        public List<string> Datas { get; set; } = new List<string>();
+        public RobotPoint Point { get; set; } = new RobotPoint();
 
-        public byte[] GetMsgBytes(string seperator, string endChar)
+        public byte[] GetMsgBytes(string seperator, string endChar, out string msg)
         {
             List<string> list = new List<string>() { ((int)Type).ToString("D2"), ID.ToString("D2") };
 
@@ -73,34 +119,51 @@
             {
                 list.Add(((int)Action).ToString("D2"));
 
-                list.Add(((int)Para1).ToString("D2"));
+                list.Add(Para1.ToString("D2"));
                 list.Add(Para2.ToString("D2"));
 
-                if (Datas == null)
-                {
-                    Datas = new List<string>();
-                }
-
-                while (Datas.Count < 5)
-                {
-                    Datas.Add("0");
-                }
-
-                list.AddRange(Datas.ConvertAll(s =>
-                {
-                    string res = float.Parse(s).ToString("F7");
-
-                    while (res.Length < 11)
-                    {
-                        res = "0" + res;
-                    }
-                    return res;
-                }));
+                list.Add(GetFormatString(Point.X));
+                list.Add(GetFormatString(Point.Y));
+                list.Add(GetFormatString(Point.Z));
+                list.Add(GetFormatString_Angle(Point.A));
+                list.Add(GetFormatString_Angle(Point.B));
+                list.Add(GetFormatString_Angle(Point.C));
             }
 
-            string msg = string.Join(seperator, list);
+            msg = string.Join(seperator, list) + seperator + endChar;
 
-            return System.Text.Encoding.ASCII.GetBytes(msg + endChar);
+            return System.Text.Encoding.ASCII.GetBytes(msg);
+        }
+
+        private string GetFormatString(float x)
+        {
+            string s = x.ToString("f10");
+
+            s = s.TrimEnd(new char[] { '0' });
+
+            bool isNegative = x < 0;
+
+            while (s.Length < 11)
+            {
+                s = s.Insert(isNegative ? 1 : 0, "0");
+            }
+
+            return s;
+        }
+
+        /// <summary>
+        /// 灏嗚搴︽暟鍊艰浆鎹负11浣嶅瓧绗︿覆锛岃緭鍏ヨ搴﹀尯闂�0~360锛岃緭鍑鸿搴﹀尯闂�-180~+180
+        /// </summary>
+        /// <param name="x"></param>
+        /// <returns></returns>
+        private string GetFormatString_Angle(float x)
+        {
+            if (x > 180)
+            {
+                x = x - 360;
+            }
+
+            return GetFormatString(x);
         }
 
         public static RobotMsg GetRobotMsg(string data, string seperator)
@@ -116,10 +179,22 @@
             {
                 msg.Action = (RobotMsgAction)int.Parse(datas[2]);
 
-                msg.Para1 = (RobotMsgParas)int.Parse(datas[3]);
+                msg.Para1 = int.Parse(datas[3]);
                 msg.Para2 = int.Parse(datas[4]);
 
-                msg.Datas = datas.Skip(5).ToList();
+                msg.Point = new RobotPoint()
+                {
+                    X = float.Parse(datas[5]),
+                    Y = float.Parse(datas[6]),
+                    Z = float.Parse(datas[7]),
+                    A = float.Parse(datas[8]) < 0 ? float.Parse(datas[8]) + 360 : float.Parse(datas[8]),
+                    B = float.Parse(datas[9]) < 0 ? float.Parse(datas[9]) + 360 : float.Parse(datas[9]),
+                    C = float.Parse(datas[10]) < 0 ? float.Parse(datas[10]) + 360 : float.Parse(datas[10]),
+                };
+            }
+            else
+            {
+                msg.Para1 = int.Parse(datas[2]);
             }
 
             return msg;
@@ -127,7 +202,7 @@
 
         public string GetDisplayText()
         {
-            string msg = $"搴忓彿锛歿ID},{Action.ToString()}_{Para1.ToString()}_{Para2.ToString()}_{(Datas.Count > 0 ? ("_" + string.Join(",", Datas)) : "")}";
+            string msg = $"搴忓彿锛歿ID},{Action.ToString()}_{Para1.ToString()}_{Para2.ToString()}_{Point.GetDisplayText()}";
             return msg;
         }
     }
@@ -143,20 +218,62 @@
         Move = 1,
         Unload = 2,
         Load = 3,
-        IO = 6,
+        GetPosition = 4,
+        /// <summary>
+        /// 鎸囧畾褰撳墠鐐逛綅涓哄熀鍑嗙偣
+        /// </summary>
+        BasePoint = 5,
+        IOSet = 6,
+        IOQuery = 7,
         Calibration = 9,
         StandardPoint = 10,
     }
 
-    public enum RobotMsgParas
+    public enum MoveType
     {
-        None = 0,
-        Home = 1,
-        LineSnap = 2,
-        EmptyTray = 3,
-        FullTray = 4,
-        UnloadEmptyTraySnap = 5,
-        LoadFullTraySnap = 6,
-        Query = 7,
+        [Description("缁濆杩愬姩")]
+        AbsoluteMove = 1,
+        [Description("鏈哄櫒浜哄潗鏍囩郴鐩稿杩愬姩")]
+        RobotRelativeMove = 2,
+        [Description("鐩稿鏌愪釜鍩哄噯鐐逛綅鐨勭浉瀵硅繍鍔�")]
+        BasedPointRelativeMove = 3,
+        [Description("鍥炲師鐐�")]
+        Origin = 4,
+        [Description("宸︿晶濮垮娍")]
+        LeftPose = 6,
+        [Description("鍙充晶濮垮娍")]
+        RightPose = 5,
+        [Description("鍓嶄晶濮垮娍")]
+        FrontPose = 7,
+        [Description("鐩告満鍧愭爣绯荤浉瀵硅繍鍔�")]
+        CameraRelativeMove = 12,
     }
+
+    public enum TrayType
+    {
+        FullTray = 1,
+        EmptyTray = 2,
+    }
+
+    //public enum RobotMsgAction
+    //{
+    //    Move = 1,
+    //    Unload = 2,
+    //    Load = 3,
+    //    IO = 6,
+    //    Calibration = 9,
+    //    StandardPoint = 10,
+    //}
+
+    //public enum RobotMsgParas
+    //{
+    //    None = 0,
+    //    Home = 1,
+    //    LineSnap = 2,
+    //    EmptyTray = 3,
+    //    FullTray = 4,
+    //    UnloadEmptyTraySnap = 5,
+    //    LoadFullTraySnap = 6,
+    //    Query = 7,
+    //}
 }
diff --git a/src/Bro.Device.AuboRobot/AuboRobotDriver.cs b/src/Bro.Device.AuboRobot/AuboRobotDriver.cs
index 11f343f..02691de 100644
--- a/src/Bro.Device.AuboRobot/AuboRobotDriver.cs
+++ b/src/Bro.Device.AuboRobot/AuboRobotDriver.cs
@@ -10,6 +10,7 @@
 using System.Net.Sockets;
 using System.Threading;
 using System.Threading.Tasks;
+using static Bro.Common.Helper.EnumHelper;
 
 namespace Bro.Device.AuboRobot
 {
@@ -38,7 +39,7 @@
 
             if (string.IsNullOrWhiteSpace(IConfig.EndChar))
             {
-                throw new ProcessException("鍗忚鏂囨湰鐨勭粨鏉熷瓧绗︿笉鍙负绌猴紝璇锋鏌ラ厤缃�", null);
+                throw new ProcessException("鍗忚鏂囨湰鐨勭粨鏉熷瓧绗︿笉鍙负绌猴紝璇锋鏌ラ厤缃�");
             }
 
             client = new TcpClient();
@@ -46,6 +47,10 @@
             client.Client.Blocking = true;
             client.NoDelay = true;
             client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
+
+            replyHandleDict = new Dictionary<int, AutoResetEvent>();
+            replyErrorCodeDict = new Dictionary<int, int>();
+            taskHandleDict = new Dictionary<int, ManualResetEvent>();
         }
 
         protected override void Pause()
@@ -62,18 +67,24 @@
             //Query Robot IOs
             //SendMsg(RobotMsgType.Send, 0, true, RobotMsgAction.IO, RobotMsgParas.Query, new List<string>());
 
-            scanMsg = new RobotMsg();
-            scanMsg.Action = RobotMsgAction.IO;
-            scanMsg.Para1 = RobotMsgParas.Query;
+            //scanMsg = new RobotMsg();
+            //scanMsg.Action = RobotMsgAction.IO;
+            //scanMsg.Para1 = RobotMsgParas.Query;
 
-            Task.Run(() =>
-            {
-                Monitor();
-            });
+            //Task.Run(() =>
+            //{
+            //    Monitor();
+            //});
         }
 
         protected override void Stop()
         {
+            replyHandleDict.Values.ToList().ForEach(h => h.Set());
+            replyHandleDict.Clear();
+
+            taskHandleDict.Values.ToList().ForEach(h => h.Set());
+            taskHandleDict.Clear();
+
             if (client != null && client.Connected)
             {
                 client.Close();
@@ -95,7 +106,8 @@
             }
             catch (Exception ex)
             {
-                OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage());
+                //OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage());
+                LogAsync(DateTime.Now, "杩炴帴寮傚父", ex.GetExceptionMessage());
 
                 if (client != null && client.Connected)
                 {
@@ -110,13 +122,12 @@
             try
             {
                 int dataLength = stream.EndRead(ar);
-
                 if (dataLength > 0)
                 {
                     byte[] data = buffer.Take(dataLength).ToArray();
 
                     string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim();
-                    //OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}鎺ユ敹鏁版嵁锛歿dataStr}", null, null);
+
                     AnalyzeData(dataStr);
 
                     stream.BeginRead(buffer, 0, buffer.Length, OnDataReceived, null);
@@ -125,19 +136,21 @@
                 {
                     if (!client.Connected)
                     {
-                        OnLog?.Invoke(DateTime.Now, this, "杩斿洖绌烘暟鎹紝杩炴帴涓柇");
+                        //OnLog?.Invoke(DateTime.Now, this, "杩斿洖绌烘暟鎹紝杩炴帴涓柇");
+                        LogAsync(DateTime.Now, "杩炴帴涓柇", "杩斿洖绌烘暟鎹紝杩炴帴涓柇");
                         client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
                     }
                 }
             }
             catch (Exception ex)
             {
-                OnLog?.Invoke(DateTime.Now, this, $"{Name}鏁版嵁鎺ユ敹寮傚父锛歿ex.GetExceptionMessage()}");
+                //OnLog?.Invoke(DateTime.Now, this, $"{Name}锛歿ex.GetExceptionMessage()}");
+                LogAsync(DateTime.Now, "鏁版嵁鎺ユ敹寮傚父", ex.GetExceptionMessage());
             }
         }
 
         string msg = "";
-        static object analyzeLock = new object();
+        object analyzeLock = new object();
         private async void AnalyzeData(string data)
         {
             await Task.Run(() =>
@@ -168,41 +181,58 @@
             await Task.Run(() =>
             {
                 Array.ForEach(datas, data =>
-                 {
-                     RobotMsg msg = RobotMsg.GetRobotMsg(data, IConfig.Seperator);
+                {
+                    RobotMsg msg = RobotMsg.GetRobotMsg(data, IConfig.Seperator);
 
-                     if (msg.Type == RobotMsgType.Rec)
-                     {
-                         if (replyHandleDict.ContainsKey(msg.ID))
-                         {
-                             replyHandleList.Remove(msg.ID);
+                    if (msg.Type == RobotMsgType.Rec)
+                    {
+                        replyErrorCodeDict[msg.ID] = msg.Para1;
+                        if (replyHandleDict.ContainsKey(msg.ID))
+                        {
+                            replyHandleDict[msg.ID].Set();
+                        }
+                    }
+                    else
+                    {
+                        if (msg.Action == RobotMsgAction.IOQuery)
+                        {
+                            newValues = new List<int>();
 
-                             replyHandleDict[msg.ID].Set();
-                             replyHandleDict.Remove(msg.ID);
-                         }
-                     }
-                     else
-                     {
-                         canMonitor = true;
+                            for (int i = msg.Para1.ToString().Length - 1; i >= 0; i--)
+                            {
+                                newValues.Add((msg.Para1 >> i) & 1);
+                            }
 
-                         if (msg.Action == RobotMsgAction.IO && msg.Para1 == RobotMsgParas.Query)
-                         {
-                             string resultStr = msg.Datas[0];
-                             newValues = new List<int>();
+                            MonitorHandle.Set();
+                        }
+                        else
+                        {
+                            canMonitor = true;
+                            switch (msg.Action)
+                            {
+                                case RobotMsgAction.Move:
+                                    CurrentPoint = msg.Point;
+                                    break;
+                                //case RobotMsgAction.Load:
+                                //    //SlotIndex = msg.Para1;
+                                //    break;
+                                case RobotMsgAction.GetPosition:
+                                    CurrentPoint = msg.Point;
+                                    break;
+                                default:
+                                    break;
+                            }
 
-                             for (int i = resultStr.Length - 1; i >= 0; i--)
-                             {
-                                 newValues.Add(int.Parse(resultStr[i].ToString()));
-                             }
+                            if (taskHandleDict.ContainsKey(msg.ID))
+                            {
+                                taskHandleDict[msg.ID].Set();
+                            }
 
-                             MonitorHandle.Set();
-                         }
-                         else
-                         {
-                             OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null);
-                         }
-                     }
-                 });
+                            LogAsync(DateTime.Now, "鎸囦护鍙嶉", msg.GetDisplayText());
+                            OnMsgReceived?.BeginInvoke(DateTime.Now, this, msg, null, null);
+                        }
+                    }
+                });
             });
         }
 
@@ -220,24 +250,9 @@
             }
         }
 
-        List<int> replyHandleList = new List<int>();
         Dictionary<int, AutoResetEvent> replyHandleDict = new Dictionary<int, AutoResetEvent>();
-
-        public void SendMsg(RobotMsgAction action, RobotMsgParas para1, int para2, List<float> paras = null)
-        {
-            RobotMsg msg = new RobotMsg();
-            msg.Type = RobotMsgType.Send;
-            msg.ID = SID;
-
-            msg.Action = action;
-            msg.Para1 = para1;
-            msg.Para2 = para2;
-
-            msg.Datas = new List<string>((paras ?? new List<float>()).ConvertAll(i => i.ToString()));
-
-            OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}鍙戦�佹寚浠わ細{msg.GetDisplayText()}", null, null);
-            SendMsg(msg, true);
-        }
+        Dictionary<int, int> replyErrorCodeDict = new Dictionary<int, int>();
+        Dictionary<int, ManualResetEvent> taskHandleDict = new Dictionary<int, ManualResetEvent>();
 
         public void SendReplyMsg(int replyId)
         {
@@ -253,37 +268,183 @@
         object monitorLock = new object();
         public void SendMsg(RobotMsg msg, bool isWaitReply = true, bool isMonitorMsg = false)
         {
+            replyErrorCodeDict[msg.ID] = 0;
+
             if (isWaitReply)
             {
-                replyHandleList.Add(msg.ID);
                 replyHandleDict[msg.ID] = new AutoResetEvent(false);
             }
 
-            byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar);
-
-            lock (monitorLock)
+            byte[] bytes = msg.GetMsgBytes(IConfig.Seperator, IConfig.EndChar, out string dataStr);
+            if (!isMonitorMsg)
             {
-                if (!isMonitorMsg)
-                {
-                    canMonitor = false;
-                }
-
-                if (isMonitorMsg && !canMonitor)
-                    return;
-
-                //lock (this)
-                {
-                    stream.Write(bytes, 0, bytes.Length);
-                }
+                LogAsync(DateTime.Now, "鎸囦护鍙戦��", dataStr);
             }
+
+            bool isNotTimeout = true;
+            int reTryTime = IConfig.TimeoutRetryTimes;
+            do
+            {
+                lock (monitorLock)
+                {
+                    if (!isMonitorMsg)
+                    {
+                        canMonitor = false;
+                    }
+
+                    if (isMonitorMsg && !canMonitor)
+                        return;
+
+                    stream.Write(bytes, 0, bytes.Length);
+
+                    if (!isMonitorMsg)
+                    {
+                        LogAsync(DateTime.Now, "鏁版嵁鍙戦��", BitConverter.ToString(bytes));
+                    }
+                }
+
+                if (isWaitReply)
+                {
+                    int errorCode = replyErrorCodeDict[msg.ID];
+
+                    if (errorCode != 0)
+                    {
+                        var desc = IConfig.RobotWarnings.FirstOrDefault(u => u.WarningCode == errorCode);
+                        throw new ProcessException($"{Name}{msg.ID}浠诲姟鍙嶉寮傚父{errorCode},寮傚父鎻忚堪锛歿(desc == null ? "鏃�" : desc.WarningDescription)}");
+                    }
+
+                    isNotTimeout = replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
+
+                    if (!isNotTimeout)
+                    {
+                        reTryTime--;
+                    }
+                }
+            } while (reTryTime > 0 && !isNotTimeout);
 
             if (isWaitReply)
             {
-                replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
+                replyHandleDict.Remove(msg.ID);
+            }
 
-                if (replyHandleList.Contains(msg.ID))
+            if (!isNotTimeout)
+            {
+                throw new ProcessException($"{Name}鍙嶉鏁版嵁瓒呮椂\r\n" + msg.GetDisplayText());
+            }
+        }
+
+        #region 鎵ц缁撴灉灞炴��
+        public RobotPoint CurrentPoint { get; set; } = null;
+        //public int SlotIndex { get; set; } = 0;
+        #endregion
+
+        public void Move(RobotPoint point, MoveType isAbs, bool isWaitFinished)
+        {
+            CurrentPoint = null;
+
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.Move;
+            msg.Para1 = (int)isAbs;
+
+            msg.Point = point ?? new RobotPoint();
+
+            SendMsg(msg, true);
+
+            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}{(isAbs.GetEnumDescription())}鑷硔point.GetDisplayText()}鍔ㄤ綔瓒呮椂");
+        }
+
+        public void Load(RobotPoint point, TrayType trayType, bool isWaitFinished)
+        {
+            //SlotIndex = 0;
+
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.Load;
+            msg.Para1 = (int)trayType;
+            msg.Point = point;
+
+            SendMsg(msg, true);
+
+            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}鍙杮trayType.ToString()}{point.GetDisplayText()}鍔ㄤ綔瓒呮椂");
+
+            //if (isWaitFinished && SlotIndex <= 0)
+            //{
+            //    throw new ProcessException($"{Name}娌℃湁鍙敤鐨勭┖鐧芥牸浣�,鏃犳硶鏀剧疆鍗峰畻");
+            //}
+        }
+
+        public void UnLoad(RobotPoint point, TrayType trayType, bool isWaitFinished)
+        {
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.Unload;
+            msg.Para1 = (int)trayType;
+            msg.Point = point;
+
+            SendMsg(msg, true);
+
+            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}鍗竰trayType.ToString()}{point.GetDisplayText()}鍔ㄤ綔瓒呮椂");
+        }
+
+        public void GetPosition(bool isWaitFinished)
+        {
+            CurrentPoint = null;
+
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.GetPosition;
+
+            SendMsg(msg, true);
+
+            TaskTimeoutCheck(isWaitFinished, msg.ID, $"{Name}鑾峰彇褰撳墠鍧愭爣瓒呮椂");
+        }
+
+        public void SetBasePoint()
+        {
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.BasePoint;
+
+            SendMsg(msg, true);
+        }
+
+        public void SetIO(int outputIndex, bool isOn)
+        {
+            RobotMsg msg = new RobotMsg();
+            msg.Type = RobotMsgType.Send;
+            msg.ID = SID;
+
+            msg.Action = RobotMsgAction.IOSet;
+            msg.Para1 = outputIndex;
+            msg.Para2 = isOn ? 1 : 0;
+
+            SendMsg(msg, true);
+        }
+
+        private void TaskTimeoutCheck(bool isWaitFinished, int msgId, string errorMsg)
+        {
+            if (isWaitFinished)
+            {
+                taskHandleDict[msgId] = new ManualResetEvent(false);
+                taskHandleDict[msgId].Reset();
+                bool isNotTimeout = taskHandleDict[msgId].WaitOne((int)(IConfig.OperationTimeout * 60 * 1000));
+
+                taskHandleDict.Remove(msgId);
+
+                if (!isNotTimeout)
                 {
-                    throw new ProcessException("鍙嶉鏁版嵁瓒呮椂\r\n" + msg.GetDisplayText(), null);
+                    throw new ProcessException(errorMsg);
                 }
             }
         }
@@ -295,14 +456,16 @@
         protected List<int> oldValues = new List<int>();
         List<int> newValues = new List<int>();
         public ManualResetEvent MonitorHandle { get; set; } = new ManualResetEvent(false);
-        //public ManualResetEvent IOChangedHandle { get; set; } = new ManualResetEvent(true);
-        public List<int> GetMonitorValues(int startAddress, int length)
+        public List<int> GetIOValues()
         {
             MonitorHandle.Reset();
             scanMsg.ID = SID;
             SendMsg(scanMsg, true, true);
 
-            MonitorHandle.WaitOne(IConfig.ReplyTimeout);
+            var isNotTimeout = MonitorHandle.WaitOne(IConfig.ReplyTimeout * 3);
+
+            if (!isNotTimeout)
+                throw new ProcessException($"{Name}鐩戝惉鎿嶄綔瓒呮椂");
 
             return newValues;
         }
@@ -313,29 +476,32 @@
             {
                 try
                 {
-                    List<int> newValues = GetMonitorValues(0, 0);
-
-                    if (newValues == null || newValues.Count == 0)
-                        continue;
-
-                    if (oldValues.Count == 0)
+                    if (IConfig.IsEnableMonitor)
                     {
-                        oldValues = newValues.ConvertAll(s => -1).ToList();
-                    }
+                        List<int> newValues = GetIOValues();
 
-                    if (oldValues.Count == newValues.Count)
-                    {
-                        var tempNew = new List<int>(newValues);
-                        var tempOld = new List<int>(oldValues);
-                        MonitorCheckAndInvoke(tempNew, tempOld);
+                        if (newValues == null || newValues.Count == 0)
+                            continue;
+
+                        if (oldValues.Count == 0)
+                        {
+                            oldValues = newValues.ConvertAll(s => -1).ToList();
+                        }
+
+                        if (oldValues.Count == newValues.Count)
+                        {
+                            var tempNew = new List<int>(newValues);
+                            var tempOld = new List<int>(oldValues);
+                            MonitorCheckAndInvoke(tempNew, tempOld);
+                        }
+                        oldValues = new List<int>(newValues);
                     }
-                    oldValues = new List<int>(newValues);
 
                     Thread.Sleep(IConfig.ScanInterval);
                 }
                 catch (Exception ex)
                 {
-                    OnLog?.Invoke(DateTime.Now, this, $"{Name}鐩戝惉寮傚父:{ex.GetExceptionMessage()}");
+                    LogAsync(DateTime.Now, "鐩戝惉寮傚父", ex.GetExceptionMessage());
                 }
             }
         }
diff --git a/src/Bro.Device.Common/Base/DeviceBase.cs b/src/Bro.Device.Common/Base/DeviceBase.cs
index 11aa9cf..25b45fb 100644
--- a/src/Bro.Device.Common/Base/DeviceBase.cs
+++ b/src/Bro.Device.Common/Base/DeviceBase.cs
@@ -14,6 +14,7 @@
 //using BroCComn.PubSub;
 using static Bro.Common.Helper.EnumHelper;
 using System.ComponentModel;
+using System.IO;
 
 namespace Bro.Common.Base
 {
@@ -393,7 +394,7 @@
             {
                 string currentStateStr = CurrentStateToBe.GetEnumDescription();
                 string stateToBeStr = stateToBe.GetEnumDescription();
-                throw new ProcessException($"{InitialConfig.Name}璁惧鐨勫綋鍓嶇姸鎬佷负{currentStateStr}锛屾棤娉曞垏鎹㈣嚦{stateToBeStr}", null);
+                throw new ProcessException($"{InitialConfig.Name}璁惧鐨勫綋鍓嶇姸鎬佷负{currentStateStr}锛屾棤娉曞垏鎹㈣嚦{stateToBeStr}");
             }
 
             CurrentState = EnumHelper.DeviceState.TBD;
@@ -417,7 +418,7 @@
                     }
                     else
                     {
-                        throw new ProcessException($"{InitialConfig.Name}璁惧鎿嶄綔瓒呮椂", null);
+                        throw new ProcessException($"{InitialConfig.Name}璁惧鎿嶄綔瓒呮椂");
                     }
                 }
 
@@ -489,7 +490,7 @@
                         //this.CurrentState = EnumHelper.DeviceState.DSExcept;
                         //this.CurrentStateToBe = EnumHelper.DeviceState.DSExcept;
 
-                        throw new ProcessException($"璁惧{InitialConfig.Name}鐨剓CurrentStateToBe.GetEnumDescription()}鎿嶄綔閲嶅3娆″け璐�", ex);
+                        throw new ProcessException($"璁惧{InitialConfig.Name}鐨剓CurrentStateToBe.GetEnumDescription()}鎿嶄綔閲嶅3娆″け璐�", ExceptionLevel.Warning, ex);
                     }
                 }
             }
@@ -515,5 +516,40 @@
             CurrentUserId = obj;
         }
         #endregion
+
+        #region 鏃ュ織澶勭悊
+        object logObject = new object();
+        public virtual async void LogAsync(DateTime dt, string prefix, string msg)
+        {
+            await Task.Run(() =>
+            {
+                if (InitialConfig.IsEnableLog)
+                {
+                    OnLog?.Invoke(dt, this, prefix + "\t" + msg);
+
+                    if (string.IsNullOrWhiteSpace(InitialConfig.LogPath) || !Path.IsPathRooted(InitialConfig.LogPath))
+                    {
+                        return;
+                    }
+
+                    if (!Directory.Exists(InitialConfig.LogPath))
+                    {
+                        Directory.CreateDirectory(InitialConfig.LogPath);
+                    }
+
+                    string filePath = Path.Combine(InitialConfig.LogPath, $"Log_{Name}_{DateTime.Now.ToString("yyyyMMdd")}.txt");
+                    lock (logObject)
+                    {
+                        using (StreamWriter writer = new StreamWriter(filePath, true, Encoding.UTF8))
+                        {
+                            writer.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t{prefix}\t{msg}");
+                            writer.Flush();
+                            writer.Close();
+                        }
+                    }
+                }
+            });
+        }
+        #endregion
     }
 }
diff --git a/src/Bro.Device.Common/Base/DeviceConfigBase.cs b/src/Bro.Device.Common/Base/DeviceConfigBase.cs
index 1150d4e..0f28653 100644
--- a/src/Bro.Device.Common/Base/DeviceConfigBase.cs
+++ b/src/Bro.Device.Common/Base/DeviceConfigBase.cs
@@ -1,7 +1,9 @@
-锘縰sing Bro.Common.Interface;
+锘縰sing Bro.Common.Helper;
+using Bro.Common.Interface;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Drawing.Design;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -28,6 +30,18 @@
         /// </summary>
         [Category("閫氱敤閰嶇疆")]
         [Description("璁惧鏄惁鍚敤")]
-        public bool IsEnabled { get; set; } = false;        
+        public bool IsEnabled { get; set; } = false;
+
+        [Browsable(false)]
+        public virtual string DriverType { get; set; } = "";
+
+        [Category("鏃ュ織閰嶇疆")]
+        [Description("鏃ュ織璁板綍鐩綍")]
+        [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))]
+        public string LogPath { get; set; }
+
+        [Category("鏃ュ織閰嶇疆")]
+        [Description("true锛氬惎鐢ㄦ棩蹇楄褰�  false锛氫笉鍚敤鏃ュ織璁板綍")]
+        public bool IsEnableLog { get; set; } = false;
     }
 }
diff --git a/src/Bro.Device.Common/DeviceBase/HDevEngineTool.cs b/src/Bro.Device.Common/DeviceBase/HDevEngineTool.cs
index 6e3645f..bb3966c 100644
--- a/src/Bro.Device.Common/DeviceBase/HDevEngineTool.cs
+++ b/src/Bro.Device.Common/DeviceBase/HDevEngineTool.cs
@@ -12,7 +12,7 @@
 
 namespace Bro.Common.Base
 {
-    public class HDevEngineTool
+    public class HDevEngineTool : IDisposable
     {
         #region 甯搁噺
 
@@ -41,7 +41,7 @@
         /// <summary>
         /// 绋嬪簭杩愯鏄惁鎴愬姛
         /// </summary>
-        private bool isSuccess = false;
+        public bool IsSuccessful { get; set; } = false;
 
         /// <summary>
         /// 鎺у埗鍙傛暟瀛楀吀
@@ -132,11 +132,11 @@
 
                 procedureCall.Execute();
 
-                isSuccess = true;
+                IsSuccessful = true;
             }
             catch (HDevEngineException ex)
             {
-                isSuccess = false;
+                IsSuccessful = false;
                 Trace.TraceInformation("HDevProgram {0} Run fail , Line number: {1}, Halcon error number : {2},ex:{3}", ex.ProcedureName, ex.LineNumber, ex.HalconError, ex.Message);
                 return;
             }
@@ -144,7 +144,7 @@
 
         public HTuple GetResultTuple(string key)
         {
-            if (isSuccess)
+            if (IsSuccessful)
             {
                 return procedureCall.GetOutputCtrlParamTuple(key);
             }
@@ -157,7 +157,7 @@
 
         public HObject GetResultObject(string key, bool ignoreError = false)
         {
-            if (ignoreError || isSuccess)
+            if (ignoreError || IsSuccessful)
             {
                 return procedureCall.GetOutputIconicParamObject(key);
             }
@@ -166,6 +166,17 @@
                 return new HObject();
             }
         }
+
+        public void Dispose()
+        {
+            //foreach (HObject obj in InputImageDic.Values)
+            //{
+            //    obj.Dispose();
+            //}
+
+            procedureCall.Dispose();
+            myEngine.Dispose();
+        }
     }
 
     public static class HalconHelper
diff --git a/src/Bro.Device.Common/DeviceBase/PLCBase.cs b/src/Bro.Device.Common/DeviceBase/PLCBase.cs
index 10d42f1..2141644 100644
--- a/src/Bro.Device.Common/DeviceBase/PLCBase.cs
+++ b/src/Bro.Device.Common/DeviceBase/PLCBase.cs
@@ -147,7 +147,7 @@
             });
         }
 
-        private void OnMethodInvoked(IAsyncResult ar)
+        protected virtual void OnMethodInvoked(IAsyncResult ar)
         {
             MonitorSet monitorSet = ar.AsyncState as MonitorSet;
 
@@ -186,7 +186,7 @@
 
                         if (repeatTime <= 0)
                         {
-                            new ProcessException("PLC鍙嶉鍐欏叆寮傚父", ex);
+                            new ProcessException("PLC鍙嶉鍐欏叆寮傚父", ExceptionLevel.Info, ex);
                         }
                     }
                 } while (repeatTime > 0);
@@ -234,13 +234,13 @@
         [Description("瓒呮椂璁剧疆锛屽崟浣嶏細ms")]
         public int Timeout { get; set; } = 500;
 
-        [Category("杈撳嚭璁剧疆")]
-        [Description("鏄惁鏃ュ織杈撳嚭")]
-        public bool IsEnabelLog { get; set; } = false;
+        //[Category("杈撳嚭璁剧疆")]
+        //[Description("鏄惁鏃ュ織杈撳嚭")]
+        //public bool IsEnabelLog { get; set; } = false;
 
-        [Category("杈撳嚭璁剧疆")]
-        [Description("杈撳嚭鏂囦欢璺緞")]
-        public string LogPath { get; set; } = @"D:\PLCLog.txt";
+        //[Category("杈撳嚭璁剧疆")]
+        //[Description("杈撳嚭鏂囦欢璺緞")]
+        //public string LogPath { get; set; } = @"D:\PLCLog.txt";
 
         #region 鍦板潃璁剧疆
         [Category("浜嬩欢鍦板潃璁剧疆")]
diff --git a/src/Bro.Device.Common/Helper/AspectHelper.cs b/src/Bro.Device.Common/Helper/AspectHelper.cs
index 0176023..0c3178f 100644
--- a/src/Bro.Device.Common/Helper/AspectHelper.cs
+++ b/src/Bro.Device.Common/Helper/AspectHelper.cs
@@ -45,7 +45,7 @@
             IOperationConfig config = args.Arguments.FirstOrDefault() as IOperationConfig;
             if (config == null)
             {
-                throw new ProcessException("璁惧鎿嶄綔杞叆鍙傛暟绫诲瀷閿欒锛�", null);
+                throw new ProcessException("璁惧鎿嶄綔杞叆鍙傛暟绫诲瀷閿欒锛�");
             }
 
             if (device.DeviceMode == DeviceMode.Run)
diff --git a/src/Bro.Device.OmronFins/FinsFrame.cs b/src/Bro.Device.OmronFins/FinsFrame.cs
index dabb024..4189eba 100644
--- a/src/Bro.Device.OmronFins/FinsFrame.cs
+++ b/src/Bro.Device.OmronFins/FinsFrame.cs
@@ -292,7 +292,7 @@
                 List<byte> errorCode = bytes.Skip(4 + 4 + 4).Take(4).ToList();
                 if (errorCode.Any(u => u != 0x00))
                 {
-                    throw new ProcessException($"杩斿洖寮傚父锛岄敊璇爜{string.Join("", errorCode)}", null);
+                    throw new ProcessException($"杩斿洖寮傚父锛岄敊璇爜{string.Join("", errorCode)}");
                 }
 
                 bytes = bytes.Skip(4 + 4 + 4 + 4).ToArray();
@@ -323,7 +323,7 @@
 
             if (beginIndex == -1)
             {
-                throw new ProcessException("娆у榫橮LC閫氳甯ч敊璇�", null);
+                throw new ProcessException("娆у榫橮LC閫氳甯ч敊璇�");
             }
 
             List<byte> singleBytes = bytes.Skip(beginIndex).ToList();
@@ -411,7 +411,7 @@
 
             if (wordAddress == 0 && byteAddress == 0)
             {
-                throw new ProcessException("娆у榫橮LC鐩戝惉鍦板潃璁剧疆閿欒", null);
+                throw new ProcessException("娆у榫橮LC鐩戝惉鍦板潃璁剧疆閿欒");
             }
 
             //瀛楀湴鍧�
diff --git a/src/Bro.Device.OmronFins/OmronFinsDriver.cs b/src/Bro.Device.OmronFins/OmronFinsDriver.cs
index 534c13e..695423b 100644
--- a/src/Bro.Device.OmronFins/OmronFinsDriver.cs
+++ b/src/Bro.Device.OmronFins/OmronFinsDriver.cs
@@ -13,6 +13,7 @@
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using static Bro.Common.Helper.EnumHelper;
 
 namespace Bro.Device.OmronFins
 {
@@ -31,11 +32,11 @@
             }
 
             byte[] data = opFrame.GetSendReadFrameBytes(item, CurrentSid);
-            var stream = opClient.GetStream();
-            stream.Write(data, 0, data.Length);
+            //var stream = opClient.GetStream();
+            opStream.Write(data, 0, data.Length);
 
             byte[] buffer = new byte[2048];
-            int readSize = stream.Read(buffer, 0, buffer.Length);
+            int readSize = opStream.Read(buffer, 0, buffer.Length);
 
             if (readSize > 0)
             {
@@ -70,7 +71,7 @@
             Stopwatch sw = new Stopwatch();
             sw.Start();
 
-            NetworkStream stream = null;
+            //NetworkStream stream = null;
             lock (opClientLock)
             {
                 do
@@ -80,13 +81,13 @@
                         InitialOpClient();
 
                         byte[] data = opFrame.GetSendWriteFrameBytes(item, CurrentSid);
-                        stream = opClient.GetStream();
-                        stream.Write(data, 0, data.Length);
+                        //stream = opClient.GetStream();
+                        opStream.Write(data, 0, data.Length);
 
                         sw.Stop();
                         if (sw.ElapsedMilliseconds > 10)
                         {
-                            LogAsync(DateTime.Now, $"鍙戦�佸畬鎴愶紝鑰楁椂锛歿sw.ElapsedMilliseconds}");
+                            LogAsync(DateTime.Now, $"鍙戦�佸畬鎴�", $"鍙戦�佽�楁椂锛歿sw.ElapsedMilliseconds}");
                         }
                         repeatTime = 0;
 
@@ -101,7 +102,7 @@
                         }
                         else
                         {
-                            LogAsync(DateTime.Now, "Send Exception:" + ex.GetExceptionMessage());
+                            LogAsync(DateTime.Now, "Send Exception", ex.GetExceptionMessage());
                         }
                     }
                 } while (repeatTime > 0);
@@ -111,7 +112,7 @@
                     try
                     {
                         byte[] buffer = new byte[1024];
-                        int bufferCount = stream.Read(buffer, 0, buffer.Length);
+                        int bufferCount = opStream.Read(buffer, 0, buffer.Length);
                         if (bufferCount > 0)
                         {
                             opFrame.AnalyseReceivedItems(buffer.Take(bufferCount).ToArray(), item);
@@ -119,7 +120,7 @@
                     }
                     catch (Exception ex)
                     {
-                        LogAsync(DateTime.Now, "鍐欏叆鍙嶉寮傚父\r\n" + ex.GetExceptionMessage());
+                        LogAsync(DateTime.Now, "鍐欏叆鍙嶉寮傚父", ex.GetExceptionMessage());
                     }
                 }
                 else
@@ -129,7 +130,7 @@
                         try
                         {
                             byte[] buffer = new byte[1024];
-                            int bufferCount = stream.Read(buffer, 0, buffer.Length);
+                            int bufferCount = opStream.Read(buffer, 0, buffer.Length);
                             if (bufferCount > 0)
                             {
                                 opFrame.AnalyseReceivedItems(buffer.Take(bufferCount).ToArray(), item);
@@ -137,7 +138,7 @@
                         }
                         catch (Exception ex)
                         {
-                            LogAsync(DateTime.Now, "鍐欏叆鍙嶉寮傚父\r\n" + ex.GetExceptionMessage());
+                            LogAsync(DateTime.Now, "鍐欏叆鍙嶉寮傚父", ex.GetExceptionMessage());
                         }
                     });
                 }
@@ -163,6 +164,7 @@
 
             item.ADDRESS = "D" + address.ToString();
             item.ITEM_LENGTH = 1;
+            item.ITEM_VALUE_TYPE = 1;
             item.ITEM_VALUE = writeValue.ToString();
 
             //lock (opClient)
@@ -403,7 +405,9 @@
         static object opClientLock = new object();
 
         TcpClient scanClient = new TcpClient();
+        NetworkStream scanStream = null;
         TcpClient opClient = new TcpClient();
+        NetworkStream opStream = null;
 
         IPEndPoint plcEP;
 
@@ -455,10 +459,10 @@
                 scanFrame = new FinsFrame(IConfig.DNA, serverNode, IConfig.DA2, IConfig.SNA, scanNode, IConfig.SA2, false);
 
                 byte[] dataRequest = scanFrame.GetTcpRequestFrame(0);
-                var stream = scanClient.GetStream();
-                stream.Write(dataRequest, 0, dataRequest.Length);
+                scanStream = scanClient.GetStream();
+                scanStream.Write(dataRequest, 0, dataRequest.Length);
                 byte[] dataRead = new byte[2048];
-                int readSize = stream.Read(dataRead, 0, dataRead.Length);
+                int readSize = scanStream.Read(dataRead, 0, dataRead.Length);
 
                 if (readSize <= 0)
                 {
@@ -489,10 +493,10 @@
 
                 opFrame = new FinsFrame(IConfig.DNA, serverNode, IConfig.DA2, IConfig.SNA, opNode, IConfig.SA2, false);
                 byte[] dataRequest = opFrame.GetTcpRequestFrame(0);
-                var stream = opClient.GetStream();
-                stream.Write(dataRequest, 0, dataRequest.Length);
+                opStream = opClient.GetStream();
+                opStream.Write(dataRequest, 0, dataRequest.Length);
                 byte[] dataRead = new byte[2048];
-                int readSize = stream.Read(dataRead, 0, dataRead.Length);
+                int readSize = opStream.Read(dataRead, 0, dataRead.Length);
 
                 if (readSize <= 0)
                 {
@@ -524,14 +528,15 @@
             PLC_ITEM item = new PLC_ITEM();
             item.ADDRESS = "D" + startAddress;
             item.OP_TYPE = 1;
+            item.ITEM_VALUE_TYPE = 1;
             item.ITEM_LENGTH = length;
 
             var data = opFrame.GetSendReadFrameBytes(item, CurrentSid);
-            var stream = opClient.GetStream();
-            stream.Write(data, 0, data.Length);
+            opStream.Write(data, 0, data.Length);
+            opStream.Flush();
 
             byte[] buffer = new byte[2048];
-            int readSize = stream.Read(buffer, 0, buffer.Length);
+            int readSize = opStream.Read(buffer, 0, buffer.Length);
 
             if (readSize > 0)
             {
@@ -555,6 +560,7 @@
             PLC_ITEM item = new PLC_ITEM();
             item.ADDRESS = "D" + startAddress;
             item.OP_TYPE = 1;
+            item.ITEM_VALUE_TYPE = 1;
             item.ITEM_LENGTH = length;
 
             if (scanBuffer == null)
@@ -562,11 +568,11 @@
                 scanBuffer = scanFrame.GetSendReadFrameBytes(item, CurrentSid);
             }
 
-            var stream = scanClient.GetStream();
-            stream.Write(scanBuffer, 0, scanBuffer.Length);
+            //var stream = scanClient.GetStream();
+            scanStream.Write(scanBuffer, 0, scanBuffer.Length);
 
             byte[] buffer = new byte[2048];
-            int readSize = stream.Read(buffer, 0, buffer.Length);
+            int readSize = scanStream.Read(buffer, 0, buffer.Length);
 
             if (readSize > 0)
             {
@@ -578,69 +584,52 @@
                 return new List<int>();
             }
         }
-        #endregion
 
-        #region Log
-        object logLock = new object();
-        private async void LogAsync(DateTime dt, string info)
+        protected override void OnMethodInvoked(IAsyncResult ar)
         {
-            await Task.Run(() =>
+            MonitorSet monitorSet = ar.AsyncState as MonitorSet;
+
+            ProcessResponse resValues = monitorSet.Response;
+
+            if (resValues.ResultValue == (int)PLCReplyValue.IGNORE)
             {
-                if (IConfig.IsEnabelLog)
+                return;
+            }
+
+            if (monitorSet.ReplyDataAddress != -1 && resValues.DataList.Count > 0)
+            {
+                PLC_ITEM item = new PLC_ITEM();
+                item.OP_TYPE = 2;
+                item.ITEM_LENGTH = resValues.DataList.Count;
+                item.ADDRESS = "D" + monitorSet.ReplyDataAddress.ToString();
+                item.ITEM_VALUE = String.Join(",", resValues.DataList);
+                item.ITEM_VALUE_TYPE = (int)PLCItemType.Integer;
+                WriteItem(item, false);
+            }
+
+            if (monitorSet.NoticeAddress != -1)
+            {
+                int repeatTime = 5;
+
+                do
                 {
-                    lock (logLock)
+                    try
                     {
-                        DirectoryInfo dir = new DirectoryInfo(IConfig.LogPath);
-                        if (!dir.Exists)
+                        this.WriteSingleAddress(monitorSet.NoticeAddress, resValues.ResultValue, false);
+                        repeatTime = 0;
+                    }
+                    catch (Exception ex)
+                    {
+                        repeatTime--;
+
+                        if (repeatTime <= 0)
                         {
-                            dir.Create();
-                        }
-
-                        string filePath = Path.Combine(IConfig.LogPath, "PLC_" + DateTime.Now.ToString("yyyyMMdd") + ".txt");
-
-                        using (StreamWriter writer = new StreamWriter(filePath, true))
-                        {
-                            writer.WriteLine(dt.ToString("HH:mm:ss.fff"));
-                            writer.WriteLine(info);
-                            writer.WriteLine();
-
-                            writer.Flush();
-                            writer.Close();
+                            new ProcessException("PLC鍙嶉鍐欏叆寮傚父", ExceptionLevel.Info, ex);
                         }
                     }
-                }
-            });
+                } while (repeatTime > 0);
+            }
         }
-
-        //private async void LogAsync(DateTime dt, IModbusFrame frame)
-        //{
-        //    await Task.Run(() =>
-        //    {
-        //        if (IConfig.IsEnabelLog)
-        //        {
-        //            lock (logLock)
-        //            {
-        //                DirectoryInfo dir = new DirectoryInfo(IConfig.LogPath);
-        //                if (!dir.Exists)
-        //                {
-        //                    dir.Create();
-        //                }
-
-        //                string filePath = Path.Combine(IConfig.LogPath, "PLC_" + DateTime.Now.ToString("yyyyMMdd") + ".txt");
-
-        //                using (StreamWriter writer = new StreamWriter(filePath, true))
-        //                {
-        //                    writer.WriteLine(dt.ToString("HH:mm:ss.fff"));
-        //                    writer.WriteLine(frame.GetFrameString());
-        //                    writer.WriteLine();
-
-        //                    writer.Flush();
-        //                    writer.Close();
-        //                }
-        //            }
-        //        }
-        //    });
-        //}
         #endregion
     }
 }
diff --git a/src/Bro.Device.SeerAGV/Bro.Device.SeerAGV.csproj b/src/Bro.Device.SeerAGV/Bro.Device.SeerAGV.csproj
index 9b12646..927736b 100644
--- a/src/Bro.Device.SeerAGV/Bro.Device.SeerAGV.csproj
+++ b/src/Bro.Device.SeerAGV/Bro.Device.SeerAGV.csproj
@@ -36,6 +36,7 @@
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
diff --git a/src/Bro.Device.SeerAGV/SeerAGVConfig.cs b/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
index 3866776..55214f0 100644
--- a/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
+++ b/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
@@ -1,16 +1,12 @@
 锘縰sing Bro.Common.Base;
 using Bro.Common.Helper;
-using Bro.Common.Model.Helper;
+using Bro.Common.Model;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
-using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Drawing.Design;
 using System.Linq;
-using System.Net;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace Bro.Device.SeerAGV
 {
@@ -31,7 +27,19 @@
 
         [Category("鐩戝惉閰嶇疆")]
         [Description("鐩戝惉闂撮殧锛屽崟浣峬s")]
-        public int ScanInterval { get; set; } = 200;
+        public int ScanInterval { get; set; } = 500;
+
+        //[Category("鐩戝惉閰嶇疆")]
+        //[Description("鐩戝惉鐨処O淇℃伅閰嶇疆闆嗗悎")]
+        //[TypeConverter(typeof(CollectionCountConvert))]
+        //[Editor(typeof(ComplexCollectionEditor<IODefinition>), typeof(UITypeEditor))]
+        //public List<IODefinition> IOCollection { get; set; } = new List<IODefinition>();
+
+        [Category("鐩戝惉璁剧疆")]
+        [Description("鐩戝惉鎿嶄綔閰嶇疆闆嗗悎")]
+        [TypeConverter(typeof(CollectionCountConvert))]
+        [Editor(typeof(ComplexCollectionEditor<MonitorSet>), typeof(UITypeEditor))]
+        public List<MonitorSet> MonitorSetCollection { get; set; } = new List<MonitorSet>();
 
         [Category("鐩戝惉閰嶇疆")]
         [Description("鏄惁閲囩敤绠�鍗曠洃鍚ā寮忋�倀rue锛氱畝鍗曟ā寮忥紝鍙幏鍙栦换鍔$姸鎬侊紱false锛氬叏閮ㄦā寮忥紝鑾峰彇浠诲姟鎵�鏈変俊鎭�")]
@@ -53,6 +61,22 @@
             }
         }
 
+        private float batteryLvlToCharge_Recommand = 0.3f;
+        [Category("鍏呯數閰嶇疆")]
+        [Description("鍏呯數鐢垫睜瀹归噺锛岀數姹犲閲忎綆浜庤鍊兼椂锛岃澶囩┖闂叉椂寤鸿鍏呯數")]
+        public float BatteryLvlToCharge_Recommand
+        {
+            get => batteryLvlToCharge_Recommand;
+            set
+            {
+                if (value >= 1 || value <= 0)
+                {
+                    value = 0.3f;
+                }
+                batteryLvlToCharge_Recommand = value;
+            }
+        }
+
         private float batteryLvlChargeDone = 0.9f;
         [Category("鍏呯數閰嶇疆")]
         [Description("鍏呯數瀹屾垚鐢垫睜瀹归噺锛岀數姹犲閲忛珮浜庤鍊兼椂纭鍏呯數瀹屾垚")]
@@ -68,12 +92,22 @@
                 batteryLvlChargeDone = value;
             }
         }
+
+        [Category("鍔ㄤ綔璁剧疆")]
+        [Description("鍔ㄤ綔瓒呮椂璁剧疆锛屽崟浣峬in")]
+        public float OperationTimeout { get; set; } = 5;
     }
 
     [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.OperationConfig)]
     public class SeerAGVOperationConfig : OperationConfigBase
     {
+        [Category("瀵艰埅閰嶇疆")]
+        [Description("AGV琛岄┒鐩殑鍦�")]
+        public string Location { get; set; }
 
+        [Category("瀵艰埅閰嶇疆")]
+        [Description("鏄惁绛夊緟瀹屾垚淇″彿")]
+        public bool IsWaitFinished { get; set; } = true;
     }
 
     public class SeerMessage : IComplexDisplay
@@ -143,7 +177,7 @@
 
             if (data.Length < 16 + msg.DataLength)
             {
-                throw new ProcessException("鏁版嵁闀垮害閿欒", null);
+                throw new ProcessException("鏁版嵁闀垮害閿欒");
             }
 
             msg.JsonData = data.Skip(16).Take(msg.DataLength).ToArray();
@@ -171,6 +205,7 @@
     {
         QueryPosition = 0x03EC,
         QueryTaskStatus = 0x03FC,
+        QueryIO = 0x03F5,
 
         CancelTask = 0x0BBB,
         PauseTask = 0x0BB9,
diff --git a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
index b875bda..bb05aee 100644
--- a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
+++ b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
@@ -1,25 +1,27 @@
 锘縰sing Bro.Common.Base;
 using Bro.Common.Helper;
 using Bro.Common.Interface;
+using Bro.Common.Model;
+using Bro.Common.Model.Interface;
 using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Net;
 using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 
 namespace Bro.Device.SeerAGV
 {
     [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.Device)]
-    public class SeerAGVDriver : DeviceBase
+    public class SeerAGVDriver : DeviceBase, IMonitor
     {
         public Action<SeerAGVDriver, string> OnAGVPositoinChanged;
         public Action<SeerAGVDriver, AGVTaskStatus> OnAGVTaskStatusChanged;
         public Action<SeerAGVDriver, float, float> OnAGVBatteryLvlChanged;
+        public Action<SeerAGVDriver, IODefinition> OnAGVIOChanged;
 
         SeerAGVInitialConfig IConfig
         {
@@ -39,6 +41,15 @@
         {
             InitialTcpClient(ref client_State, IConfig.StatusPort);
             InitialTcpClient(ref client_Guide, IConfig.GuidePort);
+
+            StateHandle = new ManualResetEvent(false);
+            PositionHandle = new ManualResetEvent(false);
+            BatteryHandle = new ManualResetEvent(false);
+            IOHandle = new ManualResetEvent(false);
+
+            _taskDoneHandle = new ManualResetEvent(false);
+            _monitorLock = new ManualResetEvent(true);
+            _isTaskRunning = false;
         }
 
         private void InitialTcpClient(ref TcpClient client, int port)
@@ -66,6 +77,15 @@
             msg_Position = new SeerMessage((int)AGVCode.QueryPosition, SID);
             msg_GuideStatus = new SeerMessage((int)AGVCode.QueryTaskStatus, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : "");
             msg_Battery = new SeerMessage((int)AGVCode.QueryBattery, SID, IConfig.IsSimpleMonitor ? JsonConvert.SerializeObject(new { simple = true }) : "");
+            msg_IO = new SeerMessage((int)AGVCode.QueryIO, SID);
+
+            _taskDoneHandle.Reset();
+            _monitorLock.Set();
+
+            Task.Run(() =>
+            {
+                Monitor();
+            });
 
             Task.Run(() =>
             {
@@ -75,6 +95,14 @@
 
         protected override void Stop()
         {
+            StateHandle.Set();
+            PositionHandle.Set();
+            BatteryHandle.Set();
+            IOHandle.Set();
+
+            _taskDoneHandle.Set();
+            _monitorLock.Set();
+            
             if (client_Guide != null && client_Guide.Connected)
             {
                 CancelTask();
@@ -126,6 +154,8 @@
             }
         }
 
+        List<AGVTaskStatus> _taskRunningStates = new List<AGVTaskStatus>() { AGVTaskStatus.Running, AGVTaskStatus.Waiting, AGVTaskStatus.Suspended };
+        List<AGVTaskStatus> _taskDoneStates = new List<AGVTaskStatus>() { AGVTaskStatus.Cancelled, AGVTaskStatus.Completed, AGVTaskStatus.Failed };
         AGVTaskStatus taskStatus = AGVTaskStatus.None;
         public AGVTaskStatus TaskStatus
         {
@@ -138,6 +168,12 @@
 
                     if (taskStatus != AGVTaskStatus.None)
                     {
+                        if (_isTaskRunning && _taskDoneStates.Contains(taskStatus))
+                        {
+                            _taskDoneHandle.Set();
+                            _isTaskRunning = false;
+                        }
+
                         OnAGVTaskStatusChanged?.Invoke(this, taskStatus);
                     }
                 }
@@ -159,13 +195,24 @@
             }
         }
 
+        public string LastStation { get; set; }
+        public string Destination { get; set; } = "";
+
         SeerMessage msg_Position = new SeerMessage();
         SeerMessage msg_GuideStatus = new SeerMessage();
         SeerMessage msg_Battery = new SeerMessage();
+        SeerMessage msg_IO = new SeerMessage();
+
+        public ManualResetEvent StateHandle { get; set; } = new ManualResetEvent(false);
+        public ManualResetEvent PositionHandle { get; set; } = new ManualResetEvent(false);
+        public ManualResetEvent BatteryHandle { get; set; } = new ManualResetEvent(false);
+        public ManualResetEvent IOHandle { get; set; } = new ManualResetEvent(false);
+
         private void MonitorAGV()
         {
             while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept)
             {
+                _monitorLock.WaitOne();
                 try
                 {
                     SendMsg(client_State, IConfig.StatusPort, msg_Position);
@@ -174,10 +221,12 @@
                     Thread.Sleep(IConfig.ScanInterval);
                     SendMsg(client_State, IConfig.StatusPort, msg_Battery);
                     Thread.Sleep(IConfig.ScanInterval);
+                    SendMsg(client_State, IConfig.StatusPort, msg_IO);
+                    Thread.Sleep(IConfig.ScanInterval);
                 }
                 catch (Exception ex)
                 {
-                    OnLog?.Invoke(DateTime.Now, this, $"{Name}鐩戝惉寮傚父锛歿ex.GetExceptionMessage()}");
+                    LogAsync(DateTime.Now, "鐩戝惉寮傚父", ex.GetExceptionMessage());
                 }
             }
         }
@@ -194,7 +243,7 @@
 
                     var stream = client.GetStream();
                     stream.Write(msg.Frame, 0, msg.Frame.Length);
-
+                    stream.Flush();
                     int recSize = stream.Read(buffer, 0, buffer.Length);
                     if (recSize > 0)
                     {
@@ -202,7 +251,7 @@
                         SeerMessage recMsg = SeerMessage.GetSeerMessage(rec);
                         if (recMsg.TypeCode != (10000 + msg.TypeCode) || recMsg.SeqNum != msg.SeqNum)
                         {
-                            throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�", null);
+                            throw new ProcessException("鍙嶉淇℃伅鍜屽彂閫佷俊鎭笉涓�鑷�");
                         }
 
                         if (recMsg.JValues.ContainsKey("ret_code"))
@@ -210,7 +259,7 @@
                             int retCode = recMsg.JValues.Value<int>("ret_code");
                             if (retCode != 0)
                             {
-                                throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}", null);
+                                throw new ProcessException($"鍙嶉淇℃伅寮傚父,寮傚父鐮�:{retCode}");
                             }
                         }
 
@@ -222,18 +271,18 @@
                 catch (SocketException ex)
                 {
                     repeatTime--;
-                    new ProcessException("AGV缃戠粶閫氫俊寮傚父", ex);
+                    new ProcessException("AGV缃戠粶閫氫俊寮傚父", ExceptionLevel.Warning, ex);
 
                     if (repeatTime <= 0)
                     {
-                        throw new ProcessException("AGV缃戠粶閫氫俊澶辫触", ex);
+                        throw new ProcessException("AGV缃戠粶閫氫俊澶辫触", ExceptionLevel.Warning, ex);
                     }
 
                     Thread.Sleep(IConfig.ScanInterval);
                 }
                 catch (Exception ex)
                 {
-                    throw new ProcessException("AGV淇℃伅鍙戦�佸紓甯�", ex);
+                    throw new ProcessException("AGV淇℃伅鍙戦�佸紓甯�", ExceptionLevel.Warning, ex);
                 }
 
             } while (repeatTime > 0);
@@ -247,12 +296,35 @@
                 {
                     case (int)AGVCode.QueryPosition:
                         CurrentPosition = recMsg.JValues.Value<string>("current_station");
+                        LastStation = recMsg.JValues.Value<string>("last_station");
+
+                        PositionHandle.Set();
                         break;
                     case (int)AGVCode.QueryTaskStatus:
                         TaskStatus = (AGVTaskStatus)recMsg.JValues.Value<int>("task_status");
+
+                        StateHandle.Set();
                         break;
                     case (int)AGVCode.QueryBattery:
                         BatteryLvl = recMsg.JValues.Value<float>("battery_level");
+
+                        BatteryHandle.Set();
+                        break;
+                    case (int)AGVCode.QueryIO:
+                        //recMsg.JValues.Value<JArray>("DI").ToList().ForEach(j =>
+                        //{
+                        //    var ioDefinition = IConfig.IOCollection.FirstOrDefault(i => i.IOIndex == j.Value<int>("id"));
+
+                        //    if (ioDefinition != null && j.Value<bool>("status") != ioDefinition.CurrentValue)
+                        //    {
+                        //        ioDefinition.CurrentValue = j.Value<bool>("status");
+                        //        OnAGVIOChanged?.Invoke(this, ioDefinition);
+                        //    }
+                        //});
+
+                        //楂樼數骞� 1  浣庣數骞� 0
+                        _ioDict = recMsg.JValues.Value<JArray>("DI").ToDictionary(u => u.Value<int>("id"), u => u.Value<bool>("status") ? 1 : 0);
+                        IOHandle.Set();
                         break;
                     default:
                         break;
@@ -272,13 +344,102 @@
             SendMsg(client_Guide, IConfig.GuidePort, msg);
         }
 
-        public void TaskOrder(string dest)
+        ManualResetEvent _taskDoneHandle = new ManualResetEvent(false);
+        ManualResetEvent _monitorLock = new ManualResetEvent(true);
+        bool _isTaskRunning = false;
+        public void TaskOrder(string dest, bool isWaitFinished)
         {
-            CurrentPosition = "";
-            SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest }));
+            _monitorLock.Reset();
+            Thread.Sleep(IConfig.ScanInterval);
 
-            OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}琛岄┒鍚� {dest}", null, null);
+            CurrentPosition = "";
+            Destination = dest;
+            TaskStatus = AGVTaskStatus.None;
+
+            SeerMessage msg = new SeerMessage((int)AGVCode.TaskOrder, SID, JsonConvert.SerializeObject(new { id = dest }));
+            //OnLog?.BeginInvoke(DateTime.Now, this, $"{Name}琛岄┒鍚� {dest}", null, null);
+            LogAsync(DateTime.Now, "", $"{Name}琛岄┒鍚� {dest}");
+
             SendMsg(client_Guide, IConfig.GuidePort, msg);
+            //Thread.Sleep(IConfig.ScanInterval);
+            _monitorLock.Set();
+
+            if (isWaitFinished)
+            {
+                _isTaskRunning = true;
+                _taskDoneHandle.Reset();
+                bool isNotTimeout = _taskDoneHandle.WaitOne((int)(IConfig.OperationTimeout * 60 * 1000));
+                if (!isNotTimeout)
+                {
+                    throw new ProcessException($"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔瓒呮椂");
+                }
+
+                if (TaskStatus == AGVTaskStatus.Failed)
+                {
+                    throw new ProcessException($"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔澶辫触");
+                }
+                else if (TaskStatus == AGVTaskStatus.Cancelled)
+                {
+                    //OnLog?.Invoke(DateTime.Now, this, $"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔鍙栨秷");
+                    LogAsync(DateTime.Now, "", $"{Name}鎵ц鍘诲線{dest}鍔ㄤ綔鍙栨秷");
+                }
+            }
         }
+
+        #region IMonitor
+        public event OnMonitorInvokeDelegate OnMonitorInvoke;
+        public event OnMonitorAlarmDelegate OnMonitorAlarm;
+
+        Dictionary<int, int> _ioDict = new Dictionary<int, int>();
+        public void Monitor()
+        {
+            while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept)
+            {
+                try
+                {
+                    IOHandle.Reset();
+
+                    var isNotTimeout = IOHandle.WaitOne(IConfig.ScanInterval * 3);
+
+                    if (!isNotTimeout)
+                        throw new ProcessException($"{Name}鐩戝惉瓒呮椂");
+
+                    IConfig.MonitorSetCollection.ForEach(m =>
+                    {
+                        if (_ioDict.ContainsKey(m.TriggerIndex))
+                        {
+                            if ((m.TriggerValue == _ioDict[m.TriggerIndex] || m.TriggerIndex == -999) && _ioDict[m.TriggerIndex] != m.CurrentValue)
+                            {
+                                if (m.OpConfig == null)
+                                {
+                                    m.OpConfig = new OperationConfigBase();
+                                }
+
+                                m.OpConfig.InputPara = m.InputDataIndex.ConvertAll(index =>
+                                {
+                                    if (_ioDict.ContainsKey(index))
+                                    {
+                                        return _ioDict[index];
+                                    }
+                                    else
+                                    {
+                                        return -1;
+                                    }
+                                }).ToList();
+
+                                OnMonitorInvoke?.BeginInvoke(DateTime.Now, this, m, null, null);
+                            }
+
+                            m.CurrentValue = _ioDict[m.TriggerIndex];
+                        }
+                    });
+                }
+                catch (Exception ex)
+                {
+                    OnLog?.Invoke(DateTime.Now, this, $"{Name}鐩戝惉寮傚父:{ex.GetExceptionMessage()}");
+                }
+            }
+        }
+        #endregion
     }
 }

--
Gitblit v1.8.0