using HH.WCS.JunzhouNongfu.device;
using HH.WCS.Mobox3.HD.api;
using HH.WCS.Mobox3.HD.device;
using HH.WCS.Mobox3.HD.dispatch;
using HH.WCS.Mobox3.HD.models;
using HH.WCS.Mobox3.HD.util;
using HH.WCS.Mobox3.HD.wms;
using Newtonsoft.Json;
using NLog;
using S7.Net;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static HH.WCS.Mobox3.HD.api.DigitHelper;
using static HH.WCS.Mobox3.HD.core.Monitor;
using static HH.WCS.Mobox3.HD.dispatch.ShopFloorControl;
using static HH.WCS.Mobox3.HD.process.TaskProcess;
using static HH.WCS.Mobox3.HD.util.Settings;
using static HH.WCS.Mobox3.HD.wms.WCSHelper;
using static System.Runtime.CompilerServices.RuntimeHelpers;
namespace HH.WCS.Mobox3.HD.core
{
///
/// 定时轮询任务
///
internal class Monitor
{
// 每十分钟对未连接的pic,尝试进行重新连接
public static void PlcAgainLink()
{
foreach (var item in S7Helper.plcDic)
{
S7Helper.Link(item.Value);
}
}
///
/// 监听分拣区设备和货位,自动发布空盘垛出库任务
///
public static void MonitorSortArea() {
List linePlcInfos = WCSHelper.GetLinePlcInfoList(2);
foreach (var line in linePlcInfos)
{
var wmsTask = WMSHelper.GetWmsTaskByEnd(line.localtion);
if (wmsTask == null) {
// 线体货位
Location location = LocationHelper.GetLoc(line.localtion);
// 线体信号
PipelineSignalInfo lineSignalInfo = WCSHelper.readPipelineInfo(line);
LogHelper.Info("分拣区设备编号:"+ line.deviceNo +"线体编号:" + line.code+",设备信号:" + JsonConvert.SerializeObject(lineSignalInfo), "分拣区");
try
{
if (lineSignalInfo != null)
{
if (lineSignalInfo.agvTaskFeedback == 1 || lineSignalInfo.agvTaskFeedback == 2)
{
// 清除AGV任务反馈
S7Helper.WriteInt(line.deviceNo, 101, line.writeAddr + 14, 0);
LogHelper.Info("清除AGV任务反馈", "分拣区");
}
if (line.actType.Equals("入库"))
{
if (lineSignalInfo.lineState == 0 && lineSignalInfo.linePhotoelectric == 0 && lineSignalInfo.agvInfo == 1)
{
Location endLoc = location;
if (endLoc != null && endLoc.N_LOCK_STATE == 0)
{
Location startLoc = WMSHelper.GetEmptyTrayStartLocation(endLoc.S_CODE);
if (startLoc != null)
{
var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
if (locCntrRels.Count == 1)
{
var cntrItemRels = ContainerHelper.GetCntrItemRel(locCntrRels[0].S_CNTR_CODE);
if (cntrItemRels == null || cntrItemRels.Count == 0)
{
// 外侧接驳位
LogHelper.Info($"分拣区设备编号:{line.deviceNo} ,线体编号:{line.code}", "Mobox");
var connectLocCode = LocationHelper.GetConnectLocation(startLoc.S_AREA_CODE, 2, startLoc.N_ROADWAY, 1).FirstOrDefault(); // 查询接驳位
var connectLoc = LocationHelper.GetLoc(connectLocCode);
if (connectLoc != null)
{
// 内测接驳位
/* string conLocCode = WCSHelper.GetLinePlcInfoByDesc(connectLoc.S_CODE).localtion;
connectLoc = LocationHelper.GetLoc(conLocCode);*/
wmsTask = new WMSTask()
{
S_CNTR_CODE = locCntrRels[0].S_CNTR_CODE,
S_CODE = WMSHelper.GenerateTaskNo(),
S_START_LOC = startLoc.S_CODE,
S_START_AREA = startLoc.S_AREA_CODE,
S_END_LOC = endLoc.S_CODE,
S_END_AREA = endLoc.S_AREA_CODE,
S_TYPE = "空盘垛出库",
S_OP_DEF_NAME = "空盘垛出库",
T_START_TIME = DateTime.Now,
N_PRIORITY = 8,
};
if (WMSHelper.CreateWmsTask(wmsTask))
{
string eqNo = ApiHelper.getEqNo(startLoc.S_AREA_CODE, startLoc.N_ROADWAY);
WCSTask wcsTask = new WCSTask
{
S_OP_NAME = wmsTask.S_OP_DEF_NAME,
S_CODE = WCSHelper.GenerateTaskNo(),
S_TYPE = wmsTask.S_TYPE + "-1",
S_START_LOC = wmsTask.S_START_LOC,
S_START_AREA = wmsTask.S_START_AREA,
S_END_LOC = connectLoc.S_CODE,
S_END_AREA = connectLoc.S_AREA_CODE,
S_CNTR_CODE = wmsTask.S_CNTR_CODE,
S_SCHEDULE_TYPE = "RB",
S_OP_CODE = wmsTask.S_CODE,
S_EQ_NO = eqNo,
N_PRIORITY = wmsTask.N_PRIORITY,
};
if (WCSHelper.CreateTask(wcsTask))
{
// 对开始货位、接驳货位、终点货位进行加锁
LocationHelper.LockLoc(startLoc.S_CODE, 2);
LocationHelper.LockLoc(connectLoc.S_CODE, 1);
// 更新作业任务状态
wmsTask.N_B_STATE = 1;
WMSHelper.UpdateTaskState(wmsTask);
}
}
}
else
{
LogHelper.Info("没有可出库的接驳位", "分拣区");
}
}
}
}
else
{
LogHelper.Info("没有可出库的空盘垛", "分拣区");
}
}
}
}
}
}
catch (Exception ex)
{
LogHelper.Info("监听分拣区错误,错误原因:" + ex.Message, "分拣区");
}
}
}
}
public static Dictionary logisticsTaskIdDict= new Dictionary();
public class NotificationInfo {
public string logisticsTaskId { get; set; }
public string locCode { get; set; }
}
///
/// 定时通知车间下发灵动任务(之前通知失败的任务)
/// 每10秒通知一次,如5分钟内没有通知成功,则不再通知
///
public static void TimerNotification() {
foreach (var item in logisticsTaskIdDict)
{
var notificationResult = ShopFloorControl.notificationCreateTransportOrder(new TransferTiledData() { logisticsTaskId = item.Key.logisticsTaskId });
if (notificationResult)
{
logisticsTaskIdDict.Remove(item.Key);
LogHelper.Info("灵动AGV出库任务已下发,并通知车间下发灵动AGV任务,物流ID:" + item.Key.logisticsTaskId, "输送线");
}
else {
LogHelper.Info("通知车间下发灵动AGV任务失败,已重置发送次数:"+ item.Value / 10000 +",物流ID:" + item.Key.logisticsTaskId, "输送线");
if (item.Value == 300000)
{
logisticsTaskIdDict.Remove(item.Key);
LogHelper.Info("向输送线发送报警信号" + item.Key, "输送线");
LinePlcInfo line = WCSHelper.GetLinePlcInfoByLoc(item.Key.locCode);
S7Helper.WriteInt(line.deviceNo, 101, line.writeAddr + 18, 1);
}
else {
logisticsTaskIdDict[item.Key] = item.Value + 10000;
}
}
}
}
///
/// 监测输送线
///
public static void MonitorPipeline()
{
List linePlcInfos = WCSHelper.GetLinePlcInfoList(1);
LogHelper.Info("-------------------------------------------------------------------------------------", "输送线");
foreach (var line in linePlcInfos)
{
// 线体货位
Location originLocation = LocationHelper.GetLoc(line.localtion);
Location descLocation = LocationHelper.GetLoc(line.descLocation);
LocCntrRel locCntrRel = ContainerHelper.getLocCntrByLoc(originLocation.S_CODE);
// 线体信号
LogHelper.Info("输送线,线体:"+line.code, "输送线");
PipelineSignalInfo lineSignalInfo = WCSHelper.readPipelineInfo(line);
try
{
if (lineSignalInfo != null)
{
LogHelper.Info("000000", "输送线");
if (lineSignalInfo.agvTaskFeedback == 1 || lineSignalInfo.agvTaskFeedback == 2)
{
// 清除AGV任务反馈
S7Helper.WriteInt(line.deviceNo, 101, line.writeAddr + 14, 0);
LogHelper.Info("清除输送线【"+ line.deviceNo + "】的AGV任务反馈", "输送线");
}
if (locCntrRel != null)
{
LogHelper.Info("1111111", "输送线");
if (lineSignalInfo.faultMessage == 1)
{
// 回报车间控制器
LogHelper.Info("输送线,线体【" + line.code + "】调整为手动状态", "输送线");
continue;
}
WMSTask wmsTask = WMSHelper.GetWmsTaskByCntr(locCntrRel.S_CNTR_CODE);
if (wmsTask == null)
{
LogHelper.Info("没有正在执行的任务,货位:" + locCntrRel.S_LOC_CODE + " 容器:" + locCntrRel.S_CNTR_CODE, "输送线");
continue;
}
var date = DateTime.Now.ToString("yyMMdd");
string opTaskId = lineSignalInfo.taskId.ToString().PadLeft(4, '0');
LogHelper.Info("任务号:" + opTaskId, "输送线");
if (line.actType.Equals("入库") && line.sort == 1)
{
// 判断 请求去向 = 1 、线体光电 = 1
if (lineSignalInfo.requestReadCode == 1 && lineSignalInfo.linePhotoelectric == 1)
{
// 向该线体发送指令,任务号,目标地址
var descLinePlcInfo = WCSHelper.GetLinePlcInfo(line.descLocation);
if (locCntrRel.S_CNTR_CODE.Equals(lineSignalInfo.trayCode))
{
issueCommand(line, int.Parse(wmsTask.S_CODE.Substring(8)), (short)descLinePlcInfo.code, 2);
LogHelper.Info("向线体发送入库指令 ,任务号:" + int.Parse(wmsTask.S_CODE.Substring(4)) + ", 目标地址:" + (short)descLinePlcInfo.code, "输送线");
}
else if(lineSignalInfo.receiveInstruction != 3)
{
issueCommand(line, int.Parse(wmsTask.S_CODE.Substring(8)), (short)descLinePlcInfo.code, 3);
LogHelper.Info("托盘码不一致,向线体发送退回指令 ,输送线托盘码:" + lineSignalInfo.trayCode + "任务托盘码:" + locCntrRel.S_CNTR_CODE, "输送线");
TrayErrorFeedbackInfo info = new TrayErrorFeedbackInfo()
{
wmsId = wmsTask.S_CODE,
errMsg = "托盘码错误"
};
ShopFloorControl.trayErrorFeedback(info);
}
}
// 指令已读,清除指令
if (lineSignalInfo.receiveInstruction == 2)
{
issueCommand(line, 0, 0, 0);
LocationHelper.UnBindingLoc(originLocation.S_CODE, new List() { locCntrRel.S_CNTR_CODE });
LocationHelper.BindingLoc(descLocation.S_CODE, new List() { locCntrRel.S_CNTR_CODE });
LogHelper.Info("入库指令已读,清除入库指令", "输送线");
}
else if (lineSignalInfo.receiveInstruction == 3)
{
issueCommand(line, 0, 0, 0);
LogHelper.Info("退回指令已读,清除退回指令", "输送线");
}
try
{
// 更新物料重量数据
LogHelper.Info("更新物料重量数据 ,重量:" + lineSignalInfo.weight, "输送线");
var cntrItemRels = ItemHelper.GetCntrItemByCntrCode(wmsTask.S_CNTR_CODE);
if (cntrItemRels != null && cntrItemRels.Count > 0)
{
foreach (var cntrItemRel in cntrItemRels)
{
cntrItemRel.F_WEIGHT = lineSignalInfo.weight;
if (cntrItemRel.F_INIT_WEIGHT == 0)
{
cntrItemRel.F_INIT_WEIGHT = lineSignalInfo.weight;
}
ItemHelper.updateCntrItem(cntrItemRel);
}
}
// 输送线称重回报车间控制器
LogHelper.Info("输送线称重回报车间控制器", "输送线");
ProductWeightInfo productWeightInfo = new ProductWeightInfo()
{
wmsId = wmsTask.S_CODE,
trayCode = lineSignalInfo.trayCode,
weight = lineSignalInfo.weight.ToString(),
weightTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
};
ShopFloorControl.reportSemilFinishedProductWeight(productWeightInfo);
}
catch (Exception ex) {
LogHelper.Info("输送线称重回报车间控制器错误 ,错误原因:" + ex.Message, "输送线");
}
}
if (line.actType.Equals("入库") && line.sort == 2)
{
// 判断 任务号、目标地址、是否允许堆垛机取货
LogHelper.Info("输送线里侧货位入库" , "输送线");
if (opTaskId == wmsTask.S_CODE.Substring(8) && lineSignalInfo.linePhotoelectric == 1 && lineSignalInfo.ddjInfo == 2)
{
LogHelper.Info("输送线条件满足", "输送线");
WCSTask wcsTask = WCSHelper.GetTaskByStart(originLocation.S_CODE, wmsTask.S_CODE);
if (wcsTask == null)
{
LogHelper.Info("开始下发堆垛机入库任务", "输送线");
string itemCode = null;
var cntrItems = ContainerHelper.GetCntrItemRel(wmsTask.S_CNTR_CODE);
if (cntrItems != null && cntrItems.Count > 0)
{
itemCode = cntrItems[0].S_ITEM_CODE;
}
LogHelper.Info("堆垛机入库任务终点", "输送线");
Location endLoc = WMSHelper.GetEndLocation(wmsTask.S_END_AREA, itemCode, originLocation.N_ROADWAY, originLocation.N_ROW);
LogHelper.Info($"堆垛机入库任务终点:{endLoc.S_CODE}", "输送线");
wmsTask.S_END_LOC = endLoc.S_CODE;
WMSHelper.UpdateTask(wmsTask);
string eqNo = ApiHelper.getEqNo(endLoc.S_AREA_CODE, endLoc.N_ROADWAY);
List areaCdoes = Settings.getStoreAreaCodes(2, 1);
WCSTask twoWcsTask = new WCSTask
{
S_OP_NAME = wmsTask.S_OP_DEF_NAME,
S_OP_CODE = wmsTask.S_CODE,
S_CODE = WCSHelper.GenerateTaskNo(),
S_CNTR_CODE = wmsTask.S_CNTR_CODE,
S_TYPE = wmsTask.S_TYPE + "-2",
S_START_LOC = originLocation.S_CODE,
S_START_AREA = originLocation.S_AREA_CODE,
S_END_LOC = wmsTask.S_END_LOC,
S_END_AREA = wmsTask.S_END_AREA,
S_EQ_NO = eqNo,
S_SCHEDULE_TYPE = "RB",
T_START_TIME = DateTime.Now,
};
if (WCSHelper.CreateTask(twoWcsTask))
{
// 接驳位加出库锁,终点货位加入库锁
LocationHelper.LockLoc(twoWcsTask.S_START_LOC, 2);
LocationHelper.LockLoc(twoWcsTask.S_END_LOC, 1);
LogHelper.Info("堆垛机入库任务已下发,任务信息:" + JsonConvert.SerializeObject(twoWcsTask), "输送线");
}
}
else {
LogHelper.Info("任务已下发", "输送线");
}
}
}
if (line.actType.Equals("出库") && line.sort == 1)
{
if (lineSignalInfo.linePhotoelectric == 1)
{
// 向该线体发送入库指令,任务号,目标地址
var descLinePlcInfo = WCSHelper.GetLinePlcInfo(line.descLocation);
issueCommand(line, int.Parse(wmsTask.S_CODE.Substring(8)), (short)descLinePlcInfo.code, 1);
LogHelper.Info("向线体发送出库指令 ,任务号:" + int.Parse(wmsTask.S_CODE.Substring(8)) + ", 目标地址:" + (short)descLinePlcInfo.code, "输送线");
}
if (lineSignalInfo.receiveInstruction == 1)
{
issueCommand(line, 0, 0, 0);
LocationHelper.UnBindingLoc(originLocation.S_CODE, new List() { locCntrRel.S_CNTR_CODE });
LocationHelper.BindingLoc(descLocation.S_CODE, new List() { locCntrRel.S_CNTR_CODE });
LogHelper.Info("出库指令已读,清除出库指令", "输送线");
}
}
if (line.actType.Equals("出库") && line.sort == 2)
{
// 判断 任务号、目标地址、托盘码、是否允许堆垛机取货
if (opTaskId == wmsTask.S_CODE.Substring(8) && lineSignalInfo.linePhotoelectric == 1 )
{
if (locCntrRel.S_CNTR_CODE.Equals(lineSignalInfo.trayCode))
{
WCSTask wcsTask = WCSHelper.GetTaskByStart(originLocation.S_CODE, wmsTask.S_CODE);
if (wcsTask == null)
{
LogHelper.Info("开始下发灵动AGV出库任务", "输送线");
var twoWcsTask = new WCSTask
{
S_OP_NAME = wmsTask.S_OP_DEF_NAME,
S_CODE = WCSHelper.GenerateTaskNo(),
S_TYPE = wmsTask.S_TYPE + "-2",
S_START_LOC = originLocation.S_CODE,
S_START_AREA = originLocation.S_AREA_CODE,
S_END_LOC = wmsTask.S_END_LOC,
S_END_AREA = wmsTask.S_END_AREA,
S_SCHEDULE_TYPE = "LD",
S_CNTR_CODE = wmsTask.S_CNTR_CODE,
N_CNTR_COUNT = 1,
S_OP_CODE = wmsTask.S_CODE,
N_PRIORITY = wmsTask.N_PRIORITY,
T_START_TIME = DateTime.Now,
};
if (wmsTask.S_TYPE.Equals("半成品/成品出库") || wmsTask.S_TYPE.Equals("叫托盘出库"))
{
twoWcsTask.S_SCHEDULE_TYPE = "LD-AUTO";
}
if (WCSHelper.CreateTask(twoWcsTask))
{
LocationHelper.LockLoc(twoWcsTask.S_START_LOC, 2);
LocationHelper.LockLoc(twoWcsTask.S_END_LOC, 1);
var notificationResult = ShopFloorControl.notificationCreateTransportOrder(new TransferTiledData() { logisticsTaskId = wmsTask.S_OP_DEF_CODE });
if (notificationResult)
{
WCSHelper.UpdateStatus(twoWcsTask,"已推送");
LogHelper.Info("灵动AGV出库任务已下发,并通知车间下发灵动AGV任务,任务信息:" + JsonConvert.SerializeObject(twoWcsTask), "输送线");
}
else
{
NotificationInfo notificationInfo = new NotificationInfo() {
logisticsTaskId = wmsTask.S_OP_DEF_CODE,
locCode = originLocation.S_CODE
};
LogHelper.Info("物流任务信息:" + JsonConvert.SerializeObject(notificationInfo), "输送线");
if (notificationInfo.logisticsTaskId != null && notificationInfo.locCode != null) {
logisticsTaskIdDict.Add(notificationInfo, 0);
}
LogHelper.Info("通知车间下发灵动AGV任务失败,任务信息:" + JsonConvert.SerializeObject(twoWcsTask), "输送线");
}
}
}
}
else
{
LogHelper.Info("托盘码不一致,请进行人工干预 ,输送线托盘码:" + lineSignalInfo.trayCode + "任务托盘码:" + locCntrRel.S_CNTR_CODE, "输送线");
}
}
}
}
// 向数字孪生推送输送线状态信息
MQTTCore.MqttClientService mqttClientService = null;
try
{
SSXStatusInfo info = new SSXStatusInfo()
{
deviceNo = line.code.ToString(),
status = lineSignalInfo.lineState.ToString(),
existCargo = lineSignalInfo.linePhotoelectric.ToString(),
alertorInfo = lineSignalInfo.faultMessage.ToString(),
dataDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
};
MQTTCore.mqqtClients.TryGetValue("数字孪生", out mqttClientService);
mqttClientService.Publish("pipelineStatus", JsonConvert.SerializeObject(info));
}
catch (Exception ex)
{
LogHelper.Error("推送输送线状态信息错误", ex, "数字孪生");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
LogHelper.Info("输送线错误,错误信息:" + ex.Message, "哈电");
}
}
}
///
/// 清除输送线命令
///
///
///
///
///
public static void issueCommand(LinePlcInfo line,int taskId ,short descLine, short command) {
S7Helper.WriteDint(line.deviceNo, 101, line.writeAddr + 2, taskId); // 任务号
S7Helper.WriteInt(line.deviceNo, 101, line.writeAddr + 6, descLine); // 目标线体
S7Helper.WriteInt(line.deviceNo, 101, line.writeAddr + 8, command); // 下发指令(默认=0 入库=2 出库=1 不合格退回=3)
}
public class SSXStatusInfo {
public string deviceNo { get; set; }
public string status { get; set; }
public string existCargo { get; set; }
public string alertorInfo { get; set; }
public string dataDate { get; set; }
}
///
/// 检测堆垛机信号
///
internal static void MonitorDDJSignal()
{
var ddjPlcInfos = Settings.devicePlcInfos.Where(a => a.deviceType == 1).ToList();
foreach (var item in ddjPlcInfos)
{
//1.检测堆垛机信号
LogHelper.Info("读取堆垛机 " + item.deviceNo, "堆垛机");
short[] resSignal1 = S7Helper.ReadInt(item.deviceNo, 551, 0, 8);
int resSignal2 = S7Helper.ReadDint(item.deviceNo, 551, 16);
short[] resSignal3 = S7Helper.ReadInt(item.deviceNo, 551, 20, 3);
LogHelper.Info("读取堆垛机 "+item.deviceNo + " 信号: resSignal1:" + JsonConvert.SerializeObject(resSignal1)+ " resSignal2(任务号):" + JsonConvert.SerializeObject(resSignal2) + " resSignal3:" + JsonConvert.SerializeObject(resSignal3), "堆垛机");
if (resSignal1 != null && resSignal2 != 0 && resSignal3 != null)
{
ResSignalInfo resSignalInfo = new ResSignalInfo()
{
HandShake = resSignal1[0],
SRM_Num = resSignal1[1],
Auto = resSignal1[2],
Alarm_Code = resSignal1[3],
State = resSignal1[4],
TaskStatus1 = resSignal1[5],
Loaded1 = resSignal1[6],
Busines1 = resSignal1[7],
TaskId1 = resSignal2,
Row = resSignal3[0],
Layer = resSignal3[1],
b_Fork1Pos = resSignal3[2],
};
LogHelper.Info("检测堆垛机信号:" + JsonConvert.SerializeObject(resSignalInfo), "堆垛机");
// 3.堆垛机任务处理
taskProcessing(item.deviceNo, resSignalInfo);
}
}
}
///
/// 堆垛机任务处理
///
internal static void taskProcessing(string deviceNo, ResSignalInfo resSignalInfo)
{
// 堆垛机当前模式为联机自动 且 报警代码为1正常
if (resSignalInfo.Auto == 1)
{
// 查询任务
/*var wcsTask = WCSHelper.GetTask("TN25" + resSignalInfo.TaskId1.ToString().PadLeft(9, '0'));*/
LogHelper.Info("任务号:" + resSignalInfo.TaskId1, "堆垛机");
var wcsTask = WCSHelper.GetWcsTask(resSignalInfo.TaskId1.ToString());
if (wcsTask != null)
{
WMSTask wmsTask = WMSHelper.GetWmsTask(wcsTask.S_OP_CODE);
if (resSignalInfo.Alarm_Code == 1)
{
if (wcsTask.N_B_STATE < 3 && wcsTask.S_SCHEDULE_TYPE.Equals("RB"))
{
// 任务状态
switch (resSignalInfo.TaskStatus1)
{
case 1:// 确认接收任务
WCSHelper.Begin(wcsTask);
break;
case 3: // 完成
case 5: // 强制完成
// 1.开始货位解绑、终点货位绑定
LocationHelper.UnBindingLoc(wcsTask.S_START_LOC, new List { wcsTask.S_CNTR_CODE });
LocationHelper.UnLockLoc(wcsTask.S_START_LOC);
LocationHelper.BindingLoc(wcsTask.S_END_LOC, new List { wcsTask.S_CNTR_CODE });
LocationHelper.UnLockLoc(wcsTask.S_END_LOC);
WCSHelper.End(wcsTask);
LogHelper.Info("检测堆垛机任务完成,任务:" + JsonConvert.SerializeObject(wcsTask), "堆垛机");
// 2.判断是一段任务,还是二段任务
if (wmsTask != null && wmsTask.S_END_LOC.Equals(wcsTask.S_END_LOC))
{
wmsTask.N_B_STATE = 2;
wmsTask.T_END_TIME = DateTime.Now;
WMSHelper.UpdateTaskState(wmsTask);
// 2.1更新出入库记录
var cntrItemRels = ItemHelper.GetCntrItemByCntrCode(wcsTask.S_CNTR_CODE);
if (cntrItemRels != null && cntrItemRels.Count > 0)
{
foreach (var cntrItemRel in cntrItemRels)
{
WMSHelper.AddStockRecord(wmsTask, cntrItemRel);
}
}
else
{
WMSHelper.AddStockRecord(wmsTask, null);
}
}
// 3.当收到PLC的完成时(TaskStatus1=3)上位写3确认,PLC收到确认,清除任务状态
S7Helper.WriteInt(deviceNo, 550, 28, 3);
// 4.任务完成,清除堆垛机数据
clearingDDJData(deviceNo);
break;
case 6:
// 取消任务
WCSHelper.Fail(wcsTask);
LocationHelper.UnLockLoc(wcsTask.S_START_LOC);
LocationHelper.UnLockLoc(wcsTask.S_END_LOC);
/* clearingDDJData(deviceNo);*/
// 取消作业
wmsTask.N_B_STATE = 3;
wmsTask.T_END_TIME = DateTime.Now;
WMSHelper.UpdateTaskState(wmsTask);
LocationHelper.UnLockLoc(wmsTask.S_END_LOC);
LogHelper.Info("任务取消,任务号:" + wcsTask.S_CODE, "堆垛机");
break;
}
WCSHelper.AddActionRecord(wcsTask.S_CODE, resSignalInfo.TaskStatus1, wcsTask.S_EQ_NO, null);
}
}
else
{
if (resSignalInfo.Busines1 == 1 || resSignalInfo.Busines1 == 3)
{
// 再清除wcs写入通道内任务数据,同时为该任务计算一个新的放货终点。
var cntrItemRels = ItemHelper.GetCntrItemByCntrCode(wcsTask.S_CNTR_CODE);
Location formerEndLoc = LocationHelper.GetLoc(wcsTask.S_END_LOC);
Location endLoc = WMSHelper.GetEndLocation(formerEndLoc.S_AREA_CODE, cntrItemRels[0].S_ITEM_CODE, formerEndLoc.N_ROADWAY, 1);
wcsTask.S_END_LOC = endLoc.S_CODE;
wcsTask.N_B_STATE = 0;
wcsTask.S_B_STATE = "等待";
wcsTask.N_PRIORITY = 10;
wcsTask.S_ERR = resSignalInfo.Busines1.ToString() + ":满入和放货阻塞报警;阻塞货位:" + formerEndLoc.S_CODE;
WCSHelper.UpdateWcsTask(wcsTask);
LocationHelper.UnLockLoc(formerEndLoc.S_CODE);
LocationHelper.LockLoc(formerEndLoc.S_CODE, 3);
LocationHelper.LockLoc(endLoc.S_CODE, 1);
if (formerEndLoc.S_CODE == wmsTask.S_END_LOC)
{
wmsTask.S_END_LOC = endLoc.S_CODE;
WMSHelper.UpdateTask(wmsTask);
}
// wcs在任务推送后需追加循环读取该地址信号。若为1. 需先写入地址4为12通知堆垛机清除其对应通道任务数据。
S7Helper.WriteInt(deviceNo, 550, 4, 12);
LogHelper.Info("满入和放货阻塞报警", "堆垛机");
}
if (resSignalInfo.Busines1 == 2 || resSignalInfo.Busines1 == 4)
{
/* S7Helper.WriteInt(deviceNo, 550, 4, 12);
var cntrItemRels = ItemHelper.GetCntrItemByCntrCode(wcsTask.S_CNTR_CODE);
LocationHelper.UnLockLoc(formerStartLoc.S_CODE);
LocationHelper.LockLoc(formerStartLoc.S_CODE, 3);*/
Location formerStartLoc = LocationHelper.GetLoc(wcsTask.S_START_LOC);
wcsTask.N_B_STATE = 4;
wcsTask.S_B_STATE = "错误";
wcsTask.S_ERR = resSignalInfo.Busines1.ToString() + ":空取和取货阻塞报警; 取货货位:" + formerStartLoc.S_CODE;
LogHelper.Info("空取和取货阻塞报警", "堆垛机");
}
}
}
else
{
LogHelper.Info($"任务号:{resSignalInfo.TaskId1},未查询到堆垛机任务", "堆垛机");
}
}
// 堆垛机任务状态推送
try
{
// FromWcs(DB550)下发任务数据
short[] resSignal = S7Helper.ReadInt(deviceNo, 550, 8, 8);
// 1.堆垛机状态推送数字孪生
MQTTCore.MqttClientService mqttClientService = null;
DDJStatusInfo info = new DDJStatusInfo()
{
deviceNo = resSignalInfo.SRM_Num.ToString(),
auto = resSignalInfo.Auto.ToString(),
status = resSignalInfo.State.ToString(),
alertorInfo = resSignalInfo.Alarm_Code.ToString(),
Loaded1 = resSignalInfo.Loaded1.ToString(),
Busines1 = resSignalInfo.Busines1.ToString(),
Row = resSignalInfo.Row.ToString(),
Layer = resSignalInfo.Layer.ToString(),
b_Fork1Pos = resSignalInfo.b_Fork1Pos.ToString(),
TaskId1 = resSignalInfo.TaskId1.ToString(),
dataDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
};
if (resSignal != null) {
info.Source_Z_S1 = resSignal[0].ToString();
info.Source_X_S1 = resSignal[1].ToString();
info.Source_Y_S1 = resSignal[2].ToString();
info.Dest_Z_S1 = resSignal[4].ToString();
info.Dest_X_S1 = resSignal[5].ToString();
info.Dest_Y_S1 = resSignal[6].ToString();
}
MQTTCore.mqqtClients.TryGetValue("数字孪生", out mqttClientService);
mqttClientService.Publish("stackerStatus", JsonConvert.SerializeObject(info));
// 2.向数字孪生推送堆垛机任务数据
MQTTCore.mqqtClients.TryGetValue("数字孪生", out mqttClientService);
mqttClientService.Publish("unfinishedTask", JsonConvert.SerializeObject(WCSHelper.getDDJProceedTaskData()));
}
catch (Exception ex)
{
LogHelper.Error("推送堆垛机任务数据错误", ex, "数字孪生");
}
}
public static void clearingDDJData(string plc) {
short HandShake = 0;
short[] handShakeValues = S7Helper.ReadInt(plc, 551, 0, 1);
if (handShakeValues != null)
{
if (handShakeValues[0] == 0)
{
HandShake = 1;
}
else if (handShakeValues[0] == 1)
{
HandShake = 0;
}
}
// TODO s7 wcs -> plc 写入任务
RBWriteTaskInfo rBWriteTaskInfo = new RBWriteTaskInfo()
{
HandShake = HandShake,
SRM_Num = 0,
CommandType = 0,
Source_Z_S1 = 0,
Source_X_S1 = 0,
Source_Y_S1 = 0,
Source_L_S1 = 0,
Dest_Z_S1 = 0,
Dest_X_S1 = 0,
Dest_Y_S1 = 0,
Dest_L_S1 = 0,
Task_S1 = 0, // TODO 任务号待确定
ConfirmSignal1 = 0,
};
RBWriteTask(plc, rBWriteTaskInfo);
LogHelper.Info("堆垛机任务取消或完成,清除数据:" + JsonConvert.SerializeObject(rBWriteTaskInfo), "堆垛机");
}
[SugarTable("TN_Test_StackerCrane")]
public class ResSignalInfo : BaseModel
{
public short HandShake { get; set; } // 心跳
public short SRM_Num { get; set; } // 堆垛机号
public short Auto { get; set; } // 堆垛机当前模式指示 1 联机自动;2手动;3半自动;4维修;
public short Alarm_Code { get; set; } // 堆垛机报警代码 0:默认;1:正常 ;其他数字故障信息
public short State { get; set; } // 1:状态正常,允许任务下发(联机自动模式,不报警,叉在中位,无上条任务残留数据时才为1)其他:异常状态
public short TaskStatus1 { get; set; } // 0:默认; 1:确认接收任务; 3:工位1正常任务完成; 5.工位1强制完成 ; 6.取消任务
public short Loaded1 { get; set; } // 工位1载货台有无货 1:有货;0:无货
public short Busines1 { get; set; } // 工位1特殊业务状态反馈 [1:满入,2.空取,3:放货阻塞,4:取货阻塞]
public int TaskId1 { get; set; } // 工位1任务号
public short Row { get; set; } // 堆垛机当前列(行走方向)
public short Layer { get; set; } // 堆垛机当前层(升降方向)
public short b_Fork1Pos { get; set; } // 堆垛机货叉1位置 [1:左远,2.左近,3:居中,4:右近,5:右远]
}
}
}