1. 修改SeerAGV驱动通信代码
2. 修改机器人通信部分代码
3. 取消原有流程任务队列模式,使用即时方法调用。
10个文件已修改
891 ■■■■■ 已修改文件
src/A032.Config/ConfigFrm.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Config/ConfigFrm.designer.cs 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Process/AGVBindUnit.cs 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Process/ProcessConfig.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Process/ProcessControl.cs 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Process/ProcessControl_Method.cs 587 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.AuboRobot/AuboRobotConfig.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.AuboRobot/AuboRobotDriver.cs 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.SeerAGV/SeerAGVConfig.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.SeerAGV/SeerAGVDriver.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/A032.Config/ConfigFrm.cs
@@ -22,6 +22,7 @@
using Bro.Common.UI;
using Bro.Common.PubSub;
using static Bro.Common.Helper.EnumHelper;
using Bro.Device.HikCamera;
namespace M065.Config
{
@@ -727,5 +728,10 @@
                chkContinueMode.Checked = false;
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            (Process as ProcessControl).Robot_Monitor_FullTrayFull(new OperationConfigBase() { InputPara = new List<int>() { 1 } }, new HikCameraDriver { Id = "3680EBF8-D9F8-4E14-8B0D-6E53BE3BB96D" });
        }
    }
}
src/A032.Config/ConfigFrm.designer.cs
@@ -51,6 +51,7 @@
            this.cboTestMethod = new System.Windows.Forms.ComboBox();
            this.tbLog = new System.Windows.Forms.TabPage();
            this.splitContainer1 = new System.Windows.Forms.SplitContainer();
            this.chkHardwareTrigger = new System.Windows.Forms.CheckBox();
            this.lblFrameRate = new System.Windows.Forms.Label();
            this.chkContinueMode = new System.Windows.Forms.CheckBox();
            this.btnSnap = new System.Windows.Forms.Button();
@@ -74,7 +75,6 @@
            this.cboProductionCode = new System.Windows.Forms.ComboBox();
            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
            this.tsslLoginStatus = new System.Windows.Forms.ToolStripStatusLabel();
            this.chkHardwareTrigger = new System.Windows.Forms.CheckBox();
            this.tabControl1.SuspendLayout();
            this.tbConfig.SuspendLayout();
            this.tbCalibration.SuspendLayout();
@@ -331,6 +331,17 @@
            this.splitContainer1.SplitterDistance = 497;
            this.splitContainer1.TabIndex = 2;
            // 
            // chkHardwareTrigger
            //
            this.chkHardwareTrigger.AutoSize = true;
            this.chkHardwareTrigger.Location = new System.Drawing.Point(220, 12);
            this.chkHardwareTrigger.Name = "chkHardwareTrigger";
            this.chkHardwareTrigger.Size = new System.Drawing.Size(60, 16);
            this.chkHardwareTrigger.TabIndex = 6;
            this.chkHardwareTrigger.Text = "硬触发";
            this.chkHardwareTrigger.UseVisualStyleBackColor = true;
            this.chkHardwareTrigger.CheckedChanged += new System.EventHandler(this.chkHardwareTrigger_CheckedChanged);
            //
            // lblFrameRate
            // 
            this.lblFrameRate.AutoSize = true;
@@ -451,7 +462,7 @@
            this.button1.TabIndex = 1;
            this.button1.Text = "Test";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Visible = false;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // btnLoadWarningFromFile
            // 
