Files
6098/Cowain.Bake.Main/Station/TaskStation.cs

583 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<CavityInfoModel> _stationCavity;
public List<TStation> _station = null;
public AutoResetEvent _newTaskEvent = new AutoResetEvent(true);
public TaskStation(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
_station = _unityContainer.Resolve<MemoryDataProvider>().AllStation;
config = _unityContainer.Resolve<DeviceConfigService>().GetConfig(EDeviceType.PLC, EDeviceName.AGV)[0];
_stationCavity = _unityContainer.Resolve<CavityInfoService>().GetAllStation();
Start();
StartNewTask();
}
public void Start()
{
var task = _unityContainer.Resolve<TaskRecordService>().UnexecuteTask();
if (null == task)
{
_lastStepId = (int)ETaskStep.None;
}
else
{
_lastStepId = (short)task.StepId;
}
agv = _unityContainer.Resolve<IPLCDevice>(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<IPLCDevice>(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<Variable>(nodeTemp);
if (null == node || !node.Quality || null == node.CurValue) //无值,退出
{
return;
}
TTaskRecord oldTask = _unityContainer.Resolve<TaskRecordService>().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<TaskRecordService>().ModifyTaskStatus(ETaskStatus.Executing)) //更新任务状态为执行中
{
LogHelper.Instance.Fatal("更改任务状态失败");
}
CommonCoreHelper.Instance.BlockTask.Add(task); //任务没有执行完。所以不需要更新界面
}
void SetCount(Variable node)
{
var model = agv.Read<Int16>(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<TaskRecordService>().UnexecuteTask();
if (oldTask != null)
{
return GetStationManualTask(oldTask);
}
//看到过有任务还生成
return _unityContainer.Resolve<TaskRecordService>().GetTask(); //获得调度任务,并插入一条任务进任务记录表
}
else //手动从数据库获取
{
TTaskRecord manualTask = _unityContainer.Resolve<TaskRecordService>().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<dynamic>(node.TrigJson);
if (null == agv || !agv.IsConnect)
{
msg = "连接机器人的PLC断开!";
LogHelper.Instance.Error(msg);
_unityContainer.Resolve<MainWindowViewModel>().AddPromptContent(msg);
return false;
}
try
{
var stepValue = agv.Read<Int16>((string)d.ReadCmd); //可以改成直接读PLC [命令地址]
var resultValue = agv.Read<int>((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<ETaskStep>(stepValue.Content)) //不在范围内
{
LogHelper.Instance.Warn($"获取PLC的命令有问题值:{countValue}", true);
return false;
}
_unityContainer.Resolve<EquipmentMonitorViewModel>().SetAgvImage(resultValue.Content);
if (resultValue.Content == (int)EAgvMoveStatus.Error) // -1:表示没有完成
{
//if (countValue > SettingProvider.Instance.CountCmd) 此时上位机是1PLC是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<TaskRecordService>().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<TaskStepService>().UpdateEndTime(detailTask.Id, (ETaskStep)cmdValue))
{
LogHelper.Instance.Error($"修改命令结束时间失败任务ID:{detailTask.Id},命令:{_lastStepId}");
}
return UpdateFinishStep(detailTask);
}
bool StartStep(TaskEntity detailTask)
{
if (0 >= _unityContainer.Resolve<TaskStepService>().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<CavityInfoService>().SetRobotPos(stationTask.FromStationNumber);
break;
case (int)ETaskStep.Pick:
UpdateOutStoveTime(stationTask); //更改出炉时间
result = _unityContainer.Resolve<TaskRecordService>().BindPalletToRobot(); //将夹具绑定在机器人上
break;
case (int)ETaskStep.MoveTo:
result = _unityContainer.Resolve<CavityInfoService>().SetRobotPos(stationTask.ToStationNumber);
break;
case (int)ETaskStep.Place:
result = _unityContainer.Resolve<TaskRecordService>().UpdateTask(); //1.加锁解锁2.绑定解绑夹具3.更新机器人的位置,4.更新任务状态完成,
SendIntoStove(stationTask); //如果是满载夹具,要将调用烘烤进站接口
_unityContainer.Resolve<TaskRecordService>().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<PalletInfoService>().UpdateOutStoveTime(cavityStove.PalletId);
}
}
void SendIntoStove(TaskEntity stationTask)
{
//if (!_unityContainer.Resolve<TaskTypeService>().IsPullInBaker(stationTask.TaskTypeId))
if (1 != stationTask.TaskTypeId)// 1: 上料满夹具->烤箱
{
return ;
}
var cavityInfo = _stationCavity.Where(x=>x.Id == stationTask.Target).FirstOrDefault();
var palletInfo = _unityContainer.Resolve<PalletInfoService>().GetPalletInfo(stationTask.PalletId);
List<string> batteryCodes = _unityContainer.Resolve<BatteryInfoService>().GetBatteryInfos(palletInfo.VirtualId).Select(x=>x.BatteryCode).ToList();
if (int.Parse(_unityContainer.Resolve<SysSetupService>().GetValueByParaID(ESysSetup.MOMEnable.ToString())) == (int)EMOMEnable.Enable
&& 0 != batteryCodes.Count)
{
_unityContainer.Resolve<MESProcess>().MESBakingInput(cavityInfo.CavityName, palletInfo.PalletCode, batteryCodes, _unityContainer.Resolve<BasicInfoViewModel>().CurrentOperation);
}
}
public TaskEntity GetStationManualTask(TTaskRecord task)
{
TaskEntity taskEn = JSON.DeserializeObject<TaskEntity>(JSON.SerializeObject(task));
var sourceDetail = _unityContainer.Resolve<CavityInfoService>().GetStationDetailById(task.Source);
var targetDetail = _unityContainer.Resolve<CavityInfoService>().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<RgvActionService>().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<AddrValue> makeAddrValues = new List<AddrValue>();
dynamic d = JsonConvert.DeserializeObject<dynamic>(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<Int16>(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<LogService>().AddLog("TaskStation:SendTask:发送任务结束", E_LogType.Info.ToString());
return result.IsSuccess;
}
public void Stop()
{
// 在需要取消任务的时候,调用以下代码:
cts.Cancel();
}
}
}