Files
wcs/WCS.BLL/Manager/AGVManager.cs
hehaibing-1996 cb16700a71 日志完善
2025-03-06 11:28:24 +08:00

618 lines
28 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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)
{
//每5秒同步一次
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", true);
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);
}
}
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", true);
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,
})
.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)
{
var currentLocationId = shelf.CurrentLocationId;
//RCS中有货架储位信息
if (shelfCodesInRcs.Contains(shelf.ShelfCode))
{
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(20000);
}
});
#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())
{
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())
{
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,
}
}