From 7971d855ba2cf9772b46a7f67e2b669c0afcb91b Mon Sep 17 00:00:00 2001
From: patrick <patrick.xu@broconcentric.com>
Date: 星期二, 22 十月 2019 11:30:35 +0800
Subject: [PATCH] 1. 添加标定操作及界面 2. 修改配置界面方法调用参数 3. SeerAGV添加电池信息监听 4. 添加AGV电池充电操作 5. 修改AGV状态变化操作,添加操作锁

---
 src/A032.Process/Calibration/CalibrationConfig.cs  |   32 +
 src/Bro.Device.SeerAGV/SeerAGVConfig.cs            |   34 ++
 src/Bro.Common.Model/Interface/IStationConfig.cs   |    4 
 src/A032.Config/ConfigFrm.cs                       |   52 ++-
 src/A032.Process/ProcessControl_Calibration.cs     |  372 +++++++++++++++++++---
 src/Bro.Device.SeerAGV/SeerAGVDriver.cs            |   24 +
 src/A032.Process/ProcessControl.cs                 |   15 
 src/A032.Process/AGVPath.cs                        |   22 +
 src/A032.Process/ProcessControl_Method.cs          |  157 +++++++--
 src/A032.Config/ConfigFrm.designer.cs              |   57 +++
 src/A032.Process/Forms/OperationConfigBindFrm.cs   |   36 -
 src/A032.Process/AGVBindUnit.cs                    |   37 ++
 src/Bro.Common.Model/Helper/UIHelper.cs            |   15 
 src/A032.Process/Calibration/FrmCalib9PDynamic.cs  |   40 ++
 src/A032.Process/Calibration/CtrlCalib9PDynamic.cs |   52 ++-
 15 files changed, 747 insertions(+), 202 deletions(-)

diff --git a/src/A032.Config/ConfigFrm.cs b/src/A032.Config/ConfigFrm.cs
index cb7c154..388f59d 100644
--- a/src/A032.Config/ConfigFrm.cs
+++ b/src/A032.Config/ConfigFrm.cs
@@ -42,6 +42,8 @@
                 {
                     InitialCalibrationMethod();
                     InitialAllTestMethod();
+
+                    InitialDevices();
                 }
             }
         }
@@ -285,7 +287,7 @@
         private void btnStartCalibration_Click(object sender, EventArgs e)
         {
             btnStartCalibration.Enabled = false;
-
+            IDevice device = cboCalibDevices.SelectedItem as IDevice;
             try
             {
                 IOperationConfig config = propCalibrationConfig.SelectedObject as IOperationConfig;
@@ -294,7 +296,7 @@
                     config.InputPara = null;
                 }
 
-                _calibrationMethod.Invoke(Process, new object[] { config });
+                _calibrationMethod.Invoke(Process, new object[] { config, device });
             }
             catch (Exception ex)
             {
@@ -314,6 +316,16 @@
         #region Test
         Dictionary<ProcessMethodAttribute, MethodInfo> _allTestMethod = new Dictionary<ProcessMethodAttribute, MethodInfo>();
         MethodInfo _testMethod = null;
+
+        List<IDevice> _deviceList = new List<IDevice>();
+        private void InitialDevices()
+        {
+            _deviceList = (Process as ProcessControl).GetDeviceList();
+
+            List<ISimpleDevice> list = _deviceList.Select(u => u as ISimpleDevice).ToList();
+            UIHelper.SetCombo(cboCalibDevices, list, "Name", "Id");
+            UIHelper.SetCombo(cboDevices, list, "Name", "Id");
+        }
 
         private void InitialAllTestMethod()
         {
@@ -337,28 +349,29 @@
 
         private void cboTestMethod_SelectedIndexChanged(object sender, EventArgs e)
         {
-            //if (cboTestMethod.SelectedIndex >= 0)
-            //{
-            //    string methodCode = cboTestMethod.SelectedValue.ToString();
-            //    var attr = _allTestMethod.Keys.FirstOrDefault(u => u.MethodCode == methodCode);
-            //    if (attr == null)
-            //        return;
+            if (cboTestMethod.SelectedIndex >= 0)
+            {
+                string methodCode = cboTestMethod.SelectedValue.ToString();
+                var attr = _allTestMethod.Keys.FirstOrDefault(u => u.MethodCode == methodCode);
+                if (attr == null)
+                    return;
 
-            //    _testMethod = _allTestMethod[attr];
+                _testMethod = _allTestMethod[attr];
 
-            //    if (Process.StationConfig.ProcessOpConfigDict.Keys.Contains(methodCode))
-            //    {
-            //        propGridTestMethod.SelectedObject = Process.StationConfig.ProcessOpConfigDict[methodCode];
-            //    }
-            //    else
-            //    {
-            //        MessageBox.Show(@"Config of " + methodCode + @" is not found");
-            //    }
-            //}
+                if (Process.StationConfig.ProcessOpConfigDict.Keys.Contains(methodCode))
+                {
+                    propGridTestMethod.SelectedObject = Process.StationConfig.ProcessOpConfigDict[methodCode];
+                }
+                else
+                {
+                    MessageBox.Show(@"Config of " + methodCode + @" is not found");
+                }
+            }
         }
 
         private void btnManualTrigger_Click(object sender, EventArgs e)
         {
+            IDevice device = cboDevices.SelectedItem as IDevice;
             new Task((m) =>
             {
                 MethodInfo method = m as MethodInfo;
@@ -370,14 +383,13 @@
                     invokeTimes = 1;
                 }
                 ProcessResponse response = null;
-
                 if (invokeTimes == 1)
                 {
                     try
                     {
                         Stopwatch sw = new Stopwatch();
                         sw.Start();
-                        response = method.Invoke(Process, new object[] { propGridTestMethod.SelectedObject as IOperationConfig }) as ProcessResponse;
+                        response = method.Invoke(Process, new object[] { propGridTestMethod.SelectedObject as IOperationConfig, device }) as ProcessResponse;
                         sw.Stop();
 
                         //RecordMsg($"{method.Name}璋冪敤鑰楁椂锛歿sw.ElapsedMilliseconds}ms");
diff --git a/src/A032.Config/ConfigFrm.designer.cs b/src/A032.Config/ConfigFrm.designer.cs
index 5c1f834..5b9fb52 100644
--- a/src/A032.Config/ConfigFrm.designer.cs
+++ b/src/A032.Config/ConfigFrm.designer.cs
@@ -75,6 +75,10 @@
             this.cboProductionCode = new System.Windows.Forms.ComboBox();
             this.statusStrip1 = new System.Windows.Forms.StatusStrip();
             this.tsslLoginStatus = new System.Windows.Forms.ToolStripStatusLabel();
+            this.cboDevices = new System.Windows.Forms.ComboBox();
+            this.label5 = new System.Windows.Forms.Label();
+            this.label6 = new System.Windows.Forms.Label();
+            this.cboCalibDevices = new System.Windows.Forms.ComboBox();
             this.tabControl1.SuspendLayout();
             this.tbConfig.SuspendLayout();
             this.tbCalibration.SuspendLayout();
@@ -162,6 +166,8 @@
             // 
             // tbCalibration
             // 
+            this.tbCalibration.Controls.Add(this.label6);
+            this.tbCalibration.Controls.Add(this.cboCalibDevices);
             this.tbCalibration.Controls.Add(this.label1);
             this.tbCalibration.Controls.Add(this.propCalibrationConfig);
             this.tbCalibration.Controls.Add(this.btnStartCalibration);
@@ -177,7 +183,7 @@
             // label1
             // 
             this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(22, 20);
+            this.label1.Location = new System.Drawing.Point(262, 12);
             this.label1.Name = "label1";
             this.label1.Size = new System.Drawing.Size(53, 12);
             this.label1.TabIndex = 7;
@@ -211,7 +217,7 @@
             | System.Windows.Forms.AnchorStyles.Right)));
             this.cboCalibrationMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
             this.cboCalibrationMethod.FormattingEnabled = true;
-            this.cboCalibrationMethod.Location = new System.Drawing.Point(12, 41);
+            this.cboCalibrationMethod.Location = new System.Drawing.Point(252, 33);
             this.cboCalibrationMethod.Name = "cboCalibrationMethod";
             this.cboCalibrationMethod.Size = new System.Drawing.Size(185, 20);
             this.cboCalibrationMethod.TabIndex = 4;
@@ -220,8 +226,10 @@
             // 
             this.tbTest.Controls.Add(this.label3);
             this.tbTest.Controls.Add(this.txtInvokeTimes);
+            this.tbTest.Controls.Add(this.label5);
             this.tbTest.Controls.Add(this.label2);
             this.tbTest.Controls.Add(this.propGridTestMethod);
+            this.tbTest.Controls.Add(this.cboDevices);
             this.tbTest.Controls.Add(this.btnTrigger);
             this.tbTest.Controls.Add(this.cboTestMethod);
             this.tbTest.Location = new System.Drawing.Point(4, 22);
@@ -254,7 +262,7 @@
             // label2
             // 
             this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(21, 13);
+            this.label2.Location = new System.Drawing.Point(262, 12);
             this.label2.Name = "label2";
             this.label2.Size = new System.Drawing.Size(53, 12);
             this.label2.TabIndex = 11;
@@ -288,7 +296,7 @@
             | System.Windows.Forms.AnchorStyles.Right)));
             this.cboTestMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
             this.cboTestMethod.FormattingEnabled = true;
