|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using SlnMesnac.Repository.service;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using SlnMesnac.Repository;
|
|
|
|
|
using SlnMesnac.Repository.service.Impl;
|
|
|
|
|
using TouchSocket.Sockets;
|
|
|
|
|
using SlnMesnac.Model.domain;
|
|
|
|
|
using SlnMesnac.TouchSocket;
|
|
|
|
|
using System.Timers;
|
|
|
|
|
using SlnMesnac.Model.Enum;
|
|
|
|
|
using HslCommunication.Enthernet;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using SlnMesnac.TouchSocket.Entity;
|
|
|
|
|
using SlnMesnac.Model.AirportApiEntity;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace SlnMesnac.Business.@base
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 航班任务业务类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class BaseTaskInfoBusiness
|
|
|
|
|
{
|
|
|
|
|
public const int AMRStackNumber = 10;
|
|
|
|
|
public const int DeliverStackNumber = 15;
|
|
|
|
|
private TcpServer _tcpServer = null;
|
|
|
|
|
public Action<AirportTask> _Taskaction;
|
|
|
|
|
public Action<string> _RefreshLogMessageAction;
|
|
|
|
|
private static BaseTaskInfoBusiness instance;
|
|
|
|
|
private ILogger<BaseTaskInfoBusiness> _logger;
|
|
|
|
|
private IAirportTaskService _Taskservice;
|
|
|
|
|
private IAGVMapPointService _AGVMapPointService;
|
|
|
|
|
private IAGVStateService _AGVStateService;
|
|
|
|
|
private IAGVJobService _AGVJobService;
|
|
|
|
|
private AirPorthttpClient _airpttpClient;
|
|
|
|
|
private BaseAGVBusiness _baseAGVBusiness;
|
|
|
|
|
System.Timers.Timer RefreshTimer;
|
|
|
|
|
public BaseTaskInfoBusiness(
|
|
|
|
|
ILogger<BaseTaskInfoBusiness> logger,
|
|
|
|
|
IAirportTaskService Taskservice,
|
|
|
|
|
IAGVStateService agvService,
|
|
|
|
|
IAGVMapPointService aGVMapPointService,
|
|
|
|
|
IAGVJobService agvJobService,
|
|
|
|
|
TcpServer tcpServer,
|
|
|
|
|
AirPorthttpClient airPorthttpClient,
|
|
|
|
|
BaseAGVBusiness baseAGVBusiness)
|
|
|
|
|
{
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_tcpServer = tcpServer;
|
|
|
|
|
_Taskservice = Taskservice;
|
|
|
|
|
_AGVStateService = agvService;
|
|
|
|
|
_airpttpClient = airPorthttpClient;
|
|
|
|
|
InitClearTimer();
|
|
|
|
|
//doWhileGetAGVTaskInfo();
|
|
|
|
|
RefreshTimer = new System.Timers.Timer(1000);
|
|
|
|
|
RefreshTimer.Elapsed += (sender, e) => RefreshTaskState();
|
|
|
|
|
_baseAGVBusiness = baseAGVBusiness;
|
|
|
|
|
_AGVMapPointService = aGVMapPointService;
|
|
|
|
|
_AGVJobService = agvJobService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static BaseTaskInfoBusiness GetInstance(
|
|
|
|
|
ILogger<BaseTaskInfoBusiness> logger,
|
|
|
|
|
IAirportTaskService Taskservice,
|
|
|
|
|
IAGVStateService agvService,
|
|
|
|
|
IAGVMapPointService aGVMapPointService,
|
|
|
|
|
IAGVJobService aAGVJobService,
|
|
|
|
|
TcpServer tcpServer,
|
|
|
|
|
AirPorthttpClient airPorthttpClient,
|
|
|
|
|
BaseAGVBusiness baseAGVBusiness)
|
|
|
|
|
{
|
|
|
|
|
if (instance == null)
|
|
|
|
|
{
|
|
|
|
|
instance = new BaseTaskInfoBusiness(logger, Taskservice, agvService, aGVMapPointService, aAGVJobService, tcpServer, airPorthttpClient, baseAGVBusiness);
|
|
|
|
|
}
|
|
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从航班接口获取到新任务插入数据库
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<bool> NewTaskInfo(string taskNo, string conveyNo, string flightNo, int totalCount)
|
|
|
|
|
{
|
|
|
|
|
var task = new AirportTask()
|
|
|
|
|
{
|
|
|
|
|
taskno = taskNo,
|
|
|
|
|
conveyorno = conveyNo, //判断条件
|
|
|
|
|
flightno = flightNo,
|
|
|
|
|
amragvno = string.Empty, //需要判断,更新 是否有AMR分配
|
|
|
|
|
amragvisarrive = string.Empty, //需要判断,更新 AMR是否到达
|
|
|
|
|
deliveragvno = string.Empty, //需要判断,更新 是否有Deliver分配
|
|
|
|
|
deliveragvisarrive = string.Empty, //需要判断,更新 Deliver是否到达
|
|
|
|
|
totalcount = totalCount, //判断条件 总数量是多少
|
|
|
|
|
loadcount = 0, //需要判断,更新 现抓取数量
|
|
|
|
|
taskstate = "等待", //需要判断,更新 任务状态
|
|
|
|
|
starttime = DateTime.Now,
|
|
|
|
|
finishtime = null,
|
|
|
|
|
deliveragvTaskNo = string.Empty, //需要判断,更新
|
|
|
|
|
amragvTaskNo = string.Empty, //需要判断,更新
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _Taskservice.AddTaskAsync(task);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError("航班任务新建失败");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AGV状态查询控制
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="state"></param>
|
|
|
|
|
public void AGVStateUpdateTimerOperation(TimerControl state)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
switch (state)
|
|
|
|
|
{
|
|
|
|
|
case TimerControl.Start:
|
|
|
|
|
RefreshTimer.Start();
|
|
|
|
|
break;
|
|
|
|
|
case TimerControl.Stop:
|
|
|
|
|
RefreshTimer.Stop();
|
|
|
|
|
break;
|
|
|
|
|
case TimerControl.Dispose:
|
|
|
|
|
RefreshTimer.Dispose();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_logger.LogError("未知状态");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError("AGV状态操作失败!" + ex.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Timer刷新任务状态, 有新任务初次下发AGV
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void RefreshTaskState()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//获取任务列表
|
|
|
|
|
List<AirportTask> Task = _Taskservice.GetAGVTaskInfos();
|
|
|
|
|
if (Task != null && Task.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
//更新前端
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("任务数量:" + Task.Count);
|
|
|
|
|
foreach(AirportTask taskItem in Task)
|
|
|
|
|
{
|
|
|
|
|
//查询待执行任务
|
|
|
|
|
if (taskItem.taskstate == "等待" || string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
//首先调一辆最优AMR
|
|
|
|
|
AGVState firstAMR = _baseAGVBusiness.GetBestAGV(AgvType.AMR);
|
|
|
|
|
string amrTaskId = _baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(
|
|
|
|
|
firstAMR.agvno,
|
|
|
|
|
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("1000入位", taskItem.conveyorno).JobName);
|
|
|
|
|
taskItem.amragvTaskNo = amrTaskId;
|
|
|
|
|
taskItem.amragvno = firstAMR.agvno;
|
|
|
|
|
taskItem.amragvisarrive = "未到达";
|
|
|
|
|
taskItem.taskstate = "执行中";
|
|
|
|
|
//需要AGV和AMR才能装下
|
|
|
|
|
if (taskItem.totalcount > (AMRStackNumber - firstAMR.stackcount))
|
|
|
|
|
{
|
|
|
|
|
//调一辆最优Deliver
|
|
|
|
|
AGVState firstDeliver = _baseAGVBusiness.GetBestAGV(AgvType.Deliver);
|
|
|
|
|
string deliverTaskID = _baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(
|
|
|
|
|
firstDeliver.agvno,
|
|
|
|
|
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入位", taskItem.conveyorno).JobName);
|
|
|
|
|
taskItem.deliveragvTaskNo = amrTaskId;
|
|
|
|
|
taskItem.deliveragvno = firstDeliver.agvno;
|
|
|
|
|
taskItem.deliveragvisarrive = "未到达";
|
|
|
|
|
}
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError($"查询任务列表初次下发任务发生错误Message:{ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取任务列表,向待执行任务派发AGV (定期执行)
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void GetAGVTaskInfo(object source, ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//获取任务列表
|
|
|
|
|
List<AirportTask> Task = _Taskservice.GetAGVTaskInfos();
|
|
|
|
|
if (Task != null && Task.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
//更新前端
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("任务数量:" + Task.Count);
|
|
|
|
|
foreach (AirportTask taskItem in Task)
|
|
|
|
|
{
|
|
|
|
|
//判断任务是否未完成
|
|
|
|
|
if (taskItem.totalcount < taskItem.loadcount && taskItem.finishtime == null && taskItem.taskstate != "已完成")
|
|
|
|
|
{
|
|
|
|
|
//判断任务是否有小车正在执行
|
|
|
|
|
if (!string.IsNullOrEmpty(taskItem.deliveragvno) && !string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//Deliver未派发,AMR未派发
|
|
|
|
|
if (string.IsNullOrEmpty(taskItem.deliveragvno) && string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
_RefreshLogMessageAction?.Invoke($"正在为AGV,AMR分配任务...");
|
|
|
|
|
_logger.LogInformation($"正在为AGV,AMR分配任务");
|
|
|
|
|
|
|
|
|
|
//查询AGV设备状态及AMR设备状态
|
|
|
|
|
|
|
|
|
|
//这里要看AGV是否会立刻更新状态
|
|
|
|
|
CreateAGVTask(taskItem);
|
|
|
|
|
//查询机械臂状态
|
|
|
|
|
}
|
|
|
|
|
//Deliver已派发,AMR未派发
|
|
|
|
|
if (!string.IsNullOrEmpty(taskItem.deliveragvno) && string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
_RefreshLogMessageAction?.Invoke($"正在为AMR分配任务...");
|
|
|
|
|
_logger.LogInformation($"正在为AMR分配任务");
|
|
|
|
|
//查询AMR状态
|
|
|
|
|
CreateAMRTask(taskItem);
|
|
|
|
|
}
|
|
|
|
|
//Deliver未派发,AMR已派发
|
|
|
|
|
if (string.IsNullOrEmpty(taskItem.deliveragvno) && !string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
_RefreshLogMessageAction?.Invoke($"正在为AGV分配任务...");
|
|
|
|
|
_logger.LogInformation($"正在为AGV分配任务");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_Taskaction?.Invoke(taskItem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 调用接口更新指定的任务状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
public void RefreshTaskStateForResopnse(AGVRequestTaskStateDetailEntity request)
|
|
|
|
|
{
|
|
|
|
|
AGVResponseEntity<ResponseTaskStateDetailDataEntity> response = _airpttpClient.AGVGetTaskStateDetailRequest(request);
|
|
|
|
|
if (response.code == 1)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError("返回错误:" + response.message);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (response.code == 0)
|
|
|
|
|
{
|
|
|
|
|
AirportTask record = new AirportTask();
|
|
|
|
|
List<AirportTask> list = _Taskservice.GetTaskInfos();
|
|
|
|
|
//list.Where(x => x.taskno == response.Data
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 持续读取AGV状态信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void doWhileGetAGVTaskInfo()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
GetAGVTaskInfo(null, null);
|
|
|
|
|
Task.Delay(1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 清理Timer
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void InitClearTimer()
|
|
|
|
|
{
|
|
|
|
|
System.Timers.Timer timer = new System.Timers.Timer
|
|
|
|
|
{
|
|
|
|
|
Interval = 1000, // 每天执行一次
|
|
|
|
|
AutoReset = true,
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
timer.Elapsed += GetAGVTaskInfo;
|
|
|
|
|
timer.Start();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 向AMR派发任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="AirportTask"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool CreateAMRTask(AirportTask AirportTask)
|
|
|
|
|
{
|
|
|
|
|
bool iflag = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
iflag = true;
|
|
|
|
|
//获取AMR设备状态
|
|
|
|
|
List<AGVState> State = _AGVStateService.GetAgvState(AgvType.AMR);
|
|
|
|
|
foreach (var AgvItem in State)
|
|
|
|
|
{
|
|
|
|
|
//根据规则筛选最优AGV
|
|
|
|
|
if (AgvItem.agvworkstate == "任务空闲")
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"获取空闲AMR列表");
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("执行站台[" + AirportTask.conveyorno + "],下发" + "[" + AirportTask.taskno + "]任务");
|
|
|
|
|
//调用派发任务接口,向任务状态为任务空闲的AGV派发任务
|
|
|
|
|
bool iTaskflag = true;
|
|
|
|
|
if (iTaskflag)
|
|
|
|
|
{
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("[" + AgvItem.agvno + "]AMR,执行任务[" + AirportTask.taskno + "]");
|
|
|
|
|
AgvItem.taskno = AirportTask.taskno;
|
|
|
|
|
AgvItem.agvworkstate = "任务执行中";
|
|
|
|
|
AgvItem.refreshtime = DateTime.Now;
|
|
|
|
|
_AGVStateService.UpdateAsync(AgvItem);
|
|
|
|
|
|
|
|
|
|
//更新任务信息表状态为执行中
|
|
|
|
|
AirportTask.amragvno = AgvItem.agvno;
|
|
|
|
|
AirportTask.taskstate = "执行中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(AirportTask);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return iflag;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return iflag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 向DeliverAGV派发任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
private bool CreateAGVTask(AirportTask AirportTask)
|
|
|
|
|
{
|
|
|
|
|
bool iflag = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
iflag = true;
|
|
|
|
|
//获取DeliverAGV设备状态
|
|
|
|
|
List<AGVState> State = _AGVStateService.GetAgvState(AgvType.Deliver);
|
|
|
|
|
foreach (var AgvItem in State)
|
|
|
|
|
{
|
|
|
|
|
//根据规则筛选最优AGV
|
|
|
|
|
if (AgvItem.agvworkstate == "任务空闲")
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"获取空闲AGV列表");
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("执行站台[" + AirportTask.conveyorno + "],下发" + "[" + AirportTask.taskno + "]任务");
|
|
|
|
|
//调用派发任务接口,向任务状态为任务空闲的AGV派发任务
|
|
|
|
|
bool iTaskflag = true;
|
|
|
|
|
if (iTaskflag)
|
|
|
|
|
{
|
|
|
|
|
_RefreshLogMessageAction?.Invoke("[" + AgvItem.agvno + "]AGV,执行任务[" + AirportTask.taskno + "]");
|
|
|
|
|
AgvItem.taskno = AirportTask.taskno;
|
|
|
|
|
AgvItem.agvworkstate = "任务执行中";
|
|
|
|
|
AgvItem.refreshtime = DateTime.Now;
|
|
|
|
|
_AGVStateService.UpdateAsync(AgvItem);
|
|
|
|
|
|
|
|
|
|
//更新任务信息表状态为执行中
|
|
|
|
|
AirportTask.deliveragvno = AgvItem.agvno;
|
|
|
|
|
AirportTask.taskstate = "执行中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(AirportTask);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return iflag;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return iflag;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取任务状态详情
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void GetTaskStateDetail()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
List<AirportTask> Task = _Taskservice.GetAGVTaskInfos();
|
|
|
|
|
if (Task.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
// 设置计时器
|
|
|
|
|
Stopwatch stopwatch = new Stopwatch();
|
|
|
|
|
stopwatch.Start();
|
|
|
|
|
//通过任务编号查询agv任务
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否超过两秒
|
|
|
|
|
if (stopwatch.ElapsedMilliseconds > 2000)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError("超时");
|
|
|
|
|
}
|
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|