using Microsoft.Extensions.Logging;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.Enum;
using SlnMesnac.Repository;
using SlnMesnac.Repository.service;
using SlnMesnac.TouchSocket;
using SlnMesnac.TouchSocket.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
namespace SlnMesnac.Business.@base
{
///
/// 视觉系统业务类
///
public class VisionBusiness
{
private ILogger _logger;
private static VisionBusiness instance;
private TcpServer _tcpServer;
private IAirportTaskService _airportTaskService;
private IVisionSettingService _visionSettingService;
private IAGVStateService _aGVStateService;
private IAGVJobService _AGVJobService;
private BaseAGVBusiness _baseAGVBusiness;
public VisionBusiness(ILogger logger, TcpServer tcpServer, IAirportTaskService airportTaskService, IVisionSettingService visionSettingService, IAGVStateService aGVStateService, IAGVJobService aGVJobService)
{
_logger = logger;
_tcpServer = tcpServer;
_airportTaskService = airportTaskService;
_visionSettingService = visionSettingService;
_aGVStateService = aGVStateService;
_AGVJobService = aGVJobService;
//视觉系统回复状态
_tcpServer.ReceiveVisionSysStateEvent += VisionStateRequest;
//视觉系统回复开始码垛
_tcpServer.ReceiveVisionStartWorkEvent += GetVisionWorkState;
//视觉系统通知一次码垛完成结果
_tcpServer.ReceiveStackWorkDoneEvent += AutoStackResultSend;
//_tcpServer.ReceiveStackWorkDoneEvent += AutoStackResultSend;
//视觉系统通知人工异常处理完成
_tcpServer.ReceiveManualExceptionDealDoneEvent += GetManualExceptionDealDone;
//视觉系统回复复位结果
_tcpServer.ReceiveStackRobotResetEvent += GetResetResult;
_AGVJobService = aGVJobService;
}
public static VisionBusiness GetInstance(ILogger logger, TcpServer tcpServer, IAirportTaskService airportTaskService, IVisionSettingService visionSettingService, IAGVStateService aGVStateService, IAGVJobService aGVJobService)
{
if (instance == null)
{
instance = new VisionBusiness(logger, tcpServer, airportTaskService, visionSettingService, aGVStateService, aGVJobService);
}
return instance;
}
///
/// AMR就绪,请求视觉开始工作
///
public void RequestVisionStartWork(StackState state, int count, string id)
{
_tcpServer.SendAMRRequestVisionStartWork(new byte[2] { (byte)state, (byte)count }, id);
}
///
/// 码垛结束,请求视觉系统复位
///
public void RequestVisionReplace(string ip)
{
_tcpServer.SendStackOverRequestVisionSysReplace(ip);
VDCount = 1;
VACount = 0;
TotalJudge = false;
}
///
/// 上位机调度系统每隔固定时间,请求视觉系统状态
///
public void VisionStateRequest(TcpVisionEntity entity, string id)
{
if (entity.DataLength == 2)
{
}
//Thread.Sleep(1000);
//SendRequestVisionSysState(id);
}
///
/// 接受开始工作状态
///
///
///
private void GetVisionWorkState(TcpVisionEntity entity, string id)
{
try
{
if (entity.DataLength == 3)
{
//正常开始工作
if (entity.DataBytes[0] == 0x00)
{
_logger.LogInformation($"视觉系统收到开始工作状态:正常开始工作");
VisionSetting record = _visionSettingService.GetList(x => x.VisionID == id).ToList().First();
//大端字节序
Array.Reverse(entity.SN);
AirportTask airportTask = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID &&
x.visiontaskno == (BitConverter.ToUInt16(entity.SN, 0) - 1).ToString() && x.taskstate == "抓取中").First();
//判断视觉计数和上位机技术是否一致,如果不一致,向视觉计数统一
//如果这次码垛是AMR
if (entity.DataBytes[2] == 00)
{
AGVState AMR = _aGVStateService.GetSingleAGVState(airportTask.amragvno);
//如果不一样
if (entity.DataBytes[1] != AMR.stackcount)
{
AMR.stackcount = entity.DataBytes[1];
_aGVStateService.UpdateAsync(AMR);
}
}
//如果这次码垛是Deliver
else if (entity.DataBytes[2] == 01)
{
AGVState Deliver = _aGVStateService.GetSingleAGVState(airportTask.deliveragvno);
//如果不一样
if (entity.DataBytes[1] != Deliver.stackcount)
{
Deliver.stackcount = entity.DataBytes[1];
_aGVStateService.UpdateAsync(Deliver);
}
}
//内容
else
{
_logger.LogError($"视觉系统收到开始工作状态:返回未知代码");
}
}
else if (entity.DataBytes[0] == 0x01)
{
_logger.LogError($"视觉系统收到开始工作状态:异常不能开始工作");
}
else
{
_logger.LogError($"视觉系统收到开始工作状态:返回未知代码");
}
}
else
{
_logger.LogError($"视觉系统收到开始工作状态:数据返回格式错误");
}
}
catch (Exception ex)
{
RequestVisionReplace(id);
_logger.LogError($"接受开始工作状态发生错误 {ex.Message}");
}
}
///
/// 收到堆筐请求
///
///
///
///
public void AutoStackResultSend(TcpVisionEntity entity, string id)
{
try
{
if (entity.DataLength == 2)
{
if (entity.DataBytes[0] == 0x00)
{
_logger.LogInformation($"视觉系统一次码垛结束,码垛完成 Deliver:{VDCount} AMR:{VACount}");
//上位机回复收到码垛结果
_tcpServer.SendReplayStackResult(id);
VisionSetting record = _visionSettingService.GetList(x => x.VisionID == id).ToList().First();
//大端字节序
Array.Reverse(entity.SN);
AirportTask airportTask = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID &&
x.visiontaskno == (BitConverter.ToUInt16(entity.SN, 0) - 1).ToString() && x.taskstate == "抓取中").First();
//成功码垛先码垛计数
StackCount(airportTask, entity.DataBytes[1]);
//取出两辆小车的计数
int AMRCount = _aGVStateService.GetSingleAGVState(airportTask.amragvno).stackcount;
int DeliverCount = 0;
if (!string.IsNullOrEmpty(airportTask.deliveragvno))
{
DeliverCount = _aGVStateService.GetSingleAGVState(airportTask.deliveragvno).stackcount;
}
//////////////下面是下一次码垛的综合判断条件//////////////
//先判断总数是否需要继续工作
if (airportTask.totalcount > airportTask.loadcount)
{
//如上一次是AMR 如有Deliver 判断是否到达 到达向deliver发送开始工作,没就判断amr是否装满 继续向amr
//上一次是AMR
if (entity.DataBytes[1] == 0x00)
{
//妹有Deliver的任务(小车号和是否已到达都没有)amr肯定能抓完 继续amr抓取
if (string.IsNullOrEmpty(airportTask.deliveragvno) && string.IsNullOrEmpty(airportTask.deliveragvisarrive))
{
//一直向amr抓,直到抓满
RequestVisionStartWork(StackState.NXAMRNoPositioning, AMRCount, id);
}
//有Delievr任务(有任务号且状态为未到达)继续amr抓取
else if (!string.IsNullOrEmpty(airportTask.deliveragvno) && airportTask.deliveragvisarrive == "未到达")
{
//判断AMR小车是否装满,没满就开装,满了就结束,开始循环判断deliver是否到达
//amr没满 继续装amr
if (_aGVStateService.GetSingleAGVState(airportTask.amragvno).stackcount < BaseTaskInfoBusiness.AMRStackNumber)
{
RequestVisionStartWork(StackState.NXAMRNoPositioning, AMRCount, id);
}
//AMR满了
else
{
AirportTask task;
//结束抓取、循环判断deliver是否到达,到了就向新的Deliver开始抓取
Task.Run(() =>
{
//请求复位
RequestVisionReplace(id);
while (true)
{
//循环判断该任务的deliver是否到达
Task.Delay(1000);
task = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID && x.taskstate == "抓取中").First();
if (task.deliveragvisarrive == "已到达")
{
RequestVisionStartWork(StackState.NXAGVNeedPositioning, DeliverCount, id);
break;
}
}
});
}
}
//有Deliver任务(有任务号且已到达)向Deliver发送开始抓取
else if (!string.IsNullOrEmpty(airportTask.deliveragvno) && airportTask.deliveragvisarrive == "已到达")
{
RequestVisionStartWork(StackState.NXAGVNeedPositioning, DeliverCount, id);
}
//异常情况
else
{
throw new Exception($"任务 {airportTask.taskno} 状态异常!请清除任务并重新下发任务!");
}
}
//如上一次是deliver-->则判断deliver是否装满-->装满则deliver入库-->判断剩下的数量用不用调新的deliver-->用就调新的deliver然后发向amr抓取(还得判断AMR是否抓满)-->不用就直接向amr抓取
//上一次是Deliver
else if (entity.DataBytes[1] == 0x01)
{
//判断Deliver是否装满,装满就直接入库,未装满继续装
//deliver没满,继续装
if (_aGVStateService.GetSingleAGVState(airportTask.deliveragvno).stackcount < BaseTaskInfoBusiness.DeliverStackNumber)
{
RequestVisionStartWork(StackState.NXAGVNoPositioning, DeliverCount, id);
}
//deliver满了,入库然后判断
else
{
//入库代码
_baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(airportTask.deliveragvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入库", airportTask.conveyorno).JobName);
airportTask.deliveragvno = null;
airportTask.deliveragvisarrive = null;
_airportTaskService.UpdateTaskAsync(airportTask);
//判断剩下的数量用不用调用新的deliver
//剩下的数量不用 直接向amr抓取
int amrleft = BaseTaskInfoBusiness.AMRStackNumber - _aGVStateService.GetSingleAGVState(airportTask.amragvno).stackcount;
if (airportTask.totalcount - airportTask.loadcount < amrleft)
{
RequestVisionStartWork(StackState.NXAMRNeedPositioning, AMRCount, id);
}
//剩下的数量需要调用,并判断向AMR抓取
else
{
//调新的deliver
AGVState newagv = _baseAGVBusiness.GetBestAGV(AgvType.Deliver);
_baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(newagv.agvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入位", airportTask.conveyorno).JobName);
airportTask.deliveragvno = newagv.agvno;
airportTask.deliveragvisarrive = "未到达";
_airportTaskService.UpdateTaskAsync(airportTask);
//amr无容量,结束抓取,等待Deliver到达
if (amrleft == 0)
{
AirportTask task;
//结束抓取、循环判断deliver是否到达,到了就向新的Deliver开始抓取
Task.Run(() =>
{
//请求复位
RequestVisionReplace(id);
while (true)
{
//循环判断该任务的deliver是否到达
Task.Delay(1000);
task = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID && x.taskstate == "抓取中").First();
if (task.deliveragvisarrive == "已到达")
{
RequestVisionStartWork(StackState.NXAGVNeedPositioning, DeliverCount, id);
break;
}
}
});
}
//amr有容量,抓
else
{
RequestVisionStartWork(StackState.NXAMRNeedPositioning, AMRCount, id);
}
}
}
}
//未知代码
else
{
throw new Exception($"任务 {airportTask.taskno} 未知上次码垛代码!请检查视觉系统状态!");
}
}
//总数达标,结束任务,复位机械臂,调回小车,任务状态调整
else
{
_baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(airportTask.amragvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("1000入库", airportTask.conveyorno).JobName);
airportTask.amragvno = null;
airportTask.amragvisarrive = null;
airportTask.visiontaskno = null;
if (!string.IsNullOrEmpty(airportTask.deliveragvno))
{
_baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(airportTask.deliveragvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入库", airportTask.conveyorno).JobName);
airportTask.deliveragvno = null;
airportTask.deliveragvisarrive = null;
}
airportTask.finishtime = DateTime.Now;
airportTask.taskstate = "已完成";
_airportTaskService.UpdateTaskAsync(airportTask);
}
}
//码垛过程失败
else if (entity.DataBytes[0] == 0x01)
{
VisionSetting record = _visionSettingService.GetList(x => x.VisionID == id).ToList().First();
//大端字节序
Array.Reverse(entity.SN);
AirportTask airportTask = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID &&
x.visiontaskno == (BitConverter.ToUInt16(entity.SN, 0) - 1).ToString() && x.taskstate == "抓取中").First();
//取出两辆小车的计数
int AMRCount = _aGVStateService.GetSingleAGVState(airportTask.amragvno).stackcount;
int DeliverCount = 0;
if (!string.IsNullOrEmpty(airportTask.deliveragvno))
{
DeliverCount = _aGVStateService.GetSingleAGVState(airportTask.deliveragvno).stackcount;
}
_logger.LogError($"视觉系统一次码垛结束,码垛过程失败,重新发送码垛信号");
if (entity.DataBytes[1] == 0x00)
{
//发送向复合机器人(AMR)码垛的信号
RequestVisionStartWork(StackState.NXAMRNoPositioning, AMRCount, id);
_logger.LogInformation("下一次码垛开始,方向:复合机器人");
}
else if (entity.DataBytes[1] == 0x01)
{
//发送向搬运机器人(AGVDeliver)码垛的信号
RequestVisionStartWork(StackState.NXAGVNoPositioning, DeliverCount, id);
_logger.LogInformation("下一次码垛开始,方向:搬运机器人");
}
else
{
_logger.LogError($"码垛失败返回未知码垛结果代码,请手动重新发送码垛信号");
}
}
//码垛检查失败
else if (entity.DataBytes[0] == 0x02)
{
_logger.LogError($"视觉系统一次码垛结束,码垛检查失败,请手动矫正并手动开始下一次码垛");
//仍然要码垛计数,只是筐码的不准
VisionSetting record = _visionSettingService.GetList(x => x.VisionID == id).ToList().First();
AirportTask airportTask = _airportTaskService.GetTaskInfos(x => x.amragvno == record.AMRGUID &&
x.visiontaskno == (BitConverter.ToInt16(entity.SN, 0) - 1).ToString() && x.taskstate == "抓取中").First();
StackCount(airportTask, entity.DataBytes[1]);
}
//未知代码
else
{
_logger.LogError($"视觉系统一次码垛结束,未知返回代码!请检查视觉系统状态!");
throw new Exception($"视觉系统 {id}一次码垛结束,未知返回代码!请检查视觉系统状态!");
}
}
//数据格式错误
else
{
_logger.LogError($"视觉系统一次码垛结束,返回数据格式错误,请检查视觉系统状态!");
}
}
catch(Exception ex)
{
RequestVisionReplace(id);
_logger.LogError($"接受工作结束再分配状态发生错误 {ex.Message}");
}
}
public void StackCount(AirportTask airportTask, byte lastCount)
{
//AMR码垛计数
if (lastCount == 0x00)
{
airportTask.loadcount++;
AGVState aGVState = _aGVStateService.GetSingleAGVState(airportTask.amragvno);
aGVState.stackcount++;
//判断返回结果
if (_aGVStateService.UpdateAsync(aGVState).Result || _airportTaskService.UpdateTaskAsync(airportTask).Result)
{
_logger.LogInformation($"计数更新成功 {airportTask.amragvno} AMR: {aGVState.stackcount} Total: {airportTask.loadcount}");
}
else
{
_logger.LogError("计数更新失败!");
throw new Exception("计数更新失败!");
}
}
//Deliver码垛计数
else if (lastCount == 0x01)
{
airportTask.loadcount++;
AGVState aGVState = _aGVStateService.GetSingleAGVState(airportTask.deliveragvno);
aGVState.stackcount++;
//判断返回结果
if (_aGVStateService.UpdateAsync(aGVState).Result || _airportTaskService.UpdateTaskAsync(airportTask).Result)
{
_logger.LogInformation($"计数更新成功 {airportTask.amragvno} AMR: {aGVState.stackcount} Total: {airportTask.loadcount}");
}
else
{
_logger.LogError("计数更新失败!");
throw new Exception("计数更新失败!");
}
}
else
{
throw new Exception($"任务 {airportTask.taskno} 未知上次码垛代码!请检查视觉系统状态!");
}
}
int VDCount = 1;
int VACount = 0;
int VDTotal = 8;
int VATotal = 6;
bool Vjudge = true;
bool VNow = true;
public bool TotalJudge = false;
///
/// 接受码垛结果,进行下一次码垛判断
///
public void StackResultSend(TcpVisionEntity entity, string id)
{
if (entity.DataLength == 1)
{
if (entity.DataBytes[0] == 0x00)
{
_logger.LogInformation($"视觉系统一次码垛结束,码垛完成 Deliver:{VDCount} AMR:{VACount}");
//上位机回复收到码垛结果
_tcpServer.SendReplayStackResult(id);
//这里写是否继续下一次码垛的判断条件
//判断总数是否继续工作
if ((VDCount < VDTotal && Vjudge == true && TotalJudge == true) || (VACount < VATotal && Vjudge == false && TotalJudge == true))
{
//如果码垛没结束继续发下一次的码垛信号
if (Vjudge) //这里写向哪个机器人码垛的判断条件
{
//发送向搬运机器人(AGVDeliver)码垛的信号
RequestVisionStartWork(StackState.NXAGVNoPositioning, VDCount, id);
_logger.LogInformation("下一次码垛开始,方向:搬运机器人");
VDCount++;
VNow = true;
if (VDCount >= VDTotal)
{
Vjudge = false;
}
}
else
{
//发送向复合机器人(AMR)码垛的信号
RequestVisionStartWork(StackState.NXAMRNoPositioning, VACount, id);
_logger.LogInformation("下一次码垛开始,方向:复合机器人");
VACount++;
VNow = false;
if (VACount >= VATotal)
{
Vjudge = true;
}
}
}
else
{
//如果码垛结束就请求复位
RequestVisionReplace(id);
_logger.LogInformation("本次码垛结束,请求复位");
}
}
else if (entity.DataBytes[0] == 0x01)
{
_logger.LogError($"视觉系统一次码垛结束,码垛过程失败 Deliver:{VDCount} AMR:{VACount}");
//如果码垛没结束继续发下一次的码垛信号
if (VNow) //这里写向哪个机器人码垛的判断条件
{
//发送向搬运机器人(AGVDeliver)码垛的信号
RequestVisionStartWork(StackState.NXAGVNoPositioning, VDCount, id);
_logger.LogInformation("下一次码垛开始,方向:搬运机器人");
}
else
{
//发送向复合机器人(AMR)码垛的信号
RequestVisionStartWork(StackState.NXAMRNoPositioning, VACount, id);
_logger.LogInformation("下一次码垛开始,方向:复合机器人");
}
}
else if (entity.DataBytes[0] == 0x02)
{
_logger.LogError($"视觉系统一次码垛结束,码垛检查失败");
}
else
{
_logger.LogError($"视觉系统一次码垛结束,未知返回代码");
}
}
else
{
_logger.LogError($"视觉系统一次码垛结束,返回数据格式错误");
}
}
///
/// 收到视觉系统复位结果
///
public void GetResetResult(TcpVisionEntity entity, string id)
{
if (entity.DataLength == 0x01)
{
if (entity.DataBytes[0] == 0x00)
{
_logger.LogInformation($"视觉系统码垛结束,复位正常");
}
else if (entity.DataBytes[0] == 0x01)
{
_logger.LogError($"视觉系统码垛结束,复位异常");
}
else
{
_logger.LogError($"视觉系统码垛结束,未知返回代码");
}
}
else
{
_logger.LogError($"视觉系统码垛结束,返回数据格式错误");
}
}
///
/// 人工异常处理完成并更新计数
///
public void GetManualExceptionDealDone(TcpVisionEntity entity, string id)
{
_tcpServer.SendReplyGetManualException(id);
}
}
}