-            this.cboTestMethod.Location = new System.Drawing.Point(11, 34);
+            this.cboTestMethod.Location = new System.Drawing.Point(252, 33);
             this.cboTestMethod.Name = "cboTestMethod";
             this.cboTestMethod.Size = new System.Drawing.Size(185, 20);
             this.cboTestMethod.TabIndex = 9;
@@ -606,6 +614,43 @@
             this.tsslLoginStatus.Text = "鏈櫥褰�";
             this.tsslLoginStatus.Click += new System.EventHandler(this.tsslLoginStatus_Click);
             // 
+            // cboDevices
+            // 
+            this.cboDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cboDevices.FormattingEnabled = true;
+            this.cboDevices.Location = new System.Drawing.Point(21, 33);
+            this.cboDevices.Name = "cboDevices";
+            this.cboDevices.Size = new System.Drawing.Size(185, 20);
+            this.cboDevices.TabIndex = 9;
+            this.cboDevices.SelectedIndexChanged += new System.EventHandler(this.cboTestMethod_SelectedIndexChanged);
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(31, 12);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(53, 12);
+            this.label5.TabIndex = 11;
+            this.label5.Text = "閫夋嫨璁惧";
+            // 
+            // label6
+            // 
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(31, 12);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(53, 12);
+            this.label6.TabIndex = 13;
+            this.label6.Text = "閫夋嫨璁惧";
+            // 
+            // cboCalibDevices
+            // 
+            this.cboCalibDevices.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cboCalibDevices.FormattingEnabled = true;
+            this.cboCalibDevices.Location = new System.Drawing.Point(21, 33);
+            this.cboCalibDevices.Name = "cboCalibDevices";
+            this.cboCalibDevices.Size = new System.Drawing.Size(185, 20);
+            this.cboCalibDevices.TabIndex = 12;
+            // 
             // ConfigFrm
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@@ -688,6 +733,10 @@
         private System.Windows.Forms.StatusStrip statusStrip1;
         private System.Windows.Forms.ToolStripStatusLabel tsslLoginStatus;
         private System.Windows.Forms.CheckBox chkHardwareTrigger;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.ComboBox cboDevices;
+        private System.Windows.Forms.Label label6;
+        private System.Windows.Forms.ComboBox cboCalibDevices;
     }
 }
 
diff --git a/src/A032.Process/AGVBindUnit.cs b/src/A032.Process/AGVBindUnit.cs
index 507d8c8..4aa8d0b 100644
--- a/src/A032.Process/AGVBindUnit.cs
+++ b/src/A032.Process/AGVBindUnit.cs
@@ -191,6 +191,35 @@
             //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)
@@ -288,9 +317,9 @@
             {
                 ProcessConfig config = scope.Resolve<ProcessConfig>();
 
-                config.RobotConfigCollection.ForEach(plc =>
+                config.RobotConfigCollection.ForEach(robot =>
                 {
-                    _hash[plc.ID] = plc.Name;
+                    _hash[robot.ID] = robot.Name;
                 });
             }
         }
@@ -304,9 +333,9 @@
             {
                 ProcessConfig config = scope.Resolve<ProcessConfig>();
 
-                config.CameraConfigCollection.ForEach(plc =>
+                config.CameraConfigCollection.ForEach(camera =>
                 {
-                    _hash[plc.ID] = plc.Name;
+                    _hash[camera.ID] = camera.Name;
                 });
             }
         }
diff --git a/src/A032.Process/AGVPath.cs b/src/A032.Process/AGVPath.cs
index 1bfb3e0..2e19e32 100644
--- a/src/A032.Process/AGVPath.cs
+++ b/src/A032.Process/AGVPath.cs
@@ -25,6 +25,8 @@
         LoadFullTray = 3,
         [Description("鍗歌浇婊ray鍦扮偣")]
         UnloadFullTray = 4,