@@ -595,17 +606,6 @@
            this.tsslLoginStatus.Text = "未登录";
            this.tsslLoginStatus.Click += new System.EventHandler(this.tsslLoginStatus_Click);
            // 
            // chkHardwareTrigger
            //
            this.chkHardwareTrigger.AutoSize = true;
            this.chkHardwareTrigger.Location = new System.Drawing.Point(220, 12);
            this.chkHardwareTrigger.Name = "chkHardwareTrigger";
            this.chkHardwareTrigger.Size = new System.Drawing.Size(60, 16);
            this.chkHardwareTrigger.TabIndex = 6;
            this.chkHardwareTrigger.Text = "硬触发";
            this.chkHardwareTrigger.UseVisualStyleBackColor = true;
            this.chkHardwareTrigger.CheckedChanged += new System.EventHandler(this.chkHardwareTrigger_CheckedChanged);
            //
            // ConfigFrm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@@ -614,8 +614,8 @@
            this.Controls.Add(this.statusStrip1);
            this.Controls.Add(this.cboProductionCode);
            this.Controls.Add(this.tabControl1);
            this.Controls.Add(this.plAdvanced);
            this.Controls.Add(this.plBasic);
            this.Controls.Add(this.plAdvanced);
            this.Name = "ConfigFrm";
            this.Text = "配置界面";
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ConfigFrm_FormClosing);
src/A032.Process/AGVBindUnit.cs
@@ -33,7 +33,7 @@
    {
        public TaskAvailableLevel Level { get; set; } = TaskAvailableLevel.Robot;
        public Func<IOperationConfig, IDevice, ProcessResponse> MethodFunc { get; set; }
        public string MethodName { get; set; }
        public IOperationConfig OpConfig { get; set; }
@@ -43,10 +43,10 @@
        public AGVTaskModel() { }
        public AGVTaskModel(TaskAvailableLevel level, Func<IOperationConfig, IDevice, ProcessResponse> methodFunc, IOperationConfig opConfig = null, IDevice device = null)
        public AGVTaskModel(TaskAvailableLevel level, string methodName, IOperationConfig opConfig = null, IDevice device = null)
        {
            Level = level;
            MethodFunc = methodFunc;
            MethodName = methodName;
            OpConfig = opConfig ?? new OperationConfigBase();
            Device = device;
        }
@@ -57,7 +57,7 @@
        #region 可编辑项目
        [Category("设备绑定")]
        [Description("绑定Id")]
        [ReadOnly(true)]
        [Browsable(false)]
        public string Id { get; set; } = Guid.NewGuid().ToString();
        [Category("设备绑定")]
@@ -92,7 +92,7 @@
        [Browsable(false)]
        [JsonIgnore]
        public Action<AGVBindUnit> OnMethodInvoke { get; set; }
        public Action<AGVTaskModel> OnMethodInvoke { get; set; }
        public string AGVDest { get; set; } = "";
@@ -105,7 +105,7 @@
            set
            {
                agvStatus = value;
                InvokeTaskCheck();
                //InvokeTaskCheck();
            }
        }
@@ -118,7 +118,7 @@
            set
            {
                robotStatus = value;
                InvokeTaskCheck();
                //InvokeTaskCheck();
            }
        }
@@ -153,9 +153,10 @@
        [Browsable(false)]
        [JsonIgnore]
        public CameraBase Camera { get; set; } = null;
        [Browsable(false)]
        [JsonIgnore]
        public ObservableCollection<AGVTaskModel> TaskList { get; set; } = new ObservableCollection<AGVTaskModel>();
        //[Browsable(false)]
        //[JsonIgnore]
        //public ObservableCollection<AGVTaskModel> TaskList { get; set; } = new ObservableCollection<AGVTaskModel>();
        [Browsable(false)]
        [JsonIgnore]
@@ -175,56 +176,92 @@
        [Browsable(false)]
        [JsonIgnore]
        public bool IsFullTrayTaskAssigned { get; set; }
        [Browsable(false)]
        [JsonIgnore]
        public bool IsEmptyTrayTaskAssigned { get; set; }
        [Browsable(false)]
        [JsonIgnore]
        public ManualResetEvent RobotIOHandle { get; set; } = new ManualResetEvent(false);
        public AGVBindUnit()
        {
            TaskList.CollectionChanged += TaskList_CollectionChanged;
            //TaskList.CollectionChanged += TaskList_CollectionChanged;
        }
        private void TaskList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                InvokeTaskCheck();
            }
        }
        //private void TaskList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        //{
        //    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
        //    {
        //        InvokeTaskCheck();
        //    }
        //}
        private void InvokeTaskCheck()
        {
            for (int i = 0; i < TaskList.Count; i++)
            {
                var task = TaskList[i];
        //private void InvokeTaskCheck()
        //{
        //    lock (taskLock)
        //    {
        //        for (int i = 0; i < TaskList.Count; i++)
        //        {
        //            var task = TaskList[i];
                bool isAgvOK = false;
                bool isRobotOK = false;
        //            bool isAgvOK = false;
        //            bool isRobotOK = false;
                if ((task.Level & TaskAvailableLevel.AGV) == TaskAvailableLevel.AGV)
                {
                    isAgvOK = AGVStatus == TaskStatus.Available;
                }
                else
                {
                    isAgvOK = true;
                }
        //            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 ((task.Level & TaskAvailableLevel.Robot) == TaskAvailableLevel.Robot)
        //            {
        //                isRobotOK = RobotStatus == TaskStatus.Available;
        //            }
        //            else
        //            {
        //                isRobotOK = true;
        //            }
                if (isRobotOK && isAgvOK)
                {
                    OnMethodInvoke?.Invoke(this);
                    TaskList.RemoveAt(i);
                    break;
                }
            }
        }
        //            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
@@ -288,7 +325,7 @@
                config.PLCConfigCollection.ForEach(plc =>
                {
                    _hash[plc.ID] = plc.Name;
                });
                });
            }
        }
    }
