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.

366 lines
13 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;
public BaseAGVBusiness(ILogger<BaseAGVBusiness> logger,
AirPorthttpClient airPorthttpClient,
IAGVStateService AGVStateService,
IAGVMapPointService aGVMapPointService,
AppConfig appConfig)
{
_logger = logger;
_airPorthttpClient = airPorthttpClient;
_AGVStateService = AGVStateService;
_AGVMapPointService = aGVMapPointService;
_appConfig = appConfig;
}
public static BaseAGVBusiness GetInstance(ILogger<BaseAGVBusiness> logger,
AirPorthttpClient airPorthttpClient,
IAGVStateService AGVStateService,
IAGVMapPointService aGVMapPointService,
AppConfig appConfig)
{
if (instance == null)
{
instance = new BaseAGVBusiness(logger, airPorthttpClient, AGVStateService, aGVMapPointService, appConfig);
}
return instance;
}
/// <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 jobName)
{
bool result = false;
try
{
//终止小车当前任务
result = EndTaskAndClearError(agvguid);
var param = _appConfig.JobConfig.Where(x => x.JobName == jobName).First();
//调用小车到抓取位置
return DownloadTask(agvguid, param.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(_appConfig.AGVConfig.Where(x => x.AGVGUID == agvguid).First().AGVIp);
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)
{
return null;
}
}
else
{
if (min >= BaseTaskInfoBusiness.DeliverStackNumber)
{
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;
}
}
}
}