|
|
|
|
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;
|
|
|
|
|
using SlnMesnac.Business.util;
|
|
|
|
|
|
|
|
|
|
namespace SlnMesnac.Business.@base
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 航班任务业务类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class BaseTaskInfoBusiness
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AMR最大运载量
|
|
|
|
|
/// </summary>
|
|
|
|
|
public const int AMRStackNumber = 10;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Deliver最大运载量
|
|
|
|
|
/// </summary>
|
|
|
|
|
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 IVisionSettingService _AGVVisionSettingService;
|
|
|
|
|
private AirPorthttpClient _airPorthttpClient;
|
|
|
|
|
private BaseAGVBusiness _baseAGVBusiness;
|
|
|
|
|
private VisionBusiness _visionBusiness;
|
|
|
|
|
System.Timers.Timer RefreshTimer;
|
|
|
|
|
public BaseTaskInfoBusiness(
|
|
|
|
|
ILogger<BaseTaskInfoBusiness> logger,
|
|
|
|
|
IAirportTaskService Taskservice,
|
|
|
|
|
IAGVStateService agvService,
|
|
|
|
|
IAGVMapPointService aGVMapPointService,
|
|
|
|
|
IAGVJobService agvJobService,
|
|
|
|
|
IVisionSettingService aVisionSettingService,
|
|
|
|
|
TcpServer tcpServer,
|
|
|
|
|
AirPorthttpClient airPorthttpClient,
|
|
|
|
|
BaseAGVBusiness baseAGVBusiness,
|
|
|
|
|
VisionBusiness visionBusiness)
|
|
|
|
|
{
|
|
|
|
|
_logger = logger;
|
|
|
|
|
_tcpServer = tcpServer;
|
|
|
|
|
_Taskservice = Taskservice;
|
|
|
|
|
_AGVStateService = agvService;
|
|
|
|
|
_airPorthttpClient = airPorthttpClient;
|
|
|
|
|
//doWhileGetAGVTaskInfo();
|
|
|
|
|
_baseAGVBusiness = baseAGVBusiness;
|
|
|
|
|
_AGVMapPointService = aGVMapPointService;
|
|
|
|
|
_AGVJobService = agvJobService;
|
|
|
|
|
_AGVVisionSettingService = aVisionSettingService;
|
|
|
|
|
|
|
|
|
|
//新建Timer
|
|
|
|
|
RefreshTimer = new System.Timers.Timer(1000);
|
|
|
|
|
RefreshTimer.Elapsed += (sender, e) =>
|
|
|
|
|
{
|
|
|
|
|
//不清理满载AGV 刷新状态
|
|
|
|
|
//ClearFullAGV();
|
|
|
|
|
RefreshTaskState();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_visionBusiness = visionBusiness;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static BaseTaskInfoBusiness GetInstance(
|
|
|
|
|
ILogger<BaseTaskInfoBusiness> logger,
|
|
|
|
|
IAirportTaskService Taskservice,
|
|
|
|
|
IAGVStateService agvService,
|
|
|
|
|
IAGVMapPointService aGVMapPointService,
|
|
|
|
|
IAGVJobService aAGVJobService,
|
|
|
|
|
IVisionSettingService aVisionSettingService,
|
|
|
|
|
TcpServer tcpServer,
|
|
|
|
|
AirPorthttpClient airPorthttpClient,
|
|
|
|
|
BaseAGVBusiness baseAGVBusiness,
|
|
|
|
|
VisionBusiness visionBusiness)
|
|
|
|
|
{
|
|
|
|
|
if (instance == null)
|
|
|
|
|
{
|
|
|
|
|
instance = new BaseTaskInfoBusiness(logger,
|
|
|
|
|
Taskservice, agvService, aGVMapPointService, aAGVJobService, aVisionSettingService,
|
|
|
|
|
tcpServer, airPorthttpClient, baseAGVBusiness, visionBusiness);
|
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return await _Taskservice.AddTaskAsync(task);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError("航班任务新建失败");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务刷新Timer控制
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="state"></param>
|
|
|
|
|
public void TaskStateUpdateTimerOperation(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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 任务初次派车调度
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AGV调度
|
|
|
|
|
/// Timer刷新任务状态, 有新任务初次下发AGV, Timer执行
|
|
|
|
|
/// </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 == "等待")
|
|
|
|
|
{
|
|
|
|
|
/////////////////////////////////////////////////////// 如果AMR还没分配是空的 /////////////////////////////////////////////////////
|
|
|
|
|
if (string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
// 首先调一辆最优AMR
|
|
|
|
|
AGVState firstAMR = _baseAGVBusiness.GetBestAGV(AgvType.AMR);
|
|
|
|
|
// 有空闲车辆 赋值 准备看看是否需要deliver
|
|
|
|
|
if (firstAMR != null && !string.IsNullOrEmpty(firstAMR.agvno))
|
|
|
|
|
{
|
|
|
|
|
string amrTaskId = _baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(
|
|
|
|
|
firstAMR.agvno,
|
|
|
|
|
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("1000入位", taskItem.conveyorno).JobGuid);
|
|
|
|
|
_logger.LogInformation($"为AMR[ {firstAMR.agvno}]分配任务,目标:[ {taskItem.conveyorno} ]号传送带");
|
|
|
|
|
taskItem.amragvno = firstAMR.agvno;
|
|
|
|
|
taskItem.amragvisarrive = "未到达";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
}
|
|
|
|
|
// 如果没调到AMR直接 goto结束
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"任务 [{taskItem.taskno}] 暂时匹配不到空闲AMR!");
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 需要Deliver和AMR才能装下
|
|
|
|
|
if (taskItem.totalcount > (AMRStackNumber - firstAMR.stackcount))
|
|
|
|
|
{
|
|
|
|
|
// 调一辆最优Deliver
|
|
|
|
|
AGVState firstDeliver = _baseAGVBusiness.GetBestAGV(AgvType.Deliver);
|
|
|
|
|
// 如果有Deliver 赋值 调整状态为派车中
|
|
|
|
|
if (firstDeliver != null && !string.IsNullOrEmpty(firstDeliver.agvno))
|
|
|
|
|
{
|
|
|
|
|
string deliverTaskID = _baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(
|
|
|
|
|
firstDeliver.agvno,
|
|
|
|
|
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入位", taskItem.conveyorno).JobGuid);
|
|
|
|
|
_logger.LogInformation($"为Deliver[ {firstDeliver.agvno} ]分配任务,目标:[ {taskItem.conveyorno} ]号传送带");
|
|
|
|
|
taskItem.deliveragvno = firstDeliver.agvno;
|
|
|
|
|
taskItem.deliveragvisarrive = "未到达";
|
|
|
|
|
taskItem.taskstate = "派车中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
// 如果没调到Deliver直接 goto结束
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"任务 [{taskItem.taskno}] 暂时匹配不到空闲Deliver!");
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 如果不需要直接调整状态为派车 goto结束
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
taskItem.taskstate = "派车中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/////////////////////////////////////////////////////// 如果AMR已分配不是空的 /////////////////////////////////////////////////////
|
|
|
|
|
if (!string.IsNullOrEmpty(taskItem.amragvno))
|
|
|
|
|
{
|
|
|
|
|
AGVState TaskAMR = _AGVStateService.GetSingleAGVState(taskItem.amragvno);
|
|
|
|
|
// 看看是否需要AGV和AMR才能装下
|
|
|
|
|
if (taskItem.totalcount > (AMRStackNumber - TaskAMR.stackcount))
|
|
|
|
|
{
|
|
|
|
|
// 调一辆最优Deliver
|
|
|
|
|
AGVState firstDeliver = _baseAGVBusiness.GetBestAGV(AgvType.Deliver);
|
|
|
|
|
// 如果有Deliver 赋值 调整状态为派车中
|
|
|
|
|
if (firstDeliver != null && !string.IsNullOrEmpty(firstDeliver.agvno))
|
|
|
|
|
{
|
|
|
|
|
string deliverTaskID = _baseAGVBusiness.EndTaskAndClearErrorAndDownloadTask(
|
|
|
|
|
firstDeliver.agvno,
|
|
|
|
|
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入位", taskItem.conveyorno).JobGuid);
|
|
|
|
|
_logger.LogInformation($"为Deliver[ {firstDeliver.agvno} ]分配任务,目标:[ {taskItem.conveyorno} ]号传送带");
|
|
|
|
|
taskItem.deliveragvno = firstDeliver.agvno;
|
|
|
|
|
taskItem.deliveragvisarrive = "未到达";
|
|
|
|
|
taskItem.taskstate = "派车中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
// 匹配不到直接goto
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"任务 [{taskItem.taskno}] 暂时匹配不到空闲Deliver!");
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 不需要Delievr直接改任务状态
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
taskItem.taskstate = "派车中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
goto OUT_POINT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OUT_POINT:; //未分配成功的退出点
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据小车状态更新任务表中AMR是否到达状态,如果到达就改变任务表的状态
|
|
|
|
|
if (!string.IsNullOrEmpty(taskItem.amragvno) && taskItem.amragvisarrive == "未到达")
|
|
|
|
|
{
|
|
|
|
|
AGVState agvstate = _AGVStateService.GetSingleAGVState(taskItem.amragvno);
|
|
|
|
|
if (agvstate.taskstate == "已暂停")
|
|
|
|
|
{
|
|
|
|
|
taskItem.amragvisarrive = "已到达";
|
|
|
|
|
_logger.LogInformation($"[ {taskItem.conveyorno} ]号传送带AMR[ {agvstate.agvno} ]已到达");
|
|
|
|
|
}
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据小车状态更新任务表中Deliver是否到达状态,如果到达就改变任务表的状态
|
|
|
|
|
if (!string.IsNullOrEmpty(taskItem.deliveragvno) && taskItem.deliveragvisarrive == "未到达")
|
|
|
|
|
{
|
|
|
|
|
AGVState agvstate = _AGVStateService.GetSingleAGVState(taskItem.deliveragvno);
|
|
|
|
|
if (agvstate.taskstate == "已暂停")
|
|
|
|
|
{
|
|
|
|
|
taskItem.deliveragvisarrive = "已到达";
|
|
|
|
|
_logger.LogInformation($"[ {taskItem.conveyorno} ]号传送带Deliver[ {agvstate.agvno} ]已到达");
|
|
|
|
|
}
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//查询执行中的任务车辆是否到达,如果指派的车都到达就开始抓取
|
|
|
|
|
if (taskItem.taskstate == "派车中")
|
|
|
|
|
{
|
|
|
|
|
//只有amr的情况
|
|
|
|
|
if (taskItem.amragvisarrive == "已到达" && string.IsNullOrEmpty(taskItem.deliveragvno))
|
|
|
|
|
{
|
|
|
|
|
int amrStackNo = _AGVStateService.GetSingleAGVState(taskItem.amragvno).stackcount;
|
|
|
|
|
//调用机械臂向AMR小车抓取
|
|
|
|
|
_visionBusiness.RequestVisionStartWork(StackState.NXAMRNeedPositioning, amrStackNo, _tcpServer.VID);
|
|
|
|
|
taskItem.taskstate = "抓取中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
_logger.LogInformation($"[ {taskItem.conveyorno} ]号传送带开始工作");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//amr和deliver都用的情况
|
|
|
|
|
if (taskItem.amragvisarrive == "已到达" && taskItem.deliveragvisarrive == "已到达")
|
|
|
|
|
{
|
|
|
|
|
int agvStackNo = _AGVStateService.GetSingleAGVState(taskItem.deliveragvno).stackcount;
|
|
|
|
|
//调用机械臂向Deliver小车抓取
|
|
|
|
|
_visionBusiness.RequestVisionStartWork(StackState.NXAGVNeedPositioning, agvStackNo, _tcpServer.VID);
|
|
|
|
|
taskItem.taskstate = "抓取中";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskItem);
|
|
|
|
|
_logger.LogInformation($"[ {taskItem.conveyorno} ]号传送带开始工作");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError($"查询任务列表初次下发任务发生错误Message:{ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 停止所有任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void StopAllTask()
|
|
|
|
|
{
|
|
|
|
|
List<AirportTask> taskList = _Taskservice.GetTaskInfos(x => x.taskstate == "抓取中" || x.taskstate == "派车中").ToList();
|
|
|
|
|
//任务状态设置为已终止并且机械臂复位
|
|
|
|
|
foreach (var taskInfo in taskList)
|
|
|
|
|
{
|
|
|
|
|
_visionBusiness.RequestVisionReplace(_AGVVisionSettingService.GetVisionSettingByAMRGUID(taskInfo.amragvno).VisionID);
|
|
|
|
|
taskInfo.finishtime = DateTime.Now;
|
|
|
|
|
taskInfo.taskstate = "已终止";
|
|
|
|
|
_Taskservice.UpdateTaskAsync(taskInfo);
|
|
|
|
|
_logger.LogInformation($"任务 [{taskInfo.taskno}] 已终止");
|
|
|
|
|
}
|
|
|
|
|
//agv全部停止
|
|
|
|
|
var responseList = _airPorthttpClient.AGVAllStateRequest();
|
|
|
|
|
if (responseList == null || responseList.count == 0)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation($"连接失败或无小车连接");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
foreach (var response in responseList.Data)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(response.TaskID) && response.AgvMoveStatus != 1 && response.AgvMoveStatus != 3)
|
|
|
|
|
{
|
|
|
|
|
_baseAGVBusiness.EndTaskAndClearError(response.Guid);
|
|
|
|
|
_logger.LogInformation($"小车 [{response.Name}] 任务已终止");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_logger.LogInformation($"全部复位完毕");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|