|
|
|
|
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>
|
|
|
|
|
/// 结束当前任务 清除报警 下发任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="agvName"></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)
|
|
|
|
|
{
|
|
|
|
|
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, 返回GUID
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public AGVState GetBestAGV(AgvType agvType)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
List<AGVState> lists = _AGVStateService.GetAgvState(agvType).Where(x => x.agvworkstate == "待机").ToList();
|
|
|
|
|
AGVState agv = lists.Where(x => x.stackcount == lists.Min(x => x.stackcount)).FirstOrDefault();
|
|
|
|
|
//var list = _AGVStateService
|
|
|
|
|
return agv;
|
|
|
|
|
}
|
|
|
|
|
catch(Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogError($"AGV筛选发生错误:{ex.Message}");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// AGV任务状态代码匹配
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="no"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static string AGVTaskStatusSelect(int no)
|
|
|
|
|
{
|
|
|
|
|
switch (no)
|
|
|
|
|
{
|
|
|
|
|
case 0: return "已终止";
|
|
|
|
|
case 1: return "待执行";
|
|
|
|
|
case 2: return "正在执行";
|
|
|
|
|
case 3: return "已完成";
|
|
|
|
|
case 4: return "已取消";
|
|
|
|
|
case 5: return "已暂停";
|
|
|
|
|
case 6: return "匹配中";
|
|
|
|
|
case 7: return "核验中";
|
|
|
|
|
default: return "未知代码";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|