You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

434 lines
15 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Microsoft.Extensions.Logging;
using SlnMesnac.Config;
using SlnMesnac.Model.AirportApiEntity;
using SlnMesnac.Model.domain;
using SlnMesnac.Model.Enum;
using SlnMesnac.Repository;
using SlnMesnac.Repository.service;
using SlnMesnac.TouchSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SlnMesnac.Business.@base
{
/// <summary>
/// AGV业务类
/// </summary>
public class BaseAGVBusiness
{
private ILogger<BaseAGVBusiness> _logger;
private static BaseAGVBusiness instance;
private AppConfig _appConfig;
private AirPorthttpClient _airPorthttpClient;
private IAGVStateService _AGVStateService;
private IAGVMapPointService _AGVMapPointService;
private IAGVJobService _AGVJobService;
private IAGVSettingService _AGVSettingService;
public BaseAGVBusiness(ILogger<BaseAGVBusiness> logger,
AirPorthttpClient airPorthttpClient,
IAGVStateService AGVStateService,
IAGVMapPointService aGVMapPointService,
AppConfig appConfig,
IAGVJobService aGVJobService,
IAGVSettingService aGVSettingService)
{
_logger = logger;
_airPorthttpClient = airPorthttpClient;
_AGVStateService = AGVStateService;
_AGVMapPointService = aGVMapPointService;
_appConfig = appConfig;
_AGVJobService = aGVJobService;
_AGVSettingService = aGVSettingService;
}
public static BaseAGVBusiness GetInstance(ILogger<BaseAGVBusiness> logger,
AirPorthttpClient airPorthttpClient,
IAGVStateService AGVStateService,
IAGVMapPointService aGVMapPointService,
AppConfig appConfig,
IAGVJobService aGVJobService,
IAGVSettingService aGVSettingService
)
{
if (instance == null)
{
instance = new BaseAGVBusiness(logger, airPorthttpClient, AGVStateService, aGVMapPointService, appConfig, aGVJobService, aGVSettingService);
}
return instance;
}
public int AGVConnectState
{
get
{
return _airPorthttpClient.GetConnectState();
}
}
/// <summary>
/// 封装任务类
/// </summary>
/// <param name="AGVGUID"></param>
/// <param name="JobGUID"></param>
/// <param name="PointGUID"></param>
/// <param name="ParamName"></param>
/// <param name="TaskName"></param>
/// <param name="RobotType"></param>
/// <returns></returns>
public AGVRequestAddTaskEntity NewTaskEntity(string AGVGUID, string JobGUID, string PointGUID, string ParamName, string TaskName = "AGVCTask", string RobotType = "S800")
{
AGVRequestAddTaskEntity aGVRequestAddTaskEntity = new AGVRequestAddTaskEntity()
{
businessOrderId = TaskName,
priority = 0,
RobotType = RobotType,
robotId = AGVGUID,
group = "",
taskSource = "agvc",
taskType = 0,
verifyStatus = 0,
enableSplitCar = 0,
load = new List<LoadsEntity>()
{
new LoadsEntity()
{
jobid = JobGUID,
location = PointGUID,
param = new List<ParamEntity>()
{
new ParamEntity()
{
paramname = ParamName,
paramvalue = PointGUID,
}
},
robotPort = ""
}
},
};
return aGVRequestAddTaskEntity;
}
/// <summary>
/// 发送封装的任务类
/// </summary>
/// <returns>任务ID</returns>
public string DownloadTask(string AGVGUID, string JobGUID, string PointGUID, string ParamName, string TaskName = "AGVCTask", string RobotType = "S800")
{
try
{
var result = _airPorthttpClient.AGVAddTaskRequest(NewTaskEntity(AGVGUID, JobGUID, PointGUID, ParamName, TaskName, RobotType));
if (result.code == 0)
{
return result.Data.guid;
}
else
{
_logger.LogError("错误响应:" + result.message);
return string.Empty;
}
}
catch (Exception ex)
{
_logger.LogError($"接口发生错误:{ex.Message}");
return string.Empty;
}
}
/// <summary>
/// 结束指定AGV的任务
/// </summary>
/// <param name="AGVGUID">AGV小车编号</param>
/// <returns></returns>
public bool EndAGVTask(string AGVGUID)
{
try
{
AGVState agvState = _AGVStateService.GetSingleAGVState(AGVGUID);
if (agvState == null)
{
return false;
}
if (agvState.agvworkstate != "待机")
{
var response = _airPorthttpClient.AGVOperationalTaskRequest(new AGVRequestOperationalTaskEntity()
{
taskid = agvState.taskno,
state = 0,
operatingSource = "agvc",
operatingUser = "agvc",
remark = "agvcEnd"
});
if (response.code == 0)
{
_logger.LogInformation($"AGV {agvState.agvno} 任务 {agvState.taskno} 结束成功");
return true;
}
else
{
_logger.LogError($"AGV {agvState.agvno} 任务 {agvState.taskno} 结束失败 ERROR:{response.message}");
return false;
}
}
else if (agvState.agvworkstate == "待机")
{
_logger.LogError($"AGV {agvState.agvno} 现在无任务");
return false;
}
else
{
_logger.LogError($"AGV {agvState.agvno} 终止任务失败!");
return false;
}
}
catch (Exception ex)
{
_logger.LogError($"AGV任务结束失败 ERROR{ex.Message}");
return false;
}
}
/// <summary>
/// 获取活跃地图的点位更新到数据库
/// </summary>
/// <returns></returns>
public bool GetActiveMapPoint()
{
var result = _airPorthttpClient.AGVMapActiveRequest();
if (result == null)
{
_logger.LogError("AGV活跃地图获取返回Null");
return false;
}
if (result.code != 0)
{
_logger.LogError("AGV活跃地图获取错误内容" + result.message);
return false;
}
if (result.Data == null)
{
_logger.LogError("活跃地图获取无数据");
return false;
}
string mapID = result.Data.guid;
var res = _airPorthttpClient.AGVMapPositionRequest(mapID);
if (res == null)
{
_logger.LogError("地图点位获取返回Null");
return false;
}
if (res.code != 0)
{
_logger.LogError($"地图点位获取错误,内容:{res.message}");
}
if (res.Data == null)
{
_logger.LogError("地图点位获取无数据");
return false;
}
List<AGVMapPoint> list = new List<AGVMapPoint>();
foreach (var a in res.Data)
{
list.Add(new AGVMapPoint()
{
MapID = a.mapId,
PointGuid = a.guid,
PointName = a.name,
PointType = a.type.ToString(),
MapName = a.name,
});
}
return _AGVMapPointService.DeleteAndAddAgvMapPoint(list);
}
/// <summary>
/// 结束当前任务 清除报警 下发任务 1s
/// </summary>
/// <param name="agvguid"></param>
/// <param name="jobName"></param>
/// <returns>新任务GUID</returns>
public string EndTaskAndClearErrorAndDownloadTask(string agvguid, string jobGuid)
{
bool result = false;
try
{
//终止小车当前任务
result = EndTaskAndClearError(agvguid);
var param = _AGVJobService.GetAGVJobByJobGuid(jobGuid);
//调用小车到抓取位置
return DownloadTask(agvguid, jobGuid, param.PointGuid, param.PointParamName);
}
catch (Exception ex)
{
_logger.LogError($"结束当前任务清除报警任务下发失败Message:{ex}");
return string.Empty;
}
}
/// <summary>
/// 结束任务并清除报警 延迟1s
/// </summary>
public bool EndTaskAndClearError(string agvguid)
{
bool result1 = false, result2 = false;
try
{
Task.Run(() =>
{
result1 = EndAGVTask(agvguid);
Task.Delay(500);
result2 = ClaerError(agvguid);
});
return result1 && result2;
}
catch (Exception ex)
{
_logger.LogError("结束任务并清除报警发生异常 " + ex);
return false;
}
}
/// <summary>
/// 清除报警 延迟500ms
/// </summary>
public bool ClaerError(string agvguid)
{
bool result = false;
try
{
Task.Run(() =>
{
var response = _airPorthttpClient.AGVErrorClear(_AGVSettingService.GetAgvSettingByAgvGuid(agvguid).AGVNo);
Task.Delay(500);
if (response == null)
{
_logger.LogError("清除报警返回空数据");
result = false;
return false;
}
if (response.code == 0)
{
_logger.LogError("清除报警成功");
result = true;
return true;
}
else
{
_logger.LogError("清除报警失败 message:" + response.message);
result = false;
return false;
}
});
return result;
}
catch (Exception ex)
{
_logger.LogError("清除报警发生异常 " + ex);
return false;
}
}
/// <summary>
/// 筛选一辆空闲且指定类型剩余可用空间最大的AGV, 返回调用的AGVState
/// </summary>
/// <returns></returns>
public AGVState GetBestAGV(AgvType agvType)
{
try
{
//对应类型的待机的agv列表
List<AGVState> lists = _AGVStateService.GetAgvState(agvType).Where(x => x.agvworkstate == "待机").ToList();
if (lists.Count == 0)
{
return null;
}
//找到堆筐最少的agv
int min = lists.Min(x => x.stackcount);
//判断堆筐最少的AGV是不是满的, 如果都满返回null
if (agvType == AgvType.AMR)
{
if (min >= BaseTaskInfoBusiness.AMRStackNumber)
{
_logger.LogInformation("无可用车辆!");
return null;
}
}
else
{
if (min >= BaseTaskInfoBusiness.DeliverStackNumber)
{
_logger.LogInformation("无可用车辆!");
return null;
}
}
AGVState agv = lists.Where(x => x.stackcount == min).FirstOrDefault();
//var list = _AGVStateService
return agv;
}
catch (Exception ex)
{
_logger.LogError($"AGV筛选发生错误{ex.Message}");
return null;
}
}
/// <summary>
/// 入库所有即将满载AGV
/// </summary>
public void ClearFullAGV()
{
try
{
var list = _AGVStateService.GetAgvState(AgvType.Deliver);
foreach (var record in list)
{
if (record.stackcount >= BaseTaskInfoBusiness.DeliverStackNumber - 2 && record.agvworkstate == "待机")
{
//入库代码
EndTaskAndClearErrorAndDownloadTask(record.agvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("800入库", "0").JobGuid);
_AGVStateService.ResetAGVStackCount(record.agvno);
_logger.LogInformation($"Deliver [{record.agvno}] 入库");
}
}
list = _AGVStateService.GetAgvState(AgvType.AMR);
foreach (var record in list)
{
if (record.stackcount >= BaseTaskInfoBusiness.AMRStackNumber - 2 && record.agvworkstate == "待机")
{
//入库代码
EndTaskAndClearErrorAndDownloadTask(record.agvno,
_AGVJobService.GetAGVJobListByTypeAndConveyorNo("1000入库", "0").JobGuid);
_AGVStateService.ResetAGVStackCount(record.agvno);
_logger.LogInformation($"AMR [{record.agvno}] 入库");
}
}
}
catch (Exception ex)
{
_logger.LogError($"清理满载AGV时发生错误Error: [{ex.Message}]");
}
}
/// <summary>
/// 下载AGV模板和点位到数据库
/// </summary>
public bool DownloadAgvJob()
{
List<AGVJob> joblist = new List<AGVJob>();
return false;
}
}
}