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
|
{
|
/// <summary>
|
/// 定时轮询任务
|
/// </summary>
|
internal class Monitor
|
{
|
|
// 每十分钟对未连接的pic,尝试进行重新连接
|
public static void PlcAgainLink()
|
{
|
foreach (var item in S7Helper.plcDic)
|
{
|
S7Helper.Link(item.Value);
|
}
|
}
|
|
|
/// <summary>
|
/// 监听分拣区设备和货位,自动发布空盘垛出库任务
|
/// </summary>
|
public static void MonitorSortArea() {
|
List<LinePlcInfo> 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<NotificationInfo, int> logisticsTaskIdDict= new Dictionary<NotificationInfo, int>();
|
|
public class NotificationInfo {
|
public string logisticsTaskId { get; set; }
|
public string locCode { get; set; }
|
}
|
|
/// <summary>
|
/// 定时通知车间下发灵动任务(之前通知失败的任务)
|
/// 每10秒通知一次,如5分钟内没有通知成功,则不再通知
|
/// </summary>
|
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;
|
}
|
}
|
}
|
}
|
|
/// <summary>
|
/// 监测输送线
|
/// </summary>
|
public static void MonitorPipeline()
|
{
|
List<LinePlcInfo> 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", "输送线");
|
WMSTask wmsTask = WMSHelper.GetWmsTaskByCntr(locCntrRel.S_CNTR_CODE);
|
if (wmsTask == null)
|
{
|
LogHelper.Info("没有正在执行的任务,货位:" + locCntrRel.S_LOC_CODE + " 容器:" + locCntrRel.S_CNTR_CODE, "输送线");
|
continue;
|
}
|
|
if (lineSignalInfo.faultMessage != 0)
|
{
|
// 回报车间控制器
|
WMSStatusInfo statusInfo = new WMSStatusInfo()
|
{
|
wmsId = wmsTask.S_CODE,
|
errMsg = $"{line.code}输送线故障,故障编码:{lineSignalInfo.faultMessage}"
|
};
|
ShopFloorControl.wmsUpdateStatus(statusInfo);
|
|
if (lineSignalInfo.faultMessage == 1)
|
{
|
LogHelper.Info("输送线,线体【" + line.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<string>() { locCntrRel.S_CNTR_CODE });
|
LocationHelper.BindingLoc(descLocation.S_CODE, new List<string>() { 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);
|
if (endLoc != null)
|
{
|
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<string> 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($"堆垛机入库任务终点:null", "输送线");
|
}
|
}
|
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<string>() { locCntrRel.S_CNTR_CODE });
|
LocationHelper.BindingLoc(descLocation.S_CODE, new List<string>() { 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, "哈电");
|
}
|
}
|
}
|
|
/// <summary>
|
/// 清除输送线命令
|
/// </summary>
|
/// <param name="line"></param>
|
/// <param name="taskId"></param>
|
/// <param name="descLine"></param>
|
/// <param name="command"></param>
|
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)
|
}
|
|
/// <summary>
|
/// 清除输送线命令
|
/// </summary>
|
/// <param name="line"></param>
|
/// <param name="command"> 1.agv任务异常取消</param>
|
public static void triggerAlarmCommand(LinePlcInfo line, short command)
|
{
|
S7Helper.WriteDint(line.deviceNo, 101, line.writeAddr + 20, command); // 任务号
|
}
|
|
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; }
|
}
|
|
|
|
|
/// <summary>
|
/// 检测堆垛机信号
|
/// </summary>
|
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);
|
}
|
}
|
}
|
|
/// <summary>
|
/// 堆垛机任务处理
|
/// </summary>
|
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<string> { wcsTask.S_CNTR_CODE });
|
LocationHelper.UnLockLoc(wcsTask.S_START_LOC);
|
|
LocationHelper.BindingLoc(wcsTask.S_END_LOC, new List<string> { 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:右远]
|
|
|
}
|
|
}
|
}
|