+        [Description("鍏呯數鍦扮偣")]
+        Charge = 5,
     }
 
     public class PathPosition : IComplexDisplay
@@ -73,7 +75,7 @@
         [Description("璇ヤ綅缃爣鍑嗙偣浣嶄俊鎭�")]
         [TypeConverter(typeof(ComplexObjectConvert))]
         [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
-        public CustomizedPoint StandardPoint { get; set; } = new CustomizedPoint();
+        public CustomizedPointWithAngle StandardPoint { get; set; } = new CustomizedPointWithAngle();
 
         [Category("瑙嗚閰嶇疆")]
         [Description("璇ヤ綅缃媿鎽勯厤缃�")]
@@ -102,7 +104,23 @@
 
                 config.PositionCollection.ForEach(p =>
                 {
-                    _hash[p.PositionCode] = $"{p.PositionCode}-{p.Description.GetEnumDescription()}";
+                    _hash[p.PositionCode] = $"{p.PositionCode}-{p.PositionNo}-{p.Description.GetEnumDescription()}";
+                });
+            }
+        }
+    }
+
+    public class PositionNoConverter : ComboBoxItemTypeConvert
+    {
+        public override void GetConvertHash()
+        {
+            using (var scope = GlobalVar.Container.BeginLifetimeScope())
+            {
+                var config = scope.Resolve<ProcessConfig>();
+
+                config.PositionCollection.ForEach(p =>
+                {
+                    _hash[p.PositionNo] = $"{p.PositionNo}-{p.PositionCode}-{p.Description.GetEnumDescription()}";
                 });
             }
         }
diff --git a/src/A032.Process/Calibration/CalibrationConfig.cs b/src/A032.Process/Calibration/CalibrationConfig.cs
index 8c0d7fe..1b8f099 100644
--- a/src/A032.Process/Calibration/CalibrationConfig.cs
+++ b/src/A032.Process/Calibration/CalibrationConfig.cs
@@ -1,6 +1,7 @@
 锘縰sing Bro.Common.Base;
 using Bro.Common.Helper;
 using Bro.Common.Model;
+using Bro.Common.Model.Interface;
 using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
@@ -14,12 +15,12 @@
 namespace A032.Process.Calibration
 {
     [Device("CalibrationCollection", "澶氭鏍囧畾閰嶇疆", EnumHelper.DeviceAttributeType.OperationConfig)]
-    public class CalibrationConfigCollection : OperationConfigBase
+    public class CalibrationConfigCollection : OperationConfigBase, IComplexDisplay,IHalconToolPath
     {
         [Category("鍏宠仈閰嶇疆")]
-        [Description("浣嶇疆浠g爜")]
-        [TypeConverter(typeof(PositionCodeConverter))]
-        public string PositionCode { get; set; }
+        [Description("浣嶇疆搴忓彿")]
+        [TypeConverter(typeof(PositionNoConverter))]
+        public int PositionNo { get; set; }
 
         [Category("鍏宠仈閰嶇疆")]
         [Description("閫傜敤鐩告満缂栧彿")]
@@ -31,10 +32,24 @@
         [TypeConverter(typeof(CollectionCountConvert))]
         [Editor(typeof(ComplexCollectionEditor<CalibrationConfig>), typeof(UITypeEditor))]
         public List<CalibrationConfig> Configs { get; set; } = new List<CalibrationConfig>();
+
+        [Category("鏄剧ず閰嶇疆")]
+        [Description("鏄惁鏄剧ずUI锛屼粠UI鍚姩鏍囧畾")]
+        public bool IsStartedFromUI { get; set; } = false;
+
+        public string GetDisplayText()
+        {
+            return $"PositionNo:{PositionNo}; Configs:{Configs.Count}";
+        }
+
+        public List<string> GetHalconToolPathList()
+        {
+            return Configs.SelectMany(c => c.GetHalconToolPathList()).ToList();
+        }
     }
 
     //[Device("Calibration", "鍗曟鏍囧畾閰嶇疆", EnumHelper.DeviceAttributeType.OperationConfig)]
-    public class CalibrationConfig : OperationConfigBase, IComplexDisplay, INotifyPropertyChanged
+    public class CalibrationConfig : OperationConfigBase, IComplexDisplay, INotifyPropertyChanged, IHalconToolPath
     {
         private Bitmap image = null;
         [JsonIgnore]
@@ -63,7 +78,7 @@
         [Description("鍥惧儚鏍囧噯鐐瑰潗鏍�")]
         [TypeConverter(typeof(ComplexObjectConvert))]
         [Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
-        public CustomizedPoint ImageMarkPoint { get; set; } = new CustomizedPoint();
+        public CustomizedPointWithAngle ImageMarkPoint { get; set; } = new CustomizedPointWithAngle();
 
         [Category("鐩告満閰嶇疆")]
         [Description("鐩告満鎿嶄綔閰嶇疆")]
@@ -83,5 +98,10 @@
         {
             return JsonConvert.SerializeObject(this);
         }
+
+        public List<string> GetHalconToolPathList()
+        {
+            return CameraOpConfig.GetHalconToolPathList();
+        }
     }
 }
diff --git a/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs b/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
index dcf6c73..1cce895 100644
--- a/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
+++ b/src/A032.Process/Calibration/CtrlCalib9PDynamic.cs
@@ -20,7 +20,7 @@
 namespace A032.Process.Calibration
 {
     [Device("Calibration_9P_Dynamic", "鍔ㄦ��9鐐规爣瀹�", EnumHelper.DeviceAttributeType.OperationConfigCtrl)]
-    public partial class CtrlCalib9PDynamic : UserControl, IConfigCtrl<CameraBase, CalibrationConfigCollection>
+    public partial class CtrlCalib9PDynamic : UserControl//, IConfigCtrl<CameraBase, CalibrationConfigCollection>
     {
         PubSubCenter PubSubCenter = PubSubCenter.GetInstance();
         AutoResetEvent _confirmHandle = new AutoResetEvent(false);
@@ -30,20 +30,29 @@
             InitializeComponent();
         }
 
-        public CtrlCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation)
+        public CtrlCalib9PDynamic(ProcessControl process, CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position, Action<AGVBindUnit, int, int> commuAction, Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> finalCalculation)
         {
             InitializeComponent();
 
             ProcessControl = process;
-            Camera = device as CameraBase;
-            Config = config as CalibrationConfigCollection;
+
+            Config = calibConfig as CalibrationConfigCollection;
+
+            Camera = bind.Camera as CameraBase;
+
+            Bind = bind;
+            Position = position;
+            CommuAction = commuAction;
             FinalCalculation = finalCalculation;
         }
 
-        public CalibrationConfigCollection Config { get; set; }
-        public CameraBase Camera { get; set; }
-        public ProcessControl ProcessControl { get; set; }
-        public Action<List<CalibrationConfig>> FinalCalculation { get; set; }
+        AGVBindUnit Bind { get; set; }
+        PathPosition Position { get; set; }
+        Action<AGVBindUnit, int, int> CommuAction;
+        CalibrationConfigCollection Config { get; set; }
+        CameraBase Camera { get; set; }
+        ProcessControl ProcessControl { get; set; }
+        Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> FinalCalculation { get; set; }
 
         public CalibrationConfigCollection GetConfig()
         {
@@ -159,7 +168,7 @@
 
             if (chkManualConfirm.Checked)
             {
-                this.Invoke(new Action(() => btnContinueCalib.Visible = true));                ;
+                this.Invoke(new Action(() => btnContinueCalib.Visible = true)); ;
                 _confirmHandle.WaitOne();
             }
 
@@ -188,14 +197,16 @@
 
         private void btnStartCalib_Click(object sender, EventArgs e)
         {
-            if (chkOfflineCalib.Checked)
-            {
-                //ProcessControl.Calibration_Pick_9P_Dynamic_Offline(Config.Configs);
-            }
-            else
-            {
-                //ProcessControl.SendCalibStartSignal(Config.TriggerAddress);
-            }
+            //if (chkOfflineCalib.Checked)
+            //{
+            //    //ProcessControl.Calibration_Pick_9P_Dynamic_Offline(Config.Configs);
+            //}
+            //else
+            //{
+            //    //ProcessControl.SendCalibStartSignal(Config.TriggerAddress);
+            //}
+
+            ProcessControl.MultipleStepsProcess(Config, Bind, CommuAction);
         }
 
         private void btnLoadOfflineImages_Click(object sender, EventArgs e)
@@ -213,7 +224,7 @@
 
         private void btnStepRun_Click(object sender, EventArgs e)
         {
-            //CalibrationConfig config = propGridConfig.SelectedObject as CalibrationConfig;
+            CalibrationConfig config = propGridConfig.SelectedObject as CalibrationConfig;
             //if (!chkOfflineRun.Checked)
             //{
             //    ProcessControl.CalibMarkPoint(Camera, config, _selectedStepIndex + 1);
@@ -224,11 +235,14 @@
             //}
 
             //tsslInfo.Text = $"鍗曟杩愮畻瀹屾垚銆傛爣璁扮偣鍧愭爣锛歿config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}";
+
+            ProcessControl.SingleStepProcess(config, CommuAction, Bind, Position.PositionNo, _selectedStepIndex);
+            tsslInfo.Text = $"鍗曟杩愮畻瀹屾垚銆傛爣璁扮偣鍧愭爣锛歿config.ImageMarkPoint.X},{config.ImageMarkPoint.Y}";
         }
 
         private void btnCalcuMatrix_Click(object sender, EventArgs e)
         {
-            FinalCalculation.Invoke(Config.Configs);
+            FinalCalculation.Invoke(Config, Bind, Position);
         }
 
         private void btnSnap_Click(object sender, EventArgs e)
diff --git a/src/A032.Process/Calibration/FrmCalib9PDynamic.cs b/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
index e780681..5fe5c52 100644
--- a/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
+++ b/src/A032.Process/Calibration/FrmCalib9PDynamic.cs
@@ -16,25 +16,49 @@
 {
     public partial class FrmCalib9PDynamic : Form
     {
+        //private CalibrationConfigCollection calibConfig;
+        //private AGVBindUnit bind;
+        //private PathPosition position;
+        //private Action<AGVBindUnit, int, int> sendMessageToRobot_Calibration;
+        //private Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> calculateMatrix;
+
         public FrmCalib9PDynamic()
         {
             InitializeComponent();
         }
 
-        public FrmCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation)
+        //public FrmCalib9PDynamic(ProcessControl process, IDevice device, IOperationConfig config, Action<List<CalibrationConfig>> finalCalculation)
+        //{
+        //    InitializeComponent();
+
+        //    Device = device as CameraBase;
+        //    Config = config as CalibrationConfigCollection;
+        //    FinalCalculation = finalCalculation;
+        //    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)
         {
             InitializeComponent();
 
-            Device = device as CameraBase;
-            Config = config as CalibrationConfigCollection;
-            FinalCalculation = finalCalculation;
-            CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, device, config, finalCalculation);
+            //Config = calibConfig;
+            //Bind = bind;
+            //Camera = Bind.Camera;
+            //Position = position;
+            //CommuAction = commuAction;
+            //FinalCalculation = finalCalculation;
+
+            CtrlCalib9PDynamic = new CtrlCalib9PDynamic(process, calibConfig, bind, position, commuAction, finalCalculation);
         }
 
-        CameraBase Device { get; set; }
-        CalibrationConfigCollection Config { get; set; }
+        //AGVBindUnit Bind { get; set; }
+        //CameraBase Camera { get; set; }
+        //CalibrationConfigCollection Config { get; set; }
+        //PathPosition Position { get; set; }
+        //Action<AGVBindUnit, int, int> CommuAction;
+        //Action<CalibrationConfigCollection, AGVBindUnit, PathPosition> FinalCalculation { get; set; }
+
         CtrlCalib9PDynamic CtrlCalib9PDynamic { get; set; }
-        Action<List<CalibrationConfig>> FinalCalculation { get; set; }
 
         private void FrmCalib9PDynamic_Load(object sender, EventArgs e)
         {
diff --git a/src/A032.Process/Forms/OperationConfigBindFrm.cs b/src/A032.Process/Forms/OperationConfigBindFrm.cs
index 8896b86..b8e498c 100644
--- a/src/A032.Process/Forms/OperationConfigBindFrm.cs
+++ b/src/A032.Process/Forms/OperationConfigBindFrm.cs
@@ -14,6 +14,8 @@
 using Bro.Common.Base;
 using Bro.Common.Factory;
 using A032.Process;
+using Bro.Common.Model;
+using Autofac;
 
 namespace Bro.Device.Station.Forms
 {
@@ -141,38 +143,12 @@
 
         private void LoadMethodCodes()
         {
-            IStationProcess sp = new ProcessControl();
-            //switch (StationCode)
-            //{
-            //    case "S1":
-            //        sp = new StationProcess_S1(false);
-            //        break;
-            //    case "S2":
-            //        sp = new StationProcess_S2(false);
-            //        break;
-            //    case "S3":
-            //        sp = new StationProcess_S3(false);
-            //        break;
-            //    case "S4":
-            //        sp = new StationProcess_S4(false);
-            //        break;
-            //    case "S5":
-            //        sp = new StationProcess_S5(false);
-            //        break;
-            //    case "S6":
-            //        sp = new StationProcess_S6(false);
-            //        break;
-            //    case "S7":
-            //        sp = new StationProcess_S7(false);
-            //        break;
-            //        //case "S0":
-            //        //    sp = new StationProcess_S0(false);
-            //        //    break;
-            //}
-
             OpBinds = new Dictionary<string, IOperationConfig>();
 
-            ProcessMethodList = sp.CollectProcessMethods();
+            using (var scope = GlobalVar.Container.BeginLifetimeScope())
+            {
+                ProcessMethodList = scope.Resolve<List<ProcessMethodAttribute>>();
+            }
 
             ProcessMethodList.ForEach(u =>
             {
diff --git a/src/A032.Process/ProcessControl.cs b/src/A032.Process/ProcessControl.cs
index 7ceda2f..dfd85ab 100644
--- a/src/A032.Process/ProcessControl.cs
+++ b/src/A032.Process/ProcessControl.cs
@@ -263,7 +263,7 @@
             });
         }
 
-        Dictionary<string, MethodInfo> InvokeMethodDict = new Dictionary<string, MethodInfo>();
+        //Dictionary<string, MethodInfo> InvokeMethodDict = new Dictionary<string, MethodInfo>();
         public List<ProcessMethodAttribute> CollectProcessMethods()
         {
             List<ProcessMethodAttribute> resultList = new List<ProcessMethodAttribute>();
@@ -275,7 +275,7 @@
                 if (attr != null)
                 {
                     resultList.Add(attr);
-                    InvokeMethodDict[attr.MethodCode] = m;
+                    //InvokeMethodDict[attr.MethodCode] = m;
                 }
             });
 
@@ -289,19 +289,16 @@
             StationConfig = LoadStationConfig(configPath);
 
             #region 涓埆閰嶇疆鐨勭壒鍒鐞�
-
             #endregion
 
             _warningRemains.CollectionChanged -= _warningRemains_CollectionChanged;
             _warningRemains.CollectionChanged += _warningRemains_CollectionChanged;
 
             InitialPLCs();
-            InitialRobots();
             InitialAGVs();
+            InitialRobots();
             InitialCameras();
-
             InitialAGVBindUnit();
-
             InitialMachineTrayNums();
 
             AutoFacRegister();
@@ -393,6 +390,7 @@
 
                 agv.OnAGVPositoinChanged = OnAGVPositionChanged;
                 agv.OnAGVTaskStatusChanged = OnAGVTaskStatusChanged;
+                agv.OnAGVBatteryLvlChanged = OnAGVBatterLvlChanged;
             });
         }
 
@@ -542,6 +540,11 @@
             {
                 InitialHalconTool(c as IHalconToolPath);
             });