src/A032.Process/ProcessConfig.cs
@@ -151,6 +151,10 @@
        [Editor(typeof(ComplexCollectionEditor<PositionVisionConfig>), typeof(UITypeEditor))]
        public List<PositionVisionConfig> VisionConfigCollection { get; set; } = new List<PositionVisionConfig>();
        [Category("视觉配置")]
        [Description("是否启用视觉引导")]
        public bool IsEnableVisionGuide { get; set; } = false;
        /// <summary>
        /// 空Tray上料阈值,AGV上的空tray数量不大于该数值时,AGV可以执行空Tray上料任务
        /// </summary>
src/A032.Process/ProcessControl.cs
@@ -263,6 +263,7 @@
            });
        }
        Dictionary<string, MethodInfo> InvokeMethodDict = new Dictionary<string, MethodInfo>();
        public List<ProcessMethodAttribute> CollectProcessMethods()
        {
            List<ProcessMethodAttribute> resultList = new List<ProcessMethodAttribute>();
@@ -274,6 +275,7 @@
                if (attr != null)
                {
                    resultList.Add(attr);
                    InvokeMethodDict[attr.MethodCode] = m;
                }
            });
@@ -333,7 +335,7 @@
                    u.Camera = CameraDict[u.CameraId];
                }
                u.OnMethodInvoke = OnBindUnitTaskInvoke;
                //u.OnMethodInvoke = OnBindUnitTaskInvoke;
            });
        }
src/A032.Process/ProcessControl_Method.cs
@@ -8,6 +8,7 @@
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -64,6 +65,24 @@
                //}
                bind.AGVStatus = TaskStatus.Available;
                PathPosition position = Config.PositionCollection.FirstOrDefault(p => p.PositionCode == bind.AGVDest);
                switch (position.Description)
                {
                    case PathPositionDefinition.LoadEmptyTray:
                        Robot_LoadEmptyTray(bind.Id, position);
                        break;
                    case PathPositionDefinition.LoadFullTray:
                        break;
                    case PathPositionDefinition.UnloadEmptyTray:
                        Robot_UnloadEmptyTraySnap(bind.Id, position);
                        break;
                    case PathPositionDefinition.UnloadFullTray:
                        Robot_UnloadFullTraySnap(bind.Id, position);
                        break;
                    default:
                        break;
                }
            }
        }
@@ -78,7 +97,7 @@
                throw new ProcessException("未能根据机器人信息获取绑定设备信息", null);
            }
            List<AGVTaskModel> models = new List<AGVTaskModel>();
            //List<AGVTaskModel> models = new List<AGVTaskModel>();
            switch (msg.Action)
            {
@@ -130,6 +149,10 @@
                                        {
                                            RobotMsg_UnloadEmptyTray.Para2 = msg.Para2;
                                            robot.SendMsg(RobotMsg_UnloadEmptyTray, true);
                                        }
                                        else
                                        {
                                            bind.RobotStatus = TaskStatus.Available;
                                        }
                                    }
                                    else
@@ -199,17 +222,17 @@
                    break;
            }
            if (models.Count > 0)
            {
                models.ForEach(model =>
                {
                    if (!bind.TaskList.Any(t => t.MethodFunc.Method.Name == model.MethodFunc.Method.Name))
                    {
                        model.OpConfig = new AGVBindOpConfig(bind.Id);
                        bind.TaskList.Add(model);
                    }
                });
            }
            //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()
@@ -220,39 +243,40 @@
            });
        }
        private void OnBindUnitTaskInvoke(AGVBindUnit bind)
        {
            var task = bind.TaskList[0];
            var response = task.MethodFunc.Invoke(task.OpConfig, task.Device);
        }
        //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);
        //private void AddNewTaskToBind(string robotId, List<AGVTaskModel> models)
        //{
        //    var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == robotId);
            if (bind == null)
            {
                throw new ProcessException("未能根据机器人信息获取绑定设备信息", null);
            }
        //    if (bind == null)
        //    {
        //        throw new ProcessException("未能根据机器人信息获取绑定设备信息", null);
        //    }
            AddNewTaskToBind(bind, models);
        }
        //    AddNewTaskToBind(bind, models);
        //}
        private void AddNewTaskToBind(AGVBindUnit bind, List<AGVTaskModel> models)
        {
            if (models.Count > 0)
            {
                models.ForEach(model =>
                {
                    if (!bind.TaskList.Any(t => t.MethodFunc.Method.Name == model.MethodFunc.Method.Name))
                    {
                        model.OpConfig = new AGVBindOpConfig(bind.Id);
                        bind.TaskList.Add(model);
                    }
                });
            }
        }
        //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)
