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
}
}