| | |
| | | using HH.WCS.Mobox3.AnGang.dispatch; |
| | | using HH.WCS.Mobox3.AnGang.models; |
| | | using HH.WCS.Mobox3.AnGang.process; |
| | | using HH.WCS.Mobox3.AnGang.config; |
| | | using Newtonsoft.Json; |
| | | using SqlSugar; |
| | | using System; |
| | |
| | | public static ReturnResult OperateAgvTaskStatus(AgvTaskState model) { |
| | | var result = new ReturnResult(); |
| | | try { |
| | | if (model.state > 0 && model.state < 1000) { |
| | | if (model.state > 0) { |
| | | // AGV 执行任务的逻辑处理 |
| | | if (!AgvTaskProcessOk(model)) { |
| | | // 执行不OK,说明没有找到任务 |
| | |
| | | if (TN_Task.S_TYPE == TaskName.产品入库 || TN_Task.S_TYPE == TaskName.产品部分回库) { |
| | | var captureTask = Task.Run(() => { |
| | | CapturePic(TN_Task); |
| | | LogHelper.Info($"{TN_Task}:拍照Task结束"); |
| | | }); |
| | | } |
| | | |
| | |
| | | var setEndLocTask = Task.Run(() => { |
| | | // 只要任务为产品入库(PDA),就需要重新指定终点(默认endLoc为"") |
| | | SetEndLoc(TN_Task); |
| | | LogHelper.Info("设置终点Task结束"); |
| | | }); |
| | | } |
| | | |
| | | if (TN_Task.S_TYPE == TaskName.产品部分回库) { |
| | | var weightTask = Task.Run(() => { |
| | | UpdateWeight(TN_Task); |
| | | LogHelper.Info("称重Task结束"); |
| | | }); |
| | | } |
| | | |
| | |
| | | break; |
| | | case 2: // 完成 |
| | | WCSHelper.End(TN_Task); // 任务状态改成结束 |
| | | |
| | | break; |
| | | case 7: // 异常 |
| | | TaskProcess.OperateStatus(TN_Task, 7); // 异常处理 |
| | |
| | | public static void CapturePic(TN_Task model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | |
| | | var filepath = SnapManager.GetCapturePicturePath(); |
| | | if (string.IsNullOrEmpty(filepath)) { |
| | | LogHelper.Info("图片地址为空"); |
| | | return; |
| | | try { |
| | | var filepath = SnapManager.GetCapturePicturePath(); |
| | | if (string.IsNullOrEmpty(filepath)) { |
| | | LogHelper.Info("图片地址为空"); |
| | | return; |
| | | } |
| | | |
| | | if (db.Updateable<TN_Loc_Container>() |
| | | .SetColumns(d => d.S_IMG_URL == filepath) |
| | | .Where(d => d.S_CNTR_CODE == model.S_CNTR_CODE).ExecuteCommand() <= 0) { |
| | | |
| | | LogHelper.Info($"图片URL '{filepath}' 写入数据库失败"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (db.Updateable<TN_CG_Detail>() |
| | | .SetColumns(d => d.S_IMG_URL == filepath) |
| | | .Where(d => d.S_CNTR_CODE == model.S_CNTR_CODE).ExecuteCommand() <= 0) { |
| | | |
| | | LogHelper.Info($"图片URL '{filepath}' 写入数据库失败"); |
| | | return; |
| | | catch (Exception ex) { |
| | | LogHelper.Info($"发生了错误:{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | public static void SetEndLoc(TN_Task tn_task) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var endLoc = db.Queryable<TN_Location>() |
| | | .First(a => a.S_CODE == tn_task.S_END_LOC); |
| | | var info = ""; |
| | | try { |
| | | var endLoc = db.Queryable<TN_Location>() |
| | | .First(a => a.S_CODE == tn_task.S_END_LOC); |
| | | |
| | | // 如果已经设置的终点货位,就不要再进入这个流程 |
| | | if (endLoc != null) { |
| | | LogHelper.Info("已经设置了终点货位:" + JsonConvert.SerializeObject(endLoc)); |
| | | return; |
| | | // 如果已经设置的终点货位,就不要再进入这个流程 |
| | | if (endLoc != null) { |
| | | LogHelper.Info("已经设置了终点货位:" + JsonConvert.SerializeObject(endLoc)); |
| | | return; |
| | | } |
| | | |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_CNTR_CODE == tn_task.S_CNTR_CODE).First(); |
| | | |
| | | if (cgDetail == null) { |
| | | LogHelper.Info("设置终点货位失败:当前任务的托盘号在物料表中不存在"); |
| | | return; |
| | | } |
| | | |
| | | var data = GZRobot.CustomBuf(); |
| | | |
| | | if (data.Count == 0) { |
| | | LogHelper.Info("设置终点货位失败:没有接受到来自国自AGV的重量信息"); |
| | | //cgDetail.F_QTY = 0; // 不设置为空,便于测试时预先设置一个正常值 |
| | | } |
| | | else { |
| | | var weight_str = data[0].parameter_varchar200_up.Split(';')[1].Split('-')[1]; |
| | | |
| | | var weight = float.Parse(weight_str); |
| | | cgDetail.F_QTY = weight; |
| | | tn_task.F_WEIGHT = weight; |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => it.F_QTY).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info("修改物料表重量失败"); |
| | | return; |
| | | } |
| | | |
| | | if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => it.F_WEIGHT).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info("修改任务表重量失败"); |
| | | return; |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | } |
| | | |
| | | LogHelper.Info($"修改任务号{tn_task.S_CODE}物料重量为{weight}", "HosttoagvTask"); |
| | | if (weight > 2000) { |
| | | LogHelper.Info($"物料重量超过2t", "HosttoagvTask"); |
| | | } |
| | | } |
| | | |
| | | // 终点货架为空时,不判断,交给人工处理 |
| | | if (tn_task.S_END_LOC == "0") { |
| | | LogHelper.Info("终点货架为空,不处理"); |
| | | return; |
| | | } |
| | | |
| | | if (!int.TryParse(tn_task.S_END_LOC.Trim(), out int row)) { |
| | | LogHelper.Info($"终点货架号 '{tn_task.S_END_LOC}' 无法转成数字"); |
| | | return; |
| | | } |
| | | |
| | | //row -= 100; // 111-118 => 1-8 |
| | | |
| | | // 只当之前指定终点货架后,才尝试计算终点货位 |
| | | if (cgDetail.F_QTY > 2000) { |
| | | // 重量超过 2t |
| | | endLoc = null; |
| | | LogHelper.Info("重量超过2t,不允许入库"); |
| | | |
| | | // 传递给国自AGV |
| | | if (GZRobot.TryGetInteractionInfoId(tn_task.S_CODE, out var id1)) { |
| | | if (GZRobot.UpdateInteractInfo(new UpdateInteractInfo { |
| | | type_name = "GET_DST", |
| | | interaction_info_id = id1, |
| | | info_status = "error", |
| | | })) { |
| | | LogHelper.Info($"国自AGV接受超重取消信息成功", "HosttoagvTask"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"国自AGV接受超重取消信息失败", "HosttoagvTask"); |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"AGV:获取任务{tn_task.S_CODE}的interaction_info_id失败!", "HosttoagvTask"); |
| | | } |
| | | |
| | | return; // 超重会自己return,如果国自agv没接受到也不需要提前return |
| | | } |
| | | else if (cgDetail.F_QTY > 1500) { |
| | | // 重量超过1.5t,需要选择1-2层货架 |
| | | endLoc = db.Queryable<TN_Location>() |
| | | .First(a => a.N_ROW == row && a.N_LAYER <= 2 |
| | | && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y"); |
| | | } |
| | | else if (cgDetail.F_QTY > 0) { |
| | | // 重量未超过1.5t,在指定货架随便选择1个 |
| | | endLoc = db.Queryable<TN_Location>().Where(a => a.N_ROW == row |
| | | && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") |
| | | .OrderBy(a => a.N_LAYER > 2 ? 0 : 1).First(); // 优先选层级高的 |
| | | } |
| | | else { |
| | | // 没有接收到重量,或重量出错 |
| | | endLoc = null; |
| | | LogHelper.Info($"错误的重量信息:{cgDetail.F_QTY}"); |
| | | return; |
| | | } |
| | | |
| | | // 如果没有符合条件的货位,置空,等待PDA重新确定 |
| | | if (endLoc == null) { |
| | | tn_task.S_END_AREA = Settings.Areas[AreaIndex.H货架区][0]; // HJQ |
| | | tn_task.S_END_LOC = "0"; |
| | | |
| | | // 不需要再给GZ AGV传空值,一开始就没给具体货位,只给了Area |
| | | //var request = new UpdateInteractInfo { |
| | | // interaction_info_id = 3, // 更改终点信息 |
| | | // info_status = "active", |
| | | // return_value = "", |
| | | //}; |
| | | //GZRobot.UpdateInteractInfo(request); |
| | | |
| | | if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC }) |
| | | .ExecuteCommand() > 0) { |
| | | //LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 |
| | | LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改成功,修改终点货位为 0空"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改失败,修改终点货位为 0空"); |
| | | } |
| | | } |
| | | else { |
| | | // 找到合适的货位,推送 |
| | | tn_task.S_END_LOC = endLoc.S_CODE; |
| | | |
| | | LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 |
| | | |
| | | // 传递给国自AGV |
| | | if (GZRobot.TryGetInteractionInfoId(tn_task.S_CODE, out var id2)) { |
| | | if (GZRobot.UpdateInteractInfo(new UpdateInteractInfo { |
| | | type_name = "GET_DST", |
| | | interaction_info_id = id2, |
| | | info_status = "invalid", |
| | | return_value = LocationHelper.GetAgvSite(tn_task.S_END_LOC), // 目前使用agvsite |
| | | })) { |
| | | LogHelper.Info($"国自AGV接受终点信息成功", "HosttoagvTask"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"国自AGV接受终点信息失败", "HosttoagvTask"); |
| | | return; |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"AGV:获取任务{tn_task.S_CODE}的interaction_info_id失败!", "HosttoagvTask"); |
| | | return; |
| | | } |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC }) |
| | | .ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info($"计算货位成功,任务'{tn_task.S_CODE}'修改失败,终点货架为{endLoc.N_ROW},修改终点位置为 {endLoc.S_CODE}"); |
| | | } |
| | | if (db.Updateable<TN_Location>(endLoc).UpdateColumns(it => new { |
| | | it.N_LOCK_STATE, |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY |
| | | }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"更新终点货位锁状态失败:起点货位{endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_CNTR_CODE == tn_task.S_CNTR_CODE).First(); |
| | | |
| | | if (cgDetail == null) { |
| | | LogHelper.Info("设置终点货位失败:当前任务的托盘号在物料表中不存在"); |
| | | return; |
| | | catch (Exception ex) { |
| | | LogHelper.Info($"发生了错误:{ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | var data = GZRobot.CustomBuf(); |
| | | public static void UpdateWeight(TN_Task tn_task) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | |
| | | if (data.Count == 0) { |
| | | LogHelper.Info("设置终点货位失败:没有接受到来自国自AGV的重量信息"); |
| | | //return; // TODO 正式运行有国自AGV的时候恢复 |
| | | } |
| | | else { |
| | | var weight = float.Parse(data[0].parameter_varchar200_up); |
| | | try { |
| | | |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_CNTR_CODE == tn_task.S_CNTR_CODE).First(); |
| | | |
| | | if (cgDetail == null) { |
| | | LogHelper.Info("更新物料重量失败:当前任务的托盘号在物料表中不存在"); |
| | | return; |
| | | } |
| | | |
| | | var data = GZRobot.CustomBuf(); |
| | | |
| | | if (data.Count == 0) { |
| | | LogHelper.Info("更新物料重量失败:没有接受到来自国自AGV的重量信息"); |
| | | return; |
| | | } |
| | | var weight_str = data[0].parameter_varchar200_up.Split(';')[1].Split('-')[1]; |
| | | |
| | | var weight = float.Parse(weight_str); |
| | | cgDetail.F_QTY = weight; |
| | | |
| | | if (db.Updateable<TN_CG_Detail>(cgDetail).UpdateColumns(it => it.F_QTY).ExecuteCommand() <= 0) { |
| | | LogHelper.Info("修改物料表重量失败"); |
| | | return; |
| | | } |
| | | |
| | | LogHelper.Info($"修改任务号{tn_task.S_CODE}物料重量为{weight}", "HosttoagvTask"); |
| | | |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Info($"发生了错误:{ex.Message}"); |
| | | } |
| | | |
| | | // 终点货架为空时,不判断,交给人工处理 |
| | | if (tn_task.S_END_LOC == "0") { |
| | | LogHelper.Info("终点货架为空,不处理"); |
| | | return; |
| | | } |
| | | |
| | | if (!int.TryParse(tn_task.S_END_LOC.Trim(), out int row)) { |
| | | LogHelper.Info($"终点货架号 '{tn_task.S_END_LOC}' 无法转成数字"); |
| | | return; |
| | | } |
| | | |
| | | // 只当之前指定终点货架后,才尝试计算终点货位 |
| | | if (cgDetail.F_QTY > 1500) { |
| | | // 重量超过1.5t,需要选择1-3层货架 |
| | | endLoc = db.Queryable<TN_Location>() |
| | | .First(a => a.N_ROW == row && a.N_LAYER <= 3 |
| | | && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y"); |
| | | } |
| | | else if (cgDetail.F_QTY > 0) { |
| | | // 重量未超过1.5t,在指定货架随便选择1个 |
| | | endLoc = db.Queryable<TN_Location>().First(a => a.N_ROW == row |
| | | && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y"); |
| | | } |
| | | else { |
| | | // 没有接收到重量,或重量出错 |
| | | endLoc = null; |
| | | LogHelper.Info($"错误的重量信息:{cgDetail.F_QTY}"); |
| | | return; |
| | | } |
| | | |
| | | // 如果没有符合条件的货位,置空,等待PDA重新确定 |
| | | if (endLoc == null) { |
| | | tn_task.S_END_AREA = "HJQ"; |
| | | tn_task.S_END_LOC = "0"; |
| | | |
| | | // 不需要再给GZ AGV传空值,一开始就没给具体货位,只给了Area |
| | | |
| | | //var request = new UpdateInteractInfo { |
| | | // interaction_info_id = 3, // 更改终点信息 |
| | | // info_status = "active", |
| | | // return_value = "", |
| | | //}; |
| | | |
| | | //GZRobot.UpdateInteractInfo(request); |
| | | if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC }) |
| | | .ExecuteCommand() > 0) { |
| | | //LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 |
| | | LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改成功,修改终点货位为 0空"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"重新计算后没有合适货位,任务 {tn_task.S_CODE} 修改失败,修改终点货位为 0空"); |
| | | } |
| | | } |
| | | else { |
| | | // 找到合适的货位,推送 |
| | | tn_task.S_END_LOC = endLoc.S_CODE; |
| | | |
| | | if (db.Updateable<TN_Task>(tn_task).UpdateColumns(it => new { it.S_END_LOC }) |
| | | .ExecuteCommand() > 0) { |
| | | LocationHelper.LockLoc(endLoc.S_CODE, 1);//终点入库锁 |
| | | LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改成功,终点货架为 {endLoc.N_ROW},修改终点位置为 {endLoc.S_CODE}"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"计算货位成功,任务 {tn_task.S_CODE} 修改失败,终点货架为 {endLoc.N_ROW},修改终点位置为 {endLoc.S_CODE}"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | { |
| | | //使用自定义任务推送 |
| | | TaskProcess.SendTask(task);//调度NDC或杭奥或国自设备 |
| | | //TaskProcess.SendGZTask(task);///调度国自设备 |
| | | |
| | | }); |
| | | } |
| | | else |
| | |
| | | } |
| | | } |
| | | |
| | | public static ReturnResult SafetyInteraction(SafetyInteractionInfo model) { |
| | | var gzResult = new ReturnResult(); |
| | | //var db = new SqlHelper<object>().GetInstance(); |
| | | //ModbusHelper.Relink(); |
| | | |
| | | //var productionLineInfo = Settings.ProductionLines[0]; |
| | | //var prodLineDevice = new ProductionLineDevice(productionLineInfo.PlcIp, productionLineInfo.PlcPort); |
| | | //if (!prodLineDevice.LoadDeviceStateOk()) { |
| | | // LogHelper.Info("加载设备信息失败"); |
| | | //} |
| | | |
| | | //var tn_task = db.Queryable<TN_Task>().First(a => a.S_CODE == model.task_no); |
| | | //if (tn_task == null) { |
| | | // LogHelper.Info($"任务号 '{model.task_no}' 不存在"); |
| | | //} |
| | | |
| | | //if (prodLineDevice.SystemState == 1 |
| | | // && prodLineDevice.FullOffline == 1 && tn_task.S_TYPE == "成品胶下线-托盘(WMS)") { |
| | | // if (!prodLineDevice.SetAgvPicking(1)) { |
| | | // LogHelper.Info("写入输送线 PLC 失败"); |
| | | // } |
| | | //} |
| | | |
| | | //if (prodLineDevice.SystemState == 1 |
| | | // && prodLineDevice.AllowAgvPlacePallet == 1 && tn_task.S_TYPE == "空托盘上线(WMS)") { |
| | | // if (!prodLineDevice.SetAgvPlacingPallet(1)) { |
| | | // LogHelper.Info("写入输送线 PLC 失败"); |
| | | // } |
| | | //} |
| | | |
| | | //LogHelper.Info(JsonConvert.SerializeObject(prodLineDevice, Formatting.Indented)); |
| | | // DOC 4. 站台申请安全交互 RCS->WMS |
| | | public static gzResult SafetyInteraction(SafetyInteractionInfo model) { |
| | | var gzResult = new gzResult() { |
| | | code = 0, |
| | | msg = "success" |
| | | }; |
| | | // 目前该项目没有站台安全交互的功能 |
| | | return gzResult; |
| | | } |
| | | } |