@@ -273,7 +297,7 @@
        [ProcessMethod("", "Robot_Monitor_EmptyTrayEmpty", "机器人监听事件-空Tray区域清空", true)]
        public ProcessResponse Robot_Monitor_EmptyTrayEmpty(IOperationConfig config, IDevice device)
        {
            bool isEmptyTrayEmpty = config.InputPara[0] == 1;
            bool isEmptyTrayEmpty = config.InputPara[0] == 0;
            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == device.Id);
            if (isEmptyTrayEmpty)
            {
@@ -281,16 +305,20 @@
                Task.Run(() =>
                {
                    Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadEmptyTray;
                    while (bind.IsEmptyTrayEmpty && bind.TaskList.Count == 0 && !bind.TaskList.Any(u => u.MethodFunc.Method.Name == action.Method.Name))
                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadEmptyTray;
                    while (bind.IsEmptyTrayEmpty && !bind.IsEmptyTrayTaskAssigned)
                    {
                        if (bind.TaskList.Count == 0)
                        //if (bind.TaskList.Count == 0)
                        if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available)
                        {
                            List<AGVTaskModel> models = new List<AGVTaskModel>();
                            models.Add(new AGVTaskModel(TaskAvailableLevel.Both, AGV_LoadEmptyTray));
                            models.Add(new AGVTaskModel(TaskAvailableLevel.AGV, AfterEmptyTrayPositionArrived));
                            //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);
                            //AddNewTaskToBind(device.Id, models);
                            AGV_LoadEmptyTray(bind.Id);
                            bind.IsEmptyTrayTaskAssigned = true;
                        }
                        else
                        {
@@ -298,11 +326,11 @@
                        }
                    }
                });
            }
            else
            {
                bind.IsEmptyTrayEmpty = false;
                bind.IsEmptyTrayTaskAssigned = false;
            }
            return new ProcessResponse(true);