+
+            Config.ProcessOpConfigDict.Values.ToList().ForEach(c =>
+            {
+                InitialHalconTool(c as IHalconToolPath);
+            });
             #endregion
         }
 
diff --git a/src/A032.Process/ProcessControl_Calibration.cs b/src/A032.Process/ProcessControl_Calibration.cs
index 49fa9ee..44a19ea 100644
--- a/src/A032.Process/ProcessControl_Calibration.cs
+++ b/src/A032.Process/ProcessControl_Calibration.cs
@@ -3,99 +3,355 @@
 using Bro.Common.Helper;
 using Bro.Common.Interface;
 using Bro.Common.Model;
+using HalconDotNet;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
+using static Bro.Common.Helper.EnumHelper;
 
 namespace A032.Process
 {
     public partial class ProcessControl
     {
+        CalibReplyMsg _calibReply = new CalibReplyMsg();
+
         [ProcessMethod("CalibrationCollection", "RobotCalibration", "鏈哄櫒浜�9鐐规爣瀹�", true)]
-        public ProcessResponse RobotCalibration(IOperationConfig config)
+        public ProcessResponse RobotCalibration(IOperationConfig config, IDevice device)
         {
+            CalibrationConfigCollection calibConfig = config as CalibrationConfigCollection;
+
+            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‘浣嶇疆淇℃伅");
+            }
+
+            if (calibConfig.Configs.Count < 9)
+            {
+                throw new ProcessException("璇疯嚦灏戦厤缃�9涓爣瀹氱偣浣�");
+            }
+
+            if (calibConfig.IsStartedFromUI)
+            {
+                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Calibration, CalculateMatrix);
+                frm.ShowDialog();
+            }
+            else
+            {
+                MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Calibration);
+
+                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);
         }
 
         [ProcessMethod("CalibrationCollection", "StandardPointCalibration", "鏍囧噯鐐逛綅鏍囧畾", true)]
