using Cowain.Bake.BLL; using Cowain.Bake.Common; using Cowain.Bake.Common.Core; using Cowain.Bake.Common.Enums; using Cowain.Bake.Common.Interface; using Cowain.Bake.Common.Models; using Cowain.Bake.Communication.Interface; using Cowain.Bake.Communication.MOM; using Cowain.Bake.Main.ViewModels; using Cowain.Bake.Model; using Cowain.Bake.Model.Entity; using Cowain.Bake.Model.Models; using HslCommunication; using Newtonsoft.Json; using Opc.Ua; using Prism.Ioc; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Unity; using JSON = Newtonsoft.Json.JsonConvert; namespace Cowain.Bake.Main.Station { public class TaskStation: IServerManager { public string Name { get; set; } static Int16 _lastStepId = 0; public IUnityContainer _unityContainer { get; set; } readonly CancellationTokenSource cts = new CancellationTokenSource(); readonly TDeviceConfig config; IPLCDevice agv = null; readonly List _stationCavity; public List _station = null; public AutoResetEvent _newTaskEvent = new AutoResetEvent(true); public TaskStation(IUnityContainer unityContainer) { _unityContainer = unityContainer; _station = _unityContainer.Resolve().AllStation; config = _unityContainer.Resolve().GetConfig(EDeviceType.PLC, EDeviceName.AGV)[0]; _stationCavity = _unityContainer.Resolve().GetAllStation(); Start(); StartNewTask(); } public void Start() { var task = _unityContainer.Resolve().UnexecuteTask(); if (null == task) { _lastStepId = (int)ETaskStep.None; } else { _lastStepId = (short)task.StepId; } agv = _unityContainer.Resolve(config.Name); //TTaskRecord task = await GenerateTask(); #测试 } public async Task DealTask(DataValue data, Variable node) { bool dealResult = false; //进去这里,看会不会触发别的 LogHelper.Instance.Info($"开始任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId},{node.VarDesc}"); do { // 启动任务并等待结果 //dealResult = await Task.Run(() => ThreadDealTask(data, node)); dealResult = ThreadDealTask(data, node); if (!dealResult) { LogHelper.Instance.Error("-------------------------处理任务异常!"); await Task.Delay(2 * 1000); } } while(!dealResult); LogHelper.Instance.Info($"完成任务--------------信号,线程ID:{System.Threading.Thread.CurrentThread.ManagedThreadId}"); } void StartNewTask() { Task.Run( () => { agv = _unityContainer.Resolve(config.Name); while (!cts.Token.IsCancellationRequested) { if (Global.AppExit) { return; } DealNewTask(); } }); } public void DealNewTask() { _newTaskEvent.WaitOne(10*1000); Variable nodeTemp = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务 from item in secondaryList.VariableList where item.ParamName == EAgvPLC.RetCount.ToString() select item).FirstOrDefault(); Variable node = BasicFramework.DeepCopy(nodeTemp); if (null == node || !node.Quality || null == node.CurValue) //无值,退出 { return; } TTaskRecord oldTask = _unityContainer.Resolve().UnexecuteTask(); //1.有任务 + 自动 ,退出 //2.有任务 + 手动 + 任务执行中: 退出 if (null != oldTask) { if (oldTask.Status != (int)ETaskStatus.UnExecute) { return; } } TaskEntity task = GetTask(); if (null == task) { return; } CommonCoreHelper.Instance.BlockTask.Add(task); //更新界面(任务未执行) SetCount(node); _lastStepId = (int)ETaskStep.MoveFrom; //StepId:手动第一次为1,自动第一次为10 if (!SendNextStep(task, node.Json, false)) //发送第一步 { return; //发送失败 } //一条任务第一次发任务时 if (!_unityContainer.Resolve().ModifyTaskStatus(ETaskStatus.Executing)) //更新任务状态为执行中 { LogHelper.Instance.Fatal("更改任务状态失败"); } CommonCoreHelper.Instance.BlockTask.Add(task); //任务没有执行完。所以不需要更新界面 } void SetCount(Variable node) { var model = agv.Read(node.Address + node.VarName); if (!model.IsSuccess || 1 != model.Content) { SettingProvider.Instance.CountCmd = 0; //每条任务从1开始 } else { SettingProvider.Instance.CountCmd = 100; } } private TaskEntity GetTask() { if (SettingProvider.Instance.DispMode == EDispatchMode.Auto) { var oldTask = _unityContainer.Resolve().UnexecuteTask(); if (oldTask != null) { return GetStationManualTask(oldTask); } //看到过有任务还生成 return _unityContainer.Resolve().GetTask(); //获得调度任务,并插入一条任务进任务记录表 } else //手动从数据库获取 { TTaskRecord manualTask = _unityContainer.Resolve().UnexecuteTask(); if (null == manualTask) { return null; //没有任务(手动任务),就退出 } return GetStationManualTask(manualTask); } } /* //1.执行中:机器人正在执行任务中, 如果上位机重启,会触发, //2.无务任或任务执行完成:计命令计算为0或最后一步执行完成,更新状态(无任务不需要),生成任务,下发下一步指令 //3.一步任务完成: 更新状态, 下发下一步指令 */ public bool ThreadDealTask(DataValue data, Variable node) { string msg = ""; LogHelper.Instance.Error("开始接收调度机器人信息!"); Int16 countValue ; dynamic d = JsonConvert.DeserializeObject(node.TrigJson); if (null == agv || !agv.IsConnect) { msg = "连接机器人的PLC断开!"; LogHelper.Instance.Error(msg); _unityContainer.Resolve().AddPromptContent(msg); return false; } try { var stepValue = agv.Read((string)d.ReadCmd); //可以改成直接读PLC [命令地址] var resultValue = agv.Read((string)d.ReadResult); //这是直接读PLC [执行命令结果] if (!stepValue.IsSuccess || !resultValue.IsSuccess) { LogHelper.Instance.Error($"PLC反馈任务时,读取失败!,失败原因:{stepValue.Message},{stepValue.Message}"); return false; } if (data.WrappedValue.TypeInfo.BuiltInType == Opc.Ua.BuiltInType.Int16) { countValue = (Int16)data.WrappedValue.Value; LogHelper.Instance.Debug($"接收任务信息:计数:{countValue},命令步:{stepValue.Content},结果:{resultValue.Content},当前命令步:{_lastStepId},当前计数:{SettingProvider.Instance.CountCmd}"); } else { LogHelper.Instance.Warn($"没有找到这个数据类型,节点名为{node.VarDesc}", true); return false; } if (!EnumHelper.IsDefined(stepValue.Content)) //不在范围内 { LogHelper.Instance.Warn($"获取PLC的命令有问题,值:{countValue}", true); return false; } _unityContainer.Resolve().SetAgvImage(resultValue.Content); if (resultValue.Content == (int)EAgvMoveStatus.Error) // -1:表示没有完成 { //if (countValue > SettingProvider.Instance.CountCmd) 此时上位机是1,PLC是3。 如果执行下面,后续PLC执行1,就不会任务了 //{ // SettingProvider.Instance.CountCmd = countValue; // LogHelper.Instance.Debug($"更改当前计数:{SettingProvider.Instance.CountCmd}"); //} return false; } //1.机器人正在执行任务中, 如果上位机重启,此时又有任务 //如果:countValue=3000,Instance.CountCmd=1,时,到下面退出,也不影响。 if (countValue == SettingProvider.Instance.CountCmd - 1) //(重启上位机,任务在执行中) { LogHelper.Instance.Warn($"重启上位机,此时又有任务在执行中!"); return true; } if (_lastStepId == (int)ETaskStep.None) { LogHelper.Instance.Warn($"重启上位机, 没有任务在执行!"); return true; } //表示执行完成了,执行下一个; 或无任务 if ( countValue >= SettingProvider.Instance.CountCmd && stepValue.Content == _lastStepId ) { SettingProvider.Instance.CountCmd = countValue; //PLC跳步 TTaskRecord task = _unityContainer.Resolve().UnexecuteTask(); if (null == task) //无任务:不需要做什么,有任务:更新状态 { LogHelper.Instance.Fatal($"此时应该数据库中要有未执行的任务,计数:{countValue},命令:{stepValue}"); return true; } TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息 detailTask.StepId = (sbyte)stepValue.Content; if (!DealFinishCmd(detailTask, _lastStepId)) { return false; } if (_lastStepId == (int)ETaskStep.Place //表示当前是一个任务的最后一条命令 /* || 0 == countCmd*/) //PLC重启为0,一条完整的任务完成了,将获取最后一条指令 { detailTask.StepId = (int)ETaskStep.Finish; CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示 CommonCoreHelper.Instance.MainViewAutoEvent.Set(); _newTaskEvent.Set(); return true; //完成了一条完整的任务,另外一个方法生成新的任务 } //发送下一步命令 if (!SendNextStep(detailTask, node.Json)) { return false; } CommonCoreHelper.Instance.BlockTask.Add(detailTask); //机器人界面显示 CommonCoreHelper.Instance.MainViewAutoEvent.Set(); LogHelper.Instance.Error("处理完接收调度机器人信息!"); } else { LogHelper.Instance.Error($"接收到的信息PLC的调试任务异常,plc cmd:{stepValue},plc 计数:{countValue};\r" + $"上位机 cmd:{_lastStepId},上位机 计数:{SettingProvider.Instance.CountCmd},正常不会执行到这里!"); } } catch(Exception ex) { LogHelper.Instance.GetCurrentClassError($"{ex.Message}-{ex.StackTrace}"); return false; } return true; } public bool SendNextStep(TaskEntity detailTask, string json, bool next = true) { LogHelper.Instance.Info($"发送步骤:{detailTask.StepId},命令计数:{SettingProvider.Instance.CountCmd}"); detailTask = SetNextStep(detailTask, next); //会设置CountCmd StepId if (!SendTask(detailTask, json)) //发送任务 { LogHelper.Instance.Error($"发送任务信息失败,{JsonConvert.SerializeObject(detailTask)}!"); return false; } _lastStepId = detailTask.StepId; SettingProvider.Instance.CountCmd = detailTask.CountCmd; LogHelper.Instance.Debug($"计数改变:{SettingProvider.Instance.CountCmd}"); return StartStep(detailTask); } public bool ManualTaskCmd(TTaskRecord task, short stepId) //界面上指定再发送一次时, { Variable nodeCountCmd = (from secondaryList in agv.Storages //不能做触发,因为没有任务。要地直运行里面,来检测是否有任务 from item in secondaryList.VariableList where item.ParamName == EAgvPLC.RetCount.ToString() select item).FirstOrDefault(); _lastStepId = (short)stepId; TaskEntity detailTask = GetStationManualTask(task); //通过任务,获取工站信息 return SendNextStep(detailTask, nodeCountCmd.Json, false); } bool DealFinishCmd(TaskEntity detailTask, Int16 cmdValue) { if (0 >= _unityContainer.Resolve().UpdateEndTime(detailTask.Id, (ETaskStep)cmdValue)) { LogHelper.Instance.Error($"修改命令结束时间失败!任务ID:{detailTask.Id},命令:{_lastStepId}"); } return UpdateFinishStep(detailTask); } bool StartStep(TaskEntity detailTask) { if (0 >= _unityContainer.Resolve().UpdateStartTime((int)detailTask.Id, detailTask.CountCmd, detailTask.StepId)) { LogHelper.Instance.Error($"修改命令开始时间失败!任务ID:{detailTask.Id},命令:{detailTask.StepId},命令计算:{detailTask.CountCmd}"); return false; } return true; } bool UpdateFinishStep(TaskEntity stationTask) { int result = 0; switch (stationTask.StepId) { case (int)ETaskStep.MoveFrom: //修改机器人的位置,给界面发信号 result =_unityContainer.Resolve().SetRobotPos(stationTask.FromStationNumber); break; case (int)ETaskStep.Pick: UpdateOutStoveTime(stationTask); //更改出炉时间 result = _unityContainer.Resolve().BindPalletToRobot(); //将夹具绑定在机器人上 break; case (int)ETaskStep.MoveTo: result = _unityContainer.Resolve().SetRobotPos(stationTask.ToStationNumber); break; case (int)ETaskStep.Place: result = _unityContainer.Resolve().UpdateTask(); //1.加锁,解锁,2.绑定,解绑夹具,3.更新机器人的位置,4.更新任务状态完成, SendIntoStove(stationTask); //如果是满载夹具,要将调用烘烤进站接口 _unityContainer.Resolve().UpdateFinishStepId(stationTask.Id); //修改任务步为完成 break; default: break; } if (result <= 0) { LogHelper.Instance.Error($"接到任务完成,但处理异常:{result},cmd:{stationTask.StepId}"); //return false; } return true; } void UpdateOutStoveTime(TaskEntity stationTask) { var cavityStove = _stationCavity.Where(x => x.Id == stationTask.Source && x.Type == (int)EStationType.Stove).FirstOrDefault(); if (null != cavityStove) //更改出炉时间 { _unityContainer.Resolve().UpdateOutStoveTime(cavityStove.PalletId); } } void SendIntoStove(TaskEntity stationTask) { //if (!_unityContainer.Resolve().IsPullInBaker(stationTask.TaskTypeId)) if (1 != stationTask.TaskTypeId)// 1: 上料满夹具->烤箱 { return ; } var cavityInfo = _stationCavity.Where(x=>x.Id == stationTask.Target).FirstOrDefault(); var palletInfo = _unityContainer.Resolve().GetPalletInfo(stationTask.PalletId); List batteryCodes = _unityContainer.Resolve().GetBatteryInfos(palletInfo.VirtualId).Select(x=>x.BatteryCode).ToList(); if (int.Parse(_unityContainer.Resolve().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable && 0 != batteryCodes.Count) { _unityContainer.Resolve().MESBakingInput(cavityInfo.CavityName, palletInfo.PalletCode, batteryCodes, _unityContainer.Resolve().CurrentOperation); } } public TaskEntity GetStationManualTask(TTaskRecord task) { TaskEntity taskEn = JSON.DeserializeObject(JSON.SerializeObject(task)); var sourceDetail = _unityContainer.Resolve().GetStationDetailById(task.Source); var targetDetail = _unityContainer.Resolve().GetStationDetailById(task.Target); var stationTask = MakeManualTask(taskEn, sourceDetail, targetDetail); //stationTask.Copy(task, stationTask); return stationTask; } TaskEntity SetNextStep(TaskEntity task, bool isNext = true) { sbyte nextStepId = (sbyte)_lastStepId; if (isNext) { nextStepId = (sbyte)_unityContainer.Resolve().GetNext(_lastStepId); //下一步 } task.CountCmd = SettingProvider.Instance.CountCmd + 1; //下一个计数 task.StepId = (sbyte)nextStepId; return task; } public TaskEntity MakeManualTask(TaskEntity taskEn, TCavityInfo src, TCavityInfo desc) { taskEn.FromStationNumber = src.StationNumber; taskEn.FromRow = src.Layer; taskEn.FromColumn = src.Column; taskEn.ToStationNumber = desc.StationNumber; taskEn.ToRow = desc.Layer; taskEn.ToColumn = desc.Column; return taskEn; } public bool SendTask(TaskEntity task, string json) { LogHelper.Instance.Info($"发送任务开始"); List makeAddrValues = new List(); dynamic d = JsonConvert.DeserializeObject(json); string fromStation = d.FromStation; string fromLayer = d.FromRow; string fromColumn = d.FromColumn; string toStation = d.ToStation; string toLayer = d.ToRow; string toColumn = d.ToColumn; string cmd = d.Cmd; string countAddr = d.Count; makeAddrValues.Add(new AddrValue() { Addr = fromStation, Value = (int)task.FromStationNumber, }); var from = _station.Where(p => p.Id == (int)task.FromStationNumber).FirstOrDefault(); if (from.Type == (int)EStationType.Loading || from.Type == (int)EStationType.UnLoading) { makeAddrValues.Add(new AddrValue() { Addr = fromLayer, Value = (int)task.FromRow, }); makeAddrValues.Add(new AddrValue() { Addr = fromColumn, Value = (int)task.FromColumn, }); } else { makeAddrValues.Add(new AddrValue() { Addr = fromLayer, Value = (int)task.FromColumn, }); makeAddrValues.Add(new AddrValue() { Addr = fromColumn, Value = (int)task.FromRow, }); } makeAddrValues.Add(new AddrValue() { Addr = toStation, Value = (int)task.ToStationNumber, }); var to = _station.Where(p => p.Id == (int)task.ToStationNumber).FirstOrDefault(); if (to.Type == (int)EStationType.Loading || to.Type == (int)EStationType.UnLoading) { makeAddrValues.Add(new AddrValue() { Addr = toLayer, Value = (int)task.ToRow, }); makeAddrValues.Add(new AddrValue() { Addr = toColumn, Value = (int)task.ToColumn, }); } else { makeAddrValues.Add(new AddrValue() { Addr = toLayer, Value = (int)task.ToColumn, }); makeAddrValues.Add(new AddrValue() { Addr = toColumn, Value = (int)task.ToRow, }); } makeAddrValues.Add(new AddrValue() { Addr = cmd, Value = (Int16)task.StepId, }); //makeAddrValues.Add(new AddrValue() //{ // Addr = countAddr, // Value = (Int16)task.CountCmd, //必须最后一个写 //}); OperateResult result = agv.Writes(makeAddrValues.Select(x => x.Addr).ToArray(), makeAddrValues.Select(x => x.Value).ToArray()); if (!result.IsSuccess) { LogHelper.Instance.Fatal($"写任务步骤失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}"); } result = agv.Write(countAddr, (Int16)task.CountCmd); if (!result.IsSuccess) { LogHelper.Instance.Fatal($"写任务计数失败:{JsonConvert.SerializeObject(makeAddrValues)},{JsonConvert.SerializeObject(makeAddrValues)}"); } LogHelper.Instance.Debug($"发送任务:{JsonConvert.SerializeObject(makeAddrValues)}"); LogHelper.Instance.Debug($"发送计数:{countAddr}:{(Int16)task.CountCmd}"); //_unityContainer.Resolve().AddLog("TaskStation:SendTask:发送任务结束", E_LogType.Info.ToString()); return result.IsSuccess; } public void Stop() { // 在需要取消任务的时候,调用以下代码: cts.Cancel(); } } }