@@ -319,16 +347,21 @@
                Task.Run(() =>
                {
                    Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadFullTray;
                    while (bind.IsFullTrayFull && !bind.TaskList.Any(u => u.MethodFunc.Method.Name == action.Method.Name))
                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadFullTray;
                    while (bind.IsFullTrayFull && !bind.IsFullTrayTaskAssigned)
                    {
                        if (bind.TaskList.Count == 0)
                        //if (bind.TaskList.Count == 0)
                        if (bind.AGVStatus == TaskStatus.Available && bind.RobotStatus == TaskStatus.Available)
                        {
                            List<AGVTaskModel> models = new List<AGVTaskModel>();
                            models.Add(new AGVTaskModel(TaskAvailableLevel.Both, AGV_UnloadFullTray));
                            models.Add(new AGVTaskModel(TaskAvailableLevel.AGV, Robot_UnloadFullTray));
                            //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);
                            //AddNewTaskToBind(device.Id, models);
                            AGV_UnloadFullTray(bind.Id);
                            bind.IsFullTrayTaskAssigned = true;
                        }
                        else
                        {
@@ -340,6 +373,7 @@
            else
            {
                bind.IsFullTrayFull = false;
                bind.IsFullTrayTaskAssigned = false;
            }
            bind.RobotIOHandle.Set();
@@ -350,7 +384,7 @@
        [ProcessMethod("", "Robot_Monitor_FullTrayEmpty", "机器人监听事件-满Tray区域清空", true)]
        public ProcessResponse Robot_Monitor_FullTrayEmpty(IOperationConfig config, IDevice device)
        {
            bool isFullTrayEmpty = config.InputPara[0] == 1;
            bool isFullTrayEmpty = config.InputPara[0] == 0;
            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.RobotId == device.Id);
            bind.IsFullTrayEmpty = isFullTrayEmpty;
@@ -399,7 +433,7 @@
            taskAssignedList.RemoveAll(u => u.AgvId == device.Id);
            bind.TaskList.Clear();
            //bind.ClearTask();
            bind.RobotStatus = bind.AGVStatus = TaskStatus.Available;
            return new ProcessResponse(true);
@@ -407,10 +441,28 @@
        #endregion
        #region 空Tray上料
        [ProcessMethod("", "AGV_LoadEmptyTray", "AGV去往空Tray上料", true)]
        public ProcessResponse AGV_LoadEmptyTray(IOperationConfig config, IDevice device)
        //[ProcessMethod("", "AGV_LoadEmptyTray", "AGV去往空Tray上料", 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 void 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)
@@ -422,15 +474,34 @@
            bind.AGV.TaskOrder(position.PositionCode);
            bind.AGVStatus = TaskStatus.Running;
            return new ProcessResponse(true);
        }
        [ProcessMethod("", "AfterEmptyTrayPositionArrived", "到达空Tray上料点", true)]
        public ProcessResponse AfterEmptyTrayPositionArrived(IOperationConfig config, IDevice device)
        //[ProcessMethod("", "AfterEmptyTrayPositionArrived", "到达空Tray上料点", 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上料点", null);
        //    }
        //    if (bind.AGV.CurrentPosition != position.PositionCode)
        //    {
        //        throw new ProcessException("AGV尚未到达空Tray上料点", null);
        //    }
        //    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 == (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)
            {
@@ -444,8 +515,6 @@
            bind.Robot.SendMsg(RobotMsgAction.Load, RobotMsgParas.EmptyTray, 0);
            bind.RobotStatus = TaskStatus.Running;
            return new ProcessResponse(true);
        }
        //[ProcessMethod("", "EmptyTrayReady", "空Tray上料完成", true)]
@@ -489,13 +558,13 @@
                    });
                }
                CheckEmptyTrayTask(position.PositionNo);
                CheckUnloadEmptyTrayTask(position.PositionNo);
            }
            return new ProcessResponse(true);
        }
        private async void CheckEmptyTrayTask(int positionNo)
        private async void CheckUnloadEmptyTrayTask(int positionNo)
        {
            await Task.Run(() =>
            {
@@ -506,19 +575,21 @@
                while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
                {
                    Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadEmptyTray;
                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_UnloadEmptyTray;
                    //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodFunc.Method.Name == action.Method.Name)))
                    //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, action, new AGVBindOpConfig(bind.Id, position));
                            AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, Robot_UnloadEmptyTray, new AGVBindOpConfig(bind.Id));
                            //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.TaskList.Add(model_AGV);
                            bind.TaskList.Add(model_Robot);
                            //bind.AddTask(model_AGV);
                            //bind.AddTask(model_Robot);
                            AGV_UnloadEmptyTray(bind.Id, position);
                            taskStatus.IsTaskAssgined = true;
                            taskStatus.AgvId = bind.AGVId;
@@ -531,11 +602,9 @@
        }
        //[ProcessMethod("", "AGV_UnloadEmptyTray", "AGV去往卸载空Tray料位置", true)]
        public ProcessResponse AGV_UnloadEmptyTray(IOperationConfig config, IDevice device)
        public void AGV_UnloadEmptyTray(string bindId, PathPosition position)
        {
            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == (config as AGVBindOpConfig).BindId);
            PathPosition position = (config as AGVBindOpConfig).Position;
            var bind = Config.AGVBindCollection.FirstOrDefault(u => u.Id == bindId);
            if (position == null)
            {
@@ -546,15 +615,13 @@
            bind.AGV.TaskOrder(position.PositionCode);
            bind.AGVStatus = TaskStatus.Running;
            return new ProcessResponse(true);
        }
        //[ProcessMethod("", "Robot_UnloadEmptyTray", "机器人运动至空Tray拍照位置", true)]
        public ProcessResponse Robot_UnloadEmptyTray(IOperationConfig config, IDevice device)
        public void Robot_UnloadEmptyTraySnap(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.UnloadEmptyTray && u.PositionCode == bind.AGV.CurrentPosition);
            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)
            {
@@ -565,8 +632,6 @@
            bind.RobotStatus = TaskStatus.Running;
            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.UnloadEmptyTraySnap, position.PositionNo);
            return new ProcessResponse(true);
        }
        //[ProcessMethod("", "Camera_UnloadEmptyTray", "相机确认空Tray卸载机器人位置调整", true)]
@@ -645,49 +710,60 @@
                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($"未配置Camera_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($"未配置Camera_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 = 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 });
            RobotMsg_UnloadEmptyTray.Action = RobotMsgAction.Unload;
            RobotMsg_UnloadEmptyTray.Para1 = RobotMsgParas.EmptyTray;
            RobotMsg_UnloadEmptyTray.Para2 = position.PositionNo;
            RobotMsg_UnloadEmptyTray.Datas = new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle }.ConvertAll(s => s.ToString()).ToList();
            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);