-        public ProcessResponse StandardPointCalibration(IOperationConfig config)
+        public ProcessResponse StandardPointCalibration(IOperationConfig config, IDevice device)
         {
-            return new ProcessResponse(true);
-        }
+            CalibrationConfigCollection calibConfig = config as CalibrationConfigCollection;
 
-        public void SendCalibrationStartSignal(int stepNum)
-        {
+            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‘浣嶇疆淇℃伅");
+            }
 
-        private int MultipleStepsCalibration(CalibrationConfigCollection configs, Action<List<CalibrationConfig>> FinalCalculation)
-        {
-            throw new NotImplementedException();
+            if (calibConfig.Configs.Count < 1)
+            {
+                throw new ProcessException("璇疯嚦灏戦厤缃�1涓爣瀹氱偣浣�");
+            }
 
-            //configs.Configs.ForEach(c =>
+            if (calibConfig.IsStartedFromUI)
+            {
+                FrmCalib9PDynamic frm = new FrmCalib9PDynamic(this, calibConfig, bind, position, SendMessageToRobot_Standard, CalculateStandardPoint);
+                frm.ShowDialog();
+            }
+            else
+            {
+                MultipleStepsProcess(calibConfig, bind, SendMessageToRobot_Standard);
+
+                CalculateStandardPoint(calibConfig, bind, position);
+            }
+
+            //for (int i = 0; i < calibConfig.Configs.Count; i++)
             //{
-            //    c.Image = null;
-            //});
+            //    bind.Robot.SendMsg(Bro.Device.AuboRobot.RobotMsgAction.Calibration, Bro.Device.AuboRobot.RobotMsgParas.None, calibConfig.PositionNo, new List<float>() { i + 1 });
 
-            //if (string.IsNullOrWhiteSpace(configs.CameraId) || !CameraDict.ContainsKey(configs.CameraId))
-            //{
-            //    throw new ProcessException("鏍囧畾閰嶇疆鏈厤缃纭殑鐩告満缂栧彿");
-            //}
+            //    _calibReply.CalibHandle.WaitOne();
 
-            //if (string.IsNullOrWhiteSpace(configs.PositionCode))
-            //{
-            //    throw new ProcessException("鏍囧畾閰嶇疆鏈寚瀹氳矾寰勪綅缃�");
-            //}
-
-            //CameraBase camera = CameraDict[configs.CameraId];
-            //FrmCalib9PDynamic frm9PDynamic = new FrmCalib9PDynamic(this, camera, configs, FinalCalculation);
-            //frm9PDynamic.ShowDialog();
-
-            //if (configs.InputPara == null || configs.InputPara.Count <= 0)
-            //{
-            //    return (int)PLCReplyValue.NG;
-            //}
-
-            //if (configs.InputPara[0] <= 0 || configs.InputPara[0] > configs.Configs.Count)
-            //{
-            //    configs.InputPara = null;
-            //    return (int)PLCReplyValue.IGNORE;
-            //}
-
-            //int sequence = configs.InputPara[0];
-
-            ////绗竴娆�
-            //if (sequence == 1)
-            //{
-            //    configs.Configs.ForEach(c =>
+            //    if (_calibReply.CalibPositionNo != calibConfig.PositionNo)
             //    {
-            //        c.Image = null;
-            //        c.OfflineImagePath = "";
-            //        c.CurrentPlatPoint = new CustomizedPoint();
-            //        c.ImageMarkPoint = new CustomizedPoint();
+            //        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),
             //    });
             //}
 
-            //CalibrationConfig stepConfig = configs.Configs[sequence - 1];
+            return new ProcessResponse(true);
+        }
 
