AgvController.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. using Microsoft.AspNetCore.Mvc;
  2. using Newtonsoft.Json;
  3. using PlcSiemens.Core.Extension;
  4. using ServiceCenter.Logs;
  5. using ServiceCenter.Redis;
  6. using ServiceCenter.SqlSugars;
  7. using WCS.Core;
  8. using WCS.Entity;
  9. using WCS.Entity.Protocol.Station;
  10. using WCS.WorkEngineering.Extensions;
  11. using WCS.WorkEngineering.Systems;
  12. using WCS.WorkEngineering.WebApi.Models.AGV;
  13. using WCS.WorkEngineering.WebApi.Models.AGV.Request;
  14. using WCS.WorkEngineering.WebApi.Models.AGV.Response;
  15. namespace WCS.WorkEngineering.WebApi.Controllers
  16. {
  17. /// <summary>
  18. /// AGV相关接口控制器
  19. /// </summary>
  20. [ApiController]
  21. [Route("api/[controller]/[action]")]
  22. public class AgvController : ControllerBase
  23. {
  24. /// <summary>
  25. /// AGV任务下发测试
  26. /// </summary>
  27. /// <param name="type">任务类型</param>
  28. /// <param name="code">RFID</param>
  29. /// <param name="pos">目标位置</param>
  30. /// <returns></returns>
  31. [HttpPost]
  32. public string AgvDebug(int type, string code, string pos)
  33. {
  34. try
  35. {
  36. switch (type)
  37. {
  38. case 1:
  39. AgvApi.机台补空(pos, code, "1");
  40. break;
  41. case 2:
  42. //AgvApi.机台补满();
  43. break;
  44. case 3:
  45. AgvApi.满轮入库(code, pos, Guid.NewGuid().ToString().Replace("-", ""), "1");
  46. break;
  47. default:
  48. break;
  49. }
  50. return "成功";
  51. }
  52. catch (Exception ex)
  53. {
  54. return $"Error-----" +
  55. $"{ex.Message}------" +
  56. $"{ex.StackTrace}";
  57. }
  58. }
  59. /// <summary>
  60. /// 背负式agv请求出库任务
  61. /// </summary>
  62. /// <param name="reqDto">请求参数</param>
  63. /// <returns></returns>
  64. [HttpPost]
  65. public ApplyEmptySpoolResponse ApplyEmptySpool([FromBody] AgvFillEmptySpaceRequest reqDto)
  66. {
  67. lock (LockHub.ApplyEmptySpoolLock)
  68. {
  69. LogHub.InterfacePublish(nameof(ApplyEmptySpool), $"传入参数--{JsonConvert.SerializeObject(reqDto)}");
  70. ApplyEmptySpoolResponse agvFill = new ApplyEmptySpoolResponse();
  71. try
  72. {
  73. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  74. if (!World.IsStart)
  75. {
  76. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  77. agvFill.ResMsg = "WCS初始化中";
  78. return agvFill;
  79. }
  80. var obj = World.GetSystemInstance<GetDeviceSystem>().Invoke("输送机") as List<Station>;
  81. // 检测三个站台是否有货
  82. obj = obj.Where(v => v.Entity.Code is "1012" or "1014" or "1016").Where(v => v.Data3.Status.HasFlag(StatusEunm.PH_Status)).ToList();
  83. if (!obj.Any())
  84. {
  85. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  86. agvFill.ResMsg = "无空轮";
  87. return agvFill;
  88. }
  89. SqlSugarHelper.Do(db =>
  90. {
  91. var res = WmsApi.GetTunnelEmptyConCount();
  92. var agvStations = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(tabs => tabs.Take(2))
  93. .Where(v => v.Status < AGVTaskStatus.Complete3 && v.TaskType == AGVTaskType.CallForMaterial).Select(v => v.Station).ToList();
  94. obj = obj.Where(v => !agvStations.Contains(v.Entity.Code)).ToList();
  95. if (!obj.Any())
  96. {
  97. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  98. agvFill.ResMsg = "无可用取货站点";
  99. return;
  100. }
  101. foreach (var item in res.ResDataList)
  102. {
  103. var station = Device.All.Where(v => v.Code == "TY" + item.Tunnel.ToString())
  104. .Select(v => v.Targets).SelectMany(v => v)
  105. .Where(v => v.HasProtocol(typeof(IStation520)))
  106. .Where(v => v.Code is "1012" or "1014" or "1016")
  107. .FirstOrDefault();
  108. item.Tunnel = station.ToInt();
  109. }
  110. var stationNo = res.ResDataList.OrderBy(v => v.Count).Select(v => v.Tunnel.ToString()).ToList();
  111. var dev = obj.MinBy(v => stationNo.IndexOf(v.Entity.Code));
  112. var id = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(v => v.Take(1)).Max(v => v.ID);
  113. var agv = new WCS_AgvTaskInfo()
  114. {
  115. ID = db.GetAGVTaskId(),
  116. TaskType = AGVTaskType.CallForMaterial,
  117. Status = AGVTaskStatus.NewBuild,
  118. Station = dev.Entity.Code,
  119. AddWho = "WCS"
  120. };
  121. //创建对应的AGV任务
  122. db.Default.Insertable(agv).SplitTable().ExecuteCommand();
  123. var task = db.Default.Queryable<WCS_TaskInfo>().First(v => v.ID == dev.Data.TaskNumber) ?? throw new Exception("无有效任务");
  124. task.AgvTaskID = agv.ID;
  125. db.Default.Updateable(task).ExecuteCommand();
  126. agvFill.LocCode = dev.Entity.Code;
  127. agvFill.SpoolType = "4";
  128. agvFill.ResMsg = "";
  129. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.Sucess;
  130. });
  131. }
  132. catch (Exception ex)
  133. {
  134. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  135. agvFill.ResMsg = ex.Message;
  136. }
  137. LogHub.InterfacePublish(nameof(ApplyEmptySpool), $"返回参数{JsonConvert.SerializeObject(agvFill)}");
  138. return agvFill;
  139. }
  140. }
  141. /// <summary>
  142. /// AGV执行回调
  143. /// </summary>
  144. /// <param name="reqDto"></param>
  145. /// <returns></returns>
  146. [HttpPost]
  147. public AgvCallbackResponse AgvCallback([FromBody] AgvCallbackRequest reqDto)
  148. {
  149. lock (LockHub.AgvCallbackLock)
  150. {
  151. LogHub.InterfacePublish(nameof(AgvCallback), $"传入参数--{JsonConvert.SerializeObject(reqDto)}");
  152. var res = new AgvCallbackResponse() { code = AgvResponseCode.Fail, message = "失败" };
  153. WCS_TaskInfo taskInfo = null;
  154. try
  155. {
  156. SqlSugarHelper.Do(db =>
  157. {
  158. //跟据AGVid找到对应的AGV任务
  159. var agvTask = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(tabs => tabs.Take(2)).First(v => v.AgvID == reqDto.taskCode && v.Status < AGVTaskStatus.MissionCompleted);
  160. if (agvTask == null && reqDto.method != "applySecurity")
  161. {
  162. res.code = AgvResponseCode.Fail;
  163. res.message = "未找到对应的AGV任务";
  164. return;
  165. }
  166. switch (reqDto.method)
  167. {
  168. //case "start": //表示请求巷道
  169. // agvTask.Status = AGVTaskStatus.RequestOrPermission1;
  170. // break;
  171. //case "end": //表示请求巷道
  172. // agvTask.Status = AGVTaskStatus.RequestOrPermission1;
  173. // break;
  174. case "applyContinue": //表示请求巷道
  175. agvTask.AgvStatus = AGVTaskStatus.RequestOrPermission1;
  176. break;
  177. case "applySecurity": //表示请求放货或取货
  178. if (reqDto.callCode is "1012" or "1014" or "1016")
  179. {
  180. agvTask = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(tabs => tabs.Take(2))
  181. .First(v => v.Status == AGVTaskStatus.NewBuild && v.TaskType == AGVTaskType.CallForMaterial && v.Station == reqDto.callCode)
  182. ?? throw new Exception("为找找到对应AGV任务");
  183. agvTask.AgvID = reqDto.taskCode;
  184. var obj = World.GetSystemInstance<GetDeviceSystem>().Invoke("输送机") as List<Station>;
  185. var id = obj.FirstOrDefault(v => v.Entity.Code == agvTask.Station).Data.TaskNumber;
  186. taskInfo = db.Default.Queryable<WCS_TaskInfo>().First(v => v.ID == id) ?? throw new Exception("为找找到对应WCS任务");
  187. taskInfo.AgvTaskID = agvTask.ID;
  188. taskInfo.Status = Entity.TaskStatus.AGVExecution;
  189. db.Default.Updateable(taskInfo).ExecuteCommand();
  190. taskInfo.AddWCS_TASK_DTL(db, agvTask.Station, "agv执行中");
  191. }
  192. if (agvTask == null)
  193. {
  194. res.code = AgvResponseCode.Fail;
  195. res.message = "未找到对应的AGV任务";
  196. return;
  197. }
  198. agvTask.AgvStatus = AGVTaskStatus.RequestOrPermission2;
  199. break;
  200. case "hjend_2": //补空任务完成
  201. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  202. break;
  203. case "endhjBM": //取满任务完成
  204. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  205. break;
  206. case "end": //二楼出满任务完成
  207. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  208. break;
  209. case "tcEnd": //机台补空任务完成
  210. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  211. break;
  212. case "exc_end": //异常信息上抛-值不匹配
  213. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  214. break;
  215. case "outbin": //小车退出取货位
  216. agvTask.AgvStatus = AGVTaskStatus.Complete3;
  217. break;
  218. case "cancel": //取消任务
  219. agvTask.AgvStatus = AGVTaskStatus.Cancel;
  220. break;
  221. default:
  222. break;
  223. }
  224. db.Default.Updateable(agvTask).SplitTable().ExecuteCommand();
  225. res.code = AgvResponseCode.Success;
  226. res.message = "成功";
  227. });
  228. }
  229. catch (Exception ex)
  230. {
  231. res.code = AgvResponseCode.Error;
  232. res.message = ex.Message;
  233. }
  234. LogHub.InterfacePublish(nameof(AgvCallback), $"返回结果--{JsonConvert.SerializeObject(res)}");
  235. return res;
  236. }
  237. }
  238. }
  239. /// <summary>
  240. /// AGV相关接口控制器
  241. /// </summary>
  242. [ApiController]
  243. [Route("api/[controller]/[action]")]
  244. public class AgvController : ControllerBase
  245. {
  246. /// <summary>
  247. /// AGV任务下发测试
  248. /// </summary>
  249. /// <param name="type">任务类型</param>
  250. /// <param name="code">RFID</param>
  251. /// <param name="pos">目标位置</param>
  252. /// <returns></returns>
  253. [HttpPost]
  254. public string AgvDebug(int type, string code, string pos)
  255. {
  256. try
  257. {
  258. switch (type)
  259. {
  260. case 1:
  261. AgvApi.机台补空(pos, code, "1");
  262. break;
  263. case 2:
  264. //AgvApi.机台补满();
  265. break;
  266. case 3:
  267. AgvApi.满轮入库(code, pos, Guid.NewGuid().ToString().Replace("-", ""), "1");
  268. break;
  269. default:
  270. break;
  271. }
  272. return "成功";
  273. }
  274. catch (Exception ex)
  275. {
  276. return $"Error-----" +
  277. $"{ex.Message}------" +
  278. $"{ex.StackTrace}";
  279. }
  280. }
  281. /// <summary>
  282. /// 背负式AGV请求出库任务
  283. /// </summary>
  284. /// <param name="reqDto">请求参数</param>
  285. /// <returns></returns>
  286. [HttpPost]
  287. public ApplyEmptySpoolResponse ApplyEmptySpool([FromBody] AgvFillEmptySpaceRequest reqDto)
  288. {
  289. var key = $"WCS:Lock:AGV:{nameof(ApplyEmptySpool)}";
  290. ApplyEmptySpoolResponse agvFill = new ApplyEmptySpoolResponse();
  291. try
  292. {
  293. if (RedisHub.Default.Get(key) != null)
  294. {
  295. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  296. agvFill.ResMsg = $"[{nameof(ApplyEmptySpool)}]--触发并发管控";
  297. }
  298. else
  299. {
  300. RedisHub.Default.Set(key, nameof(ApplyEmptySpool));
  301. LogHub.InterfacePublish(nameof(ApplyEmptySpool), $"传入参数--{JsonConvert.SerializeObject(reqDto)}");
  302. try
  303. {
  304. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  305. if (!World.IsStart)
  306. {
  307. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  308. agvFill.ResMsg = "WCS初始化中";
  309. return agvFill;
  310. }
  311. var obj = World.GetSystemInstance<GetDeviceSystem>().Invoke("输送机") as List<Station>;
  312. // 检测三个站台是否有货
  313. obj = obj.Where(v => v.Entity.Code is "1012" or "1014" or "1016").Where(v => v.Data3.Status.HasFlag(StatusEunm.PH_Status)).ToList();
  314. if (!obj.Any())
  315. {
  316. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  317. agvFill.ResMsg = "无空轮";
  318. return agvFill;
  319. }
  320. SqlSugarHelper.Do(db =>
  321. {
  322. var res = WmsApi.GetTunnelEmptyConCount();
  323. var agvStations = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(tabs => tabs.Take(2))
  324. .Where(v => v.Status < AGVTaskStatus.Complete3 && v.TaskType == AGVTaskType.CallForMaterial).Select(v => v.Station).ToList();
  325. obj = obj.Where(v => !agvStations.Contains(v.Entity.Code)).ToList();
  326. if (!obj.Any())
  327. {
  328. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  329. agvFill.ResMsg = "无可用取货站点";
  330. return;
  331. }
  332. foreach (var item in res.ResDataList)
  333. {
  334. var station = Device.All.Where(v => v.Code == "TY" + item.Tunnel.ToString())
  335. .Select(v => v.Targets).SelectMany(v => v)
  336. .Where(v => v.HasProtocol(typeof(IStation520)))
  337. .Where(v => v.Code is "1012" or "1014" or "1016")
  338. .FirstOrDefault();
  339. item.Tunnel = station.ToInt();
  340. }
  341. var stationNo = res.ResDataList.OrderBy(v => v.Count).Select(v => v.Tunnel.ToString()).ToList();
  342. var dev = obj.MinBy(v => stationNo.IndexOf(v.Entity.Code));
  343. var task = db.Default.Queryable<WCS_TaskInfo>().First(v => v.ID == dev.Data.TaskNumber) ?? throw new Exception("无有效任务");
  344. var id = db.GetAGVTaskId();
  345. var agv = new WCS_AgvTaskInfo()
  346. {
  347. ID = id,
  348. AgvID = $"HJBK{id}{task.ID}",
  349. TaskType = AGVTaskType.CallForMaterial,
  350. Status = AGVTaskStatus.NewBuild,
  351. Station = dev.Entity.Code,
  352. AddWho = "WCS"
  353. };
  354. //创建对应的AGV任务
  355. db.Default.Insertable(agv).SplitTable().ExecuteCommand();
  356. task.AgvTaskID = agv.ID;
  357. task.Status = Entity.TaskStatus.AGVExecution;
  358. db.Default.Updateable(task).ExecuteCommand();
  359. task.AddWCS_TASK_DTL(db, dev.Entity.Code, "AGV", "agv执行中");
  360. agvFill.LocCode = dev.Entity.Code;
  361. agvFill.SpoolType = "4";
  362. agvFill.ResMsg = "";
  363. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.Sucess;
  364. agvFill.TaskCode = agv.AgvID;
  365. });
  366. }
  367. catch (Exception ex)
  368. {
  369. agvFill.ResCode = Models.WMS.Response.ResponseStatusCodeEnum.DataSaveErr;
  370. agvFill.ResMsg = ex.Message;
  371. }
  372. LogHub.InterfacePublish(nameof(ApplyEmptySpool), $"返回参数{JsonConvert.SerializeObject(agvFill)}");
  373. }
  374. }
  375. finally
  376. {
  377. RedisHub.Default.Del(key);
  378. }
  379. return agvFill;
  380. }
  381. /// <summary>
  382. /// AGV执行回调
  383. /// </summary>
  384. /// <param name="reqDto"></param>
  385. /// <returns></returns>
  386. [HttpPost]
  387. public AgvCallbackResponse AgvCallback([FromBody] AgvCallbackRequest reqDto)
  388. {
  389. var key = $"WCS:Lock:AGV:{nameof(AgvCallback)}";
  390. var res = new AgvCallbackResponse() { code = AgvResponseCode.Fail, message = "失败" };
  391. try
  392. {
  393. if (RedisHub.Default.Get(key) != null)
  394. {
  395. res.code = AgvResponseCode.Error;
  396. res.message = $"[{nameof(AgvCallback)}]--触发并发管控";
  397. }
  398. else
  399. {
  400. RedisHub.Default.Set(key, nameof(AgvCallback));
  401. WCS_TaskInfo taskInfo = null;
  402. try
  403. {
  404. SqlSugarHelper.Do(db =>
  405. {
  406. //跟据AGVid找到对应的AGV任务
  407. var agvTask = db.Default.Queryable<WCS_AgvTaskInfo>().SplitTable(tabs => tabs.Take(2)).First(v => v.AgvID == reqDto.taskCode && v.Status < AGVTaskStatus.MissionCompleted);
  408. if (agvTask == null)
  409. {
  410. res.code = AgvResponseCode.Fail;
  411. res.message = "未找到对应的AGV任务";
  412. }
  413. else
  414. {
  415. switch (reqDto.method)
  416. {
  417. //case "start": //表示请求巷道
  418. // agvTask.Status = AGVTaskStatus.RequestOrPermission1;
  419. // break;
  420. //case "end": //表示请求巷道
  421. // agvTask.Status = AGVTaskStatus.RequestOrPermission1;
  422. // break;
  423. case "applyContinue": //表示请求巷道
  424. agvTask.AgvStatus = AGVTaskStatus.RequestOrPermission1;
  425. break;
  426. case "applySecurity": //表示请求放货或取货
  427. agvTask.AgvStatus = AGVTaskStatus.RequestOrPermission2;
  428. break;
  429. case "hjend_2": //补空任务完成
  430. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  431. break;
  432. case "endhjBM": //取满任务完成
  433. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  434. break;
  435. case "end": //二楼出满任务完成
  436. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  437. break;
  438. case "tcEnd": //机台补空任务完成
  439. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  440. break;
  441. case "exc_end": //异常信息上抛-值不匹配
  442. agvTask.AgvStatus = AGVTaskStatus.MissionCompleted;
  443. break;
  444. case "outbin": //小车退出取货位
  445. agvTask.AgvStatus = AGVTaskStatus.Complete3;
  446. break;
  447. case "cancel": //取消任务
  448. //agvTask.AgvStatus = AGVTaskStatus.Cancel;
  449. break;
  450. default:
  451. break;
  452. }
  453. db.Default.Updateable(agvTask).SplitTable().ExecuteCommand();
  454. res.code = AgvResponseCode.Success;
  455. res.message = "成功";
  456. }
  457. });
  458. }
  459. catch (Exception ex)
  460. {
  461. res.code = AgvResponseCode.Error;
  462. res.message = ex.Message;
  463. }
  464. }
  465. }
  466. finally
  467. {
  468. RedisHub.Default.Del(key);
  469. }
  470. return res;
  471. }
  472. }
  473. }