@@ -741,7 +817,7 @@
                while (taskStatus.IsTaskNeed && !taskStatus.IsTaskAssgined)
                {
                    Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadFullTray;
                    //Func<IOperationConfig, IDevice, ProcessResponse> action = AGV_LoadFullTray;
                    //if (!Config.AGVBindCollection.Any(b => b.TaskList.Any(t => t.MethodFunc.Method.Name == action.Method.Name)))
                    {
@@ -749,11 +825,13 @@
                        if (bind != null)
                        {
                            var position = Config.PositionCollection.FirstOrDefault(u => u.PositionNo == positionNo);
                            AGVTaskModel model_AGV = new AGVTaskModel(TaskAvailableLevel.Both, action, new AGVBindOpConfig(bind.Id, position));
                            AGVTaskModel model_Robot = new AGVTaskModel(TaskAvailableLevel.AGV, Robot_LoadFullTray, new AGVBindOpConfig(bind.Id));
                            //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.TaskList.Add(model_AGV);
                            bind.TaskList.Add(model_Robot);
                            //bind.AddTask(model_AGV);
                            //bind.AddTask(model_Robot);
                            AGV_LoadFullTray(bind.Id, position);
                            taskStatus.IsTaskAssgined = true;
                            taskStatus.AgvId = bind.AGVId;
@@ -765,12 +843,12 @@
            });
        }
        [ProcessMethod("", "AGV_LoadFullTray", "AGV去往满Tray上料位置", true)]
        public ProcessResponse AGV_LoadFullTray(IOperationConfig config, IDevice device)
        //[ProcessMethod("", "AGV_LoadFullTray", "AGV去往满Tray上料位置", true)]
        public void AGV_LoadFullTray(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 as AGVBindOpConfig).Position;
            //PathPosition position = (config as AGVBindOpConfig).Position;
            if (position == null)
            {
@@ -782,14 +860,35 @@
            bind.AGVStatus = TaskStatus.Running;
            return new ProcessResponse(true);
            //return new ProcessResponse(true);
        }
        [ProcessMethod("", "Robot_LoadFullTray", "机器人运动至满Tray拍照位置", true)]
        public ProcessResponse Robot_LoadFullTray(IOperationConfig config, IDevice device)
        //[ProcessMethod("", "Robot_LoadFullTray", "机器人运动至满Tray拍照位置", 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 == (config as AGVBindOpConfig).BindId);
            PathPosition position = Config.PositionCollection.FirstOrDefault(u => u.Description == PathPositionDefinition.LoadFullTray && u.PositionCode == bind.AGV.CurrentPosition);
            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)
            {
@@ -803,8 +902,6 @@
            bind.RobotStatus = TaskStatus.Running;
            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LoadFullTraySnap, position.PositionNo);
            return new ProcessResponse(true);
        }
        //[ProcessMethod("", "Camera_LoadFullTray", "相机确认满Tray上料机器人位置调整", true)]
@@ -883,49 +980,60 @@
                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($"未配置Camera_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($"未配置Camera_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 = 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 });
            RobotMsg_LoadFullTray.Action = RobotMsgAction.Load;
            RobotMsg_LoadFullTray.Para1 = RobotMsgParas.FullTray;
            RobotMsg_LoadFullTray.Para2 = position.PositionNo;
            RobotMsg_LoadFullTray.Datas = new List<float>() { (float)dx_Robot.D, (float)dy_Robot.D, angle }.ConvertAll(s => s.ToString()).ToList();
            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);
@@ -933,10 +1041,28 @@
        #endregion
        #region 满Tray产线下料
        [ProcessMethod("", "AGV_UnloadFullTray", "AGV去往卸载满Tray料", true)]
        public ProcessResponse AGV_UnloadFullTray(IOperationConfig config, IDevice device)
        //[ProcessMethod("", "AGV_UnloadFullTray", "AGV去往卸载满Tray料", 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);
        //    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 void 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)
@@ -948,15 +1074,34 @@
            bind.AGV.TaskOrder(position.PositionCode);
            bind.AGVStatus = TaskStatus.Running;
            return new ProcessResponse(true);
        }
        [ProcessMethod("", "Robot_UnloadFullTray", "机器人卸载满Tray", true)]
        public ProcessResponse Robot_UnloadFullTray(IOperationConfig config, IDevice device)
        //[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 (bind.AGV.CurrentPosition != position.PositionCode)
        //    {
        //        throw new ProcessException("AGV当前未处于满Tray下料点");
        //    }
        //    bind.RobotStatus = TaskStatus.Running;
        //    bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LineSnap, position.PositionNo);
        //    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)
            {
@@ -970,8 +1115,6 @@
            bind.RobotStatus = TaskStatus.Running;
            bind.Robot.SendMsg(RobotMsgAction.Move, RobotMsgParas.LineSnap, position.PositionNo);
            return new ProcessResponse(true);
        }
        //[ProcessMethod("", "Camera_UnloadFullTray", "相机操作卸载满Tray", true)]