-            //HDevEngineTool tool = _halconToolDict[]
+        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);
 
-            //CalibMarkPoint(camera, stepConfig, sequence);
+            List<double> matrix = GetMovementMatrix(calibConfig.Configs.Select(u => u.ImageMarkPoint as CustomizedPoint).ToList(), calibConfig.Configs.Select(u => u.CurrentPlatPoint).ToList(), out string msg);
 
-            ////鑾峰彇褰撳墠骞冲彴鐐逛綅
-            //stepConfig.CurrentPlatPoint = new CustomizedPoint(_monitorList.Skip(locationStartIndex).Take(4).ToList());
-            ////stepConfig.CurrentPlatPoint = new CustomizedPoint(configs.InputPara.Skip(1).Take(4).ToList());
+            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 },
+                });
+            }
 
-            ////鏈�鍚庝竴娆�
-            //if (sequence == configs.Configs.Count)
+            PubSubCenter.Publish(PubTag.CalibAllDone.ToString(), "", msg, true);
+        }
+
+        /// <summary>
+        /// 鑾峰彇鏍囧畾鐐圭殑杞崲鐭╅樀
+        /// </summary>
+        /// <param name="points"></param>
+        /// <returns></returns>
+        protected List<double> GetMovementMatrix(List<CustomizedPoint> imagePoints, List<CustomizedPoint> platPoints, out string msg)
+        {
+            HTuple uList, vList, xList, yList, matrix;
+
+            ConvertPointToHTuple(imagePoints, out uList, out vList);
+            ConvertPointToHTuple(platPoints, out xList, out yList);
+
+            HOperatorSet.VectorToHomMat2d(uList, vList, xList, yList, out matrix);
+
+            double sum = 0;
+            for (int i = 0; i < imagePoints.Count; i++)
+            {
+                HOperatorSet.AffineTransPoint2d(matrix, imagePoints[i].X, imagePoints[i].Y, out HTuple m, out HTuple n);
+
+                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()}鑴夊啿";
+
+            return matrix.DArr.ToList();
+        }
+
+        private void ConvertPointToHTuple(List<CustomizedPoint> point, out HTuple x, out HTuple y)
+        {
+            x = new HTuple(point.Select(p => p.X).ToArray());
+            y = new HTuple(point.Select(p => p.Y).ToArray());
+        }
+
+        public void CalculateStandardPoint(CalibrationConfigCollection calibConfig, AGVBindUnit bind, PathPosition position)
+        {
+            //var bind = Config.AGVBindCollection.FirstOrDefault(u => u.CameraId == calibConfig.CameraId);
+            //if (bind == null)
             //{
-            //    FinalCalculation?.Invoke(configs.Configs);
+            //    throw new ProcessException("鏈兘鑾峰彇缁戝畾璁惧淇℃伅");
             //}
 
-            //configs.InputPara = null;
-            //return (int)PLCReplyValue.OK;
+            //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)
+            {
+                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),
+                });
+            }
+
+            PubSubCenter.Publish(PubTag.CalibAllDone.ToString(), "", $"鏍囧畾瀹屾垚锛屾爣鍑嗙偣:{markPoint.GetDisplayText()}", true);
         }
+
+        public void MultipleStepsProcess(CalibrationConfigCollection calibConfig, AGVBindUnit bind, Action<AGVBindUnit, int, int> sendMessageToRobot)
+        {
+            for (int i = 0; i < calibConfig.Configs.Count; i++)
+            {
+                SingleStepProcess(calibConfig.Configs[i], sendMessageToRobot, bind, calibConfig.PositionNo, i);
+            }
+        }
+
+        public void SendMessageToRobot_Calibration(AGVBindUnit bind, int positionNo, 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);
+
+            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.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("鑾峰彇鐐逛綅淇℃伅涓嶆纭�");
+                }
+
+                config.ImageMarkPoint = new CustomizedPointWithAngle(x, y, angel);
+            }
+
+            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 97166ab..451d2bd 100644
--- a/src/A032.Process/ProcessControl_Method.cs
+++ b/src/A032.Process/ProcessControl_Method.cs
@@ -20,9 +20,49 @@
 {
     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 OnAGVBatterLvlChanged(SeerAGVDriver agv, float batterLvl)
+        {
+            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.AGVId == agv.Id);
+            SeerAGVInitialConfig iConfig = agv.InitialConfig as SeerAGVInitialConfig;
+            if (batterLvl <= 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 (batterLvl >= iConfig.BatteryLvlChargeDone)
+            {
+                bind.SetAGVStatus(TaskStatus.Available);
+                return;
+            }
+        }
 
         private void OnAGVTaskStatusChanged(SeerAGVDriver agv, AGVTaskStatus taskStatus)
         {
@@ -42,7 +82,7 @@
                 //    bind.RobotStatus = TaskStatus.Running;
                 //}
 
-                bind.AGVStatus = TaskStatus.Available;
+                bind.SetAGVStatus(TaskStatus.Available);
             }
         }
 
@@ -64,7 +104,7 @@
                 //    bind.RobotStatus = TaskStatus.Running;
                 //}
 
