using BPA.Message; using HBLConsole.Communication; using HBLConsole.Factory; using HBLConsole.Interface; using HBLConsole.Model; using HBLConsole.Service; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using BPA.Message.Enum; using HBLConsole.GVL; using BPA.Models; using BPA.Message.IOT; using HBLConsole.Abstract; using System.Diagnostics; namespace HBLConsole.MORKS { public class Control_MORKS : IControl { GVL_MORKS mORKS = new GVL_MORKS(); Alarm alarm = new Alarm(); HardwareStatus hardwareStatus = new HardwareStatus(); public void Init() { ActionManage.GetInstance.Register(new Action(() => { WriteRecipeBoms(); }), "recipeBom"); ActionManage.GetInstance.Register(new Action(() => { DeviceInit(); }), "InitCommand"); } public void ConnectOk() { WriteRecipeBoms(); ReadData(); Main(); ResetProgram(); ActionManage.GetInstance.Register(new Action(() => { Random rd = new Random(); ThreadManage.GetInstance.StartLong(new Action(() => { int NoodleLoc = rd.Next(1, 6); int BowlLoc = rd.Next(10, 11); string guid = new Guid().ToString(); mORKS.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = (ushort)NoodleLoc, SuborderId = guid }); MessageLog.GetInstance.Show($"添加订单:面条位置【{NoodleLoc}】"); mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = (ushort)BowlLoc, SuborderId = guid }); MessageLog.GetInstance.Show($"添加订单:碗位置【{BowlLoc}】"); Thread.Sleep(60000); }), "ForOrder"); }), "EnableForOrder"); ActionManage.GetInstance.Register(new Action(() => { ThreadManage.GetInstance.StopTask("ForOrder", new Action(() => { mORKS.RBTakeNoodleTask.Clear(); mORKS.TakeBowlTask.Clear(); })); }), "StopForOrder"); MessageLog.GetInstance.Show("MORKS 设备初始化完成"); } private void ResetProgram() { ThreadManage.GetInstance.StartLong(new Action(() => { if (RTrig.GetInstance("ResetProgram").Start(DeviceData.Initing)) { ThreadManage.GetInstance.StopTask("MainTask", new Action(() => { ThreadManage.GetInstance.StopTask("ReadPLCData", new Action(() => { mORKS = null; mORKS = new GVL_MORKS(); ActionManage.GetInstance.Send("ResetProgram"); ActionManage.GetInstance.Send("ClearOrders"); ReadData(); Main(); })); })); } Thread.Sleep(10); }), "ResetProgram"); } /// /// 数据读取 /// public void ReadData() { ThreadManage.GetInstance.StartLong(new Action(() => { ModbusTcpHelper.GetInstance.Readbool(323, 3, new Action((bools) => { mORKS.RobotTakeNoodle = bools[0]; mORKS.RobotOutMeal = bools[1]; mORKS.MoveTurntable = bools[2]; })); ModbusTcpHelper.GetInstance.Readbool(1120, 16, new Action((bools) => { mORKS.InitComplete = bools[0]; mORKS.TakeBowlIdle = bools[1]; mORKS.TemperatureReached = bools[2]; mORKS.AllowFallNoodle = bools[3]; mORKS.RbTakeNoodleComplete = bools[4]; mORKS.RbFallNoodleComplete = bools[5]; mORKS.RbOutMealComplete = bools[6]; mORKS.RobotIdle = bools[7]; mORKS.TakeMealDetect = bools[8]; mORKS.MissingBowl = bools[9]; DeviceData.Initing = bools[10]; mORKS.TurntableLowerLimit = bools[11]; mORKS.MissingBowlSignal2 = bools[12]; mORKS.TurntableUpLimit = bools[13]; mORKS.FeedComplete = bools[14]; mORKS.TurntableMoveInPlace = bools[15]; })); var errorStatus = ModbusTcpHelper.GetInstance.Read((ushort)ModbusTcpHelper.GetInstance.GetBoolAddress("M235.0"), ReadType.Coils, 1); if (errorStatus != null && errorStatus is bool error) mORKS.Error = error; ModbusTcpHelper.GetInstance.Readbool(1136, 7, new Action((bools) => { for (int i = 0; i < 6; i++) { mORKS.NoodleCookerStatus[i] = bools[i]; } mORKS.Feeding = bools[6]; })); ModbusTcpHelper.GetInstance.Readbool(1144, 6, new Action((bools) => { for (int i = 0; i < 6; i++) { mORKS.CookNoodlesComplete[i] = bools[i]; } })); ModbusTcpHelper.GetInstance.Readbool(1570, 20, new Action((bools) => { alarm.MachineLeftLowTemperature = bools[0]; alarm.MachineRightLowTemperature = bools[1]; alarm.Supply1_LossBowl = bools[2]; alarm.Supply2_LossBowl = bools[3]; alarm.Supply1_ErrorOutBowl = bools[4]; alarm.Supply2_ErrorOutBowl = bools[5]; alarm.PushBowlCylinderError = bools[6]; alarm.NoodleMacCommunicateError = bools[7]; alarm.DosingMacCommunicateError = bools[8]; alarm.RobotMacCommunicateError = bools[9]; alarm.RobotInitError = bools[11]; alarm.RobotUrgentStop = bools[12]; alarm.RobotNotInRemoteMode = bools[13]; alarm.RobotNotInReady = bools[14]; alarm.RobotSelfInException = bools[15]; })); var ResLoc = ModbusTcpHelper.GetInstance.Read(286, ReadType.HoldingRegisters); if (ResLoc != null) { if (ResLoc is ushort loc) { mORKS.TurntableFeedbackloc = loc; } } Thread.Sleep(500); }), "ReadPLCData"); } public void SimOrder(T simOrder) { if (simOrder != null) { if (simOrder is List locs) { string subId = Guid.NewGuid().ToString(); foreach (var item in locs) { if (item >= 1 && item <= 5) { mORKS.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = item, SuborderId = subId }); MessageLog.GetInstance.Show($"添加订单:面条位置【{item}】"); } if (item >= 10 && item <= 11) { mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = item, SuborderId = subId }); MessageLog.GetInstance.Show($"添加订单:碗位置【{item}】"); } } } } } /// /// IOT 广播消息命令 /// public void IotBroadcast(T broadcast) { if (broadcast != null && broadcast is IOTCommandModel iOTCommand) { MessageLog.GetInstance.Show($"IOT 广播消息命令 {iOTCommand.deviceName} 设备命令 {iOTCommand.CommandName} 控制变量{iOTCommand.CommandValue.Keys.First()}{iOTCommand.CommandValue[iOTCommand.CommandValue.Keys.First()]}"); switch (iOTCommand.CommandName) { case 0://控制类 if (iOTCommand.CommandValue != null) { if (iOTCommand.CommandValue.ContainsKey("order")) { List vs = new List(); vs.Add((ushort)(new Random().Next(1, 5))); vs.Add(ushort.Parse(iOTCommand.CommandValue["order"])); SimOrder(vs); } else if (iOTCommand.CommandValue.ContainsKey("init")) { DeviceInit(); } else if (iOTCommand.CommandValue.ContainsKey("stop")) { } else if (iOTCommand.CommandValue.ContainsKey("start")) { } } break; case 1://设置属性 break; case 2://通知消息 break; default: break; } } } int OrderCount = 0; /// /// 数据解析 /// public void DataParse(T order) { OrderCount++; MessageLog.GetInstance.Show($"接收到{OrderCount}次订单"); if (order is MorkOrderPush morkOrderPush) { foreach (var item in morkOrderPush.GoodBatchings) { var res = Json.Data.orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId); if (res != null) { if (ushort.TryParse(res.BatchingLoc, out ushort loc)) { if (loc >= 1 && loc <= 5) { if (mORKS.RBTakeNoodleTask.FirstOrDefault(p => p.SuborderId == morkOrderPush.SuborderId) == null) mORKS.RBTakeNoodleTask.Enqueue(new OrderLocInfo() { Loc = ushort.Parse(res.BatchingLoc), SuborderId = morkOrderPush.SuborderId, BatchingId = res.BatchingId }); } else if (loc >= 10 && loc <= 11) { int index = 0; if (Json.Data.recipeBoms != null) { index = Array.FindIndex(Json.Data.recipeBoms?.RecipeIds.ToArray(), p => p.RecipeId == morkOrderPush.RecipeId); index++; } if (mORKS.TakeBowlTask.FirstOrDefault(p => p.SuborderId == morkOrderPush.SuborderId) == null) mORKS.TakeBowlTask.Enqueue(new OrderLocInfo() { Loc = ushort.Parse(res.BatchingLoc), SuborderId = morkOrderPush.SuborderId, RecipeNumber = (index >= 1 && index <= 10) ? (ushort)index : (ushort)0 }); } } } } } } public void Main() { ThreadManage.GetInstance.StartLong(new Action(() => { mORKS.AllowRun = mORKS.InitComplete; GeneralConfig.Healthy = mORKS.Error && mORKS.InitComplete && !GeneralConfig.EnableLocalSimOrder; TakeBowlTask(); TakeNoodleTask(); OutNoodleTask(); SingleDetect(); TurntableControl(); Thread.Sleep(100); }), "MainTask"); } /// /// 取碗控制 /// private void TakeBowlTask() { if (mORKS.AllowRun && mORKS.TakeBowlTask.Count > 0 && !mORKS.TakeBowlIdle && !mORKS.TakeBowlInterlock) { if (mORKS.TakeBowlTask.TryDequeue(out OrderLocInfo orderLocInfo)) { mORKS.TakeBowlId = orderLocInfo.SuborderId; TakeBowlControl(orderLocInfo.Loc); SetRecipeNumber(orderLocInfo.RecipeNumber); SimpleFactory.GetInstance.OrderChanged(mORKS.TakeBowlId, ORDER_STATUS.COOKING); MessageLog.GetInstance.Show($"订单【{ mORKS.TakeBowlId}】执行取碗控制,位置:[{orderLocInfo.Loc}]"); } mORKS.TakeBowlInterlock = true; } } /// /// 转台控制 /// private void TurntableControl() { if (GeneralConfig.EnableLocalSimOrder) { //不做轮询,直接取面,模拟订单使用 if (mORKS.TurntableMoveInPlace && !mORKS.Feeding && mORKS.InitComplete && !mORKS.AllowTakeNoodle && mORKS.RBTakeNoodleTask.Count > 0) { if (mORKS.TurntableLowerLimit) { TurntableStart(mORKS.RBTakeNoodleTask.ElementAt(0).Loc); mORKS.TurntableLocLists.Clear(); mORKS.AllowTakeNoodle = true; MessageLog.GetInstance.Show($"控制机器人去转台【{mORKS.RBTakeNoodleTask.ElementAt(0).Loc}】号位置取面"); } } } else { //正常轮询 if (mORKS.TurntableMoveInPlace && !mORKS.Feeding && mORKS.InitComplete && !mORKS.AllowTakeNoodle && mORKS.RBTakeNoodleTask.Count > 0) { var result = Json.Data.orderMaterialDelivery.BatchingInfo.Where(p => p.BatchingId == mORKS.RBTakeNoodleTask.ElementAt(0).BatchingId).ToList(); if (result != null) { var res = result.FirstOrDefault(P => P.BatchingLoc == mORKS.TurntableFeedbackloc.ToString()); if (mORKS.TurntableLowerLimit && res != null) { //if (mORKS.RBTakeNoodleTask.ElementAt(0).Loc != mORKS.TurntableFeedbackloc) TurntableStart(mORKS.TurntableFeedbackloc); mORKS.TurntableLocLists.Clear(); mORKS.AllowTakeNoodle = true; MessageLog.GetInstance.Show($"控制机器人去转台【{mORKS.TurntableFeedbackloc}】号位置取面"); } else { if (!mORKS.TurntableInterlock) { foreach (var item in result) { if (ushort.TryParse(item.BatchingLoc, out ushort loc)) { if (mORKS.TurntableFeedbackloc != loc && !mORKS.TurntableLocLists.Contains(loc)) { TurntableStart(loc); MessageLog.GetInstance.Show($"没有物料检测的启动转台控制,转台位置:[{loc}]"); break; } else if (mORKS.TurntableFeedbackloc == loc && !mORKS.TurntableLocLists.Contains(loc)) mORKS.TurntableLocLists.Add(loc); } } } } } else MessageLog.GetInstance.Show("未找到可用的物料信息"); } } //转台到位检测 if (RTrig.GetInstance("TurntableInPlace").Start(mORKS.TurntableMoveInPlace && mORKS.CurrentLoc == mORKS.TurntableFeedbackloc)) { mORKS.CurrentLoc = 0; mORKS.TurntableInterlock = false; MessageLog.GetInstance.Show("转台到位检测"); } //补料完成检测 if (RTrig.GetInstance("FeedComplete").Start(mORKS.FeedComplete)) { if (!mORKS.AllowTakeNoodle && mORKS.TurntableLocLists.Count > 0) { mORKS.TurntableLocLists.Clear(); mORKS.TurntableInterlock = false; MessageLog.GetInstance.Show("补料完成检测"); } } } /// /// 取面任务 /// private void TakeNoodleTask() { //取面控制 if (mORKS.AllowRun && mORKS.RobotIdle && !mORKS.Feeding && !mORKS.RobotTaskInterlock && mORKS.AllowTakeNoodle && mORKS.TurntableMoveInPlace && !mORKS.TakeNoodleInterlock && !mORKS.OutNoodleing && mORKS.RBTakeNoodleTask.Count > 0) { int loc = Array.FindIndex(mORKS.NoodleCookerStatus, p => p == false);//查找煮面炉空闲位置 if (loc >= 0 && loc <= 5) { if (mORKS.RBTakeNoodleTask.TryDequeue(out OrderLocInfo orderLocInfo)) { mORKS.CookNodelId[loc] = orderLocInfo.SuborderId; SetFallNoodleLoc((ushort)(loc + 1)); //机器人开始取面 RobotTakeNoodle(); SimpleFactory.GetInstance.OrderChanged(orderLocInfo.SuborderId, ORDER_STATUS.COOKING); MessageLog.GetInstance.Show($"订单【{orderLocInfo.SuborderId}】,机器人倒面至【{loc + 1}】号煮面栏"); //写入煮面时间 //List values = new List(); //values.Add(Json.Data.parSets.ElementAt(loc).Minute); //values.Add(Json.Data.parSets.ElementAt(loc).Second); //ModbusTcpHelper.GetInstance.Write((ushort)ModbusTcpHelper.GetInstance.GetWordAddress($"VW{116 + (loc * 6)}"), WriteType.HoldingRegisters, values.ToArray()); mORKS.TakeNoodleInterlock = true; } } } } /// /// 出餐控制 /// private void OutNoodleTask() { if (mORKS.AllowFallNoodle && mORKS.RobotTaskInterlock && !mORKS.TakeNoodleInterlock && mORKS.RobotIdle && !mORKS.TakeMealDetect) { int loc = Array.FindIndex(mORKS.CookNodelId, p => p == mORKS.IngredientsCompleteId && p.Length > 0); if (loc >= 0 && loc <= 5) { if (mORKS.CookNoodlesComplete[loc]) { SetTakeNoodleLoc((ushort)(loc + 1)); RobotOutMeal(); CookNoodleStatusReset((ushort)(loc + 1)); ResetAllowFallNoodle(); mORKS.OutMealId = mORKS.IngredientsCompleteId; mORKS.IngredientsCompleteId = string.Empty; mORKS.CookNodelId[loc] = string.Empty; MessageLog.GetInstance.Show($"{loc + 1}号位置出餐控制"); mORKS.OutNoodleing = true; } } } } /// /// 信号检测 /// private void SingleDetect() { //允许倒面信号检测 if (RTrig.GetInstance("AllowFallNoodle").Start(mORKS.AllowFallNoodle)) { mORKS.IngredientsCompleteId = mORKS.TakeBowlId; mORKS.TakeBowlId = string.Empty; MessageLog.GetInstance.Show($"碗到位,允许到面,{mORKS.IngredientsCompleteId}"); mORKS.TakeBowlInterlock = false; } //出餐完成信号检测 if (RTrig.GetInstance("CompleteChange").Start(mORKS.RbOutMealComplete)) { SimpleFactory.GetInstance.OrderChanged(mORKS.OutMealId, ORDER_STATUS.COMPLETED_COOK); MessageLog.GetInstance.Show($"订单【{mORKS.OutMealId}】制作完成"); mORKS.OutNoodleing = false; } //取餐完成逻辑处理 if (DelayRTrig.GetInstance("CompleteChange1").Start(mORKS.RbOutMealComplete && !mORKS.TakeMealDetect, 2)) { SimpleFactory.GetInstance.OrderChanged(mORKS.OutMealId, ORDER_STATUS.COMPLETED_TAKE); MessageLog.GetInstance.Show($"订单【{mORKS.OutMealId}】取餐完成"); ResetCookComplete(); mORKS.OutMealId = string.Empty; } //机器人取面完成信号检测 if (RTrig.GetInstance("TakeNoodleComplete").Start(mORKS.RbTakeNoodleComplete)) { mORKS.TakeNoodleInterlock = false; mORKS.AllowTakeNoodle = false; mORKS.TurntableInterlock = false; MessageLog.GetInstance.Show("机器人取面完成信号检测"); TakeNoodleCompleteReset(); } //转台到位检测 //if (RTrig.GetInstance("TurntableInPlace").Start(mORKS.TurntableMoveInPlace)) //{ // mORKS.TurntableInterlock = false; //} int OutMealRequstCount = mORKS.CookNoodlesComplete.Where(p => p == true).ToList().Count; int mlCount = mORKS.NoodleCookerStatus.Where(p => p == true).ToList().Count; mORKS.RobotTaskInterlock = OutMealRequstCount > 0 && mORKS.AllowFallNoodle && (mlCount >= 2 || mORKS.RBTakeNoodleTask.Count == 0); } #region PLC 控制函数 /// /// 写入配方数据到 PLC /// private void WriteRecipeBoms() { List recipeBoms = new List(); if (Json.Data.recipeBoms == null) return; foreach (var item in Json.Data.recipeBoms.RecipeIds) { foreach (var rec in item.Recipes) { recipeBoms.Add((ushort)rec); } } if (recipeBoms.Count > 0) { if (ModbusTcpHelper.GetInstance.Write(1100, WriteType.HoldingRegisters, recipeBoms.ToArray())) { MessageLog.GetInstance.Show("成功写入配方数据"); } } else { MessageLog.GetInstance.Show("配方数据为空"); } } /// /// 转台移动 /// //private void MoveTurntable() //{ // //ModbusTcpHelper.GetInstance.Write(325, WriteType.Coils, true); //} /// /// 取面完成复位 /// private void TakeNoodleCompleteReset() { ModbusTcpHelper.GetInstance.Write(1124, WriteType.Coils, false); } /// /// 指定煮面口状态复位 /// /// private void CookNoodleStatusReset(int num) { if (num >= 1 && num <= 6) { ushort addRess = (ushort)(1136 + num - 1); ModbusTcpHelper.GetInstance.Write(addRess, WriteType.Coils, false); MessageLog.GetInstance.Show($"{num}号煮面口占用复位"); } } /// /// 写配方编号 /// /// private void SetRecipeNumber(ushort num) { ModbusTcpHelper.GetInstance.Write(100, WriteType.HoldingRegisters, num); } /// /// 启动转台 /// /// private void TurntableStart(ushort loc) { mORKS.CurrentLoc = loc; mORKS.TurntableInterlock = true; mORKS.TurntableLocLists.Add(loc); ModbusTcpHelper.GetInstance.Write(101, WriteType.HoldingRegisters, loc); ModbusTcpHelper.GetInstance.Write(325, WriteType.Coils, true); } /// /// 设置倒面位置 /// /// private void SetFallNoodleLoc(ushort loc) { ModbusTcpHelper.GetInstance.Write(102, WriteType.HoldingRegisters, loc); } /// /// 设置取面位置 /// /// private void SetTakeNoodleLoc(ushort loc) { ModbusTcpHelper.GetInstance.Write(103, WriteType.HoldingRegisters, loc); } /// /// 取碗控制 /// /// private void TakeBowlControl(ushort loc) { if (loc == 10)//小碗 { ModbusTcpHelper.GetInstance.Write(321, WriteType.Coils, true); } else if (loc == 11)//大碗 { ModbusTcpHelper.GetInstance.Write(322, WriteType.Coils, true); } } /// /// 机器人取面 /// private void RobotTakeNoodle() { ModbusTcpHelper.GetInstance.Write(323, WriteType.Coils, true); } /// /// 机器人取餐 /// private void RobotOutMeal() { ModbusTcpHelper.GetInstance.Write(324, WriteType.Coils, true); var result = ModbusTcpHelper.GetInstance.Read(324, ReadType.Coils); if (result is bool res) while (!res) { ModbusTcpHelper.GetInstance.Write(324, WriteType.Coils, true); } } /// /// 制作完成信号复位 /// private void ResetCookComplete() { ModbusTcpHelper.GetInstance.Write(1126, WriteType.Coils, false); } /// /// 复位允许取面信号 /// private void ResetAllowFallNoodle() { ModbusTcpHelper.GetInstance.Write(1123, WriteType.Coils, false); } /// /// 设备初始化 /// public async void DeviceInit() { ModbusTcpHelper.GetInstance.Write(320, WriteType.Coils, true); await Task.Delay(1000); ModbusTcpHelper.GetInstance.Write(320, WriteType.Coils, false); } #endregion } }