637 lines
29 KiB
C#
637 lines
29 KiB
C#
using SqlSugar;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using WCS.BLL.Config;
|
||
using WCS.BLL.DbModels;
|
||
using WCS.BLL.Tool;
|
||
using WCS.DAL.Db;
|
||
using WCS.DAL.DbModels;
|
||
using WCS.Model;
|
||
using WCS.Model.ApiModel.AGV;
|
||
using WCS.Model.ApiModel.InOutRecord;
|
||
using WCS.Model.ApiModel.MXBackgroundThread;
|
||
|
||
namespace WCS.BLL.Manager
|
||
{
|
||
//AGV动作相关
|
||
public static class AGVManager
|
||
{
|
||
public static void InitBackgroundThread()
|
||
{
|
||
#region 定时任务:定时查询任务状态
|
||
Task.Run(() =>
|
||
{
|
||
while (true)
|
||
{
|
||
|
||
//每3秒同步一次
|
||
Thread.Sleep(3000);
|
||
try
|
||
{
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/queryTaskStatus";
|
||
|
||
var tasks = DbHelp.db.Queryable<AgvTask>()
|
||
.Where(t => t.CreateTime > DateTime.Now.AddDays(-7)) //只查询7天内agv任务数据
|
||
.Where(t => t.TaskStatus != TaskStatusEnum.取消完成 && t.TaskStatus != TaskStatusEnum.已结束)
|
||
.OrderBy(t => t.Id)
|
||
.ToList();
|
||
if (tasks != null && tasks.Count > 0)
|
||
{
|
||
Logs.Write("【定时任务】获取任务状态 开始", LogsType.Tasks);
|
||
for (int i = 0; i < tasks.Count; i++)
|
||
{
|
||
try
|
||
{
|
||
//请求RCS获取任务状态
|
||
var data = new AGVQueryTaskStatusRequest();
|
||
data.taskCodes.Add(tasks[i].TaskCode);
|
||
|
||
var result = ApiHelp.GetDataFromHttp<AGVQueryTaskStatusResponse>(url, data, "POST", false);
|
||
if (result != null && result.code == "0" && result.data != null && result.data.Count > 0)
|
||
{
|
||
var isUpdate = false;
|
||
//获取成功 是否与当前任务状态一致 如果不一致 进行更新
|
||
var responseData = result.data.First();
|
||
if (responseData.agvCode != tasks[i].AgvCode)
|
||
{
|
||
isUpdate = true;
|
||
tasks[i].AgvCode = responseData.agvCode;
|
||
}
|
||
if (responseData.taskStatus != tasks[i].TaskStatus.ToString())
|
||
{
|
||
Enum.TryParse<TaskStatusEnum>(responseData.taskStatus, out TaskStatusEnum status);
|
||
isUpdate = true;
|
||
tasks[i].TaskStatus = status;
|
||
|
||
//取消任务时 货架数据需要更新
|
||
if (status == TaskStatusEnum.取消完成)
|
||
{
|
||
var shelf = DbHelp.db.Queryable<ShelfInfo>()
|
||
.Where(t => t.ShelfCode == tasks[i].ShelfCode)
|
||
.Where(t => t.CurrentTaskCode == tasks[i].TaskCode)
|
||
.Where(t => t.DestinationLocationId == tasks[i].EndLocationId)
|
||
.First();
|
||
if (shelf != null)
|
||
{
|
||
shelf.DestinationLocationId = 0;
|
||
shelf.DestinationLocaiotnCode = string.Empty;
|
||
shelf.TransStatus = TransStatusEnum.静止;
|
||
shelf.CurrentTaskCode = string.Empty;
|
||
DbHelp.db.Updateable(shelf).ExecuteCommand();
|
||
}
|
||
}
|
||
|
||
}
|
||
if (isUpdate)
|
||
{
|
||
tasks[i].ModifyTime = DateTime.Now;
|
||
if (tasks[i].TaskStatus != TaskStatusEnum.已创建 && tasks[i].TaskStatus != TaskStatusEnum.正在执行)
|
||
{
|
||
tasks[i].AgvStatus = "-";
|
||
}
|
||
DbHelp.db.Updateable(tasks[i]).ExecuteCommand();
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write("【定时任务】获取任务状态异常:" + ex.Message, LogsType.Tasks);
|
||
}
|
||
Thread.Sleep(50);
|
||
}
|
||
Logs.Write("【定时任务】获取任务状态 结束", LogsType.Tasks);
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write("【定时任务】获取任务状态异常:" + ex.Message, LogsType.Tasks);
|
||
}
|
||
}
|
||
});
|
||
#endregion
|
||
|
||
#region 定时任务:定时同步货架绑定情况
|
||
Task.Run(() =>
|
||
{
|
||
while (true)
|
||
{
|
||
Logs.Write("【定时任务】定时同步货架绑定情况,开始", LogsType.Tasks);
|
||
try
|
||
{
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/syncMapDatas";
|
||
var data = new AGVSyncMapDatasRequest();
|
||
var result = ApiHelp.GetDataFromHttp<AGVSyncMapDatasResponse>(url, data, "POST", false);
|
||
if (result != null && result.data != null && result.data.Count > 0)
|
||
{
|
||
//获取RCS地图上所有的货架
|
||
var rcsDatas = result.data.Where(t => !string.IsNullOrEmpty(t.podCode))
|
||
.Select(t => new
|
||
{
|
||
ShelfCode = t.podCode,
|
||
LocationCode = t.positionCode.Contains("XY") ? t.positionCode : t.mapDataCode,
|
||
})
|
||
.Distinct()
|
||
.ToList();
|
||
var shelfCodesInRcs = rcsDatas.Select(t => t.ShelfCode).Distinct().ToList();
|
||
var locationCodeInRcs = rcsDatas.Select(t => t.LocationCode).Distinct().ToList();
|
||
|
||
//获取位置
|
||
var Locations = DbHelp.db.Queryable<LocationInfo>()
|
||
.Where(t => locationCodeInRcs.Contains(t.LocationCode))
|
||
.ToList();
|
||
|
||
//更新货架的信息
|
||
var shelfs = DbHelp.db.Queryable<ShelfInfo>()
|
||
.Where(t => t.TransStatus == TransStatusEnum.静止)
|
||
.ToList();
|
||
|
||
foreach (var shelf in shelfs)
|
||
{
|
||
//if (shelf.ShelfCode == "600132")
|
||
// ;
|
||
var currentLocationId = shelf.CurrentLocationId;
|
||
|
||
//RCS中有货架储位信息
|
||
if (shelfCodesInRcs.Contains(shelf.ShelfCode))
|
||
{
|
||
//var data1 = result.data.Where(t => t.podCode == "600132").First();
|
||
var rcsData = rcsDatas.Where(t => t.ShelfCode == shelf.ShelfCode).FirstOrDefault();
|
||
if (rcsData == null)
|
||
{
|
||
//此情况先按兵不动
|
||
continue;
|
||
}
|
||
var location = Locations.Where(t => t.LocationCode == rcsData.LocationCode).FirstOrDefault();
|
||
//货架绑定在我系统中未配置的点位上
|
||
if (location == null)
|
||
{
|
||
shelf.CurrentLocationId = 0;
|
||
shelf.CurrentLocaiotnCode = string.Empty;
|
||
}
|
||
//货架绑定在系统中已配置的点位上
|
||
else
|
||
{
|
||
shelf.CurrentLocationId = location.Id;
|
||
shelf.CurrentLocaiotnCode = location.LocationCode;
|
||
}
|
||
}
|
||
//RCS中没有货架储位的信息
|
||
else
|
||
{
|
||
shelf.CurrentLocationId = 0;
|
||
shelf.CurrentLocaiotnCode = string.Empty;
|
||
}
|
||
//只更新产生变化的 缩小更新范围
|
||
if (currentLocationId != shelf.CurrentLocationId)
|
||
{
|
||
shelf.IsSelected = true;
|
||
}
|
||
}
|
||
shelfs = shelfs.Where(t => t.IsSelected).ToList();
|
||
|
||
if (shelfs != null && shelfs.Count > 0)
|
||
{
|
||
Logs.Write($"【定时任务】定时同步货架绑定情况,更新{shelfs.Count}个货架", LogsType.Tasks);
|
||
DbHelp.db.Updateable(shelfs)
|
||
.UpdateColumns(t => new { t.CurrentLocationId, t.CurrentLocaiotnCode })
|
||
//.Where(t => t.TransStatus == TransStatusEnum.静止)
|
||
.ExecuteCommand();
|
||
}
|
||
Logs.Write($"【定时任务】定时同步货架绑定情况,更新0个货架", LogsType.Tasks);
|
||
}
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write("【定时任务】定时同步货架绑定情况异常:" + ex.Message, LogsType.Tasks);
|
||
}
|
||
Logs.Write("【定时任务】定时同步货架绑定情况,结束", LogsType.Tasks);
|
||
//每60秒同步一次
|
||
Thread.Sleep(LocalFile.Config.SyncMapDatasIntervalTime);
|
||
}
|
||
});
|
||
#endregion
|
||
}
|
||
|
||
public static object lockFlag = new object();
|
||
/// <summary>
|
||
/// 产生AGV点到点搬运任务
|
||
/// </summary>
|
||
public static AGVResponseModel GenAgvSchedulingTask(LocationInfo startLocation, LocationInfo endLocation, string shelfCode, string createUser)
|
||
{
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/genAgvSchedulingTask";
|
||
var startPositionCodePathItem = new PositionCodePathItem()
|
||
{
|
||
positionCode = startLocation.RcsStoreCode,
|
||
};
|
||
var endPositionCodePathItem = new PositionCodePathItem()
|
||
{
|
||
positionCode = endLocation.RcsStoreCode,
|
||
};
|
||
List<PositionCodePathItem> positionCodePathItems = new List<PositionCodePathItem>();
|
||
|
||
positionCodePathItems.Add(startPositionCodePathItem);
|
||
positionCodePathItems.Add((endPositionCodePathItem));
|
||
|
||
//任务只允许一个一个发送
|
||
lock (lockFlag)
|
||
{
|
||
//正在执行中的任务
|
||
var tasks = DbHelp.db.Queryable<AgvTask>()
|
||
.Where(t => t.TaskStatus == TaskStatusEnum.已创建 || t.TaskStatus == TaskStatusEnum.正在执行)
|
||
.ToList();
|
||
//校验货架
|
||
if (tasks.Where(t => t.ShelfCode == shelfCode).Any())
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"货架[{shelfCode}]已有执行中的任务!",
|
||
};
|
||
}
|
||
//校验起点
|
||
if (tasks.Where(t => t.StratLocationId == startLocation.Id).Any())
|
||
{
|
||
//相同货架
|
||
var isSameShelf = tasks.Where(t => t.StratLocationId == startLocation.Id && t.ShelfCode == shelfCode)
|
||
.Any();
|
||
if (isSameShelf)
|
||
{
|
||
//获取对应任务
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"工位[{startLocation.LocationCode}]作为起点已有执行中的任务!",
|
||
};
|
||
}
|
||
}
|
||
//校验终点
|
||
if (tasks.Where(t => t.EndLocationId == endLocation.Id).Any())
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"工位[{endLocation.LocationCode}]作为终点已有执行中的任务!",
|
||
};
|
||
}
|
||
|
||
var body = new GenAgvSchedulingTaskRequest()
|
||
{
|
||
positionCodePath = positionCodePathItems,
|
||
};
|
||
var response = ApiHelp.GetDataFromHttp<AGVResponseModel>(url, body, "POST", true);
|
||
if (response.code == "0" && response.message == "成功")
|
||
{
|
||
//生成任务数据
|
||
var task = new AgvTask()
|
||
{
|
||
ShelfCode = shelfCode,
|
||
RequestCode = body.reqCode,
|
||
TaskCode = body.taskCode,
|
||
TaskType = "GenAgvSchedulingTask",
|
||
StratLocationId = startLocation.Id,
|
||
StartLocationCode = startLocation.LocationCode,
|
||
EndLocationId = endLocation.Id,
|
||
EndLocationCode = endLocation.LocationCode,
|
||
CreateUser = createUser
|
||
};
|
||
DbHelp.db.Insertable(task).ExecuteCommand();
|
||
}
|
||
|
||
return response;
|
||
}
|
||
}
|
||
|
||
public static AGVResponseModel GenAgvSchedulingTaskForResend(LocationInfo startLocation, LocationInfo endLocation, AgvTask agvTask, string shelfCode, string createUser)
|
||
{
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/genAgvSchedulingTask";
|
||
var startPositionCodePathItem = new PositionCodePathItem()
|
||
{
|
||
positionCode = startLocation.RcsStoreCode,
|
||
};
|
||
var endPositionCodePathItem = new PositionCodePathItem()
|
||
{
|
||
positionCode = endLocation.RcsStoreCode,
|
||
};
|
||
List<PositionCodePathItem> positionCodePathItems = new List<PositionCodePathItem>();
|
||
|
||
positionCodePathItems.Add(startPositionCodePathItem);
|
||
positionCodePathItems.Add((endPositionCodePathItem));
|
||
|
||
//任务只允许一个一个发送
|
||
lock (lockFlag)
|
||
{
|
||
//正在执行中的任务
|
||
var tasks = DbHelp.db.Queryable<AgvTask>()
|
||
.Where(t => t.TaskStatus == TaskStatusEnum.已创建 || t.TaskStatus == TaskStatusEnum.正在执行)
|
||
.ToList();
|
||
//校验货架
|
||
if (tasks.Where(t => t.ShelfCode == shelfCode).Any())
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"货架[{shelfCode}]已有执行中的任务!",
|
||
};
|
||
}
|
||
//校验起点
|
||
if (tasks.Where(t => t.StratLocationId == startLocation.Id).Any())
|
||
{
|
||
//相同货架
|
||
var isSameShelf = tasks.Where(t => t.StratLocationId == startLocation.Id && t.ShelfCode == shelfCode)
|
||
.Any();
|
||
if (isSameShelf)
|
||
{
|
||
//获取对应任务
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"工位[{startLocation.LocationCode}]作为起点已有执行中的任务!",
|
||
};
|
||
}
|
||
}
|
||
//校验终点
|
||
if (tasks.Where(t => t.EndLocationId == endLocation.Id).Any())
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-999",
|
||
message = $"工位[{endLocation.LocationCode}]作为终点已有执行中的任务!",
|
||
};
|
||
}
|
||
|
||
agvTask.TaskCode = agvTask.TaskCode + "_resend";
|
||
agvTask.CreateTime = DateTime.Now;
|
||
agvTask.CreateUser = createUser;
|
||
|
||
var body = new GenAgvSchedulingTaskRequest()
|
||
{
|
||
taskCode = agvTask.TaskCode,
|
||
positionCodePath = positionCodePathItems,
|
||
};
|
||
var response = ApiHelp.GetDataFromHttp<AGVResponseModel>(url, body, "POST", true);
|
||
if (response.code == "0" && response.message == "成功")
|
||
{
|
||
//DbHelp.db.Updateable(agvTask).ExecuteCommand();
|
||
//生成任务数据
|
||
var task = new AgvTask()
|
||
{
|
||
ShelfCode = shelfCode,
|
||
RequestCode = body.reqCode,
|
||
TaskCode = agvTask.TaskCode,
|
||
TaskType = "GenAgvSchedulingTask",
|
||
StratLocationId = startLocation.Id,
|
||
StartLocationCode = startLocation.LocationCode,
|
||
EndLocationId = endLocation.Id,
|
||
EndLocationCode = endLocation.LocationCode,
|
||
CreateUser = createUser
|
||
};
|
||
DbHelp.db.Insertable(task).ExecuteCommand();
|
||
}
|
||
|
||
return response;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// RCS取消任务
|
||
/// </summary>
|
||
/// <param name="agvTask"></param>
|
||
/// <returns></returns>
|
||
public static AGVResponseModel CancelTask(AgvTask agvTask)
|
||
{
|
||
try
|
||
{
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/cancelTask";
|
||
|
||
//任务只允许一个一个发送
|
||
lock (lockFlag)
|
||
{
|
||
var body = new AGVCancelTaskRequest()
|
||
{
|
||
taskCode = agvTask.TaskCode,
|
||
};
|
||
|
||
var response = ApiHelp.GetDataFromHttp<AGVResponseModel>(url, body, "POST", true);
|
||
if (response.code == "0" && response.message == "成功")
|
||
{
|
||
//取消会统一在后台线程更新
|
||
|
||
//agvTask.TaskStatus = Model.ApiModel.AGV.TaskStatusEnum.取消完成;
|
||
//DbHelp.db.Updateable(agvTask).ExecuteCommand();
|
||
}
|
||
return response;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-1",
|
||
message = $"发生异常:{ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// RCS货架绑定 解绑
|
||
/// </summary>
|
||
/// <param name="agvTask"></param>
|
||
/// <returns></returns>
|
||
public static AGVResponseModel BindPodAndBerth(string shelfCode, string locationCode, BindPodAndBerthMethod bindPodAndBerthMethod)
|
||
{
|
||
try
|
||
{
|
||
//货架绑定解绑地址
|
||
var url = @"http://192.168.18.150:8181/rcms/services/rest/hikRpcService/bindPodAndBerth";
|
||
|
||
//任务只允许一个一个发送
|
||
lock (lockFlag)
|
||
{
|
||
var body = new AGVBindPodAndBerthRequest()
|
||
{
|
||
podCode = shelfCode,
|
||
positionCode = locationCode,
|
||
pointCode = locationCode,
|
||
indBind = ((int)bindPodAndBerthMethod).ToString(),
|
||
};
|
||
var response = ApiHelp.GetDataFromHttp<AGVResponseModel>(url, body, "POST", true);
|
||
//if (response.code == "0" && response.message == "成功")
|
||
//{
|
||
|
||
//}
|
||
return response;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new AGVResponseModel()
|
||
{
|
||
code = "-1",
|
||
message = $"发生异常:{ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
public static void RefreshAgvStatus()
|
||
{
|
||
try
|
||
{
|
||
Logs.Write("[刷新AGV状态]开始刷新AGV状态");
|
||
var url = @"http://192.168.18.150:8181/rcms-dps/rest/queryAgvStatus";
|
||
var body = new AGVQueryAgvStatusRequest();
|
||
var response = ApiHelp.GetDataFromHttpShortTime<AGVQueryAgvStatusResponse>(url, body, "POST", true);
|
||
if (response == null)
|
||
{
|
||
Logs.Write("[刷新AGV状态]Response为空!");
|
||
return;
|
||
}
|
||
//response不为空 更新task表的状态
|
||
var tasks = DbHelp.db.Queryable<AgvTask>()
|
||
.Where(t => t.TaskStatus == TaskStatusEnum.已创建 || t.TaskStatus == TaskStatusEnum.正在执行)
|
||
.ToList();
|
||
if (tasks == null || tasks.Count == 0)
|
||
{
|
||
Logs.Write("[刷新AGV状态]状态为执行中或者已创建的任务为空!");
|
||
}
|
||
foreach (var task in tasks)
|
||
{
|
||
var agvCode = task.AgvCode;
|
||
if (string.IsNullOrEmpty(agvCode))
|
||
{
|
||
continue;
|
||
}
|
||
var dataItem = response?.data.Where(t => t.robotCode == agvCode).FirstOrDefault();
|
||
if (dataItem == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var str = string.Empty;
|
||
switch (dataItem.status)
|
||
{
|
||
case "1":
|
||
str = "任务完成";
|
||
break;
|
||
case "2":
|
||
str = "任务执行中";
|
||
break;
|
||
case "3":
|
||
str = "任务异常";
|
||
break;
|
||
case "4":
|
||
str = "任务空闲";
|
||
break;
|
||
case "5":
|
||
str = "机器人暂停";
|
||
break;
|
||
case "6":
|
||
str = "举升货架状态";
|
||
break;
|
||
case "7":
|
||
str = "充电状态";
|
||
break;
|
||
case "8":
|
||
str = "弧线行走中";
|
||
break;
|
||
case "9":
|
||
str = "充满维护";
|
||
break;
|
||
case "11":
|
||
str = "背货未识别";
|
||
break;
|
||
case "12":
|
||
str = "货架偏角过大";
|
||
break;
|
||
case "13":
|
||
str = "运动库异常";
|
||
break;
|
||
case "14":
|
||
str = "货码无法识别";
|
||
break;
|
||
case "15":
|
||
str = "货码不匹配";
|
||
break;
|
||
case "16":
|
||
str = "举升异常";
|
||
break;
|
||
case "17":
|
||
str = "充电桩异常";
|
||
break;
|
||
case "18":
|
||
str = "电量无增加";
|
||
break;
|
||
case "20":
|
||
str = "充电指令角度错误";
|
||
break;
|
||
case "21":
|
||
str = "平台下发指令错误";
|
||
break;
|
||
case "23":
|
||
str = "外力下放";
|
||
break;
|
||
case "24":
|
||
str = "货架位置偏移";
|
||
break;
|
||
case "25":
|
||
str = "小车不在锁定区";
|
||
break;
|
||
case "26":
|
||
str = "下放重试失败";
|
||
break;
|
||
case "27":
|
||
str = "货架摆歪";
|
||
break;
|
||
case "28":
|
||
str = "举升电池电量太低";
|
||
break;
|
||
case "29":
|
||
str = "后退角度偏大";
|
||
break;
|
||
case "30":
|
||
str = "未背货架举升";
|
||
break;
|
||
case "31":
|
||
str = "区域锁定失败";
|
||
break;
|
||
case "33":
|
||
str = "旋转申请暂时失败";
|
||
break;
|
||
case "34":
|
||
str = "地图切换点地码未识别";
|
||
break;
|
||
default:
|
||
str = "未知状态";
|
||
break;
|
||
}
|
||
//更新状态
|
||
task.AgvStatus = str;
|
||
}
|
||
DbHelp.db.Updateable(tasks).UpdateColumns(t => new { t.AgvStatus }).ExecuteCommand();
|
||
Logs.Write("[刷新AGV状态]结束刷新AGV状态");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logs.Write($"[刷新AGV状态]遇到异常{ex.Message}\r\n{ex.StackTrace}");
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解绑或者绑定
|
||
/// </summary>
|
||
public enum BindPodAndBerthMethod
|
||
{
|
||
解绑 = 0,
|
||
绑定 = 1,
|
||
}
|
||
}
|