-                bind.AGVStatus = TaskStatus.Available;
+                bind.SetAGVStatus(TaskStatus.Available);
 
                 PathPosition position = Config.PositionCollection.FirstOrDefault(p => p.PositionCode == bind.AGVDest);
                 switch (position.Description)
@@ -85,6 +125,7 @@
                 }
             }
         }
+        #endregion
 
         private void OnRobotMsgReceived(DateTime dt, AuboRobotDriver robot, RobotMsg msg)
         {
@@ -210,12 +251,17 @@
                     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:
@@ -309,7 +355,7 @@
                     while (bind.IsEmptyTrayEmpty && !bind.IsEmptyTrayTaskAssigned)
                     {
                         //if (bind.TaskList.Count == 0)
-                        if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available)
+                        if (bind.UnitStatus == TaskStatus.Available)
                         {
                             //List<AGVTaskModel> models = new List<AGVTaskModel>();
                             //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_LoadEmptyTray"));
@@ -317,12 +363,14 @@
 
                             //AddNewTaskToBind(device.Id, models);
 
-                            AGV_LoadEmptyTray(bind.Id);
-                            bind.IsEmptyTrayTaskAssigned = true;
+                            if (AGV_LoadEmptyTray(bind.Id))
+                            {
+                                bind.IsEmptyTrayTaskAssigned = true;
+                            }
                         }
                         else
                         {
-                            Thread.Sleep(500);
+                            Thread.Sleep(WAITTIME);
                         }
                     }
                 });
@@ -351,7 +399,7 @@
                     while (bind.IsFullTrayFull && !bind.IsFullTrayTaskAssigned)
                     {
                         //if (bind.TaskList.Count == 0)
-                        if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available)
+                        if (bind.UnitStatus == TaskStatus.Available)
                         {
                             //List<AGVTaskModel> models = new List<AGVTaskModel>();
                             //models.Add(new AGVTaskModel(TaskAvailableLevel.Both, "AGV_UnloadFullTray"));
@@ -359,13 +407,14 @@
 
                             //AddNewTaskToBind(device.Id, models);
 
-                            AGV_UnloadFullTray(bind.Id);
-
-                            bind.IsFullTrayTaskAssigned = true;
+                            if (AGV_UnloadFullTray(bind.Id))
+                            {
+                                bind.IsFullTrayTaskAssigned = true;
+                            }
                         }
                         else
                         {
-                            Thread.Sleep(500);
+                            Thread.Sleep(WAITTIME);
                         }
                     }
                 });
@@ -460,7 +509,7 @@
         //    return new ProcessResponse(true);
         //}
 
-        public void AGV_LoadEmptyTray(string bindId)
+        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);
@@ -470,10 +519,17 @@
                 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 true;
+            }
+            else
+            {
+                return false;
+            }
         }
 
         //[ProcessMethod("", "AfterEmptyTrayPositionArrived", "鍒拌揪绌篢ray涓婃枡鐐�", true)]
@@ -589,20 +645,21 @@
                             //bind.AddTask(model_AGV);
                             //bind.AddTask(model_Robot);
 
-                            AGV_UnloadEmptyTray(bind.Id, position);
-
-                            taskStatus.IsTaskAssgined = true;
-                            taskStatus.AgvId = bind.AGVId;
+                            if (AGV_UnloadEmptyTray(bind.Id, position))
+                            {
+                                taskStatus.IsTaskAssgined = true;
+                                taskStatus.AgvId = bind.AGVId;
+                            }
                         }
                     }
 
-                    Thread.Sleep(300);
+                    Thread.Sleep(WAITTIME);
                 }
             });
         }
 
         //[ProcessMethod("", "AGV_UnloadEmptyTray", "AGV鍘诲線鍗歌浇绌篢ray鏂欎綅缃�", true)]
-        public void AGV_UnloadEmptyTray(string bindId, PathPosition position)
+        public bool AGV_UnloadEmptyTray(string bindId, PathPosition position)
         {
             var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
 
@@ -611,10 +668,17 @@
                 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 true;
+            }
+            else
+            {
+                return false;
+            }
         }
 
         //[ProcessMethod("", "Robot_UnloadEmptyTray", "鏈哄櫒浜鸿繍鍔ㄨ嚦绌篢ray鎷嶇収浣嶇疆", true)]
@@ -756,7 +820,7 @@
 
                 adjust_X = (float)dx_Robot.D;
                 adjust_Y = (float)dy_Robot.D;
-                adjust_Angle = angle;
+                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 });
@@ -831,10 +895,11 @@
                             //bind.AddTask(model_AGV);
                             //bind.AddTask(model_Robot);
 
-                            AGV_LoadFullTray(bind.Id, position);
-
-                            taskStatus.IsTaskAssgined = true;
-                            taskStatus.AgvId = bind.AGVId;
+                            if (AGV_LoadFullTray(bind.Id, position))
+                            {
+                                taskStatus.IsTaskAssgined = true;
+                                taskStatus.AgvId = bind.AGVId;
+                            }
                         }
                     }
 
@@ -844,7 +909,7 @@
         }
 
         //[ProcessMethod("", "AGV_LoadFullTray", "AGV鍘诲線婊ray涓婃枡浣嶇疆", true)]
-        public void AGV_LoadFullTray(string bindId, PathPosition position)
+        public bool AGV_LoadFullTray(string bindId, PathPosition position)
         {
             var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
 
@@ -855,10 +920,17 @@
                 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 true;
+            }
+            else
+            {
+                return false;
+            }
 
             //return new ProcessResponse(true);
         }
@@ -1026,7 +1098,7 @@
 
                 adjust_X = (float)dx_Robot.D;
                 adjust_Y = (float)dy_Robot.D;
-                adjust_Angle = angle;
+                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 });
@@ -1060,7 +1132,7 @@
         //    return new ProcessResponse(true);
         //}
 
-        public void AGV_UnloadFullTray(string bindId)
+        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);
@@ -1070,10 +1142,17 @@
                 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 true;
+            }
+            else
+            {
+                return false;
+            }
         }
 
         //[ProcessMethod("", "Robot_UnloadFullTray", "鏈哄櫒浜哄嵏杞芥弧Tray", true)]
