using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using WCS.Data; using WCS.Data.Models; namespace WCS.PLC { public class Srm { #region 属性 /// /// 堆垛机名称 /// internal string SrmNo { get; set; } /// /// plc信息 /// protected WCS_PLC WCS_PLCItem { get { return Current.PlcSet.FirstOrDefault(v => v.PLC_NAME == SrmNo); } } /// /// 堆垛机信号 /// protected SrmSignal EquSignal { get { return WCS_PLCItem.WCS_StackerDataSet[0].StackerData; } } /// /// 写入DB名称 /// protected int WriteDbName { get { return WCS_PLCItem.WCS_DBSet[0].DB_NAME; } } /// /// 堆垛机出入库口设置列表 /// protected List SrmOutInInfoSet = new List(); #endregion; #region 构造函数 public Srm(string srmno) { SrmNo = srmno; } #endregion; #region 方法 private int _locExecute = 0; internal void ExecuteSrm() { if (Interlocked.Exchange(ref _locExecute, 1) == 0) { try { if (WCS_PLCItem.IsConnSuccess == false) return; //写入心跳 //WriteHandShake(); //完成任务 SRMCompleteTask(); //执行任务 SRMStartExecuteTask(); //入库分配货位 ThreadHelper.TaskThread(InTaskAssignWareCell); } catch (Exception ex) { string errormsg = string.Format("堆垛机[{0}]执行异常,消息:{1}", SrmNo, ex.ToString()); Log4netHelper.Logger_Error.ErrorFormat(errormsg); } finally { Interlocked.Exchange(ref _locExecute, 0); } } } /// /// 堆垛机任务完成 /// protected virtual void SRMCompleteTask() { try { //当前任务完成 if (EquSignal.DB521_Task_Finishi == false) return; //查询任务 var task = SugarBase.DB.Queryable().First(v => v.TASK_NO == EquSignal.DB521_Taskfinishi_ID); if (task == null) return; if (task.TASK_WKSTATUS >= 99) return; if (task.TASK_COMTYPE == (int)ComTypeEnum.入库 || task.TASK_COMTYPE == (int)ComTypeEnum.移库) { //完成任务 string result = TryCachHelper.TryTranExecute((db) => { //修改任务的状态 db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = 99, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now }) .Where(it => it.TASK_NO == task.TASK_NO) .ExecuteCommand(); //添加修改明细 string msg = string.Format("任务[{0}]完成", task.TASK_NO); CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, task.TASK_POSIDTO, msg); }); if (string.IsNullOrWhiteSpace(result)) { if (task.TASK_COMTYPE == (int)ComTypeEnum.入库) { SrmConvNoMoveToLast(task.TASK_POSIDCUR); } } } else if (task.TASK_COMTYPE == (int)ComTypeEnum.出库) { if (task.TASK_WKSTATUS == (int)WkStatus.堆垛机执行) { var routeSet = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO); var route = routeSet.FirstOrDefault(v => v.ROUTE_STARTPOS == task.TASK_SRMNO); string result = TryCachHelper.TryTranExecute((db) => { //修改任务的状态 db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = 6, TASK_POSIDCUR = route.ROUTE_NEXTPOS, TASK_POSIDNEXT = route.ROUTE_NEXTPOS, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now }) .Where(it => it.TASK_NO == task.TASK_NO) .ExecuteCommand(); //添加修改明细 string msg = string.Format("任务[{0}]堆垛机完成,修改当前地址为[{1}]", task.TASK_NO, route.ROUTE_NEXTPOS); CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, route.ROUTE_NEXTPOS, route.ROUTE_NEXTPOS, msg); }); if (string.IsNullOrWhiteSpace(result)) { SrmConvNoMoveToLast(task.TASK_POSIDNEXT); } } } //TaskComplete(task.TASK_SRMNO, task.TASK_ID, task.TASK_COMTYPE); } catch (Exception ex) { Log4netHelper.Logger_Error.ErrorFormat(ex.ToString()); } } /// /// 调整堆垛机出入口顺序 /// /// private void SrmConvNoMoveToLast(string convNo) { //检测是否是最后一项 if (SrmOutInInfoSet[SrmOutInInfoSet.Count() - 1].SRMOUTIN_CONVNO == convNo) return; //查询要调整执行顺序的输送线 var outininfo = SrmOutInInfoSet.FirstOrDefault(v => v.SRMOUTIN_CONVNO == convNo); //删除当前 SrmOutInInfoSet.Remove(outininfo); //添加到最后 SrmOutInInfoSet.Add(outininfo); } /// /// 堆垛机执行任务 /// private void SRMStartExecuteTask() { //检测堆垛机模式 if (EquSignal.DB521_Auto_status != (int)SrmModeEnum.远程) return; //检测堆垛机报警 if (EquSignal.SrmDB541_Alarm) return; //检测堆垛机状态 if (EquSignal.DB521_Srm_Status != (int)SrmStateFork1Enum.空闲) return; TryCachHelper.TryExecute((db) => { var taskSet = db.Queryable().Where(v => v.TASK_SRMNO == SrmNo).ToList(); var task = taskSet.FirstOrDefault(v => (v.TASK_WKSTATUS == (int)WkStatus.堆垛机执行)); if (task == null) { //查询移库任务 var moveTask = taskSet.FirstOrDefault(v => v.TASK_COMTYPE == 3 && v.TASK_WKSTATUS <= 1); if (moveTask != null) { WriteTaskInfoToSrm(task); } else { //查询出库任务 var tasks = taskSet.Where(v => v.TASK_COMTYPE == 2 && v.TASK_WKSTATUS <= 1).ToList(); //查询入库任务(已分配货位的任务) var inTasks = taskSet.Where(v => v.TASK_COMTYPE == 1 && v.TASK_WKSTATUS == 11).ToList(); tasks.AddRange(inTasks); OutInStockByPriority(db, tasks); } } else { Log4netHelper.Logger_Error.ErrorFormat(string.Format("堆垛机[{0}]状态正常,但是存在执行中的任务[{1}]", SrmNo, task.TASK_NO)); } }); } private void SrmOutIn(WCSWriteToSrmSignal srmSignal, string posIdnext) { if (EquSignal.DB520_Start_number == srmSignal.Start_number && EquSignal.DB520_End_number == srmSignal.End_number && EquSignal.DB520_Goodtype == srmSignal.Goodtype && EquSignal.DB520_Runmode == srmSignal.Runmode && EquSignal.DB520_FromRowPos == srmSignal.RowPos1 && EquSignal.DB520_FromColumnPos == srmSignal.Travelpos1 && EquSignal.DB520_FromLayerPos == srmSignal.Liftpos1 && EquSignal.DB520_Fork_start_pos1 == srmSignal.Fork_start_pos1 && EquSignal.DB520_ToRowPos == srmSignal.RowPos2 && EquSignal.DB520_ToColumnPos == srmSignal.Travelpos2 && EquSignal.DB520_ToLayerPos == srmSignal.Liftpos2 && EquSignal.DB520_Fork_dest_pos2 == srmSignal.Fork_dest_pos2 && EquSignal.DB520_TaskID == srmSignal.TaskID) { string result = TryCachHelper.TryTranExecute((db) => { var task = db.Queryable().First(t => t.TASK_NO == srmSignal.TaskID); db.Updateable(it => new WCS_TASK() { TASK_WKSTATUS = (int)WkStatus.堆垛机执行, TASK_POSIDNEXT = posIdnext, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now }) .Where(it => it.TASK_NO == srmSignal.TaskID).ExecuteCommand(); string msg = string.Format("任务[{0}]已下发给堆垛机执行。", task.TASK_NO); CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, posIdnext, msg); if (EquSignal.DB520_Task_trigger != 1) { if (!WCS_PLCItem.Plc.WriteSignal((ushort)WriteDbName, 28, 2, 1)) { throw new Exception(string.Format("任务[{0}]写入触发信号失败!", task.TASK_NO)); } } }); if (!string.IsNullOrWhiteSpace(result)) throw new Exception(string.Format("任务[{0}]堆垛机执行失败,原因:[{1}]", srmSignal.TaskID, result)); } else { WriteTaskToSrm(srmSignal); } } /// /// 写入任务信息到堆垛机 /// /// private void WriteTaskInfoToSrm(WCS_TASK task) { var writeSignal = new WCSWriteToSrmSignal(); writeSignal.Start_number = 0; writeSignal.End_number = 0; writeSignal.Goodtype = 0; if (task.TASK_COMTYPE == 1) { //入库 var route = Current.EquRouteSet.FirstOrDefault(v => v.ROUTE_STARTPOS == task.TASK_POSIDCUR); writeSignal.RowPos1 = (int)route.SRMROW; writeSignal.Travelpos1 = (int)route.SRMCOLUMN; writeSignal.Liftpos1 = (int)route.SRMLAYER; writeSignal.RowPos2 = task.ToRow; writeSignal.Travelpos2 = task.ToCol; writeSignal.Liftpos2 = task.ToLayer; } else if (task.TASK_COMTYPE == 2) { //出库 writeSignal.RowPos1 = task.FromRow; writeSignal.Travelpos1 = task.FromCol; writeSignal.Liftpos1 = task.FromLayer; var routeSet = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO); var route = routeSet.FirstOrDefault(v => v.ROUTE_STARTPOS == task.TASK_SRMNO); writeSignal.RowPos2 = (int)route.SRMROW; writeSignal.Travelpos2 = (int)route.SRMCOLUMN; writeSignal.Liftpos2 = (int)route.SRMLAYER; } else if (task.TASK_COMTYPE == 3) { //移库 writeSignal.RowPos1 = task.FromRow; writeSignal.Travelpos1 = task.FromCol; writeSignal.Liftpos1 = task.FromLayer; writeSignal.RowPos2 = task.ToRow; writeSignal.Travelpos2 = task.ToCol; writeSignal.Liftpos2 = task.ToLayer; } writeSignal.TaskID = task.TASK_NO; //执行任务 SrmOutIn(writeSignal, task.TASK_POSIDTO); } private void WriteTaskToSrm(WCSWriteToSrmSignal srmSignal) { List list = new List(); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Start_number).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.End_number).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Goodtype).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Runmode).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.RowPos1).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Travelpos1).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Liftpos1).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Fork_start_pos1).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.RowPos2).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Travelpos2).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Liftpos2).ToList()); list.AddRange(ExtendsUtil.UshortToByte((ushort)srmSignal.Fork_dest_pos2).ToList()); list.AddRange(ExtendsUtil.UintToByte((uint)srmSignal.TaskID).ToList()); Log4netHelper.Logger_Info.InfoFormat(string.Format("写入任务[{0}]信息", srmSignal.TaskID)); bool result = WCS_PLCItem.Plc.Write((ushort)WriteDbName, 2, list.ToArray()); } private void OutInStockByPriority(SqlSugarClient db, List tasks) { int taskMaxPriority = tasks.Max(v => v.TASK_PRIORITY); for (int index = 0; index < taskMaxPriority; index++) { var tasks_Temp = tasks.Where(v => v.TASK_PRIORITY == index).ToList(); if (InOutStock(db, tasks_Temp)) break; } } private bool InOutStock(SqlSugarClient db, List tasks) { bool result = false; if (tasks.Count == 0) return result; //克隆集合 List outininfoSet = SrmOutInInfoSet.GetRange(0, SrmOutInInfoSet.Count); foreach (var outininfo in outininfoSet) { if (outininfo.SRMOUTIN_OUTINTYPE == "in") { //检测入库口状态 var convSignal = ConveyorHelper.GetConveyorSignal(outininfo.SRMOUTIN_CONVPLCNAME, outininfo.SRMOUTIN_CONVNO); if (convSignal.DB521_Tasknum > 0 && convSignal.DB521_Goodsend.ToString() == outininfo.SRMOUTIN_CONVNO) { var curtask = tasks.FirstOrDefault(v => v.TASK_NO == convSignal.DB521_Tasknum); if (curtask != null) { WriteTaskInfoToSrm(curtask); result = true; break; } } } else if (outininfo.SRMOUTIN_OUTINTYPE == "out") { //检测出口状态 var convSignal = ConveyorHelper.GetConveyorSignal(outininfo.SRMOUTIN_CONVPLCNAME, outininfo.SRMOUTIN_CONVNO); if (convSignal.DB521_Request == false && convSignal.DB521_Tasknum <= 0) { var curOutTask = db.Queryable().First(v => v.TASK_POSIDCUR == outininfo.SRMOUTIN_CONVNO); if (curOutTask == null || ((curOutTask.TASK_WKSTATUS != (int)WkStatus.输送机执行) && (curOutTask.TASK_WKSTATUS != (int)WkStatus.堆垛机完成))) { var outtaskSet = new List(); //检测是否存在该出口的任务 foreach (var task in tasks) { var route = EquRouteHelper.QueryRoute(task.TASK_SRMNO, task.TASK_POSIDTO).FirstOrDefault(v => v.ROUTE_STARTPOS == SrmNo); if (route == null) { Log4netHelper.Logger_Error.ErrorFormat(string.Format("任务[{0}]目标地址[{1}]堆垛机[{2}]", task.TASK_NO, task.TASK_POSIDTO, SrmNo)); } if (outininfo.SRMOUTIN_CONVNO == route.ROUTE_NEXTPOS) { //outtask = task; outtaskSet.Add(task); break; } } var temptask = QueryOutTask(db, outtaskSet); if (temptask != null) { WriteTaskInfoToSrm(temptask); result = true; break; } } } } //无任务则移动到最后 SrmConvNoMoveToLast(outininfo.SRMOUTIN_CONVNO); } return result; } private WCS_TASK QueryOutTask(SqlSugarClient db, List outtaskSet) { WCS_TASK temptask = null; var outtasks = QueryOutTask(outtaskSet); foreach (var outtask in outtasks) { if (outtask.FromDepth == 2) { var oneDepthTask = Current.TaskSet.First(v => v.FromRow == outtask.FromSingleDepthRow && v.FromLayer == outtask.FromLayer && v.FromCol == outtask.FromCol && (v.TASK_WKSTATUS <= 1)); if (oneDepthTask == null) { //调用WMS接口申请移库 var moveTaskresult = Current.WmsInterface.I_WCS_GetMoveTask(new GetMoveTaskParam() { WMSTaskNum = outtask.TASK_WMSNO }); if (moveTaskresult.ResType == 0) { Log4netHelper.Logger_Error.ErrorFormat(moveTaskresult.ResMessage); } else if (moveTaskresult.ResType == 2) { //创建移库任务并执行 var moveTask = new WCS_TASK(); db.Insertable(moveTask).ExecuteCommand(); temptask = db.Queryable().First(v => v.TASK_WMSNO == moveTask.TASK_WMSNO); break; } else if (moveTaskresult.ResType == 1) { temptask = outtask; break; } } else { if (oneDepthTask.TASK_COMTYPE == 2) { //判断是否是相同出口的任务 if (outtasks.Any(v => v.TASK_NO == oneDepthTask.TASK_NO)) { temptask = oneDepthTask; } else { var routeSet = EquRouteHelper.QueryRoute(oneDepthTask.TASK_SRMNO, oneDepthTask.TASK_POSIDTO); var route = routeSet.FirstOrDefault(v => v.ROUTE_STARTPOS == outtask.TASK_SRMNO); var outinitem = SrmOutInInfoSet.FirstOrDefault(v => v.SRMOUTIN_CONVNO == route.ROUTE_NEXTPOS); var convs = ConveyorHelper.GetConveyorSignal(outinitem.SRMOUTIN_CONVPLCNAME, outinitem.SRMOUTIN_CONVNO); if (convs.DB521_Tasknum > 0) { var ttask = Current.TaskSet.FirstOrDefault(v => v.TASK_NO == convs.DB521_Tasknum && v.TASK_WKSTATUS == 2); if (ttask != null && ttask.TASK_EDITDATETIME.AddMinutes(3) < db.GetDate()) { //堆垛机出口输送线任务3分钟未执行,//调用WMS接口申请移库任务,同时建议WMS将出库任务修改为移库任务。 //调用WMS接口申请移库 var moveTaskresult = Current.WmsInterface.I_WCS_GetMoveTask(new GetMoveTaskParam() { WMSTaskNum = outtask.TASK_WMSNO }); if (moveTaskresult.ResType == 0) { Log4netHelper.Logger_Error.ErrorFormat(moveTaskresult.ResMessage); } else if (moveTaskresult.ResType == 2) { //创建移库任务并执行 var moveTask = new WCS_TASK(); db.Insertable(moveTask).ExecuteCommand(); temptask = db.Queryable().First(v => v.TASK_WMSNO == moveTask.TASK_WMSNO); break; } else if (moveTaskresult.ResType == 1) { temptask = outtask; break; } } } } } } } } return temptask; } internal virtual List QueryOutTask(List taskSet) { return taskSet.OrderByDescending(v => v.TASK_PRIORITY).OrderBy(v => v.TASK_EDITDATETIME).ToList(); } private int _locInTaskAssignWareCell = 0; /// /// 分配入库货位 /// internal void InTaskAssignWareCell() { if (Interlocked.Exchange(ref _locInTaskAssignWareCell, 1) == 0) { try { var taskSet = Current.TaskSet.Where(v => v.TASK_COMTYPE == 1 && v.TASK_SRMNO == SrmNo && v.TASK_WKSTATUS != 11 && SrmOutInInfoSet.Any(t => t.SRMOUTIN_CONVNO == v.TASK_POSIDCUR && t.SRMOUTIN_OUTINTYPE == "in")) .OrderByDescending(v => v.TASK_PRIORITY).ToList(); foreach (var task in taskSet) { if (string.IsNullOrWhiteSpace(task.TASK_POSIDTO) || task.TASK_POSIDTO == SrmNo) { //入库任务分配货位 GetWareCell(task); } } } catch (Exception ex) { Log4netHelper.Logger_Error.ErrorFormat(ex.ToString()); } finally { Interlocked.Exchange(ref _locInTaskAssignWareCell, 0); } } } public bool GetWareCell(WCS_TASK task) { string resultMsg = string.Empty; //调度接口获取货位 var getWareCell = Current.WmsInterface.I_WCS_GetWareCell(new GetWareCellParam() { WMSTaskNum = task.TASK_WMSNO.ToString(), TunnelNum = task.TASK_SRMNO, PickUpEquipmentNo = task.TASK_POSIDNEXT }); if (getWareCell.ResType) { resultMsg = TryCachHelper.TryTranExecute((db) => { //修改任务分配货位 db.Updateable(it => new WCS_TASK() { TASK_POSIDNEXT = getWareCell.CellNo, TASK_POSIDTO = getWareCell.CellNo, TASK_EDITUSERNO = "WCS", TASK_EDITDATETIME = DateTime.Now }) .Where(it => it.TASK_NO == task.TASK_NO) .ExecuteCommand(); //添加修改明细 string msg = string.Format("任务[{0}]分配货位[{1}]成功。", task.TASK_NO, getWareCell.CellNo); CommonData.AddWCS_TASK_DTL(db, task.TASK_NO, task.TASK_NO, task.TASK_POSIDCUR, task.TASK_POSIDNEXT, msg); }); } else { resultMsg = string.Format("任务[{0}]调用接口分配货位[{1}]失败,原因:{2}", task.TASK_NO, getWareCell.CellNo, getWareCell.ResMessage); Log4netHelper.Logger_Error.ErrorFormat(resultMsg); } if (string.IsNullOrWhiteSpace(resultMsg)) { task.TASK_POSIDNEXT = getWareCell.CellNo; task.TASK_POSIDTO = getWareCell.CellNo; return true; } else { return false; } } #endregion; } }