@@ -991,52 +1134,64 @@
                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 adjust_X = 0.0f;
            //float adjust_Y = 0.0f;
            //float adjust_Angle = 0.0f;
            bool isLineReady = false;
            int reTryTime = Config.LineBusyRetryTimes;
            do
            if (Config.IsEnableVisionGuide)
            {
                using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadFullTray"))
                PositionVisionConfig visionConfig = Config.VisionConfigCollection.FirstOrDefault(u => u.PositionCode == position.PositionCode && u.CameraId == bind.CameraId);
                if (visionConfig == null)
                {
                    string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
                    if (!_halconToolDict.ContainsKey(toolPath))
                    throw new ProcessException("未配置该相机的满Tray下料点的视觉操作配置");
                }
                int reTryTime = Config.LineBusyRetryTimes;
                do
                {
                    using (HObject hImage = CollectHImage(bind.Camera, visionConfig.CameraOpConfig, "Camera_UnloadFullTray"))
                    {
                        throw new ProcessException($"未配置Camera_UnloadFullTray的视觉算法路径");
                        string toolPath = visionConfig.CameraOpConfig.AlgorithemPath;
                        if (!_halconToolDict.ContainsKey(toolPath))
                        {
                            throw new ProcessException($"未配置Camera_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;
                    }
                    _halconToolDict[toolPath].SetDictionary(new Dictionary<string, HTuple>() { { "OUTPUT_Result", new HTuple() } }, new Dictionary<string, HObject>() { { "INPUT_Image", hImage } });
                    _halconToolDict[toolPath].RunProcedure();
                    if (!isLineReady)
                    {
                        Thread.Sleep(Config.LineBusyWaitInterval * 1000);
                        reTryTime--;
                    }
                    else
                    {
                        reTryTime = 0;
                    }
                } while (reTryTime > 0);
                    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" });
            //}
                //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)
            {
@@ -1052,9 +1207,15 @@
        #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() { }
src/Bro.Device.AuboRobot/AuboRobotConfig.cs
@@ -92,7 +92,7 @@
                    while (res.Length < 11)
                    {
                        res = "0" + s;
                        res = "0" + res;
                    }
                    return res;
                }));
src/Bro.Device.AuboRobot/AuboRobotDriver.cs
@@ -34,6 +34,8 @@
        protected override void Init()
        {
            oldValues = new List<int>();
            if (string.IsNullOrWhiteSpace(IConfig.EndChar))
            {
                throw new ProcessException("协议文本的结束字符不可为空,请检查配置", null);
@@ -72,7 +74,10 @@
        protected override void Stop()
        {
            client.Close();
            if (client != null && client.Connected)
            {
                client.Close();
            }
        }
        #endregion
@@ -90,30 +95,41 @@
            {
                OnLog?.Invoke(DateTime.Now, this, ex.GetExceptionMessage());
                if (client != null && client.Connected)
                {
                    client.Close();
                }
                client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
            }
        }
        private void OnDateReceived(IAsyncResult ar)
        {
            int dataLength = client.GetStream().EndRead(ar);
            if (dataLength > 0)
            try
            {
                byte[] data = buffer.Take(dataLength).ToArray();
                int dataLength = client.GetStream().EndRead(ar);
                string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim();
                AnalyzeData(dataStr);
                client.GetStream().BeginRead(buffer, 0, buffer.Length, OnDateReceived, null);
            }
            else
            {
                if (!client.Connected)
                if (dataLength > 0)
                {
                    OnLog?.Invoke(DateTime.Now, this, "返回空数据,连接中断");
                    client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
                    byte[] data = buffer.Take(dataLength).ToArray();
                    string dataStr = System.Text.Encoding.ASCII.GetString(data).Trim();
                    AnalyzeData(dataStr);
                    client.GetStream().BeginRead(buffer, 0, buffer.Length, OnDateReceived, null);
                }
                else
                {
                    if (!client.Connected)
                    {
                        OnLog?.Invoke(DateTime.Now, this, "返回空数据,连接中断");
                        client.BeginConnect(IPAddress.Parse(IConfig.RobotIP), IConfig.RobotPort, OnConnect, null);
                    }
                }
            }
            catch (Exception ex)
            {
                OnLog?.Invoke(DateTime.Now, this, $"{Name}数据接收异常:{ex.GetExceptionMessage()}");
            }
        }
@@ -173,7 +189,7 @@
                             for (int i = resultStr.Length - 1; i >= 0; i--)
                             {
                                 newValues.Add(resultStr[i]);
                                 newValues.Add(int.Parse(resultStr[i].ToString()));
                             }
                             monitorHandle.Set();
@@ -248,17 +264,18 @@
            if (isMonitorMsg && !canMonitor)
                return;
            lock (this)
            //lock (this)
            {
                client.GetStream().Write(bytes, 0, bytes.Length);
                if (isWaitReply)
                {
                    replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
            }
                    if (replyHandleList.Contains(msg.ID))
                    {
                        throw new ProcessException("反馈数据超时\r\n" + msg.GetDisplayText(), null);
                    }
            if (isWaitReply)
            {
                replyHandleDict[msg.ID].WaitOne(IConfig.ReplyTimeout);
                if (replyHandleList.Contains(msg.ID))
                {
                    throw new ProcessException("反馈数据超时\r\n" + msg.GetDisplayText(), null);
                }
            }
        }
@@ -272,8 +289,9 @@
        AutoResetEvent monitorHandle = new AutoResetEvent(false);
        public List<int> GetMonitorValues(int startAddress, int length)
        {
            scanMsg.ID = SID;
            SendMsg(scanMsg, true, true);
            monitorHandle.WaitOne();
            monitorHandle.WaitOne(IConfig.ReplyTimeout);
            return newValues;
        }
@@ -288,6 +306,11 @@
                    if (newValues == null || newValues.Count == 0)
                        continue;
                    if (oldValues.Count == 0)
                    {
                        oldValues = newValues.ConvertAll(s => -1).ToList();
                    }
                    if (oldValues.Count == newValues.Count)
                    {
@@ -310,6 +333,11 @@
        {
            IConfig.MonitorSetCollection.ForEach(m =>
            {
                if (m.TriggerIndex < 0 || m.TriggerIndex >= tempNew.Count)
                {
                    return;
                }
                int newValue = tempNew[m.TriggerIndex];
                int oldValue = tempOld[m.TriggerIndex];
src/Bro.Device.SeerAGV/SeerAGVConfig.cs
@@ -62,7 +62,7 @@
        }
        public int SyncHead { get; set; } = 0x5A;
        public int Version { get; set; }
        public int Version { get; set; } = 0x01;
        public int SeqNum { get; set; }
        public int DataLength { get; set; }
        public int TypeCode { get; set; }
src/Bro.Device.SeerAGV/SeerAGVDriver.cs
@@ -36,13 +36,13 @@
        protected override void Init()
        {
            InitialTcpClient(client_State, IConfig.StatusPort);
            InitialTcpClient(client_Guide, IConfig.GuidePort);
            InitialTcpClient(ref client_State, IConfig.StatusPort);
            InitialTcpClient(ref client_Guide, IConfig.GuidePort);
        }
        private void InitialTcpClient(TcpClient client, int port)
        private void InitialTcpClient(ref TcpClient client, int port)
        {
            if (client == null || !client_State.Connected)
            if (client == null || !client.Connected)
            {
                client = new TcpClient();
                client.SendBufferSize = client.ReceiveBufferSize = 0;
@@ -73,7 +73,18 @@
        protected override void Stop()
        {
            throw new NotImplementedException();
            if (client_Guide != null && client_Guide.Connected)
            {
                CancelTask();
                client_Guide.Close();
                client_Guide = null;
            }
            if (client_State != null && client_State.Connected)
            {
                client_State.Close();
                client_State = null;
            }
        }
        #endregion
@@ -137,10 +148,17 @@
        {
            while (CurrentState != EnumHelper.DeviceState.DSClose && CurrentState != EnumHelper.DeviceState.DSExcept)
            {
                SendMsg(client_State, IConfig.StatusPort, msg_Position);
                Thread.Sleep(IConfig.ScanInterval);
                SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus);
                Thread.Sleep(IConfig.ScanInterval);
                try
                {
                    SendMsg(client_State, IConfig.StatusPort, msg_Position);
                    Thread.Sleep(IConfig.ScanInterval);
                    SendMsg(client_State, IConfig.StatusPort, msg_GuideStatus);
                    Thread.Sleep(IConfig.ScanInterval);
                }
                catch (Exception ex)
                {
                    OnLog?.Invoke(DateTime.Now, this, $"{Name}监听异常:{ex.GetExceptionMessage()}");
                }
            }
        }
@@ -152,7 +170,7 @@
            {
                try
                {
                    InitialTcpClient(client, port);
                    InitialTcpClient(ref client, port);
                    var stream = client.GetStream();
                    stream.Write(msg.Frame, 0, msg.Frame.Length);
@@ -162,8 +180,7 @@
                    {
                        byte[] rec = buffer.Take(recSize).ToArray();
                        SeerMessage recMsg = SeerMessage.GetSeerMessage(rec);
                        if (recMsg.TypeCode != msg.TypeCode || recMsg.SeqNum != msg.SeqNum)
                        if (recMsg.TypeCode != (10000 + msg.TypeCode) || recMsg.SeqNum != msg.SeqNum)
                        {
                            throw new ProcessException("反馈信息和发送信息不一致", null);
                        }
@@ -206,7 +223,7 @@
        {
            await Task.Run(() =>
            {
                switch (recMsg.TypeCode)
                switch (recMsg.TypeCode - 10000)
                {
                    case (int)AGVCode.QueryPosition:
                        CurrentPosition = recMsg.JValues.Value<string>("current_station");