diff --git a/src/Bro.Common.Model/Helper/UIHelper.cs b/src/Bro.Common.Model/Helper/UIHelper.cs
index 8040fd0..2a0c8f9 100644
--- a/src/Bro.Common.Model/Helper/UIHelper.cs
+++ b/src/Bro.Common.Model/Helper/UIHelper.cs
@@ -14,21 +14,30 @@
         {
             cbo.DataSource = dataSource;
             cbo.DisplayMember = display;
-            cbo.ValueMember = value;
+            if (!string.IsNullOrWhiteSpace(value))
+            {
+                cbo.ValueMember = value;
+            }
         }
 
         public static void SetCombo(ToolStripComboBox cbo, object dataSource, string display, string value)
         {
             cbo.ComboBox.DataSource = dataSource;
             cbo.ComboBox.DisplayMember = display;
-            cbo.ComboBox.ValueMember = value;
+            if (!string.IsNullOrWhiteSpace(value))
+            {
+                cbo.ComboBox.ValueMember = value;
+            }
         }
 
         public static void SetCombo(DataGridViewComboBoxColumn cbo, object dataSource, string display, string value)
         {
             cbo.DataSource = dataSource;
             cbo.DisplayMember = display;
-            cbo.ValueMember = value;
+            if (!string.IsNullOrWhiteSpace(value))
+            {
+                cbo.ValueMember = value;
+            }
         }
     }
 
diff --git a/src/Bro.Common.Model/Interface/IStationConfig.cs b/src/Bro.Common.Model/Interface/IStationConfig.cs
index 3e35fba..0531cc1 100644
--- a/src/Bro.Common.Model/Interface/IStationConfig.cs
+++ b/src/Bro.Common.Model/Interface/IStationConfig.cs
@@ -73,7 +73,7 @@
         /// 鎿嶄綔閰嶇疆鐨勫瓧鍏搁泦鍚�
         /// Key锛歁ethodCode锛孷alue锛氭搷浣滈厤缃�
         /// </summary>
-        //Dictionary<string, IOperationConfig> ProcessOpConfigDict { get; set; }
+        Dictionary<string, IOperationConfig> ProcessOpConfigDict { get; set; }
 
         ///// <summary>
         ///// 浠版媿鐩告満鏍囧畾鐭╅樀
@@ -104,7 +104,7 @@
         ///// 浠版媿鐩告満鎷嶆憚鐨勫す鍏峰伐浠剁殑鏃嬭浆涓績鍥惧儚鍧愭爣 
         ///// </summary>
         //CustomizedPoint RotationCenter { get; set; }
-        
+
         /// <summary>
         /// 鏄惁杈撳嚭CSV鏂囦欢
         /// </summary>
diff --git a/src/Bro.Device.SeerAGV/SeerAGVConfig.cs b/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
index 989fea4..a094f0c 100644
--- a/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
+++ b/src/Bro.Device.SeerAGV/SeerAGVConfig.cs
@@ -36,6 +36,38 @@
         [Category("鐩戝惉閰嶇疆")]
         [Description("鏄惁閲囩敤绠�鍗曠洃鍚ā寮忋�倀rue锛氱畝鍗曟ā寮忥紝鍙幏鍙栦换鍔$姸鎬侊紱false锛氬叏閮ㄦā寮忥紝鑾峰彇浠诲姟鎵�鏈変俊鎭�")]
         public bool IsSimpleMonitor { get; set; } = true;
+
+        private float batteryLvlToCharge = 0.1f;
+        [Category("鍏呯數閰嶇疆")]
+        [Description("鍏呯數鐢垫睜瀹归噺锛岀數姹犲閲忎綆浜庤鍊兼椂闇�瑕佸厖鐢�")]
+        public float BatteryLvlToCharge
+        {
+            get => batteryLvlToCharge;
+            set
+            {
+                if (value >= 1 || value <= 0)
+                {
+                    value = 0.1f;
+                }
+                batteryLvlToCharge = value;
+            }
+        }
+
+        private float batteryLvlChargeDone = 0.9f;
+        [Category("鍏呯數閰嶇疆")]
+        [Description("鍏呯數瀹屾垚鐢垫睜瀹归噺锛岀數姹犲閲忛珮浜庤鍊兼椂纭鍏呯數瀹屾垚")]
+        public float BatteryLvlChargeDone
+        {
+            get => batteryLvlChargeDone;
+            set
+            {
+                if (value >= 1 || value <= 0)
+                {
+                    value = 0.9f;
+                }
+                batteryLvlChargeDone = value;
+            }
+        }
     }
 
     [Device("SeerAGV", "SeerAGV", EnumHelper.DeviceAttributeType.OperationConfig)]
@@ -138,6 +170,8 @@
         CancelTask = 0x0BBB,
         PauseTask = 0x0BB9,
         TaskOrder = 0x0BEB,
+
+        QueryBattery = 0x2AFF,
     }
 
     public enum AGVTaskStatus
diff --git a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
index fdb4428..635132e 100644
--- a/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
+++ b/src/Bro.Device.SeerAGV/SeerAGVDriver.cs
@@ -19,6 +19,7 @@
     {
         public Action<SeerAGVDriver, string> OnAGVPositoinChanged;
         public Action<SeerAGVDriver, AGVTaskStatus> OnAGVTaskStatusChanged;
+        public Action<SeerAGVDriver, float> OnAGVBatteryLvlChanged;
 
         SeerAGVInitialConfig IConfig
         {
@@ -64,6 +65,7 @@
         {
             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 }) : "");
 
             Task.Run(() =>
             {
@@ -76,7 +78,7 @@
             if (client_Guide != null && client_Guide.Connected)
             {
                 CancelTask();
-                client_Guide.Close();                
+                client_Guide.Close();
                 client_Guide = null;
             }
 
@@ -142,8 +144,23 @@
             }
         }
 
+        float batteryLvl = 0;
+        public float BatteryLvl
+        {
+            get => batteryLvl;
+            set
+            {
+                if (batteryLvl != value)
+                {
+                    batteryLvl = value;
+                    OnAGVBatteryLvlChanged?.Invoke(this, batteryLvl);
+                }
+            }
+        }
+
         SeerMessage msg_Position = new SeerMessage();
         SeerMessage msg_GuideStatus = new SeerMessage();
+        SeerMessage msg_Battery = new SeerMessage();
         private void MonitorAGV()
         {
             while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept)
@@ -153,6 +170,8 @@
                     SendMsg(client_State, IConfig.StatusPort, msg_Position);
                     Thread.Sleep(IConfig.ScanInterval);
                     SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus);
+                    Thread.Sleep(IConfig.ScanInterval);
+                    SendMsg(client_State, IConfig.StatusPort, msg_Battery);
                     Thread.Sleep(IConfig.ScanInterval);
                 }
                 catch (Exception ex)
@@ -231,6 +250,9 @@
                     case (int)AGVCode.QueryTaskStatus:
                         TaskStatus = (AGVTaskStatus)recMsg.JValues.Value<int>("task_status");
                         break;
+                    case (int)AGVCode.QueryBattery:
+                        BatteryLvl = recMsg.JValues.Value<float>("battery_level");
+                        break;
                     default:
                         break;
                 }

--
Gitblit v1.8.0