using ServiceCenter.Extensions;
using ServiceCenter.Logs;
using ServiceCenter.SqlSugars;
using SqlSugar;
using System.ComponentModel;
using WCS.Core;
using WCS.Entity;
using WCS.WorkEngineering.Extensions;
using WCS.WorkEngineering.Protocol.Robot;
using WCS.WorkEngineering.Protocol.Station;
using WCS.WorkEngineering.WebApi.Controllers;
using WCS.WorkEngineering.Worlds;
using DeviceFlags = WCS.WorkEngineering.Extensions.DeviceFlags;
namespace WCS.WorkEngineering.Systems
{
///
/// 机械臂
///
[BelongTo(typeof(RingWorld))]
[Description("机械臂")]
public class 机械臂 : DeviceSystem>
{
protected override bool ParallelDo => true;
protected override bool SaveLogsToFile => true;
///
/// 取货点设备集合
///
private Dictionary> PickUpDevices = new();
///
/// 放货设备
///
private Dictionary>> PutDevices = new();
public 机械臂()
{
//获取所有的机械臂 集合
var devices = Device.All.Where(v => v.HasFlag(DeviceFlags.Robot));
//开始分配
foreach (var roobot in devices)
{
//取货设备
PickUpDevices.Add(roobot.Code, roobot.Sources.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => v).ToList());
PutDevices.Add(roobot.Code, roobot.Targets.Where(v => v.HasFlag(DeviceFlags.输送机)).Select(v => new Device(v, World)).ToList());
}
}
public override void Do(Device obj)
{
#region 处理完成任务
//判断DB520 完成任务确认清除信号 是否为1
if (obj.Data.OkAck == 1 && obj.Data2.TaskFinishId1 == 0 || obj.Data2.TaskFinishId2 == 0) obj.Data.OkAck = 0;
if (obj.Data2.TaskFinishId1 > 0 || obj.Data2.TaskFinishId2 > 0)
{
//处理完成的任务信息
WCS_TaskInfo taskInfo = null;
//开始处理
SqlSugarHelper.Do(db =>
{
World.Log($"机械臂任务处理:开始--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Low);
//根据DB521任务号获取对应任务
var taskInfoList = db.Default.Queryable().Where(v => v.ID == obj.Data2.TaskFinishId1 || v.ID == obj.Data2.TaskFinishId2).ToList();
foreach (var task in taskInfoList)
{
if (task.Status != Entity.TaskStatus.StackerExecution) continue;
//根据任务类型做不同的处理
switch (task.Type)
{
case TaskType.SetPlate: //工字轮入库
//完成任务
task.Status = Entity.TaskStatus.Finish;
task.EedTime = DateTime.Now;
db.Default.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "入库任务结束");
break;
case TaskType.OutDepot:
task.Status = Entity.TaskStatus.Finish;
task.EedTime = DateTime.Now;
db.Default.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "出库任务结束");
break;
case TaskType.TransferDepot:
task.Status = Entity.TaskStatus.Finish;
task.EedTime = DateTime.Now;
db.Default.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db.Default, task.AddrTo, "移库任务结束");
break;
}
if (task.Status >= Entity.TaskStatus.Finish) task.CompleteOrCancelTasks(db.Default);
taskInfo = task;
}
});
if (taskInfo == null) throw new KnownException("数据库提交事务错误", LogLevelEnum.High);
// 写入信号
obj.Data.OkAck = 1;
//通知WMS任务完成
if (taskInfo.Status == Entity.TaskStatus.Finish) WmsApi.CompleteTask(taskInfo.ID);
if (taskInfo.Type == TaskType.OutDepot && taskInfo.Status == Entity.TaskStatus.ConveyorExecution) WmsApi.SrmPickOutCompleted(taskInfo.ID);
World.Log($"机械臂任务处理:结束--完成任务{obj.Data2.TaskFinishId1}--{obj.Data2.TaskFinishId2}", LogLevelEnum.Mid);
}
#endregion 处理完成任务
//robot是否可以下发任务
if (obj.Data2.VoucherNo != obj.Data.VoucherNo) throw new KnownException($"凭证号不一致,DB520:{obj.Data.VoucherNo},DB521:{obj.Data2.VoucherNo}", LogLevelEnum.Mid);
if (obj.Data2.RobotMode != RobotMode.Automatic) throw new KnownException($"robot处于{obj.Data2.RobotMode.GetDescription()}模式", LogLevelEnum.Low);
if (obj.Data2.RunStatus != RobotRunStatus.Idle) throw new KnownException($"robot处于{obj.Data2.RunStatus.GetDescription()}状态", LogLevelEnum.High);
//上一个周期是不是出库任务 第一次获取返回结果会是false
var lastIsOut = obj.Entity.GetFlag("LastIsOut");
obj.Entity.SetFlag("LastIsOut", !lastIsOut);
//入库任务优先 或 上一个周期是出库任务并且出库任务无优先
if (lastIsOut) //入库任务
{
//判断本次优先执行楼层,并设置下次执行时优先楼层
var floor = obj.Entity.GetFlag("FloorIn");
floor = floor % 2 + 1;
obj.Entity.SetFlag("FloorIn", floor);
//获取当前机械臂所有的取货站台
var pickUpDevices = obj.Entity.Sources.Where(x => x.HasFlag(DeviceFlags.输送机)).Where(x => x.DeviceGroup.Any()).Select(
x =>
{
var group = x.DeviceGroup.Select(s => new Device(s, World)).ToList();
return new Tuple, List>>(new Device(x, World), group);
}).ToList();
if (!pickUpDevices.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无取货路径点", LogLevelEnum.High);
//获取取货设备的设备组中都是停止运行的
var arrIn = pickUpDevices.Where(x => x.Item2.All(a => !a.Data.Status.HasFlag(StationStatus.Run)))
.Where(x => x.Item2.OrderBy(o => o.Entity.Code.ToShort()) //前两个设备中有取货任务的
.Take(2)
.Any(a => a.Data2.TaskNumber > 0 && a.Data.Status.HasFlag(StationStatus.PH_Status)))
.ToList();
if (!arrIn.Any()) throw new KnownException($"[{obj.Entity.Code}]等待入库任务输送到位", LogLevelEnum.Mid);
//等待下发的任务信息
var taskList = new List>>();
SqlSugarHelper.Do(db =>
{
//跟据设备组中第一个设备任务号最小的一个先执行
var devGroup = arrIn.MinBy(x => x.Item2.OrderBy(o => o.Data2.TaskNumber));
foreach (var dev in devGroup.Item2.OrderBy(x => x.Entity.Code.ToShort()).Take(2)
)
{
var task = db.Default.Queryable().First(v => v.Type == TaskType.SetPlate && v.Status == Entity.TaskStatus.FinishOfShunt && dev.Data2.TaskNumber == v.ID);
if (task == null) continue;
var res = WmsApi.RingApplyStockInLoc(task.ID, task.Device, dev.Entity.Code, task.Height);
task.Status = Entity.TaskStatus.StackerExecution;
task.AddrTo = res.ResData.CellNo;
task.Line = res.ResData.Row;
task.Col = res.ResData.Colomn;
task.Layer = res.ResData.Layer;
task.Depth = res.ResData.Row;
task.LastInteractionPoint = dev.Entity.Code;
task.SrmStation = dev.Entity.Code;
task.EditWho = "WCS";
db.Default.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db.Default, dev.Entity.Code, task.AddrTo, "任务下发机械臂执行");
taskList.Add(new(task, dev));
}
});
if (!taskList.Any()) return;
switch (taskList.Count)
{
case 1:
var task = taskList.FirstOrDefault().Item1;
var dev = taskList.FirstOrDefault().Item2;
//下发任务
obj.Data.TaskNumber1 = task.ID;
obj.Data.SLine1 = dev.Entity.Code.ToShort();
obj.Data.SCol1 = 0;
obj.Data.SLayer1 = 0;
obj.Data.SDepth1 = 0;
obj.Data.ELine1 = task.Line.ToShort();
obj.Data.ECol1 = task.Col.ToShort();
obj.Data.ELayer1 = task.Layer.ToShort();
obj.Data.EDepth1 = task.Depth.ToShort();
obj.Data.TaskNumber2 = 0;
obj.Data.SLine2 = 0;
obj.Data.SCol2 = 0;
obj.Data.SLayer2 = 0;
obj.Data.SDepth2 = 0;
obj.Data.ELine2 = 0;
obj.Data.ECol2 = 0;
obj.Data.ELayer2 = 0;
obj.Data.EDepth2 = 0;
obj.Data.TaskSum = taskList.Count.ToShort();
obj.Data.GoodsType = 1;
obj.Data.TaskType = 3;
obj.Data.VoucherNo++;
break;
case 2:
//一工位取深度较大的任务
var taskInfo = taskList.MaxBy(x => x.Item1.Depth);
task = taskInfo.Item1;
dev = taskInfo.Item2;
obj.Data.TaskNumber1 = task.ID;
obj.Data.SLine1 = dev.Entity.Code.ToShort();
obj.Data.SCol1 = 0;
obj.Data.SLayer1 = 0;
obj.Data.SDepth1 = 0;
obj.Data.ELine1 = task.Line.ToShort();
obj.Data.ECol1 = task.Col.ToShort();
obj.Data.ELayer1 = task.Layer.ToShort();
obj.Data.EDepth1 = task.Depth.ToShort();
//二工位取深度较少的值
taskInfo = taskList.MinBy(x => x.Item1.Depth);
task = taskInfo.Item1;
dev = taskInfo.Item2;
obj.Data.TaskNumber2 = task.ID;
obj.Data.SLine2 = dev.Entity.Code.ToShort();
obj.Data.SCol2 = 0;
obj.Data.SLayer2 = 0;
obj.Data.SDepth2 = 0;
obj.Data.ELine2 = task.Line.ToShort();
obj.Data.ECol2 = task.Col.ToShort();
obj.Data.ELayer2 = task.Layer.ToShort();
obj.Data.EDepth2 = task.Depth.ToShort();
obj.Data.TaskSum = taskList.Count.ToShort();
obj.Data.GoodsType = 1;
obj.Data.TaskType = 3;
obj.Data.VoucherNo++;
break;
default:
throw new KnownException($"无法执行多个任务", LogLevelEnum.Mid);
}
}
else if (!lastIsOut) //出库任务
{
//判断本次优先执行楼层,并设置下次执行时优先楼层
var floor = obj.Entity.GetFlag("FloorOut");
floor = floor % 2 + 1;
obj.Entity.SetFlag("FloorOut", floor);
//获取当前堆垛机所有的取货站台
var arrOut = PutDevices.First(v => v.Key == obj.Entity.Code).Value;
if (!arrOut.Any()) throw new KnownException($"机械臂{obj.Entity.Code}无放货路径点", LogLevelEnum.High);
//获取可以放货的设备集合
arrOut = arrOut.Where(v => v.Data3.Status.HasFlag(StationStatus.PH_Status)).ToList();//无光电
if (!arrOut.Any()) throw new KnownException($"[{obj.Entity.Code}]等待出库任务输送到位", LogLevelEnum.Mid);
WCS_TaskInfo taskInfo = null;
SqlSugarHelper.Do(db =>
{
var allOutCode = arrOut.Select(v => v.Entity.Code).ToList();
var task = db.Default.Queryable().Where(v => v.Type == TaskType.OutDepot && v.Status == Entity.TaskStatus.WaitingToExecute)
.Where(v => allOutCode.Contains(v.SrmStation))
.OrderByDescending(v => v.Priority)
.OrderBy(v => v.AddTime)
.First() ?? throw new KnownException($"{obj.Entity.Code}未找到出库任务", LogLevelEnum.High);
task.Status = Entity.TaskStatus.StackerExecution;
task.LastInteractionPoint = task.Device;
task.EditWho = "WCS";
db.Default.Updateable(task).ExecuteCommand();
task.AddWCS_TASK_DTL(db.Default, task.Device, task.SrmStation, "任务下发机械臂执行");
taskInfo = task;
});
if (taskInfo == null) throw new KnownException("数据更新错误", LogLevelEnum.High);
var addrFrom = taskInfo.AddrFrom.Split("-");
obj.Data.TaskNumber1 = taskInfo.ID;
obj.Data.SLine1 = addrFrom[0].ToShort();
obj.Data.SCol1 = addrFrom[1].ToShort();
obj.Data.SLayer1 = addrFrom[2].ToShort();
obj.Data.SDepth1 = addrFrom[3].ToShort();
obj.Data.ELine1 = taskInfo.SrmStation.ToShort();
obj.Data.ECol1 = taskInfo.ProdLine;
obj.Data.TaskSum = 1;
obj.Data.GoodsType = 1;
obj.Data.TaskType = 4;
obj.Data.VoucherNo++;
}
}
public override bool Select(Device dev)
{
return dev.HasFlag(DeviceFlags.Robot);
}
}
}